From 30e9b3c5fdc8ecc0a1f735d17b694fed3395497c Mon Sep 17 00:00:00 2001
From: hypercube <0hypercube@gmail.com>
Date: Fri, 4 Jul 2025 22:33:02 +0100
Subject: [PATCH] Skip complex layer thumbnails
---
editor/src/node_graph_executor/runtime.rs | 13 +++++
node-graph/gcore/src/context.rs | 2 +-
node-graph/gcore/src/lib.rs | 1 +
node-graph/gcore/src/render_complexity.rs | 58 ++++++++++++++++++++
node-graph/graph-craft/src/document/value.rs | 2 +-
node-graph/gsvg-renderer/src/renderer.rs | 5 +-
6 files changed, 77 insertions(+), 4 deletions(-)
create mode 100644 node-graph/gcore/src/render_complexity.rs
diff --git a/editor/src/node_graph_executor/runtime.rs b/editor/src/node_graph_executor/runtime.rs
index a93f73546..850afa516 100644
--- a/editor/src/node_graph_executor/runtime.rs
+++ b/editor/src/node_graph_executor/runtime.rs
@@ -328,6 +328,19 @@ 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: "".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/context.rs b/node-graph/gcore/src/context.rs
index 3adb839b0..4e8854c90 100644
--- a/node-graph/gcore/src/context.rs
+++ b/node-graph/gcore/src/context.rs
@@ -356,7 +356,7 @@ pub struct ContextImpl<'a> {
}
impl<'a> ContextImpl<'a> {
- pub fn with_footprint<'f>(&self, new_footprint: &'f Footprint, varargs: Option<&'f impl (Borrow<[DynRef<'f>]>)>) -> ContextImpl<'f>
+ pub fn with_footprint<'f>(&self, new_footprint: &'f Footprint, varargs: Option<&'f impl Borrow<[DynRef<'f>]>>) -> ContextImpl<'f>
where
'a: 'f,
{
diff --git a/node-graph/gcore/src/lib.rs b/node-graph/gcore/src/lib.rs
index 973b2f4d2..b63f83c95 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 000000000..8472320b0
--- /dev/null
+++ b/node-graph/gcore/src/render_complexity.rs
@@ -0,0 +1,58 @@
+use crate::raster_types::{CPU, GPU, Raster};
+use crate::{Artboard, Color, GraphicElement, instances::Instances, vector::VectorData};
+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()).sum()
+ }
+}
+
+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) as usize
+ }
+}
+
+impl RenderComplexity for Raster {
+ fn render_complexity(&self) -> usize {
+ (self.width() * self.height()) as usize
+ }
+}
+
+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/graph-craft/src/document/value.rs b/node-graph/graph-craft/src/document/value.rs
index d3b82eae1..00402776f 100644
--- a/node-graph/graph-craft/src/document/value.rs
+++ b/node-graph/graph-craft/src/document/value.rs
@@ -97,7 +97,7 @@ macro_rules! tagged_value {
}
}
/// Attempts to downcast the dynamic type to a tagged value
- pub fn try_from_std_any_ref(input: &(dyn std::any::Any)) -> Result {
+ pub fn try_from_std_any_ref(input: &dyn std::any::Any) -> Result {
use std::any::TypeId;
match input.type_id() {
diff --git a/node-graph/gsvg-renderer/src/renderer.rs b/node-graph/gsvg-renderer/src/renderer.rs
index 95e9890a8..f8faa2bc8 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;
@@ -203,7 +204,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")]
@@ -1149,7 +1150,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 {}