forked from 1b-agent/opencadstudio-upstream
Merge pull request #1015: The grid overlay was rebuilding the whole drawing
This commit is contained in:
commit
52d9c047d9
3 files changed
+208
-29
No files matched your search
+68
-3
@@ -197,6 +197,20 @@ impl OpenCADStudio {
|
||||
/// `view` so the single-window web build can render it directly, bypassing
|
||||
/// the multi-window id dispatch above (the web build has no extra windows).
|
||||
pub fn view_main(&self) -> Element<'_, Message> {
|
||||
// Section marks for `view-detail`. A closure over a RefCell rather
|
||||
// than one binding per section: two of these sections sit inside a
|
||||
// nested block and would otherwise be out of scope at the report.
|
||||
let view_t0 = crate::perf::enabled().then(iced::time::Instant::now);
|
||||
let view_marks: std::cell::RefCell<Vec<(&'static str, f64)>> =
|
||||
std::cell::RefCell::new(Vec::with_capacity(8));
|
||||
let mark = |name: &'static str| {
|
||||
if let Some(t0) = view_t0 {
|
||||
view_marks
|
||||
.borrow_mut()
|
||||
.push((name, t0.elapsed().as_secs_f64() * 1000.0));
|
||||
}
|
||||
};
|
||||
|
||||
let i = self.active_tab;
|
||||
let tab = &self.tabs[i];
|
||||
let thumbnail_capture_clean = self.thumbnail_capture_clean;
|
||||
@@ -257,6 +271,7 @@ impl OpenCADStudio {
|
||||
// the same shader as model space: a full-canvas top-locked "sheet"
|
||||
// viewport draws the layout's own geometry (white sheet + entities +
|
||||
// borders) and the floating content viewports blit on top.
|
||||
mark("viewport_3d");
|
||||
let viewport_3d: Element<'_, Message> = if tab.is_start {
|
||||
start_page_view(
|
||||
&self.patrons,
|
||||
@@ -334,6 +349,7 @@ impl OpenCADStudio {
|
||||
// the shader pane_grid (same `model_panes` → identical layout). Layered
|
||||
// above the crosshair overlay so it actually receives mouse events, and
|
||||
// it owns the divider resize. Only built for the Model layout.
|
||||
mark("model_input");
|
||||
let model_input_layer: Option<Element<'_, Message>> = if is_paper || tab.is_start {
|
||||
None
|
||||
} else {
|
||||
@@ -351,6 +367,7 @@ impl OpenCADStudio {
|
||||
)
|
||||
};
|
||||
|
||||
mark("grid");
|
||||
let grid_overlay = {
|
||||
let (vw, vh) = tab.scene.selection.borrow().vp_size;
|
||||
let model_basis = {
|
||||
@@ -365,9 +382,15 @@ impl OpenCADStudio {
|
||||
);
|
||||
(o, (ux.as_vec3(), uy.as_vec3(), uz.as_vec3()))
|
||||
};
|
||||
let grid: Vec<crate::ui::overlay::GridParams> = tab
|
||||
.scene
|
||||
.grid_views(vw, vh)
|
||||
// The first paper frame spends seconds in this block and `grid`
|
||||
// alone cannot say which part. Reported only when it costs
|
||||
// something, so ordinary frames stay quiet.
|
||||
let t_grid = crate::perf::enabled().then(iced::time::Instant::now);
|
||||
let views = tab.scene.grid_views(vw, vh);
|
||||
let views_ms = crate::perf::elapsed_ms(t_grid);
|
||||
let view_count = views.len();
|
||||
let t_params = crate::perf::enabled().then(iced::time::Instant::now);
|
||||
let grid: Vec<crate::ui::overlay::GridParams> = views
|
||||
.into_iter()
|
||||
.map(|(bounds, cam, handle)| {
|
||||
let (origin, mut axes): (glam::DVec3, _) = if is_paper {
|
||||
@@ -411,7 +434,16 @@ impl OpenCADStudio {
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let params_ms = crate::perf::elapsed_ms(t_params);
|
||||
let t_bg = crate::perf::enabled().then(iced::time::Instant::now);
|
||||
let bg = crosshair_background(tab, is_paper);
|
||||
let bg_ms = crate::perf::elapsed_ms(t_bg);
|
||||
if views_ms + params_ms + bg_ms >= 1.0 {
|
||||
crate::perf_record!(
|
||||
"[perf] grid-detail views={views_ms:.1}ms params={params_ms:.1}ms \
|
||||
bg={bg_ms:.1}ms n={view_count}"
|
||||
);
|
||||
}
|
||||
let bg_lum = 0.299 * bg[0] + 0.587 * bg[1] + 0.114 * bg[2];
|
||||
let grid_style = crate::ui::overlay::GridStyle {
|
||||
opacity: self.model_space.grid_opacity,
|
||||
@@ -420,6 +452,7 @@ impl OpenCADStudio {
|
||||
crate::ui::overlay::grid_overlay(grid, grid_style)
|
||||
};
|
||||
|
||||
mark("selection_overlay");
|
||||
let selection_overlay = {
|
||||
// Hold a single `Ref<'_, SelectionState>` for the whole overlay
|
||||
// block. The `vp_size` and `last_move_pos` reads below become
|
||||
@@ -790,6 +823,7 @@ impl OpenCADStudio {
|
||||
)
|
||||
};
|
||||
|
||||
mark("viewport_mouse");
|
||||
let viewport_mouse = mouse_area(container(
|
||||
iced::widget::Space::new().width(Fill).height(Fill),
|
||||
))
|
||||
@@ -935,6 +969,7 @@ impl OpenCADStudio {
|
||||
None
|
||||
};
|
||||
|
||||
mark("viewport_stack");
|
||||
let mut viewport_stack = if tab.is_start {
|
||||
// Start tab: only the welcome widget over a flat background.
|
||||
// Skip every drawing-only overlay (selection markers, snap info,
|
||||
@@ -1053,6 +1088,7 @@ impl OpenCADStudio {
|
||||
// both layered ABOVE the viewport mouse_area so they receive
|
||||
// clicks (the shader viewport sits below it). Positioned with
|
||||
// leading Spaces sized to the viewport's screen rectangle.
|
||||
mark("active_vp_rect");
|
||||
let active_vp_rect: Option<(acadrust::Handle, iced::Rectangle)> =
|
||||
if is_paper && !tab.is_start {
|
||||
tab.scene.active_viewport.and_then(|h| {
|
||||
@@ -1383,6 +1419,7 @@ impl OpenCADStudio {
|
||||
}
|
||||
|
||||
// Reserve the overlaid command line when placing cursor-anchored panels.
|
||||
mark("chrome");
|
||||
let command_line_inset = if self.command_line.history_open {
|
||||
self.command_line.history_height.clamp(
|
||||
crate::ui::command_line::HISTORY_HEIGHT_MIN,
|
||||
@@ -2102,6 +2139,34 @@ impl OpenCADStudio {
|
||||
};
|
||||
// Shared CAD colour picker. Indexed ACI colours use OpenCADStudio's own
|
||||
// dialog; True Color keeps the existing iced_aw gradient picker.
|
||||
// Which part of the widget tree the frame went into. Reported as a
|
||||
// breakdown rather than one number, because a first switch to a paper
|
||||
// layout spends seconds here and `view` alone cannot say where.
|
||||
if let Some(t0) = view_t0 {
|
||||
mark("end");
|
||||
let total = t0.elapsed().as_secs_f64() * 1000.0;
|
||||
if total >= 1.0 {
|
||||
let marks = view_marks.borrow();
|
||||
// A mark opens a section; the following mark closes it, so a
|
||||
// section's cost is the gap to its successor. The first mark
|
||||
// is preceded by the preamble, reported as `head`.
|
||||
let mut detail = String::new();
|
||||
if let Some((_, first)) = marks.first() {
|
||||
let _ = std::fmt::Write::write_fmt(
|
||||
&mut detail,
|
||||
format_args!(" head={first:.1}"),
|
||||
);
|
||||
}
|
||||
for pair in marks.windows(2) {
|
||||
let _ = std::fmt::Write::write_fmt(
|
||||
&mut detail,
|
||||
format_args!(" {}={:.1}", pair[0].0, pair[1].1 - pair[0].1),
|
||||
);
|
||||
}
|
||||
crate::perf_record!("[perf] view-detail total={total:.1}ms{detail}");
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((_, current)) = self.color_pick_target.as_ref() {
|
||||
match self.color_picker_tab {
|
||||
super::ColorPickerTab::Index => {
|
||||
|
||||
Reference in new issue
Block a user