mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-17 15:28:04 +08:00
Make the dynamic node graph execution asynchronous (#1218)
* Make node graph execution async Make node macro generate async node implementations Start propagating async through the node system Async checkpoint Make Any<'i> Send + Sync Determine node io type using panic node Fix types for raster_node macro Finish porting node registry? Fix lifetime errors Remove Send + Sync requirements and start making node construction async Async MVP Fix tests Clippy fix * Fix nodes * Simplify lifetims for node macro + make node macro more modular * Reenable more nodes * Fix pasting images * Remove http test from brush node * Fix output type for cache node * Fix types for let scope * Fix formatting
This commit is contained in:
committed by
Keavon Chambers
parent
5c7211cb30
commit
4bd9fbd073
@@ -1505,7 +1505,7 @@ impl DocumentMessageHandler {
|
||||
/// When working with an insert index, deleting the layers may cause the insert index to point to a different location (if the layer being deleted was located before the insert index).
|
||||
///
|
||||
/// This function updates the insert index so that it points to the same place after the specified `layers` are deleted.
|
||||
fn update_insert_index<'a>(&self, layers: &[&'a [LayerId]], path: &[LayerId], insert_index: isize, reverse_index: bool) -> Result<isize, DocumentError> {
|
||||
fn update_insert_index(&self, layers: &[&[LayerId]], path: &[LayerId], insert_index: isize, reverse_index: bool) -> Result<isize, DocumentError> {
|
||||
let folder = self.document_legacy.folder(path)?;
|
||||
let insert_index = if reverse_index { folder.layer_ids.len() as isize - insert_index } else { insert_index };
|
||||
let layer_ids_above = if insert_index < 0 { &folder.layer_ids } else { &folder.layer_ids[..(insert_index as usize)] };
|
||||
|
||||
@@ -96,7 +96,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
vec![
|
||||
DocumentNodeType {
|
||||
name: "Identity",
|
||||
category: "General",
|
||||
category: "Structural",
|
||||
identifier: NodeImplementation::proto("graphene_core::ops::IdNode"),
|
||||
inputs: vec![DocumentInputType {
|
||||
name: "In",
|
||||
@@ -108,7 +108,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Monitor",
|
||||
category: "General",
|
||||
category: "Structural",
|
||||
identifier: NodeImplementation::proto("graphene_core::ops::IdNode"),
|
||||
inputs: vec![DocumentInputType {
|
||||
name: "In",
|
||||
@@ -186,7 +186,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
category: "Ignore",
|
||||
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
||||
inputs: vec![0],
|
||||
outputs: vec![NodeOutput::new(2, 0)],
|
||||
outputs: vec![NodeOutput::new(1, 0)],
|
||||
nodes: [
|
||||
DocumentNode {
|
||||
name: "Downres".to_string(),
|
||||
@@ -200,12 +200,13 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
// We currently just clone by default
|
||||
/*DocumentNode {
|
||||
name: "Clone".to_string(),
|
||||
inputs: vec![NodeInput::node(1, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::CloneNode<_>")),
|
||||
..Default::default()
|
||||
},
|
||||
},*/
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
@@ -263,10 +264,10 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Begin Scope",
|
||||
category: "Structural",
|
||||
category: "Ignore",
|
||||
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
||||
inputs: vec![0, 2],
|
||||
outputs: vec![NodeOutput::new(1, 0), NodeOutput::new(3, 0)],
|
||||
outputs: vec![NodeOutput::new(1, 0), NodeOutput::new(2, 0)],
|
||||
nodes: [
|
||||
DocumentNode {
|
||||
name: "SetNode".to_string(),
|
||||
@@ -286,12 +287,6 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::RefNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
name: "CloneNode".to_string(),
|
||||
inputs: vec![NodeInput::node(2, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::CloneNode<_>")),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
@@ -319,7 +314,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "End Scope",
|
||||
category: "Structural",
|
||||
category: "Ignore",
|
||||
identifier: NodeImplementation::proto("graphene_std::memo::EndLetNode<_>"),
|
||||
inputs: vec![
|
||||
DocumentInputType {
|
||||
@@ -596,7 +591,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Gaussian Blur",
|
||||
category: "Image Filters",
|
||||
category: "Ignore",
|
||||
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
||||
inputs: vec![0, 1, 1],
|
||||
outputs: vec![NodeOutput::new(1, 0)],
|
||||
|
||||
@@ -24,7 +24,7 @@ struct ManipulatorGroupOverlays {
|
||||
pub out_line: Option<Vec<LayerId>>,
|
||||
}
|
||||
impl ManipulatorGroupOverlays {
|
||||
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a Option<Vec<LayerId>>> {
|
||||
pub fn iter(&self) -> impl Iterator<Item = &'_ Option<Vec<LayerId>>> {
|
||||
[&self.anchor, &self.in_handle, &self.in_line, &self.out_handle, &self.out_line].into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ impl ShapeState {
|
||||
}
|
||||
|
||||
/// Provide the currently selected points by reference.
|
||||
pub fn selected_points<'a>(&'a self) -> impl Iterator<Item = &'a ManipulatorPointId> {
|
||||
pub fn selected_points(&self) -> impl Iterator<Item = &'_ ManipulatorPointId> {
|
||||
self.selected_shape_state.values().flat_map(|state| &state.selected_points)
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ use interpreted_executor::executor::DynamicExecutor;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::sync::mpsc::{Receiver, Sender};
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -58,7 +59,7 @@ pub(crate) struct GenerationResponse {
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static NODE_RUNTIME: RefCell<Option<NodeRuntime>> = RefCell::new(None);
|
||||
pub(crate) static NODE_RUNTIME: Rc<RefCell<Option<NodeRuntime>>> = Rc::new(RefCell::new(None));
|
||||
}
|
||||
|
||||
impl NodeRuntime {
|
||||
@@ -72,7 +73,7 @@ impl NodeRuntime {
|
||||
thumbnails: Default::default(),
|
||||
}
|
||||
}
|
||||
pub fn run(&mut self) {
|
||||
pub async fn run(&mut self) {
|
||||
let mut requests = self.receiver.try_iter().collect::<Vec<_>>();
|
||||
// TODO: Currently we still render the document after we submit the node graph execution request.
|
||||
// This should be avoided in the future.
|
||||
@@ -94,7 +95,7 @@ impl NodeRuntime {
|
||||
}) => {
|
||||
let (network, monitor_nodes) = Self::wrap_network(graph);
|
||||
|
||||
let result = self.execute_network(network, image_frame);
|
||||
let result = self.execute_network(network, image_frame).await;
|
||||
let mut responses = VecDeque::new();
|
||||
self.update_thumbnails(&path, monitor_nodes, &mut responses);
|
||||
let response = GenerationResponse {
|
||||
@@ -125,7 +126,7 @@ impl NodeRuntime {
|
||||
(scoped_network, monitor_nodes)
|
||||
}
|
||||
|
||||
fn execute_network<'a>(&'a mut self, scoped_network: NodeNetwork, image_frame: Option<ImageFrame<Color>>) -> Result<TaggedValue, String> {
|
||||
async fn execute_network<'a>(&'a mut self, scoped_network: NodeNetwork, image_frame: Option<ImageFrame<Color>>) -> Result<TaggedValue, String> {
|
||||
let editor_api = EditorApi {
|
||||
font_cache: Some(&self.font_cache),
|
||||
image_frame,
|
||||
@@ -137,7 +138,7 @@ impl NodeRuntime {
|
||||
let proto_network = c.compile_single(scoped_network, true)?;
|
||||
|
||||
assert_ne!(proto_network.nodes.len(), 0, "No protonodes exist?");
|
||||
if let Err(e) = self.executor.update(proto_network) {
|
||||
if let Err(e) = self.executor.update(proto_network).await {
|
||||
error!("Failed to update executor:\n{}", e);
|
||||
return Err(e);
|
||||
}
|
||||
@@ -146,8 +147,8 @@ impl NodeRuntime {
|
||||
use graph_craft::executor::Executor;
|
||||
|
||||
let result = match self.executor.input_type() {
|
||||
Some(t) if t == concrete!(EditorApi) => self.executor.execute(editor_api.into_dyn()).map_err(|e| e.to_string()),
|
||||
Some(t) if t == concrete!(()) => self.executor.execute(().into_dyn()).map_err(|e| e.to_string()),
|
||||
Some(t) if t == concrete!(EditorApi) => self.executor.execute(editor_api.into_dyn()).await.map_err(|e| e.to_string()),
|
||||
Some(t) if t == concrete!(()) => self.executor.execute(().into_dyn()).await.map_err(|e| e.to_string()),
|
||||
_ => Err("Invalid input type".to_string()),
|
||||
};
|
||||
match result {
|
||||
@@ -200,13 +201,21 @@ impl NodeRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_node_graph() {
|
||||
NODE_RUNTIME.with(|runtime| {
|
||||
let mut runtime = runtime.borrow_mut();
|
||||
if let Some(runtime) = runtime.as_mut() {
|
||||
runtime.run();
|
||||
pub async fn run_node_graph() {
|
||||
let result = NODE_RUNTIME.try_with(|runtime| {
|
||||
let runtime = runtime.clone();
|
||||
async move {
|
||||
let mut runtime = runtime.try_borrow_mut();
|
||||
if let Ok(ref mut runtime) = runtime {
|
||||
if let Some(ref mut runtime) = runtime.as_mut() {
|
||||
runtime.run().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if let Ok(result) = result {
|
||||
result.await;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -231,8 +240,7 @@ impl Default for NodeGraphExecutor {
|
||||
let (request_sender, request_reciever) = std::sync::mpsc::channel();
|
||||
let (response_sender, response_reciever) = std::sync::mpsc::channel();
|
||||
NODE_RUNTIME.with(|runtime| {
|
||||
let mut runtime = runtime.borrow_mut();
|
||||
*runtime = Some(NodeRuntime::new(request_reciever, response_sender));
|
||||
runtime.borrow_mut().replace(NodeRuntime::new(request_reciever, response_sender));
|
||||
});
|
||||
|
||||
Self {
|
||||
|
||||
Reference in New Issue
Block a user