Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions node-graph/graph-craft/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ impl DocumentNode {
original_location: self.original_location,
skip_deduplication: self.skip_deduplication,
context_dependencies: self.context_dependencies.unwrap_or_default(),
upstream_context_features: Default::default(),
}
}
}
Expand Down
49 changes: 48 additions & 1 deletion node-graph/graph-craft/src/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ pub struct ProtoNode {
pub original_location: OriginalLocation,
pub skip_deduplication: bool,
pub(crate) context_dependencies: ContextDependencies,
/// The context features read by this node and everything upstream of it.
pub upstream_context_features: ContextFeatures,
}

impl Default for ProtoNode {
Expand All @@ -145,6 +147,7 @@ impl Default for ProtoNode {
original_location: OriginalLocation::default(),
skip_deduplication: false,
context_dependencies: Default::default(),
upstream_context_features: ContextFeatures::empty(),
}
}
}
Expand Down Expand Up @@ -180,6 +183,7 @@ impl ProtoNode {
},
skip_deduplication: false,
context_dependencies: Default::default(),
upstream_context_features: ContextFeatures::empty(),
}
}

Expand Down Expand Up @@ -280,7 +284,8 @@ impl ProtoNetwork {
// Perform topological sort once
self.reorder_ids()?;

self.find_context_dependencies(self.output);
let (output_dependencies, _) = self.find_context_dependencies(self.output);
self.nodes[self.output.0 as usize].1.upstream_context_features = output_dependencies.features;

// Perform topological sort a second time to integrate the new nodes
self.reorder_ids()?;
Expand All @@ -297,6 +302,7 @@ impl ProtoNetwork {
p.push(NodeId(10))
}

let features = context_deps.features;
let memoize_node_id = NodeId(self.nodes.len() as u64);

self.nodes.push((
Expand All @@ -309,6 +315,7 @@ impl ProtoNetwork {
path: path.clone(),
..Default::default()
},
upstream_context_features: features,
..Default::default()
},
));
Expand Down Expand Up @@ -339,6 +346,7 @@ impl ProtoNetwork {
path: path.clone(),
..Default::default()
},
upstream_context_features: features,
..Default::default()
},
));
Expand Down Expand Up @@ -380,6 +388,7 @@ impl ProtoNetwork {
// Compute the dependencies for each branch and combine all of them
for &node in &inputs {
let branch = self.find_context_dependencies(node);
self.nodes[node.0 as usize].1.upstream_context_features = branch.0.features;

combined_deps.features |= branch.0.features;
combined_deps.sources.extend(&branch.0.sources);
Expand Down Expand Up @@ -1133,6 +1142,44 @@ mod test {
.collect()
}

#[test]
fn nodes_record_the_context_features_their_output_depends_on() {
let node = |name: &'static str, construction_args: ConstructionArgs, extract: ContextFeatures, inject: ContextFeatures| ProtoNode {
identifier: ProtoNodeIdentifier::new(name),
call_argument: concrete!(()),
construction_args,
context_dependencies: ContextDependencies { extract, inject },
..Default::default()
};
let none = ContextFeatures::empty();

let mut network = ProtoNetwork {
inputs: vec![],
output: NodeId(3),
nodes: vec![
(NodeId(0), node("value", ConstructionArgs::Value(TaggedValue::Integer(2).into()), none, none)),
(
NodeId(1),
node("reader", ConstructionArgs::Nodes(vec![NodeId(0)]), ContextFeatures::ANIMATION_TIME | ContextFeatures::INDEX, none),
),
(NodeId(2), node("repeat", ConstructionArgs::Nodes(vec![NodeId(1)]), none, ContextFeatures::INDEX)),
(NodeId(3), node("wrap", ConstructionArgs::Nodes(vec![NodeId(2)]), none, none)),
],
};
network.insert_context_nullification_nodes().unwrap();

let features_of = |name: &str| network.nodes.iter().find(|(_, node)| node.identifier.as_str() == name).unwrap().1.upstream_context_features;
assert_eq!(features_of("value"), none);
assert_eq!(features_of("reader"), ContextFeatures::ANIMATION_TIME | ContextFeatures::INDEX);
assert_eq!(features_of("repeat"), ContextFeatures::ANIMATION_TIME);
assert_eq!(features_of("wrap"), ContextFeatures::ANIMATION_TIME);
assert_eq!(features_of(graphene_core::memo::memoize::IDENTIFIER.as_str()), ContextFeatures::ANIMATION_TIME);
assert_eq!(
features_of(graphene_core::context_modification::context_modification::IDENTIFIER.as_str()),
ContextFeatures::ANIMATION_TIME
);
}

fn source_branch_network(branch_a_sources: &[SourceId], branch_b_sources: &[SourceId]) -> ProtoNetwork {
let node = |name: &'static str, construction_args: ConstructionArgs| ProtoNode {
identifier: ProtoNodeIdentifier::new(name),
Expand Down
9 changes: 9 additions & 0 deletions node-graph/interpreted-executor/src/dynamic_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ pub struct BorrowTree {
nodes: HashMap<NodeId, (SharedNodeContainer, Path, Box<[NodeId]>)>,
/// A hashmap from the document path to the proto node ID.
source_map: HashMap<Path, (NodeId, NodeTypes)>,
/// The context features each node's output depends on.
context_features: HashMap<NodeId, core_types::ContextFeatures>,
}

impl BorrowTree {
Expand Down Expand Up @@ -258,6 +260,11 @@ impl BorrowTree {
self.nodes.get(&id).map(|(node, _, _)| node.clone())
}

/// The context features this node's output depends on.
pub fn context_features(&self, id: NodeId) -> core_types::ContextFeatures {
self.context_features.get(&id).copied().unwrap_or_default()
}

/// Evaluate the output node of the [`BorrowTree`].
pub fn eval<I, O>(&self, id: NodeId, input: &I) -> Option<O>
where
Expand Down Expand Up @@ -343,6 +350,7 @@ impl BorrowTree {
/// - If the node is the primary node for its path in the `source_map`, it's also removed from there.
/// - Returns `None` if the node is not found in the `nodes` HashMap.
pub fn free_node(&mut self, id: NodeId) -> Option<Path> {
self.context_features.remove(&id);
let (_, path, _) = self.nodes.remove(&id)?;
if self.source_map.get(&path)?.0 == id {
self.source_map.remove(&path);
Expand Down Expand Up @@ -413,6 +421,7 @@ impl BorrowTree {
/// - Returns an error if no constructor is found for the given node ID.
fn push_node(&mut self, id: NodeId, proto_node: ProtoNode, typing_context: &TypingContext) -> Result<(), GraphErrors> {
self.update_source_map(id, typing_context, &proto_node);
self.context_features.insert(id, proto_node.upstream_context_features);
let path = proto_node.original_location.path.clone().unwrap_or_default();

match &proto_node.construction_args {
Expand Down
Loading