Fix some fatal failures related to rendered frame memory size limits
This commit is contained in:
parent
1b50878f3f
commit
c16ee88b5d
|
|
@ -181,10 +181,6 @@ pub struct LayerReferenceInput {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub tooltip_shortcut: Option<ActionKeys>,
|
pub tooltip_shortcut: Option<ActionKeys>,
|
||||||
|
|
||||||
// Styling
|
|
||||||
#[serde(rename = "minWidth")]
|
|
||||||
pub min_width: u32,
|
|
||||||
|
|
||||||
// Callbacks
|
// Callbacks
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||||
|
|
|
||||||
|
|
@ -485,14 +485,16 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
||||||
size,
|
size,
|
||||||
imaginate_node,
|
imaginate_node,
|
||||||
} => {
|
} => {
|
||||||
if let Err(description) = self.executor.evaluate_node_graph(
|
let result = self.executor.evaluate_node_graph(
|
||||||
(document_id, &mut self.documents),
|
(document_id, &mut self.documents),
|
||||||
layer_path,
|
layer_path,
|
||||||
(image_data, size),
|
(image_data, size),
|
||||||
imaginate_node,
|
imaginate_node,
|
||||||
(preferences, &self.persistent_data),
|
(preferences, &self.persistent_data),
|
||||||
responses,
|
responses,
|
||||||
) {
|
);
|
||||||
|
|
||||||
|
if let Err(description) = result {
|
||||||
responses.push_back(
|
responses.push_back(
|
||||||
DialogMessage::DisplayDialogError {
|
DialogMessage::DisplayDialogError {
|
||||||
title: "Unable to update node graph".to_string(),
|
title: "Unable to update node graph".to_string(),
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,15 @@ export function createPortfolioState(editor: Editor) {
|
||||||
const { documentId, layerPath, svg, size, imaginateNode } = triggerNodeGraphFrameGenerate;
|
const { documentId, layerPath, svg, size, imaginateNode } = triggerNodeGraphFrameGenerate;
|
||||||
|
|
||||||
// Rasterize the SVG to an image file
|
// 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);
|
if (imageData) editor.instance.processNodeGraphFrame(documentId, layerPath, new Uint8Array(imageData.data), imageData.width, imageData.height, imaginateNode);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ export async function rasterizeSVG(svg: string, width: number, height: number, m
|
||||||
return blob;
|
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<ImageData> {
|
export async function extractPixelData(imageData: ImageBitmapSource): Promise<ImageData> {
|
||||||
// Special handling to rasterize an SVG file
|
// Special handling to rasterize an SVG file
|
||||||
let svgImageData;
|
let svgImageData;
|
||||||
|
|
@ -87,8 +87,10 @@ export async function extractPixelData(imageData: ImageBitmapSource): Promise<Im
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
canvas.width = width;
|
canvas.width = width;
|
||||||
canvas.height = height;
|
canvas.height = height;
|
||||||
|
|
||||||
const context = canvas.getContext("2d");
|
const context = canvas.getContext("2d");
|
||||||
if (!context) throw new Error("Could not create canvas context");
|
if (!context) throw new Error("Could not create canvas context");
|
||||||
context.drawImage(image, 0, 0, image.width, image.height, 0, 0, width, height);
|
context.drawImage(image, 0, 0, image.width, image.height, 0, 0, width, height);
|
||||||
|
|
||||||
return context.getImageData(0, 0, width, height);
|
return context.getImageData(0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -341,11 +341,12 @@ mod image {
|
||||||
|
|
||||||
impl Hash for Image {
|
impl Hash for Image {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&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.width.hash(state);
|
||||||
self.height.hash(state);
|
self.height.hash(state);
|
||||||
for i in 0..HASH_SAMPLES.min(self.data.len()) {
|
for i in 0..HASH_SAMPLES.min(data_length) {
|
||||||
self.data[i * self.data.len() / HASH_SAMPLES].hash(state);
|
self.data[(i * data_length / HASH_SAMPLES) as usize].hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
|
use graphene_core::Node;
|
||||||
|
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use xxhash_rust::xxh3::Xxh3;
|
use xxhash_rust::xxh3::Xxh3;
|
||||||
|
|
||||||
use graphene_core::Node;
|
|
||||||
|
|
||||||
/// Caches the output of a given Node and acts as a proxy
|
/// Caches the output of a given Node and acts as a proxy
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct CacheNode<T, CachedNode> {
|
pub struct CacheNode<T, CachedNode> {
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,10 @@ impl DynamicExecutor {
|
||||||
self.output = proto_network.output;
|
self.output = proto_network.output;
|
||||||
self.typing_context.update(&proto_network)?;
|
self.typing_context.update(&proto_network)?;
|
||||||
trace!("setting output to {}", self.output);
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -104,8 +107,8 @@ impl BorrowTree {
|
||||||
for (id, node) in proto_network.nodes {
|
for (id, node) in proto_network.nodes {
|
||||||
if !self.nodes.contains_key(&id) {
|
if !self.nodes.contains_key(&id) {
|
||||||
self.push_node(id, node, typing_context)?;
|
self.push_node(id, node, typing_context)?;
|
||||||
old_nodes.remove(&id);
|
|
||||||
}
|
}
|
||||||
|
old_nodes.remove(&id);
|
||||||
}
|
}
|
||||||
Ok(old_nodes.into_iter().collect())
|
Ok(old_nodes.into_iter().collect())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue