From c16ee88b5d19faade605b1023528352a4beee04d Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Sun, 2 Apr 2023 18:31:41 -0700 Subject: [PATCH] Fix some fatal failures related to rendered frame memory size limits --- .../layout/utility_types/widgets/input_widgets.rs | 4 ---- .../messages/portfolio/portfolio_message_handler.rs | 6 ++++-- frontend/src/state-providers/portfolio.ts | 10 +++++++++- frontend/src/utility-functions/rasterization.ts | 4 +++- node-graph/gcore/src/raster.rs | 7 ++++--- node-graph/gstd/src/memo.rs | 4 ++-- node-graph/interpreted-executor/src/executor.rs | 7 +++++-- 7 files changed, 27 insertions(+), 15 deletions(-) diff --git a/editor/src/messages/layout/utility_types/widgets/input_widgets.rs b/editor/src/messages/layout/utility_types/widgets/input_widgets.rs index 80950330..b075499c 100644 --- a/editor/src/messages/layout/utility_types/widgets/input_widgets.rs +++ b/editor/src/messages/layout/utility_types/widgets/input_widgets.rs @@ -181,10 +181,6 @@ pub struct LayerReferenceInput { #[serde(skip)] pub tooltip_shortcut: Option, - // Styling - #[serde(rename = "minWidth")] - pub min_width: u32, - // Callbacks #[serde(skip)] #[derivative(Debug = "ignore", PartialEq = "ignore")] diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index a84bb1f9..39a35068 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -485,14 +485,16 @@ impl MessageHandler { - if let Err(description) = self.executor.evaluate_node_graph( + let result = self.executor.evaluate_node_graph( (document_id, &mut self.documents), layer_path, (image_data, size), imaginate_node, (preferences, &self.persistent_data), responses, - ) { + ); + + if let Err(description) = result { responses.push_back( DialogMessage::DisplayDialogError { title: "Unable to update node graph".to_string(), diff --git a/frontend/src/state-providers/portfolio.ts b/frontend/src/state-providers/portfolio.ts index 597e42af..d13bec84 100644 --- a/frontend/src/state-providers/portfolio.ts +++ b/frontend/src/state-providers/portfolio.ts @@ -120,7 +120,15 @@ export function createPortfolioState(editor: Editor) { const { documentId, layerPath, svg, size, imaginateNode } = triggerNodeGraphFrameGenerate; // Rasterize the SVG to an image file - const imageData = (await rasterizeSVGCanvas(svg, size[0], size[1])).getContext("2d")?.getImageData(0, 0, size[0], size[1]); + let imageData; + try { + // getImageData may throw an exception if the resolution is too high + if (size[0] >= 1 && size[1] >= 1) { + imageData = (await rasterizeSVGCanvas(svg, size[0], size[1])).getContext("2d")?.getImageData(0, 0, size[0], size[1]); + } + } catch (e) { + console.error("Failed to rasterize the SVG canvas in JS to be sent back to Rust:", e); + } if (imageData) editor.instance.processNodeGraphFrame(documentId, layerPath, new Uint8Array(imageData.data), imageData.width, imageData.height, imaginateNode); }); diff --git a/frontend/src/utility-functions/rasterization.ts b/frontend/src/utility-functions/rasterization.ts index 6bad8847..7f803b05 100644 --- a/frontend/src/utility-functions/rasterization.ts +++ b/frontend/src/utility-functions/rasterization.ts @@ -54,7 +54,7 @@ export async function rasterizeSVG(svg: string, width: number, height: number, m return blob; } -/// Convert an image source (e.g. PNG document) into pixel data, a width and a height +/// Convert an image source (e.g. PNG document) into pixel data, a width, and a height export async function extractPixelData(imageData: ImageBitmapSource): Promise { // Special handling to rasterize an SVG file let svgImageData; @@ -87,8 +87,10 @@ export async function extractPixelData(imageData: ImageBitmapSource): Promise(&self, state: &mut H) { - const HASH_SAMPLES: usize = 1000; + const HASH_SAMPLES: u64 = 1000; + let data_length = self.data.len() as u64; self.width.hash(state); self.height.hash(state); - for i in 0..HASH_SAMPLES.min(self.data.len()) { - self.data[i * self.data.len() / HASH_SAMPLES].hash(state); + for i in 0..HASH_SAMPLES.min(data_length) { + self.data[(i * data_length / HASH_SAMPLES) as usize].hash(state); } } } diff --git a/node-graph/gstd/src/memo.rs b/node-graph/gstd/src/memo.rs index 1f07d488..77cb85d8 100644 --- a/node-graph/gstd/src/memo.rs +++ b/node-graph/gstd/src/memo.rs @@ -1,9 +1,9 @@ +use graphene_core::Node; + use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use xxhash_rust::xxh3::Xxh3; -use graphene_core::Node; - /// Caches the output of a given Node and acts as a proxy #[derive(Default)] pub struct CacheNode { diff --git a/node-graph/interpreted-executor/src/executor.rs b/node-graph/interpreted-executor/src/executor.rs index 3402c2e5..9755a822 100644 --- a/node-graph/interpreted-executor/src/executor.rs +++ b/node-graph/interpreted-executor/src/executor.rs @@ -42,7 +42,10 @@ impl DynamicExecutor { self.output = proto_network.output; self.typing_context.update(&proto_network)?; trace!("setting output to {}", self.output); - self.tree.update(proto_network, &self.typing_context)?; + let orphans = self.tree.update(proto_network, &self.typing_context)?; + for node_id in orphans { + self.tree.free_node(node_id) + } Ok(()) } } @@ -104,8 +107,8 @@ impl BorrowTree { for (id, node) in proto_network.nodes { if !self.nodes.contains_key(&id) { self.push_node(id, node, typing_context)?; - old_nodes.remove(&id); } + old_nodes.remove(&id); } Ok(old_nodes.into_iter().collect()) }