From 6ecb173c1c06807f13a859ef90b7d7f43af042be Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Thu, 25 Jul 2024 00:32:19 -0700 Subject: [PATCH] Add caching to boolean operations --- .../node_graph/document_node_types.rs | 136 +++++++++++------- .../document/node_graph/node_properties.rs | 9 +- .../portfolio/portfolio_message_handler.rs | 1 + .../interpreted-executor/src/node_registry.rs | 2 + 4 files changed, 92 insertions(+), 56 deletions(-) diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/document_node_types.rs index 8a0091db..e5f7a97b 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_types.rs @@ -2355,7 +2355,37 @@ fn static_nodes() -> Vec { DocumentNodeDefinition { name: "Binary Boolean Operation", category: "Vector", - implementation: DocumentNodeImplementation::proto("graphene_std::vector::BinaryBooleanOperationNode<_, _>"), + implementation: DocumentNodeImplementation::Network(NodeNetwork { + exports: vec![NodeInput::node(NodeId(1), 0)], + nodes: [ + DocumentNode { + name: "BinaryBooleanOperation".to_string(), + inputs: vec![ + NodeInput::network(concrete!(graphene_core::vector::VectorData), 0), + NodeInput::network(concrete!(graphene_core::vector::VectorData), 1), + NodeInput::network(concrete!(vector::misc::BooleanOperation), 2), + ], + implementation: DocumentNodeImplementation::proto("graphene_std::vector::BinaryBooleanOperationNode<_, _>"), + metadata: DocumentNodeMetadata { position: glam::IVec2::new(-17, -3) }, + ..Default::default() + }, + DocumentNode { + name: "MemoizeImpure".to_string(), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::ImpureMemoNode<_, _, _>")), + metadata: DocumentNodeMetadata { position: glam::IVec2::new(-10, -3) }, + manual_composition: Some(concrete!(Footprint)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + imports_metadata: (NodeId(generate_uuid()), (-25, -4).into()), + exports_metadata: (NodeId(generate_uuid()), (-2, -4).into()), + ..Default::default() + }), inputs: vec![ DocumentInputType::value("Upper Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), DocumentInputType::value("Lower Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), @@ -2370,64 +2400,60 @@ fn static_nodes() -> Vec { category: "Vector", is_layer: true, implementation: DocumentNodeImplementation::Network(NodeNetwork { - exports: vec![NodeInput::node(NodeId(4), 0)], + exports: vec![NodeInput::node(NodeId(5), 0)], nodes: [ - // Secondary (left) input type coercion - ( - NodeId(0), - DocumentNode { - name: "Boolean Operation".to_string(), - inputs: vec![NodeInput::network(generic!(T), 1), NodeInput::network(concrete!(vector::misc::BooleanOperation), 2)], - implementation: DocumentNodeImplementation::proto("graphene_std::vector::BooleanOperationNode<_>"), - metadata: DocumentNodeMetadata { position: glam::IVec2::new(-16, -1) }, - ..Default::default() - }, - ), // Primary (bottom) input type coercion - ( - NodeId(1), - DocumentNode { - name: "To Graphic Group".to_string(), - inputs: vec![NodeInput::network(generic!(T), 0)], - implementation: DocumentNodeImplementation::proto("graphene_core::ToGraphicGroupNode"), - metadata: DocumentNodeMetadata { position: glam::IVec2::new(-16, -3) }, // To Graphic Group - ..Default::default() - }, - ), - ( - NodeId(2), - DocumentNode { - name: "To Graphic Element".to_string(), - inputs: vec![NodeInput::node(NodeId(0), 0)], - implementation: DocumentNodeImplementation::proto("graphene_core::ToGraphicElementNode"), - metadata: DocumentNodeMetadata { position: glam::IVec2::new(-10, 3) }, // To Graphic Element - ..Default::default() - }, - ), + DocumentNode { + name: "ToGraphicGroup".to_string(), + inputs: vec![NodeInput::network(generic!(T), 0)], + implementation: DocumentNodeImplementation::proto("graphene_core::ToGraphicGroupNode"), + metadata: DocumentNodeMetadata { position: glam::IVec2::new(-9, -3) }, // To Graphic Group + ..Default::default() + }, + // Secondary (left) input type coercion + DocumentNode { + name: "BooleanOperation".to_string(), + inputs: vec![NodeInput::network(generic!(T), 1), NodeInput::network(concrete!(vector::misc::BooleanOperation), 2)], + implementation: DocumentNodeImplementation::proto("graphene_std::vector::BooleanOperationNode<_>"), + metadata: DocumentNodeMetadata { position: glam::IVec2::new(-16, -1) }, + ..Default::default() + }, + DocumentNode { + name: "ToGraphicElement".to_string(), + inputs: vec![NodeInput::node(NodeId(1), 0)], + implementation: DocumentNodeImplementation::proto("graphene_core::ToGraphicElementNode"), + metadata: DocumentNodeMetadata { position: glam::IVec2::new(-9, -1) }, // To Graphic Element + ..Default::default() + }, + DocumentNode { + name: "MemoizeImpure".to_string(), + inputs: vec![NodeInput::node(NodeId(2), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::ImpureMemoNode<_, _, _>")), + metadata: DocumentNodeMetadata { position: glam::IVec2::new(-2, -1) }, + manual_composition: Some(concrete!(Footprint)), + ..Default::default() + }, // The monitor node is used to display a thumbnail in the UI - ( - NodeId(3), - DocumentNode { - inputs: vec![NodeInput::node(NodeId(2), 0)], - metadata: DocumentNodeMetadata { position: glam::IVec2::new(-7, -1) }, // Monitor - ..monitor_node() - }, - ), - ( - NodeId(4), - DocumentNode { - name: "ConstructLayer".to_string(), - manual_composition: Some(concrete!(Footprint)), - inputs: vec![NodeInput::node(NodeId(1), 0), NodeInput::node(NodeId(3), 0)], - implementation: DocumentNodeImplementation::proto("graphene_core::ConstructLayerNode<_, _>"), - metadata: DocumentNodeMetadata { position: glam::IVec2::new(1, -3) }, // ConstructLayer - ..Default::default() - }, - ), + DocumentNode { + inputs: vec![NodeInput::node(NodeId(3), 0)], + metadata: DocumentNodeMetadata { position: glam::IVec2::new(5, -1) }, // Monitor + ..monitor_node() + }, + DocumentNode { + name: "ConstructLayer".to_string(), + manual_composition: Some(concrete!(Footprint)), + inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::node(NodeId(4), 0)], + implementation: DocumentNodeImplementation::proto("graphene_core::ConstructLayerNode<_, _>"), + metadata: DocumentNodeMetadata { position: glam::IVec2::new(12, -3) }, // ConstructLayer + ..Default::default() + }, ] - .into(), - imports_metadata: (NodeId(generate_uuid()), (-26, -4).into()), - exports_metadata: (NodeId(generate_uuid()), (8, -4).into()), + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + imports_metadata: (NodeId(generate_uuid()), (-24, -4).into()), + exports_metadata: (NodeId(generate_uuid()), (19, -4).into()), ..Default::default() }), inputs: vec![ diff --git a/editor/src/messages/portfolio/document/node_graph/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_properties.rs index 5a151333..43b816cb 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_properties.rs @@ -72,7 +72,14 @@ fn add_blank_assist(widgets: &mut Vec) { } fn start_widgets(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, data_type: FrontendGraphDataType, blank_assist: bool) -> Vec { - let input = document_node.inputs.get(index).expect("A widget failed to be built because its node's input index is invalid."); + let Some(input) = document_node.inputs.get(index) else { + log::warn!( + "A widget named '{name}' for node {} (alias '{}') failed to be built because its node's input index {index} is invalid.", + document_node.name, + document_node.alias + ); + return vec![]; + }; let mut widgets = vec![expose_widget(node_id, index, data_type, input.is_exposed()), TextLabel::new(name).widget_holder()]; if blank_assist { add_blank_assist(&mut widgets); diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index 39b6ba05..5dfa3603 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -386,6 +386,7 @@ impl MessageHandler> for PortfolioMes document_is_saved, document_serialized_content, } => { + // It can be helpful to temporarily set `upgrade_from_before_editable_subgraphs` to true if it's desired to upgrade a piece of artwork to use fresh copies of all nodes let upgrade_from_before_editable_subgraphs = document_serialized_content.contains("node_output_index"); let upgrade_vector_manipulation_format = document_serialized_content.contains("ManipulatorGroupIds") && !document_name.contains("__DO_NOT_UPGRADE__"); let document_name = document_name.replace("__DO_NOT_UPGRADE__", ""); diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index 47e2af08..457449b0 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -20,6 +20,7 @@ use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyNode, FutureW use graphene_std::application_io::RenderConfig; use graphene_std::raster::*; use graphene_std::wasm_application_io::*; +use graphene_std::GraphicElement; #[cfg(feature = "gpu")] use wgpu_executor::{CommandBuffer, ShaderHandle, ShaderInputFrame, WgpuExecutor, WgpuShaderInput}; use wgpu_executor::{WgpuSurface, WindowHandle}; @@ -616,6 +617,7 @@ fn node_registry() -> HashMap, input: (), output: wgpu_executor::WindowHandle, params: [wgpu_executor::WindowHandle]), async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: graphene_std::SurfaceFrame, params: [graphene_std::SurfaceFrame]), async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: RenderOutput, params: [RenderOutput]), + async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Footprint, output: GraphicElement, fn_params: [Footprint => GraphicElement]), async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Footprint, output: GraphicGroup, fn_params: [Footprint => GraphicGroup]), async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData]), #[cfg(feature = "gpu")]