1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-31 05:40:03 -04:00

Some more work on making possible to render viewport_sync in glutin

Context::current_rendering_viewport was replaced by Context::get_viewport_id
Added Context::get_parent_viewport_id
Changed Context::run to need parent_viewport_id
Changed Context::beagin to need parent_viewport_id
Added ImplContext::frame_stack
Some work on making posibile to render multiples frames at the same time
A lot of more things in glutin backend is not Arc<RwLock<T>>
This commit is contained in:
Konkitoman
2023-08-02 17:14:31 +03:00
parent c7c9713bf8
commit 34fea8a0e5
9 changed files with 248 additions and 124 deletions

View File

@@ -515,10 +515,12 @@ impl EpiIntegration {
self.frame.info.parent_viewport = parent_id; self.frame.info.parent_viewport = parent_id;
// Run user code: // Run user code:
let full_output = self.egui_ctx.run(raw_input, viewport_id, |egui_ctx| { let full_output = self
crate::profile_scope!("App::update"); .egui_ctx
app.update(egui_ctx, &mut self.frame, render.as_ref().map(|r| &***r)); .run(raw_input, viewport_id, parent_id, |egui_ctx| {
}); crate::profile_scope!("App::update");
app.update(egui_ctx, &mut self.frame, render.as_ref().map(|r| &***r));
});
self.pending_full_output.append(full_output); self.pending_full_output.append(full_output);
let full_output = std::mem::take(&mut self.pending_full_output); let full_output = std::mem::take(&mut self.pending_full_output);

View File

@@ -450,9 +450,9 @@ mod glow_integration {
/// initialized once the application has an associated `SurfaceView`. /// initialized once the application has an associated `SurfaceView`.
struct GlowWinitRunning { struct GlowWinitRunning {
gl: Arc<glow::Context>, gl: Arc<glow::Context>,
painter: egui_glow::Painter, painter: Arc<RwLock<egui_glow::Painter>>,
integration: Arc<RwLock<epi_integration::EpiIntegration>>, integration: Arc<RwLock<epi_integration::EpiIntegration>>,
app: Box<dyn epi::App>, app: Arc<RwLock<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.
glutin_ctx: Arc<RwLock<GlutinWindowContext>>, glutin_ctx: Arc<RwLock<GlutinWindowContext>>,
@@ -491,6 +491,9 @@ mod glow_integration {
window_maps: HashMap<winit::window::WindowId, u64>, window_maps: HashMap<winit::window::WindowId, u64>,
} }
unsafe impl Sync for GlutinWindowContext {}
unsafe impl Send for GlutinWindowContext {}
impl GlutinWindowContext { impl GlutinWindowContext {
/// There is a lot of complexity with opengl creation, so prefer extensive logging to get all the help we can to debug issues. /// There is a lot of complexity with opengl creation, so prefer extensive logging to get all the help we can to debug issues.
/// ///
@@ -962,12 +965,82 @@ mod glow_integration {
} }
} }
let glutin_ctx = Arc::new(RwLock::new(gl_window));
let egui_ctx = integration.egui_ctx.clone();
let glutin = glutin_ctx.clone();
let _gl = gl.clone();
let painter = Arc::new(RwLock::new(painter));
let _painter = painter.clone();
integration.egui_ctx.set_render_sync_callback(
move |viewport_builder, viewport_id, parent_viewport_id, render| {
let window = glutin.read().windows.get(&viewport_id).cloned();
if let Some(window) = window {
let window = &mut *window.write();
if let Some(winit_state) = &mut window.egui_winit {
if let Some(win) = window.window.clone() {
println!("Render beagin!");
let win = win.read();
let input = winit_state.take_egui_input(&win);
let output =
egui_ctx.run(input, viewport_id, parent_viewport_id, |ctx| {
render(&egui_ctx, viewport_id, parent_viewport_id);
});
let glutin = &mut *glutin.write();
glutin.current_gl_context = Some(
glutin
.current_gl_context
.take()
.unwrap()
.make_not_current()
.unwrap()
.make_current(window.gl_surface.as_ref().unwrap())
.unwrap(),
);
let screen_size_in_pixels: [u32; 2] = win.inner_size().into();
egui_glow::painter::clear(
&_gl,
screen_size_in_pixels,
[0.0, 0.0, 0.0, 0.0],
);
let clipped_primitives = egui_ctx.tessellate(output.shapes);
_painter.write().paint_and_update_textures(
screen_size_in_pixels,
egui_ctx.pixels_per_point(),
&clipped_primitives,
&output.textures_delta,
);
unsafe {
crate::profile_scope!("swap_buffers");
let _ = window
.gl_surface
.as_ref()
.expect("failed to get surface to swap buffers")
.swap_buffers(glutin.current_gl_context.as_ref().expect(
"failed to get current context to swap buffers",
));
}
println!("Should render sync");
return;
}
}
}
render(&egui_ctx, 0, 0);
},
);
*self.running.write() = Some(GlowWinitRunning { *self.running.write() = Some(GlowWinitRunning {
glutin_ctx: Arc::new(RwLock::new(gl_window)), glutin_ctx,
gl, gl,
painter, painter,
integration: Arc::new(RwLock::new(integration)), integration: Arc::new(RwLock::new(integration)),
app, app: Arc::new(RwLock::new(app)),
}); });
Ok(()) Ok(())
@@ -1033,7 +1106,7 @@ mod glow_integration {
fn save_and_destroy(&mut self) { fn save_and_destroy(&mut self) {
if let Some(mut running) = self.running.write().take() { if let Some(mut running) = self.running.write().take() {
running.integration.write().save( running.integration.write().save(
running.app.as_mut(), running.app.write().as_mut(),
&running &running
.glutin_ctx .glutin_ctx
.read() .read()
@@ -1044,8 +1117,8 @@ mod glow_integration {
.unwrap() .unwrap()
.read(), .read(),
); );
running.app.on_exit(Some(&running.gl)); running.app.write().on_exit(Some(&running.gl));
running.painter.destroy(); running.painter.write().destroy();
} }
} }
@@ -1059,17 +1132,15 @@ mod glow_integration {
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 running = self.running.clone();
let GlowWinitRunning {
glutin_ctx: gl_window, let integration = self.running.read().as_ref().unwrap().integration.clone();
gl, let app = self.running.read().as_ref().unwrap().app.clone();
app, let glutin_ctx = self.running.read().as_ref().unwrap().glutin_ctx.clone();
integration, let painter = self.running.read().as_ref().unwrap().painter.clone();
painter,
} = running.as_mut().unwrap();
let mut window_map = HashMap::default(); let mut window_map = HashMap::default();
for (id, window) in gl_window.read().windows.iter() { for (id, window) in glutin_ctx.read().windows.iter() {
if let Some(win) = &window.read().window { if let Some(win) = &window.read().window {
window_map.insert(*id, win.read().id()); window_map.insert(*id, win.read().id());
} }
@@ -1087,21 +1158,8 @@ 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 = gl_window.read().windows.get(&viewport_id).cloned(); let win = glutin_ctx.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
.take()
.unwrap()
.make_not_current()
.unwrap()
.make_current(win.read().gl_surface.as_ref().unwrap())
.unwrap(),
);
};
let screen_size_in_pixels: [u32; 2] = win let screen_size_in_pixels: [u32; 2] = win
.read() .read()
@@ -1112,18 +1170,6 @@ mod glow_integration {
.inner_size() .inner_size()
.into(); .into();
win.write()
.window
.as_ref()
.unwrap()
.read()
.set_transparent(true);
egui_glow::painter::clear(
gl,
screen_size_in_pixels,
app.clear_color(&integration.read().egui_ctx.style().visuals),
);
{ {
let win = &mut *win.write(); let win = &mut *win.write();
egui::FullOutput { egui::FullOutput {
@@ -1134,7 +1180,7 @@ mod glow_integration {
viewports, viewports,
viewport_commands, viewport_commands,
} = integration.write().update( } = integration.write().update(
app.as_mut(), app.write().as_mut(),
&win.window.as_ref().unwrap().read(), &win.window.as_ref().unwrap().read(),
win.egui_winit.as_mut().unwrap(), win.egui_winit.as_mut().unwrap(),
win.render.clone(), win.render.clone(),
@@ -1148,12 +1194,35 @@ mod glow_integration {
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.read().egui_ctx.tessellate(shapes) integration.read().egui_ctx.tessellate(shapes)
}; };
{
let mut gl_window = glutin_ctx.write();
gl_window.current_gl_context = Some(
gl_window
.current_gl_context
.take()
.unwrap()
.make_not_current()
.unwrap()
.make_current(win.read().gl_surface.as_ref().unwrap())
.unwrap(),
);
};
painter.paint_and_update_textures( let gl = self.running.read().as_ref().unwrap().gl.clone();
egui_glow::painter::clear(
&gl,
screen_size_in_pixels,
app.read()
.clear_color(&integration.read().egui_ctx.style().visuals),
);
painter.write().paint_and_update_textures(
screen_size_in_pixels, screen_size_in_pixels,
integration.read().egui_ctx.pixels_per_point(), integration.read().egui_ctx.pixels_per_point(),
&clipped_primitives, &clipped_primitives,
@@ -1167,12 +1236,12 @@ mod glow_integration {
if *screenshot_requested { if *screenshot_requested {
*screenshot_requested = false; *screenshot_requested = false;
let screenshot = painter.read_screen_rgba(screen_size_in_pixels); let screenshot = painter.read().read_screen_rgba(screen_size_in_pixels);
integration.frame.screenshot.set(Some(screenshot)); integration.frame.screenshot.set(Some(screenshot));
} }
integration.post_rendering( integration.post_rendering(
app.as_mut(), app.write().as_mut(),
&win.read().window.as_ref().unwrap().read(), &win.read().window.as_ref().unwrap().read(),
); );
} }
@@ -1185,7 +1254,7 @@ mod glow_integration {
.as_ref() .as_ref()
.expect("failed to get surface to swap buffers") .expect("failed to get surface to swap buffers")
.swap_buffers( .swap_buffers(
gl_window glutin_ctx
.read() .read()
.current_gl_context .current_gl_context
.as_ref() .as_ref()
@@ -1203,7 +1272,7 @@ mod glow_integration {
path.ends_with(".png"), path.ends_with(".png"),
"Expected EFRAME_SCREENSHOT_TO to end with '.png', got {path:?}" "Expected EFRAME_SCREENSHOT_TO to end with '.png', got {path:?}"
); );
let screenshot = painter.read_screen_rgba(screen_size_in_pixels); let screenshot = painter.read().read_screen_rgba(screen_size_in_pixels);
image::save_buffer( image::save_buffer(
&path, &path,
screenshot.as_raw(), screenshot.as_raw(),
@@ -1246,8 +1315,10 @@ mod glow_integration {
.collect::<Vec<EventResult>>() .collect::<Vec<EventResult>>()
}; };
integration integration.maybe_autosave(
.maybe_autosave(app.as_mut(), &win.read().window.as_ref().unwrap().read()); app.write().as_mut(),
&win.read().window.as_ref().unwrap().read(),
);
if win.read().window.as_ref().unwrap().read().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:
@@ -1261,7 +1332,7 @@ 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)| {
if let Some(w) = gl_window.read().windows.get(id) { if let Some(w) = glutin_ctx.read().windows.get(id) {
let mut w = w.write(); 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 {
@@ -1283,7 +1354,7 @@ mod glow_integration {
}); });
for (id, parent, builder, render) in viewports { for (id, parent, builder, render) in viewports {
gl_window.write().windows.insert( glutin_ctx.write().windows.insert(
id, id,
Arc::new(RwLock::new(Window { Arc::new(RwLock::new(Window {
builder, builder,
@@ -1299,7 +1370,7 @@ mod glow_integration {
} }
for (id, command) in viewport_commands { for (id, command) in viewport_commands {
if let Some(window) = gl_window.read().windows.get(&id) { if let Some(window) = glutin_ctx.read().windows.get(&id) {
let window = window.read(); let window = window.read();
if let Some(win) = &window.window { if let Some(win) = &window.window {
@@ -1334,12 +1405,11 @@ mod glow_integration {
} }
} }
let mut gl_window = glutin_ctx.write();
gl_window gl_window
.write()
.windows .windows
.retain(|id, _| active_viewports_ids.contains(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));
@@ -1499,7 +1569,7 @@ mod glow_integration {
let viewport = &mut *viewport.write(); let viewport = &mut *viewport.write();
break 'res running.integration.write().on_event( break 'res running.integration.write().on_event(
running.app.as_mut(), running.app.write().as_mut(),
event, event,
window_id, window_id,
viewport.egui_winit.as_mut().unwrap(), viewport.egui_winit.as_mut().unwrap(),

View File

@@ -183,7 +183,10 @@ struct ContextImpl {
input: HashMap<u64, InputState>, input: HashMap<u64, InputState>,
/// State that is collected during a frame and then cleared /// State that is collected during a frame and then cleared
frame_state: FrameState, frame_state: HashMap<u64, FrameState>,
// Viewport Id, Parent Viewport Id
frame_stack: Vec<(u64, u64)>,
// The output of a frame: // The output of a frame:
graphics: GraphicLayers, graphics: GraphicLayers,
@@ -216,7 +219,6 @@ struct ContextImpl {
>, >,
viewport_counter: u64, viewport_counter: u64,
current_rendering_viewport: u64,
is_desktop: bool, is_desktop: bool,
/// Written to during the frame. /// Written to during the frame.
@@ -233,9 +235,14 @@ struct ContextImpl {
} }
impl ContextImpl { impl ContextImpl {
fn begin_frame_mut(&mut self, mut new_raw_input: RawInput, viewport_id: u64) { fn begin_frame_mut(
self.current_rendering_viewport = viewport_id; &mut self,
self.repaint.start_frame(self.current_rendering_viewport); mut new_raw_input: RawInput,
viewport_id: u64,
parent_viewport_id: u64,
) {
self.frame_stack.push((viewport_id, parent_viewport_id));
self.repaint.start_frame(self.get_viewport_id());
if let Some(new_pixels_per_point) = self.memory.new_pixels_per_point.take() { if let Some(new_pixels_per_point) = self.memory.new_pixels_per_point.take() {
new_raw_input.pixels_per_point = Some(new_pixels_per_point); new_raw_input.pixels_per_point = Some(new_pixels_per_point);
@@ -268,6 +275,8 @@ impl ContextImpl {
self.input.insert(viewport_id, input); self.input.insert(viewport_id, input);
self.frame_state self.frame_state
.entry(viewport_id)
.or_default()
.begin_frame(self.input.get(&viewport_id).unwrap()); .begin_frame(self.input.get(&viewport_id).unwrap());
self.update_fonts_mut(); self.update_fonts_mut();
@@ -293,7 +302,10 @@ impl ContextImpl {
builder.set_transform(accesskit::Affine::scale(input.pixels_per_point().into())); builder.set_transform(accesskit::Affine::scale(input.pixels_per_point().into()));
let mut node_builders = IdMap::default(); let mut node_builders = IdMap::default();
node_builders.insert(id, builder); node_builders.insert(id, builder);
self.frame_state.accesskit_state = Some(AccessKitFrameState { self.frame_state
.entry(self.get_viewport_id())
.or_default()
.accesskit_state = Some(AccessKitFrameState {
node_builders, node_builders,
parent_stack: vec![id], parent_stack: vec![id],
}); });
@@ -302,10 +314,7 @@ impl ContextImpl {
/// Load fonts unless already loaded. /// Load fonts unless already loaded.
fn update_fonts_mut(&mut self) { fn update_fonts_mut(&mut self) {
let input = self let input = self.input.entry(self.get_viewport_id()).or_default();
.input
.entry(self.current_rendering_viewport)
.or_default();
let pixels_per_point = input.pixels_per_point(); let pixels_per_point = input.pixels_per_point();
let max_texture_side = input.max_texture_side; let max_texture_side = input.max_texture_side;
@@ -332,7 +341,13 @@ impl ContextImpl {
#[cfg(feature = "accesskit")] #[cfg(feature = "accesskit")]
fn accesskit_node_builder(&mut self, id: Id) -> &mut accesskit::NodeBuilder { fn accesskit_node_builder(&mut self, id: Id) -> &mut accesskit::NodeBuilder {
let state = self.frame_state.accesskit_state.as_mut().unwrap(); let state = self
.frame_state
.entry(self.get_viewport_id())
.or_default()
.accesskit_state
.as_mut()
.unwrap();
let builders = &mut state.node_builders; let builders = &mut state.node_builders;
if let std::collections::hash_map::Entry::Vacant(entry) = builders.entry(id) { if let std::collections::hash_map::Entry::Vacant(entry) = builders.entry(id) {
entry.insert(Default::default()); entry.insert(Default::default());
@@ -344,6 +359,16 @@ impl ContextImpl {
} }
} }
impl ContextImpl {
fn get_viewport_id(&self) -> u64 {
self.frame_stack.last().cloned().unwrap_or_default().0
}
fn get_parent_viewport_id(&self) -> u64 {
self.frame_stack.last().cloned().unwrap_or_default().1
}
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/// Your handle to egui. /// Your handle to egui.
@@ -464,9 +489,10 @@ impl Context {
&self, &self,
new_input: RawInput, new_input: RawInput,
viewport_id: u64, viewport_id: u64,
parent_viewport_id: u64,
run_ui: impl FnOnce(&Context), run_ui: impl FnOnce(&Context),
) -> FullOutput { ) -> FullOutput {
self.begin_frame(new_input, viewport_id); self.begin_frame(new_input, viewport_id, parent_viewport_id);
run_ui(self); run_ui(self);
self.end_frame() self.end_frame()
} }
@@ -488,8 +514,8 @@ impl Context {
/// let full_output = ctx.end_frame(); /// let full_output = ctx.end_frame();
/// // handle full_output /// // handle full_output
/// ``` /// ```
pub fn begin_frame(&self, new_input: RawInput, viewport_id: u64) { pub fn begin_frame(&self, new_input: RawInput, viewport_id: u64, parent_viewport_id: u64) {
self.write(|ctx| ctx.begin_frame_mut(new_input, viewport_id)); self.write(|ctx| ctx.begin_frame_mut(new_input, viewport_id, parent_viewport_id));
} }
} }
@@ -516,7 +542,7 @@ impl Context {
self.read(move |ctx| { self.read(move |ctx| {
reader( reader(
ctx.input ctx.input
.get(&ctx.current_rendering_viewport) .get(&ctx.get_viewport_id())
.unwrap_or(&Default::default()), .unwrap_or(&Default::default()),
) )
}) })
@@ -580,13 +606,13 @@ impl Context {
/// Read-only access to [`FrameState`]. /// Read-only access to [`FrameState`].
#[inline] #[inline]
pub(crate) fn frame_state<R>(&self, reader: impl FnOnce(&FrameState) -> R) -> R { pub(crate) fn frame_state<R>(&self, reader: impl FnOnce(&FrameState) -> R) -> R {
self.read(move |ctx| reader(&ctx.frame_state)) self.read(move |ctx| reader(ctx.frame_state.get(&ctx.get_viewport_id()).unwrap()))
} }
/// Read-write access to [`FrameState`]. /// Read-write access to [`FrameState`].
#[inline] #[inline]
pub(crate) fn frame_state_mut<R>(&self, writer: impl FnOnce(&mut FrameState) -> R) -> R { pub(crate) fn frame_state_mut<R>(&self, writer: impl FnOnce(&mut FrameState) -> R) -> R {
self.write(move |ctx| writer(&mut ctx.frame_state)) self.write(move |ctx| writer(ctx.frame_state.entry(ctx.get_viewport_id()).or_default()))
} }
/// Read-only access to [`Fonts`]. /// Read-only access to [`Fonts`].
@@ -770,7 +796,7 @@ impl Context {
if hovered { if hovered {
let pointer_pos = ctx let pointer_pos = ctx
.input .input
.get(&ctx.current_rendering_viewport) .get(&ctx.get_viewport_id())
.unwrap() .unwrap()
.pointer .pointer
.interact_pos(); .interact_pos();
@@ -867,13 +893,14 @@ impl Context {
let clicked_elsewhere = response.clicked_elsewhere(); let clicked_elsewhere = response.clicked_elsewhere();
self.write(|ctx| { self.write(|ctx| {
let viewport_id = ctx.get_viewport_id();
let memory = &mut ctx.memory; let memory = &mut ctx.memory;
if sense.focusable { if sense.focusable {
memory.interested_in_focus(id); memory.interested_in_focus(id);
} }
let input = ctx.input.get_mut(&ctx.current_rendering_viewport).unwrap(); let input = ctx.input.get_mut(&viewport_id).unwrap();
if sense.click if sense.click
&& memory.has_focus(response.id) && memory.has_focus(response.id)
@@ -1064,7 +1091,7 @@ impl Context {
/// (this will work on `eframe`). /// (this will work on `eframe`).
pub fn request_repaint(&self) { pub fn request_repaint(&self) {
// request two frames of repaint, just to cover some corner cases (frame delays): // request two frames of repaint, just to cover some corner cases (frame delays):
self.write(|ctx| ctx.repaint.request_repaint(ctx.current_rendering_viewport)); self.write(|ctx| ctx.repaint.request_repaint(ctx.get_viewport_id()));
} }
pub fn request_repaint_viewport(&self, id: u64) { pub fn request_repaint_viewport(&self, id: u64) {
@@ -1104,7 +1131,7 @@ impl Context {
// Maybe we can check if duration is ZERO, and call self.request_repaint()? // Maybe we can check if duration is ZERO, and call self.request_repaint()?
self.write(|ctx| { self.write(|ctx| {
ctx.repaint ctx.repaint
.request_repaint_after(duration, ctx.current_rendering_viewport) .request_repaint_after(duration, ctx.get_viewport_id())
}); });
} }
@@ -1328,7 +1355,7 @@ impl Context {
pub fn end_frame(&self) -> FullOutput { pub fn end_frame(&self) -> FullOutput {
let mut viewports: Vec<u64> = self.write(|ctx| { let mut viewports: Vec<u64> = self.write(|ctx| {
ctx.layer_rects_prev_viewports.insert( ctx.layer_rects_prev_viewports.insert(
ctx.current_rendering_viewport, ctx.get_viewport_id(),
std::mem::take(&mut ctx.layer_rects_this_frame), std::mem::take(&mut ctx.layer_rects_this_frame),
); );
ctx.viewports ctx.viewports
@@ -1344,9 +1371,12 @@ impl Context {
let textures_delta = self.write(|ctx| { let textures_delta = self.write(|ctx| {
ctx.memory.end_frame( ctx.memory.end_frame(
ctx.input.get(&ctx.current_rendering_viewport).unwrap(), ctx.input.get(&ctx.get_viewport_id()).unwrap(),
&viewports, &viewports,
&ctx.frame_state.used_ids, &ctx.frame_state
.entry(ctx.get_viewport_id())
.or_default()
.used_ids,
); );
let font_image_delta = ctx.fonts.as_ref().unwrap().font_image_delta(); let font_image_delta = ctx.fonts.as_ref().unwrap().font_image_delta();
@@ -1399,10 +1429,8 @@ impl Context {
.retain(|id, _| viewports.contains(id)) .retain(|id, _| viewports.contains(id))
}); });
let repaint_after = self.write(|ctx| { let repaint_after =
ctx.repaint self.write(|ctx| ctx.repaint.end_frame(ctx.get_viewport_id(), viewports));
.end_frame(ctx.current_rendering_viewport, viewports)
});
let shapes = self.drain_paint_lists(); let shapes = self.drain_paint_lists();
// This is used for, // This is used for,
@@ -1417,20 +1445,21 @@ impl Context {
let mut viewports = Vec::new(); let mut viewports = Vec::new();
self.write(|ctx| { self.write(|ctx| {
let viewport_id = ctx.get_viewport_id();
ctx.viewports ctx.viewports
.retain(|_, (builder, id, parent, used, render)| { .retain(|_, (builder, id, parent, used, render)| {
let out = *used; let out = *used;
if ctx.current_rendering_viewport == *parent { if viewport_id == *parent {
*used = false; *used = false;
} }
viewports.push((*id, *parent, builder.clone(), render.clone())); viewports.push((*id, *parent, builder.clone(), render.clone()));
(out || ctx.current_rendering_viewport != *parent) (out || viewport_id != *parent) && avalibile_viewports.contains(parent)
&& avalibile_viewports.contains(parent)
}) })
}); });
self.write(|ctx| ctx.frame_stack.pop());
FullOutput { FullOutput {
platform_output, platform_output,
repaint_after, repaint_after,
@@ -1455,7 +1484,7 @@ impl Context {
self.write(|ctx| { self.write(|ctx| {
let pixels_per_point = ctx let pixels_per_point = ctx
.input .input
.entry(ctx.current_rendering_viewport) .entry(ctx.get_viewport_id())
.or_default() .or_default()
.pixels_per_point(); .pixels_per_point();
let tessellation_options = ctx.memory.options.tessellation_options; let tessellation_options = ctx.memory.options.tessellation_options;
@@ -1500,7 +1529,11 @@ impl Context {
/// How much space is used by panels and windows. /// How much space is used by panels and windows.
pub fn used_rect(&self) -> Rect { pub fn used_rect(&self) -> Rect {
self.read(|ctx| { self.read(|ctx| {
let mut used = ctx.frame_state.used_by_panels; let mut used = ctx
.frame_state
.get(&ctx.get_viewport_id())
.unwrap()
.used_by_panels;
for window in ctx.memory.areas.visible_windows() { for window in ctx.memory.areas.visible_windows() {
used = used.union(window.rect()); used = used.union(window.rect());
} }
@@ -1670,7 +1703,7 @@ impl Context {
pub fn animate_bool_with_time(&self, id: Id, target_value: bool, animation_time: f32) -> f32 { pub fn animate_bool_with_time(&self, id: Id, target_value: bool, animation_time: f32) -> f32 {
let animated_value = self.write(|ctx| { let animated_value = self.write(|ctx| {
ctx.animation_manager.animate_bool( ctx.animation_manager.animate_bool(
ctx.input.get(&ctx.current_rendering_viewport).unwrap(), ctx.input.get(&ctx.get_viewport_id()).unwrap(),
animation_time, animation_time,
id, id,
target_value, target_value,
@@ -1690,7 +1723,7 @@ impl Context {
pub fn animate_value_with_time(&self, id: Id, target_value: f32, animation_time: f32) -> f32 { pub fn animate_value_with_time(&self, id: Id, target_value: f32, animation_time: f32) -> f32 {
let animated_value = self.write(|ctx| { let animated_value = self.write(|ctx| {
ctx.animation_manager.animate_value( ctx.animation_manager.animate_value(
ctx.input.get(&ctx.current_rendering_viewport).unwrap(), ctx.input.get(&ctx.get_viewport_id()).unwrap(),
animation_time, animation_time,
id, id,
target_value, target_value,
@@ -2014,6 +2047,8 @@ impl Context {
) -> Option<R> { ) -> Option<R> {
self.write(|ctx| { self.write(|ctx| {
ctx.frame_state ctx.frame_state
.entry(ctx.get_viewport_id())
.or_default()
.accesskit_state .accesskit_state
.is_some() .is_some()
.then(|| ctx.accesskit_node_builder(id)) .then(|| ctx.accesskit_node_builder(id))
@@ -2057,8 +2092,12 @@ impl Context {
use containers::window::ViewportBuilder; use containers::window::ViewportBuilder;
/// # Windows /// # Windows
impl Context { impl Context {
pub fn current_rendering_viewport(&self) -> u64 { pub fn get_viewport_id(&self) -> u64 {
self.read(|ctx| ctx.current_rendering_viewport) self.read(|ctx| ctx.get_viewport_id())
}
pub fn get_parent_viewport_id(&self) -> u64 {
self.read(|ctx| ctx.get_parent_viewport_id())
} }
pub fn set_render_sync_callback( pub fn set_render_sync_callback(
@@ -2091,9 +2130,10 @@ impl Context {
) { ) {
if self.is_desktop() { if self.is_desktop() {
self.write(|ctx| { self.write(|ctx| {
let viewport_id = ctx.get_viewport_id();
if let Some(window) = ctx.viewports.get_mut(&viewport_builder.title) { if let Some(window) = ctx.viewports.get_mut(&viewport_builder.title) {
window.0 = viewport_builder; window.0 = viewport_builder;
window.2 = ctx.current_rendering_viewport; window.2 = viewport_id;
window.3 = true; window.3 = true;
window.4 = Some(Arc::new(Box::new(func))); window.4 = Some(Arc::new(Box::new(func)));
} else { } else {
@@ -2104,7 +2144,7 @@ impl Context {
( (
viewport_builder, viewport_builder,
id, id,
ctx.current_rendering_viewport, viewport_id,
true, true,
Some(Arc::new(Box::new(func))), Some(Arc::new(Box::new(func))),
), ),
@@ -2125,9 +2165,10 @@ impl Context {
let mut viewport_id = 0; let mut viewport_id = 0;
let mut parent_viewport_id = 0; let mut parent_viewport_id = 0;
let render_sync = self.write(|ctx| { let render_sync = self.write(|ctx| {
viewport_id = ctx.get_viewport_id();
if let Some(window) = ctx.viewports.get_mut(&viewport_builder.title) { if let Some(window) = ctx.viewports.get_mut(&viewport_builder.title) {
window.0 = viewport_builder.clone(); window.0 = viewport_builder.clone();
window.2 = ctx.current_rendering_viewport; window.2 = viewport_id;
window.3 = true; window.3 = true;
window.4 = None; window.4 = None;
viewport_id = window.1; viewport_id = window.1;
@@ -2137,16 +2178,10 @@ impl Context {
ctx.viewport_counter = id; ctx.viewport_counter = id;
ctx.viewports.insert( ctx.viewports.insert(
viewport_builder.title.clone(), viewport_builder.title.clone(),
( (viewport_builder.clone(), id, viewport_id, true, None),
viewport_builder.clone(),
id,
ctx.current_rendering_viewport,
true,
None,
),
); );
viewport_id = id; viewport_id = id;
parent_viewport_id = ctx.current_rendering_viewport; parent_viewport_id = ctx.get_viewport_id();
} }
ctx.render_sync.clone() ctx.render_sync.clone()

View File

@@ -555,7 +555,7 @@ pub type ViewportRender = dyn Fn(&Context, u64, u64) + Sync + Send;
pub fn __run_test_ctx(mut run_ui: impl FnMut(&Context)) { pub fn __run_test_ctx(mut run_ui: impl FnMut(&Context)) {
let ctx = Context::default(); let ctx = Context::default();
ctx.set_fonts(FontDefinitions::empty()); // prevent fonts from being loaded (save CPU time) ctx.set_fonts(FontDefinitions::empty()); // prevent fonts from being loaded (save CPU time)
let _ = ctx.run(Default::default(), 0, |ctx| { let _ = ctx.run(Default::default(), 0, 0, |ctx| {
run_ui(ctx); run_ui(ctx);
}); });
} }
@@ -564,7 +564,7 @@ pub fn __run_test_ctx(mut run_ui: impl FnMut(&Context)) {
pub fn __run_test_ui(mut add_contents: impl FnMut(&mut Ui)) { pub fn __run_test_ui(mut add_contents: impl FnMut(&mut Ui)) {
let ctx = Context::default(); let ctx = Context::default();
ctx.set_fonts(FontDefinitions::empty()); // prevent fonts from being loaded (save CPU time) ctx.set_fonts(FontDefinitions::empty()); // prevent fonts from being loaded (save CPU time)
let _ = ctx.run(Default::default(), 0, |ctx| { let _ = ctx.run(Default::default(), 0, 0, |ctx| {
crate::CentralPanel::default().show(ctx, |ui| { crate::CentralPanel::default().show(ctx, |ui| {
add_contents(ui); add_contents(ui);
}); });

View File

@@ -13,7 +13,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
// The most end-to-end benchmark. // The most end-to-end benchmark.
c.bench_function("demo_with_tessellate__realistic", |b| { c.bench_function("demo_with_tessellate__realistic", |b| {
b.iter(|| { b.iter(|| {
let full_output = ctx.run(RawInput::default(), 0, |ctx| { let full_output = ctx.run(RawInput::default(), 0, 0, |ctx| {
demo_windows.ui(ctx); demo_windows.ui(ctx);
}); });
ctx.tessellate(full_output.shapes) ctx.tessellate(full_output.shapes)
@@ -22,13 +22,13 @@ pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("demo_no_tessellate", |b| { c.bench_function("demo_no_tessellate", |b| {
b.iter(|| { b.iter(|| {
ctx.run(RawInput::default(), 0, |ctx| { ctx.run(RawInput::default(), 0, 0, |ctx| {
demo_windows.ui(ctx); demo_windows.ui(ctx);
}) })
}); });
}); });
let full_output = ctx.run(RawInput::default(), 0, |ctx| { let full_output = ctx.run(RawInput::default(), 0, 0, |ctx| {
demo_windows.ui(ctx); demo_windows.ui(ctx);
}); });
c.bench_function("demo_only_tessellate", |b| { c.bench_function("demo_only_tessellate", |b| {
@@ -42,7 +42,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
let mut demo_windows = egui_demo_lib::DemoWindows::default(); let mut demo_windows = egui_demo_lib::DemoWindows::default();
c.bench_function("demo_full_no_tessellate", |b| { c.bench_function("demo_full_no_tessellate", |b| {
b.iter(|| { b.iter(|| {
ctx.run(RawInput::default(), 0, |ctx| { ctx.run(RawInput::default(), 0, 0, |ctx| {
demo_windows.ui(ctx); demo_windows.ui(ctx);
}) })
}); });
@@ -51,7 +51,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
{ {
let ctx = egui::Context::default(); let ctx = egui::Context::default();
let _ = ctx.run(RawInput::default(), 0, |ctx| { let _ = ctx.run(RawInput::default(), 0, 0, |ctx| {
egui::CentralPanel::default().show(ctx, |ui| { egui::CentralPanel::default().show(ctx, |ui| {
c.bench_function("label &str", |b| { c.bench_function("label &str", |b| {
b.iter(|| { b.iter(|| {
@@ -69,7 +69,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
{ {
let ctx = egui::Context::default(); let ctx = egui::Context::default();
ctx.begin_frame(RawInput::default(), 0); ctx.begin_frame(RawInput::default(), 0, 0);
egui::CentralPanel::default().show(&ctx, |ui| { egui::CentralPanel::default().show(&ctx, |ui| {
c.bench_function("Painter::rect", |b| { c.bench_function("Painter::rect", |b| {

View File

@@ -68,7 +68,7 @@ fn test_egui_e2e() {
const NUM_FRAMES: usize = 5; const NUM_FRAMES: usize = 5;
for _ in 0..NUM_FRAMES { for _ in 0..NUM_FRAMES {
let full_output = ctx.run(raw_input.clone(), 0, |ctx| { let full_output = ctx.run(raw_input.clone(), 0, 0, |ctx| {
demo_windows.ui(ctx); demo_windows.ui(ctx);
}); });
let clipped_primitives = ctx.tessellate(full_output.shapes); let clipped_primitives = ctx.tessellate(full_output.shapes);
@@ -87,7 +87,7 @@ fn test_egui_zero_window_size() {
const NUM_FRAMES: usize = 5; const NUM_FRAMES: usize = 5;
for _ in 0..NUM_FRAMES { for _ in 0..NUM_FRAMES {
let full_output = ctx.run(raw_input.clone(), 0, |ctx| { let full_output = ctx.run(raw_input.clone(), 0, 0, |ctx| {
demo_windows.ui(ctx); demo_windows.ui(ctx);
}); });
let clipped_primitives = ctx.tessellate(full_output.shapes); let clipped_primitives = ctx.tessellate(full_output.shapes);

View File

@@ -18,7 +18,7 @@ fn main() -> Result<(), eframe::Error> {
egui::CentralPanel::default().show(ctx, |ui| { egui::CentralPanel::default().show(ctx, |ui| {
ui.label(format!( ui.label(format!(
"Current rendering window: {}", "Current rendering window: {}",
ctx.current_rendering_viewport() ctx.get_viewport_id()
)); ));
ui.heading("My egui Application"); ui.heading("My egui Application");
ui.horizontal(|ui| { ui.horizontal(|ui| {

View File

@@ -9,5 +9,5 @@ publish = false
[dependencies] [dependencies]
eframe = { path = "../../crates/eframe", features = ["wgpu"] } eframe = { path = "../../crates/eframe" }
env_logger = "0.10" env_logger = "0.10"

View File

@@ -1,4 +1,5 @@
use eframe::egui; use eframe::egui;
use eframe::egui::window::ViewportBuilder;
use eframe::egui::Id; use eframe::egui::Id;
use eframe::NativeOptions; use eframe::NativeOptions;
@@ -10,7 +11,7 @@ fn main() {
let _ = eframe::run_simple_native( let _ = eframe::run_simple_native(
"Viewports Examples", "Viewports Examples",
NativeOptions { NativeOptions {
renderer: eframe::Renderer::Wgpu, renderer: eframe::Renderer::Glow,
..NativeOptions::default() ..NativeOptions::default()
}, },
move |ctx, _frame| { move |ctx, _frame| {
@@ -21,6 +22,22 @@ fn main() {
ctx.set_desktop(is_desktop); ctx.set_desktop(is_desktop);
ui.checkbox(&mut to_repair, "To Repair!"); ui.checkbox(&mut to_repair, "To Repair!");
ctx.create_viewport_sync(
ViewportBuilder::default().with_title("Sync rendering!"),
|ctx, viewport_id, parent_viewport_id| {
egui::CentralPanel::default().show(ctx, |ui| {
ui.horizontal(|ui| {
ui.label("Viewport ID: ");
ui.label(format!("{viewport_id}"))
});
ui.horizontal(|ui| {
ui.label("Parent Viewport ID: ");
ui.label(format!("{parent_viewport_id}"))
});
})
},
);
egui::CollapsingHeader::new("Show Test1").show(ui, |ui| { egui::CollapsingHeader::new("Show Test1").show(ui, |ui| {
egui::Window::new("Test1").show(ctx, move |ui, id, parent_id| { egui::Window::new("Test1").show(ctx, move |ui, id, parent_id| {
ui.label(format!("Frame: {}", ui.ctx().frame_nr())); ui.label(format!("Frame: {}", ui.ctx().frame_nr()));
@@ -40,7 +57,7 @@ fn main() {
let ctx = ui.ctx().clone(); let ctx = ui.ctx().clone();
ui.label(format!( ui.label(format!(
"Current rendering window: {}", "Current rendering window: {}",
ctx.current_rendering_viewport() ctx.get_viewport_id()
)); ));
if ui.button("Drag").is_pointer_button_down_on() { if ui.button("Drag").is_pointer_button_down_on() {
if id != parent_id { if id != parent_id {
@@ -71,7 +88,7 @@ fn main() {
let ctx = ui.ctx().clone(); let ctx = ui.ctx().clone();
ui.label(format!( ui.label(format!(
"Current rendering window: {}", "Current rendering window: {}",
ctx.current_rendering_viewport() ctx.get_viewport_id()
)); ));
if ui.button("Drag").is_pointer_button_down_on() { if ui.button("Drag").is_pointer_button_down_on() {
@@ -94,7 +111,7 @@ fn main() {
let ctx = ui.ctx().clone(); let ctx = ui.ctx().clone();
ui.label(format!( ui.label(format!(
"Current rendering window: {}", "Current rendering window: {}",
ctx.current_rendering_viewport() ctx.get_viewport_id()
)); ));
if ui.button("Drag").is_pointer_button_down_on() { if ui.button("Drag").is_pointer_button_down_on() {