diff --git a/editor/src/node_graph_executor/runtime.rs b/editor/src/node_graph_executor/runtime.rs index 227999143c..da92ad313b 100644 --- a/editor/src/node_graph_executor/runtime.rs +++ b/editor/src/node_graph_executor/runtime.rs @@ -328,6 +328,18 @@ impl NodeRuntime { return; } + // Skip thumbnails if the layer is too complex (for performance) + if graphic_element.render_complexity() > 1000 { + let old = thumbnail_renders.insert(parent_network_node_id, Vec::new()); + if old.is_none_or(|v| !v.is_empty()) { + responses.push_back(FrontendMessage::UpdateNodeThumbnail { + id: parent_network_node_id, + value: "Dense thumbnail omitted for performance".to_string(), + }); + } + return; + } + let bounds = graphic_element.bounding_box(DAffine2::IDENTITY, true); // Render the thumbnail from a `GraphicElement` into an SVG string diff --git a/node-graph/gcore/src/lib.rs b/node-graph/gcore/src/lib.rs index 1333ec7433..4f1f0aaf0b 100644 --- a/node-graph/gcore/src/lib.rs +++ b/node-graph/gcore/src/lib.rs @@ -22,6 +22,7 @@ pub mod ops; pub mod raster; pub mod raster_types; pub mod registry; +pub mod render_complexity; pub mod structural; pub mod text; pub mod transform; diff --git a/node-graph/gcore/src/render_complexity.rs b/node-graph/gcore/src/render_complexity.rs new file mode 100644 index 0000000000..3c137c87e8 --- /dev/null +++ b/node-graph/gcore/src/render_complexity.rs @@ -0,0 +1,61 @@ +use crate::instances::Instances; +use crate::raster_types::{CPU, GPU, Raster}; +use crate::vector::VectorData; +use crate::{Artboard, Color, GraphicElement}; +use glam::DVec2; + +pub trait RenderComplexity { + fn render_complexity(&self) -> usize { + 0 + } +} + +impl RenderComplexity for Instances { + fn render_complexity(&self) -> usize { + self.instance_ref_iter().map(|instance| instance.instance.render_complexity()).fold(0, usize::saturating_add) + } +} + +impl RenderComplexity for Artboard { + fn render_complexity(&self) -> usize { + self.graphic_group.render_complexity() + } +} + +impl RenderComplexity for GraphicElement { + fn render_complexity(&self) -> usize { + match self { + Self::GraphicGroup(instances) => instances.render_complexity(), + Self::VectorData(instances) => instances.render_complexity(), + Self::RasterDataCPU(instances) => instances.render_complexity(), + Self::RasterDataGPU(instances) => instances.render_complexity(), + } + } +} + +impl RenderComplexity for VectorData { + fn render_complexity(&self) -> usize { + self.segment_domain.ids().len() + } +} + +impl RenderComplexity for Raster { + fn render_complexity(&self) -> usize { + (self.width * self.height / 500) as usize + } +} + +impl RenderComplexity for Raster { + fn render_complexity(&self) -> usize { + // GPU textures currently can't have a thumbnail + usize::MAX + } +} + +impl RenderComplexity for String {} +impl RenderComplexity for bool {} +impl RenderComplexity for f32 {} +impl RenderComplexity for f64 {} +impl RenderComplexity for DVec2 {} +impl RenderComplexity for Option {} +impl RenderComplexity for Vec {} diff --git a/node-graph/gsvg-renderer/src/renderer.rs b/node-graph/gsvg-renderer/src/renderer.rs index 70f7c18206..a71cdf1b56 100644 --- a/node-graph/gsvg-renderer/src/renderer.rs +++ b/node-graph/gsvg-renderer/src/renderer.rs @@ -10,6 +10,7 @@ use graphene_core::instances::Instance; use graphene_core::math::quad::Quad; use graphene_core::raster::Image; use graphene_core::raster_types::{CPU, GPU, RasterDataTable}; +use graphene_core::render_complexity::RenderComplexity; use graphene_core::transform::{Footprint, Transform}; use graphene_core::uuid::{NodeId, generate_uuid}; use graphene_core::vector::VectorDataTable; @@ -204,7 +205,7 @@ pub struct RenderMetadata { } // TODO: Rename to "Graphical" -pub trait GraphicElementRendered: BoundingBox { +pub trait GraphicElementRendered: BoundingBox + RenderComplexity { fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams); #[cfg(feature = "vello")] @@ -1151,7 +1152,7 @@ impl GraphicElementRendered for GraphicElement { } /// Used to stop rust complaining about upstream traits adding display implementations to `Option`. This would not be an issue as we control that crate. -trait Primitive: std::fmt::Display + BoundingBox {} +trait Primitive: std::fmt::Display + BoundingBox + RenderComplexity {} impl Primitive for String {} impl Primitive for bool {} impl Primitive for f32 {}