mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
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:
@@ -46,6 +46,10 @@ const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[
|
||||
))),
|
||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::DocumentStructureChanged)),
|
||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::Overlays(OverlaysMessageDiscriminant::Draw))),
|
||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::NodeGraph(
|
||||
NodeGraphMessageDiscriminant::RunDocumentGraph,
|
||||
))),
|
||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::SubmitActiveGraphRender),
|
||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::RenderRulers)),
|
||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::RenderScrollbars)),
|
||||
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerStructure),
|
||||
|
||||
@@ -99,14 +99,11 @@ impl MessageHandler<AnimationMessage, ()> for AnimationMessageHandler {
|
||||
}
|
||||
}
|
||||
AnimationMessage::UpdateTime => {
|
||||
if self.is_playing() {
|
||||
responses.add(PortfolioMessage::SubmitActiveGraphRender);
|
||||
|
||||
if self.live_preview_recently_zero {
|
||||
// Update the restart and pause/play buttons
|
||||
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
||||
self.live_preview_recently_zero = false;
|
||||
}
|
||||
responses.add(PortfolioMessage::SubmitActiveGraphRender);
|
||||
if self.is_playing() && self.live_preview_recently_zero {
|
||||
// Update the restart and pause/play buttons
|
||||
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
||||
self.live_preview_recently_zero = false;
|
||||
}
|
||||
}
|
||||
AnimationMessage::RestartAnimation => {
|
||||
|
||||
@@ -2604,7 +2604,7 @@ impl DocumentMessageHandler {
|
||||
layout: Layout::WidgetLayout(document_bar_layout),
|
||||
layout_target: LayoutTarget::DocumentBar,
|
||||
});
|
||||
responses.add(NodeGraphMessage::ForceRunDocumentGraph);
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
|
||||
pub fn update_layers_panel_control_bar_widgets(&self, layers_panel_open: bool, responses: &mut VecDeque<Message>) {
|
||||
|
||||
@@ -145,74 +145,12 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
category: "General",
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
||||
exports: vec![NodeInput::node(NodeId(2), 0)],
|
||||
nodes: [
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::network(generic!(T), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::freeze_real_time::IDENTIFIER),
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(1), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::boundless_footprint::IDENTIFIER),
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, node)| (NodeId(id as u64), node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![NodeInput::value(TaggedValue::None, true)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
network_metadata: Some(NodeNetworkMetadata {
|
||||
persistent_metadata: NodeNetworkPersistentMetadata {
|
||||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Memoize".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Freeze Real Time".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Boundless Footprint".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, node)| (NodeId(id as u64), node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
}),
|
||||
input_metadata: vec![("Data", "TODO").into()],
|
||||
output_names: vec!["Data".to_string()],
|
||||
..Default::default()
|
||||
@@ -1517,7 +1455,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
||||
exports: vec![NodeInput::node(NodeId(3), 0)],
|
||||
exports: vec![NodeInput::node(NodeId(1), 0)],
|
||||
nodes: vec![
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::network(concrete!(Table<Vector>), 0), NodeInput::network(concrete!(vector::style::Fill), 1)],
|
||||
@@ -1531,18 +1469,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(1), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::freeze_real_time::IDENTIFIER),
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(2), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::boundless_footprint::IDENTIFIER),
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
@@ -1576,22 +1502,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Freeze Real Time".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Boundless Footprint".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(21, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
@@ -1615,7 +1525,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
||||
exports: vec![NodeInput::node(NodeId(4), 0)],
|
||||
exports: vec![NodeInput::node(NodeId(2), 0)],
|
||||
nodes: [
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::network(concrete!(Table<Vector>), 0)],
|
||||
@@ -1644,18 +1554,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(2), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::freeze_real_time::IDENTIFIER),
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(3), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::boundless_footprint::IDENTIFIER),
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
@@ -1702,22 +1600,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Freeze Real Time".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(21, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Boundless Footprint".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(28, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
@@ -1781,7 +1663,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
||||
exports: vec![NodeInput::node(NodeId(3), 0)],
|
||||
exports: vec![NodeInput::node(NodeId(1), 0)],
|
||||
nodes: [
|
||||
DocumentNode {
|
||||
inputs: vec![
|
||||
@@ -1799,18 +1681,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(1), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::freeze_real_time::IDENTIFIER),
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(2), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::boundless_footprint::IDENTIFIER),
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
@@ -1845,22 +1715,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Freeze Real Time".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Boundless Footprint".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(21, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
|
||||
@@ -43,6 +43,7 @@ pub(super) fn post_process_nodes(mut custom: Vec<DocumentNodeDefinition>) -> Vec
|
||||
fields,
|
||||
description,
|
||||
properties,
|
||||
context_features,
|
||||
} = metadata;
|
||||
|
||||
let Some(implementations) = &node_registry.get(id) else { continue };
|
||||
@@ -59,10 +60,11 @@ pub(super) fn post_process_nodes(mut custom: Vec<DocumentNodeDefinition>) -> Vec
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
inputs,
|
||||
call_argument: (input_type.clone()),
|
||||
call_argument: input_type.clone(),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(id.clone()),
|
||||
visible: true,
|
||||
skip_deduplication: false,
|
||||
context_features: ContextDependencies::from(context_features.as_slice()),
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
|
||||
@@ -16,6 +16,7 @@ use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput, NodeNetwork, OldDocumentNodeImplementation, OldNodeNetwork};
|
||||
use graph_craft::{Type, concrete};
|
||||
use graphene_std::Artboard;
|
||||
use graphene_std::ContextDependencies;
|
||||
use graphene_std::math::quad::Quad;
|
||||
use graphene_std::subpath::Subpath;
|
||||
use graphene_std::table::Table;
|
||||
@@ -1248,11 +1249,7 @@ impl NodeNetworkInterface {
|
||||
|
||||
/// Returns the display name of the node. If the display name is empty, it will return "Untitled Node" or "Untitled Layer" depending on the node type.
|
||||
pub fn display_name(&self, node_id: &NodeId, network_path: &[NodeId]) -> String {
|
||||
let is_layer = self
|
||||
.node_metadata(node_id, network_path)
|
||||
.expect("Could not get persistent node metadata in untitled_layer_label")
|
||||
.persistent_metadata
|
||||
.is_layer();
|
||||
let is_layer = self.is_layer(node_id, network_path);
|
||||
|
||||
let Some(reference) = self.reference(node_id, network_path) else {
|
||||
log::error!("Could not get reference in untitled_layer_label");
|
||||
@@ -4205,6 +4202,18 @@ impl NodeNetworkInterface {
|
||||
node.call_argument = call_argument;
|
||||
}
|
||||
|
||||
pub fn set_context_features(&mut self, node_id: &NodeId, network_path: &[NodeId], context_features: ContextDependencies) {
|
||||
let Some(network) = self.network_mut(network_path) else {
|
||||
log::error!("Could not get nested network in set_context_features");
|
||||
return;
|
||||
};
|
||||
let Some(node) = network.nodes.get_mut(node_id) else {
|
||||
log::error!("Could not get node in set_context_features");
|
||||
return;
|
||||
};
|
||||
node.context_features = context_features;
|
||||
}
|
||||
|
||||
pub fn set_input(&mut self, input_connector: &InputConnector, new_input: NodeInput, network_path: &[NodeId]) {
|
||||
if matches!(input_connector, InputConnector::Export(_)) && matches!(new_input, NodeInput::Network { .. }) {
|
||||
// TODO: Add support for flattening NodeInput::Network exports in flatten_with_fns https://github.com/GraphiteEditor/Graphite/issues/1762
|
||||
|
||||
@@ -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
|
||||
// ==================================
|
||||
|
||||
Reference in New Issue
Block a user