Graphene: Fine-grained context caching (#2500)

* RFC: Fine Grained Context Caching

* Fix typos

* Fix label

* Add description of inject traits

* Explicitly support context modification

* Start implementation of context invalidation

* Add inject trait variants
* Route Extract / Inject traits to the proto nodes

* Implement context dependency analysis

* Implement context modification node insertion

* Fix erronous force graph run message

* Fix Extract* Inject* annotations in the nodes

* Require Hash implementation for VarArgs

* Fix nullification node insertion

* Cross of done items unresolved questions section

* Update Cargo.lock

* Fix context features propagation

* Update demo artwork

* Remove BondlessFootprint and FreezeRealTime nodes

* Fix migration

* Add migrations for adding context features to old networks

* Always update real time regardless of animation state

* Cargo fmt

* Fix tests

* Readd sed command to hopefully fix profile result parsing

* Add debug output to profiling pr

* Use new totals instead of summaries for for iai results

* Even more debugging

* Use correct debug metrics (hopefully)

* Add more MemoNode implementations

* Add context features annotation to shader node macro

* Cleanup

* Time -> RealTime

* Code review

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Dennis Kobert
2025-09-05 11:44:26 +00:00
committed by GitHub
co-authored by Keavon Chambers
parent c081d0a9de
commit acd7ba38cc
39 changed files with 869 additions and 328 deletions
@@ -450,14 +450,6 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
node: graphene_std::transform_nodes::transform::IDENTIFIER,
aliases: &["graphene_core::transform::TransformNode"],
},
NodeReplacement {
node: graphene_std::transform_nodes::boundless_footprint::IDENTIFIER,
aliases: &["graphene_core::transform::BoundlessFootprintNode"],
},
NodeReplacement {
node: graphene_std::transform_nodes::freeze_real_time::IDENTIFIER,
aliases: &["graphene_core::transform::FreezeRealTimeNode"],
},
// ???
NodeReplacement {
node: graphene_std::vector::spline::IDENTIFIER,
@@ -485,7 +477,13 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
},
NodeReplacement {
node: graphene_std::ops::identity::IDENTIFIER,
aliases: &["graphene_core::transform::CullNode"],
aliases: &[
"graphene_core::transform::CullNode",
"graphene_core::transform::BoundlessFootprintNode",
"graphene_core::transform::FreezeRealTimeNode",
"graphene_core::transform_nodes::BoundlessFootprintNode",
"graphene_core::transform_nodes::FreezeRealTimeNode",
],
},
NodeReplacement {
node: graphene_std::vector::flatten_path::IDENTIFIER,
@@ -560,7 +558,7 @@ pub fn document_migration_upgrades(document: &mut DocumentMessageHandler, reset_
let mut default_template = NodeTemplate::default();
default_template.document_node.implementation = DocumentNodeImplementation::ProtoNode(new.clone());
document.network_interface.replace_implementation(node_id, &network_path, &mut default_template);
document.network_interface.set_call_argument(node_id, &network_path, graph_craft::Type::Generic("T".into()));
document.network_interface.set_call_argument(node_id, &network_path, default_template.document_node.call_argument);
}
}
}
@@ -587,9 +585,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
// Upgrade old nodes to use `Context` instead of `()` or `Footprint` as their call argument
if node.call_argument == graph_craft::concrete!(()) || node.call_argument == graph_craft::concrete!(graphene_std::transform::Footprint) {
document
.network_interface
.set_call_argument(node_id, network_path, graph_craft::concrete!(graphene_std::Context).into());
document.network_interface.set_call_argument(node_id, network_path, graph_craft::concrete!(graphene_std::Context));
}
// Only nodes that have not been modified and still refer to a definition can be updated
@@ -1051,6 +1047,16 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
document.network_interface.add_import(TaggedValue::U32(0), false, 1, "Loop Level", "TODO", &node_path);
}
// Add context features to nodes that don't have them (fine-grained context caching migration)
if node.context_features == graphene_std::ContextDependencies::default() {
if let Some(reference) = document.network_interface.reference(node_id, network_path).cloned().flatten() {
if let Some(node_definition) = resolve_document_node_type(&reference) {
let context_features = node_definition.node_template.document_node.context_features;
document.network_interface.set_context_features(node_id, network_path, context_features);
}
}
}
// ==================================
// PUT ALL MIGRATIONS ABOVE THIS LINE
// ==================================