Skip to content

Commit

Permalink
Move the viewport commands into the per-viewport output
Browse files Browse the repository at this point in the history
  • Loading branch information
emilk committed Nov 15, 2023
1 parent e36ef75 commit fb07dc1
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 69 deletions.
70 changes: 34 additions & 36 deletions crates/eframe/src/native/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,6 @@ mod glow_integration {
shapes,
pixels_per_point,
viewports: viewports_out,
viewport_commands,
} = full_output;

let GlutinWindowContext {
Expand Down Expand Up @@ -649,19 +648,6 @@ mod glow_integration {

glutin.process_viewport_updates(viewports_out, focused_viewport);

for (viewport_id, command) in viewport_commands {
if let Some(viewport) = glutin.viewports.get(&viewport_id) {
if let Some(window) = &viewport.window {
let is_viewport_focused = focused_viewport == Some(viewport_id);
egui_winit::process_viewport_commands(
[command],
window,
is_viewport_focused,
);
}
}
}

if integration.should_close() {
EventResult::Exit
} else {
Expand Down Expand Up @@ -1169,21 +1155,25 @@ mod glow_integration {

fn process_viewport_updates(
&mut self,
viewport_output: Vec<ViewportOutput>,
viewport_output: ViewportIdMap<ViewportOutput>,
focused_viewport: Option<ViewportId>,
) {
crate::profile_function!();

let mut active_viewports_ids = ViewportIdSet::default();
active_viewports_ids.insert(ViewportId::ROOT);

for ViewportOutput {
ids,
builder,
viewport_ui_cb,
} in viewport_output
for (
viewport_id,
ViewportOutput {
ids,
builder,
viewport_ui_cb,
commands,
},
) in viewport_output
{
active_viewports_ids.insert(ids.this);
active_viewports_ids.insert(viewport_id);

initialize_or_update_viewport(
&mut self.viewports,
Expand All @@ -1192,6 +1182,17 @@ mod glow_integration {
viewport_ui_cb,
focused_viewport,
);

if let Some(viewport) = self.viewports.get(&viewport_id) {
if let Some(window) = &viewport.window {
let is_viewport_focused = focused_viewport == Some(viewport_id);
egui_winit::process_viewport_commands(
commands,
window,
is_viewport_focused,
);
}
}
}

// GC old viewports
Expand Down Expand Up @@ -2455,10 +2456,7 @@ mod wgpu_integration {

let raw_input = egui_winit.as_mut().unwrap().take_egui_input(
window,
ViewportIdPair {
this: viewport_id,
parent: ids.parent,
},
ViewportIdPair::from_self_and_parent(viewport_id, ids.parent),
);

integration.pre_update(window);
Expand Down Expand Up @@ -2504,7 +2502,6 @@ mod wgpu_integration {
shapes,
pixels_per_point,
viewports: out_viewports,
viewport_commands,
} = full_output;

integration.handle_platform_output(window, viewport_id, platform_output, egui_winit);
Expand Down Expand Up @@ -2532,13 +2529,17 @@ mod wgpu_integration {
active_viewports_ids.insert(ViewportId::ROOT);

// Add new viewports, and update existing ones:
for ViewportOutput {
ids,
builder,
viewport_ui_cb,
} in out_viewports
for (
viewport_id,
ViewportOutput {
ids,
builder,
viewport_ui_cb,
commands,
},
) in out_viewports
{
active_viewports_ids.insert(ids.this);
active_viewports_ids.insert(viewport_id);

initialize_or_update_viewport(
viewports,
Expand All @@ -2547,16 +2548,13 @@ mod wgpu_integration {
viewport_ui_cb,
focused_viewport,
);
}

// Handle viewport commands:
for (viewport_id, command) in viewport_commands {
if let Some(window) = viewports
.get(&viewport_id)
.and_then(|vp| vp.window.as_ref())
{
let is_viewport_focused = focused_viewport == Some(viewport_id);
egui_winit::process_viewport_commands([command], window, is_viewport_focused);
egui_winit::process_viewport_commands(commands, window, is_viewport_focused);
}
}

Expand Down
49 changes: 26 additions & 23 deletions crates/egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ struct ViewportState {
// The output of a frame:
graphics: GraphicLayers,
output: PlatformOutput,
commands: Vec<ViewportCommand>,
}

/// Per-viewport state related to repaint scheduling.
Expand Down Expand Up @@ -185,7 +186,6 @@ struct ContextImpl {

viewport_parents: ViewportIdMap<ViewportId>,
viewports: ViewportIdMap<ViewportState>,
viewport_commands: Vec<(ViewportId, ViewportCommand)>,

embed_viewports: bool,

Expand Down Expand Up @@ -1563,24 +1563,36 @@ impl ContextImpl {
true
});

// This is used to resume the last frame!
self.viewport_stack.pop();

// The last viewport is not necessarily the root viewport,
// just the top _immediate_ viewport.
let is_last = self.viewport_stack.is_empty();

let out_viewports = self
.viewports
.iter()
.iter_mut()
.map(|(&id, viewport)| {
let parent = *self.viewport_parents.entry(id).or_default();
ViewportOutput {
ids: ViewportIdPair { this: id, parent },
builder: viewport.builder.clone(),
viewport_ui_cb: viewport.viewport_ui_cb.clone(),
}
let commands = if is_last {
std::mem::take(&mut viewport.commands)
} else {
vec![]
};

(
id,
ViewportOutput {
ids: ViewportIdPair::from_self_and_parent(id, parent),
builder: viewport.builder.clone(),
viewport_ui_cb: viewport.viewport_ui_cb.clone(),
commands,
},
)
})
.collect();

// This is used to resume the last frame!
self.viewport_stack.pop();

let is_last = self.viewport_stack.is_empty();

if is_last {
// Remove dead viewports:
self.viewports.retain(|id, _| all_viewport_ids.contains(id));
Expand All @@ -1597,12 +1609,6 @@ impl ContextImpl {
shapes,
pixels_per_point,
viewports: out_viewports,
// We should not process viewport commands when we are a sync viewport, because that will cause a deadlock for egui backend
viewport_commands: if is_last {
std::mem::take(&mut self.viewport_commands)
} else {
Vec::new()
},
}
}
}
Expand Down Expand Up @@ -2518,7 +2524,7 @@ impl Context {

/// Send a command to a speicfic viewport.
pub fn viewport_command_for(&self, id: ViewportId, command: ViewportCommand) {
self.write(|ctx| ctx.viewport_commands.push((id, command)));
self.write(|ctx| ctx.viewport_for(id).commands.push(command));
}

/// This creates a new native window, if possible.
Expand Down Expand Up @@ -2615,10 +2621,7 @@ impl Context {
viewport.used = true;
viewport.viewport_ui_cb = None; // it is immediate

ViewportIdPair {
this: new_viewport_id,
parent: parent_viewport_id,
}
ViewportIdPair::from_self_and_parent(new_viewport_id, parent_viewport_id)
});

let mut out = None;
Expand Down
25 changes: 15 additions & 10 deletions crates/egui/src/data/output.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! All the data egui returns to the backend at the end of each frame.
use crate::{ViewportCommand, ViewportId, ViewportOutput, WidgetType};
use crate::{ViewportIdMap, ViewportOutput, WidgetType};

/// What egui emits each frame from [`crate::Context::run`].
///
Expand All @@ -26,11 +26,8 @@ pub struct FullOutput {
/// You can pass this to [`crate::Context::tessellate`] together with [`Self::shapes`].
pub pixels_per_point: f32,

/// All the active viewports, excluding the root.
pub viewports: Vec<ViewportOutput>,

/// Commands sent to different viewports.
pub viewport_commands: Vec<(ViewportId, ViewportCommand)>,
/// All the active viewports, including the root.
pub viewports: ViewportIdMap<ViewportOutput>,
}

impl FullOutput {
Expand All @@ -41,16 +38,24 @@ impl FullOutput {
textures_delta,
shapes,
pixels_per_point,
mut viewports,
mut viewport_commands,
viewports,
} = newer;

self.platform_output.append(platform_output);
self.textures_delta.append(textures_delta);
self.shapes = shapes; // Only paint the latest
self.pixels_per_point = pixels_per_point; // Use latest
self.viewports.append(&mut viewports);
self.viewport_commands.append(&mut viewport_commands);

for (id, new_viewport) in viewports {
match self.viewports.entry(id) {
std::collections::hash_map::Entry::Vacant(entry) => {
entry.insert(new_viewport);
}
std::collections::hash_map::Entry::Occupied(mut entry) => {
entry.get_mut().append(new_viewport);
}
}
}
}
}

Expand Down
23 changes: 23 additions & 0 deletions crates/egui/src/viewport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ impl ViewportIdPair {
this: ViewportId::ROOT,
parent: ViewportId::ROOT,
};

#[inline]
pub fn from_self_and_parent(this: ViewportId, parent: ViewportId) -> Self {
Self { this, parent }
}
}

/// The user-code that shows the ui in the viewport, used for deferred viewports.
Expand Down Expand Up @@ -669,12 +674,30 @@ pub struct ViewportOutput {
///
/// `None` for immediate viewports and the ROOT viewport.
pub viewport_ui_cb: Option<Arc<ViewportUiCallback>>,

/// Commands to change the viewport, e.g. window title and size.
pub commands: Vec<ViewportCommand>,
}

impl ViewportOutput {
pub fn id(&self) -> ViewportId {
self.ids.this
}

/// Add on new output.
pub fn append(&mut self, newer: Self) {
let Self {
ids,
builder,
viewport_ui_cb,
mut commands,
} = newer;

self.ids = ids;
self.builder.patch(&builder);
self.viewport_ui_cb = viewport_ui_cb;
self.commands.append(&mut commands);
}
}

/// Viewport for immediate rendering.
Expand Down

0 comments on commit fb07dc1

Please sign in to comment.