mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-03 13:02:20 +00: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:
parent
5c7211cb30
commit
4bd9fbd073
40 changed files with 834 additions and 471 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -1659,6 +1659,7 @@ dependencies = [
|
||||||
"compilation-client",
|
"compilation-client",
|
||||||
"dyn-any",
|
"dyn-any",
|
||||||
"dyn-clone",
|
"dyn-clone",
|
||||||
|
"futures",
|
||||||
"glam",
|
"glam",
|
||||||
"gpu-compiler-bin-wrapper",
|
"gpu-compiler-bin-wrapper",
|
||||||
"gpu-executor",
|
"gpu-executor",
|
||||||
|
@ -1671,6 +1672,7 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
|
@ -2140,6 +2142,7 @@ dependencies = [
|
||||||
"borrow_stack",
|
"borrow_stack",
|
||||||
"dyn-any",
|
"dyn-any",
|
||||||
"dyn-clone",
|
"dyn-clone",
|
||||||
|
"futures",
|
||||||
"glam",
|
"glam",
|
||||||
"graph-craft",
|
"graph-craft",
|
||||||
"graphene-core",
|
"graphene-core",
|
||||||
|
@ -2148,6 +2151,7 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"serde",
|
"serde",
|
||||||
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -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).
|
/// 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.
|
/// 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 folder = self.document_legacy.folder(path)?;
|
||||||
let insert_index = if reverse_index { folder.layer_ids.len() as isize - insert_index } else { insert_index };
|
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)] };
|
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![
|
vec![
|
||||||
DocumentNodeType {
|
DocumentNodeType {
|
||||||
name: "Identity",
|
name: "Identity",
|
||||||
category: "General",
|
category: "Structural",
|
||||||
identifier: NodeImplementation::proto("graphene_core::ops::IdNode"),
|
identifier: NodeImplementation::proto("graphene_core::ops::IdNode"),
|
||||||
inputs: vec![DocumentInputType {
|
inputs: vec![DocumentInputType {
|
||||||
name: "In",
|
name: "In",
|
||||||
|
@ -108,7 +108,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||||
},
|
},
|
||||||
DocumentNodeType {
|
DocumentNodeType {
|
||||||
name: "Monitor",
|
name: "Monitor",
|
||||||
category: "General",
|
category: "Structural",
|
||||||
identifier: NodeImplementation::proto("graphene_core::ops::IdNode"),
|
identifier: NodeImplementation::proto("graphene_core::ops::IdNode"),
|
||||||
inputs: vec![DocumentInputType {
|
inputs: vec![DocumentInputType {
|
||||||
name: "In",
|
name: "In",
|
||||||
|
@ -186,7 +186,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||||
category: "Ignore",
|
category: "Ignore",
|
||||||
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
||||||
inputs: vec![0],
|
inputs: vec![0],
|
||||||
outputs: vec![NodeOutput::new(2, 0)],
|
outputs: vec![NodeOutput::new(1, 0)],
|
||||||
nodes: [
|
nodes: [
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
name: "Downres".to_string(),
|
name: "Downres".to_string(),
|
||||||
|
@ -200,12 +200,13 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")),
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
DocumentNode {
|
// We currently just clone by default
|
||||||
|
/*DocumentNode {
|
||||||
name: "Clone".to_string(),
|
name: "Clone".to_string(),
|
||||||
inputs: vec![NodeInput::node(1, 0)],
|
inputs: vec![NodeInput::node(1, 0)],
|
||||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::CloneNode<_>")),
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::CloneNode<_>")),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},*/
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
@ -263,10 +264,10 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||||
},
|
},
|
||||||
DocumentNodeType {
|
DocumentNodeType {
|
||||||
name: "Begin Scope",
|
name: "Begin Scope",
|
||||||
category: "Structural",
|
category: "Ignore",
|
||||||
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
||||||
inputs: vec![0, 2],
|
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: [
|
nodes: [
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
name: "SetNode".to_string(),
|
name: "SetNode".to_string(),
|
||||||
|
@ -286,12 +287,6 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::RefNode<_, _>")),
|
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::RefNode<_, _>")),
|
||||||
..Default::default()
|
..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()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
@ -319,7 +314,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||||
},
|
},
|
||||||
DocumentNodeType {
|
DocumentNodeType {
|
||||||
name: "End Scope",
|
name: "End Scope",
|
||||||
category: "Structural",
|
category: "Ignore",
|
||||||
identifier: NodeImplementation::proto("graphene_std::memo::EndLetNode<_>"),
|
identifier: NodeImplementation::proto("graphene_std::memo::EndLetNode<_>"),
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
DocumentInputType {
|
DocumentInputType {
|
||||||
|
@ -596,7 +591,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||||
},
|
},
|
||||||
DocumentNodeType {
|
DocumentNodeType {
|
||||||
name: "Gaussian Blur",
|
name: "Gaussian Blur",
|
||||||
category: "Image Filters",
|
category: "Ignore",
|
||||||
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
||||||
inputs: vec![0, 1, 1],
|
inputs: vec![0, 1, 1],
|
||||||
outputs: vec![NodeOutput::new(1, 0)],
|
outputs: vec![NodeOutput::new(1, 0)],
|
||||||
|
|
|
@ -24,7 +24,7 @@ struct ManipulatorGroupOverlays {
|
||||||
pub out_line: Option<Vec<LayerId>>,
|
pub out_line: Option<Vec<LayerId>>,
|
||||||
}
|
}
|
||||||
impl ManipulatorGroupOverlays {
|
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()
|
[&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.
|
/// 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)
|
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 glam::{DAffine2, DVec2};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::sync::mpsc::{Receiver, Sender};
|
use std::sync::mpsc::{Receiver, Sender};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ pub(crate) struct GenerationResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_local! {
|
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 {
|
impl NodeRuntime {
|
||||||
|
@ -72,7 +73,7 @@ impl NodeRuntime {
|
||||||
thumbnails: Default::default(),
|
thumbnails: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn run(&mut self) {
|
pub async fn run(&mut self) {
|
||||||
let mut requests = self.receiver.try_iter().collect::<Vec<_>>();
|
let mut requests = self.receiver.try_iter().collect::<Vec<_>>();
|
||||||
// TODO: Currently we still render the document after we submit the node graph execution request.
|
// TODO: Currently we still render the document after we submit the node graph execution request.
|
||||||
// This should be avoided in the future.
|
// This should be avoided in the future.
|
||||||
|
@ -94,7 +95,7 @@ impl NodeRuntime {
|
||||||
}) => {
|
}) => {
|
||||||
let (network, monitor_nodes) = Self::wrap_network(graph);
|
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();
|
let mut responses = VecDeque::new();
|
||||||
self.update_thumbnails(&path, monitor_nodes, &mut responses);
|
self.update_thumbnails(&path, monitor_nodes, &mut responses);
|
||||||
let response = GenerationResponse {
|
let response = GenerationResponse {
|
||||||
|
@ -125,7 +126,7 @@ impl NodeRuntime {
|
||||||
(scoped_network, monitor_nodes)
|
(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 {
|
let editor_api = EditorApi {
|
||||||
font_cache: Some(&self.font_cache),
|
font_cache: Some(&self.font_cache),
|
||||||
image_frame,
|
image_frame,
|
||||||
|
@ -137,7 +138,7 @@ impl NodeRuntime {
|
||||||
let proto_network = c.compile_single(scoped_network, true)?;
|
let proto_network = c.compile_single(scoped_network, true)?;
|
||||||
|
|
||||||
assert_ne!(proto_network.nodes.len(), 0, "No protonodes exist?");
|
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);
|
error!("Failed to update executor:\n{}", e);
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
|
@ -146,8 +147,8 @@ impl NodeRuntime {
|
||||||
use graph_craft::executor::Executor;
|
use graph_craft::executor::Executor;
|
||||||
|
|
||||||
let result = match self.executor.input_type() {
|
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!(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()).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()),
|
_ => Err("Invalid input type".to_string()),
|
||||||
};
|
};
|
||||||
match result {
|
match result {
|
||||||
|
@ -200,13 +201,21 @@ impl NodeRuntime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_node_graph() {
|
pub async fn run_node_graph() {
|
||||||
NODE_RUNTIME.with(|runtime| {
|
let result = NODE_RUNTIME.try_with(|runtime| {
|
||||||
let mut runtime = runtime.borrow_mut();
|
let runtime = runtime.clone();
|
||||||
if let Some(runtime) = runtime.as_mut() {
|
async move {
|
||||||
runtime.run();
|
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)]
|
#[derive(Debug)]
|
||||||
|
@ -231,8 +240,7 @@ impl Default for NodeGraphExecutor {
|
||||||
let (request_sender, request_reciever) = std::sync::mpsc::channel();
|
let (request_sender, request_reciever) = std::sync::mpsc::channel();
|
||||||
let (response_sender, response_reciever) = std::sync::mpsc::channel();
|
let (response_sender, response_reciever) = std::sync::mpsc::channel();
|
||||||
NODE_RUNTIME.with(|runtime| {
|
NODE_RUNTIME.with(|runtime| {
|
||||||
let mut runtime = runtime.borrow_mut();
|
runtime.borrow_mut().replace(NodeRuntime::new(request_reciever, response_sender));
|
||||||
*runtime = Some(NodeRuntime::new(request_reciever, response_sender));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -12,12 +12,15 @@ use axum::routing::get;
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
use fern::colors::{Color, ColoredLevelConfig};
|
use fern::colors::{Color, ColoredLevelConfig};
|
||||||
use http::{Response, StatusCode};
|
use http::{Response, StatusCode};
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
static IMAGES: Mutex<Option<HashMap<String, FrontendImageData>>> = Mutex::new(None);
|
static IMAGES: Mutex<Option<HashMap<String, FrontendImageData>>> = Mutex::new(None);
|
||||||
static EDITOR: Mutex<Option<Editor>> = Mutex::new(None);
|
thread_local! {
|
||||||
|
static EDITOR: RefCell<Option<Editor>> = RefCell::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
async fn respond_to(id: Path<String>) -> impl IntoResponse {
|
async fn respond_to(id: Path<String>) -> impl IntoResponse {
|
||||||
let builder = Response::builder().header("Access-Control-Allow-Origin", "*").status(StatusCode::OK);
|
let builder = Response::builder().header("Access-Control-Allow-Origin", "*").status(StatusCode::OK);
|
||||||
|
@ -55,7 +58,7 @@ async fn main() {
|
||||||
|
|
||||||
*(IMAGES.lock().unwrap()) = Some(HashMap::new());
|
*(IMAGES.lock().unwrap()) = Some(HashMap::new());
|
||||||
graphite_editor::application::set_uuid_seed(0);
|
graphite_editor::application::set_uuid_seed(0);
|
||||||
*(EDITOR.lock().unwrap()) = Some(Editor::new());
|
EDITOR.with(|editor| editor.borrow_mut().replace(Editor::new()));
|
||||||
let app = Router::new().route("/", get(|| async { "Hello, World!" })).route("/image/:id", get(respond_to));
|
let app = Router::new().route("/", get(|| async { "Hello, World!" })).route("/image/:id", get(respond_to));
|
||||||
|
|
||||||
// run it with hyper on localhost:3000
|
// run it with hyper on localhost:3000
|
||||||
|
@ -84,9 +87,10 @@ fn handle_message(message: String) -> String {
|
||||||
let Ok(message) = ron::from_str::<graphite_editor::messages::message::Message>(&message) else {
|
let Ok(message) = ron::from_str::<graphite_editor::messages::message::Message>(&message) else {
|
||||||
panic!("Error parsing message: {}", message)
|
panic!("Error parsing message: {}", message)
|
||||||
};
|
};
|
||||||
let mut guard = EDITOR.lock().unwrap();
|
let responses = EDITOR.with(|editor| {
|
||||||
let editor = (*guard).as_mut().unwrap();
|
let mut editor = editor.borrow_mut();
|
||||||
let responses = editor.handle_message(message);
|
editor.as_mut().unwrap().handle_message(message)
|
||||||
|
});
|
||||||
|
|
||||||
// Sends a FrontendMessage to JavaScript
|
// Sends a FrontendMessage to JavaScript
|
||||||
fn send_frontend_message_to_js(message: FrontendMessage) -> FrontendMessage {
|
fn send_frontend_message_to_js(message: FrontendMessage) -> FrontendMessage {
|
||||||
|
|
|
@ -59,16 +59,17 @@ fn window() -> web_sys::Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_animation_frame(f: &Closure<dyn FnMut()>) {
|
fn request_animation_frame(f: &Closure<dyn FnMut()>) {
|
||||||
|
//window().request_idle_callback(f.as_ref().unchecked_ref()).unwrap();
|
||||||
window().request_animation_frame(f.as_ref().unchecked_ref()).expect("should register `requestAnimationFrame` OK");
|
window().request_animation_frame(f.as_ref().unchecked_ref()).expect("should register `requestAnimationFrame` OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sends a message to the dispatcher in the Editor Backend
|
// Sends a message to the dispatcher in the Editor Backend
|
||||||
fn poll_node_graph_evaluation() {
|
async fn poll_node_graph_evaluation() {
|
||||||
// Process no further messages after a crash to avoid spamming the console
|
// Process no further messages after a crash to avoid spamming the console
|
||||||
if EDITOR_HAS_CRASHED.load(Ordering::SeqCst) {
|
if EDITOR_HAS_CRASHED.load(Ordering::SeqCst) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
editor::node_graph_executor::run_node_graph();
|
editor::node_graph_executor::run_node_graph().await;
|
||||||
|
|
||||||
// Get the editor instances, dispatch the message, and store the `FrontendMessage` queue response
|
// Get the editor instances, dispatch the message, and store the `FrontendMessage` queue response
|
||||||
EDITOR_INSTANCES.with(|instances| {
|
EDITOR_INSTANCES.with(|instances| {
|
||||||
|
@ -218,7 +219,7 @@ impl JsEditorHandle {
|
||||||
let g = f.clone();
|
let g = f.clone();
|
||||||
|
|
||||||
*g.borrow_mut() = Some(Closure::new(move || {
|
*g.borrow_mut() = Some(Closure::new(move || {
|
||||||
poll_node_graph_evaluation();
|
wasm_bindgen_futures::spawn_local(poll_node_graph_evaluation());
|
||||||
|
|
||||||
// Schedule ourself for another requestAnimationFrame callback.
|
// Schedule ourself for another requestAnimationFrame callback.
|
||||||
request_animation_frame(f.borrow().as_ref().unwrap());
|
request_animation_frame(f.borrow().as_ref().unwrap());
|
||||||
|
@ -788,7 +789,7 @@ impl JsEditorHandle {
|
||||||
Some(message_data)
|
Some(message_data)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
frontend_messages.unwrap().unwrap_or_default().into()
|
frontend_messages.unwrap().unwrap_or_default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -637,7 +637,7 @@ mod tests {
|
||||||
|
|
||||||
let outline = subpath.outline(10., crate::Join::Round, crate::Cap::Round).0;
|
let outline = subpath.outline(10., crate::Join::Round, crate::Cap::Round).0;
|
||||||
assert!(outline.manipulator_groups.windows(2).all(|pair| !pair[0].anchor.abs_diff_eq(pair[1].anchor, MAX_ABSOLUTE_DIFFERENCE)));
|
assert!(outline.manipulator_groups.windows(2).all(|pair| !pair[0].anchor.abs_diff_eq(pair[1].anchor, MAX_ABSOLUTE_DIFFERENCE)));
|
||||||
assert_eq!(outline.closed(), true);
|
assert!(outline.closed());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -193,9 +193,18 @@ unsafe impl<T: StaticTypeSized, const N: usize> StaticType for [T; N] {
|
||||||
type Static = [<T as StaticTypeSized>::Static; N];
|
type Static = [<T as StaticTypeSized>::Static; N];
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'a> StaticType for dyn DynAny<'a> + '_ {
|
unsafe impl StaticType for dyn for<'i> DynAny<'_> + '_ {
|
||||||
type Static = dyn DynAny<'static>;
|
type Static = dyn DynAny<'static>;
|
||||||
}
|
}
|
||||||
|
unsafe impl StaticType for dyn for<'i> DynAny<'_> + Send + Sync + '_ {
|
||||||
|
type Static = dyn DynAny<'static> + Send + Sync;
|
||||||
|
}
|
||||||
|
unsafe impl<T: StaticTypeSized> StaticType for dyn core::future::Future<Output = T> + Send + Sync + '_ {
|
||||||
|
type Static = dyn core::future::Future<Output = T::Static> + Send + Sync;
|
||||||
|
}
|
||||||
|
unsafe impl<T: StaticTypeSized> StaticType for dyn core::future::Future<Output = T> + '_ {
|
||||||
|
type Static = dyn core::future::Future<Output = T::Static>;
|
||||||
|
}
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub trait IntoDynAny<'n>: Sized + StaticType + 'n {
|
pub trait IntoDynAny<'n>: Sized + StaticType + 'n {
|
||||||
fn into_dyn(self) -> Box<dyn DynAny<'n> + 'n> {
|
fn into_dyn(self) -> Box<dyn DynAny<'n> + 'n> {
|
||||||
|
@ -228,13 +237,14 @@ use core::{
|
||||||
mem::{ManuallyDrop, MaybeUninit},
|
mem::{ManuallyDrop, MaybeUninit},
|
||||||
num::Wrapping,
|
num::Wrapping,
|
||||||
ops::Range,
|
ops::Range,
|
||||||
|
pin::Pin,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl_type!(
|
impl_type!(
|
||||||
Option<T>, Result<T, E>, Cell<T>, UnsafeCell<T>, RefCell<T>, MaybeUninit<T>,
|
Option<T>, Result<T, E>, Cell<T>, UnsafeCell<T>, RefCell<T>, MaybeUninit<T>,
|
||||||
ManuallyDrop<T>, PhantomData<T>, PhantomPinned, Empty<T>, Range<T>,
|
ManuallyDrop<T>, PhantomData<T>, PhantomPinned, Empty<T>, Range<T>,
|
||||||
Wrapping<T>, Duration, bool, f32, f64, char,
|
Wrapping<T>, Pin<T>, Duration, bool, f32, f64, char,
|
||||||
u8, AtomicU8, u16, AtomicU16, u32, AtomicU32, u64, usize, AtomicUsize,
|
u8, AtomicU8, u16, AtomicU16, u32, AtomicU32, u64, usize, AtomicUsize,
|
||||||
i8, AtomicI8, i16, AtomicI16, i32, AtomicI32, i64, isize, AtomicIsize,
|
i8, AtomicI8, i16, AtomicI16, i32, AtomicI32, i64, isize, AtomicIsize,
|
||||||
i128, u128, AtomicBool, AtomicPtr<T>
|
i128, u128, AtomicBool, AtomicPtr<T>
|
||||||
|
|
|
@ -60,6 +60,10 @@ where
|
||||||
Self::Output: 'i + StaticTypeSized,
|
Self::Output: 'i + StaticTypeSized,
|
||||||
Input: 'i + StaticTypeSized,
|
Input: 'i + StaticTypeSized,
|
||||||
{
|
{
|
||||||
|
fn node_name(&self) -> &'static str {
|
||||||
|
core::any::type_name::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
fn input_type(&self) -> TypeId {
|
fn input_type(&self) -> TypeId {
|
||||||
TypeId::of::<Input::Static>()
|
TypeId::of::<Input::Static>()
|
||||||
}
|
}
|
||||||
|
@ -121,6 +125,13 @@ impl<'i, I: 'i, O: 'i> Node<'i, I> for Pin<Box<dyn for<'a> Node<'a, I, Output =
|
||||||
(**self).eval(input)
|
(**self).eval(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<'i, I: 'i, O: 'i> Node<'i, I> for Pin<&'i (dyn NodeIO<'i, I, Output = O> + 'i)> {
|
||||||
|
type Output = O;
|
||||||
|
|
||||||
|
fn eval(&'i self, input: I) -> Self::Output {
|
||||||
|
(**self).eval(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub use crate::raster::image::{EditorApi, ExtractImageFrame};
|
pub use crate::raster::image::{EditorApi, ExtractImageFrame};
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub struct AddParameterNode<Second> {
|
||||||
second: Second,
|
second: Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(AddParameterNode)]
|
#[node_macro::node_new(AddParameterNode)]
|
||||||
fn add_parameter<U, T>(first: U, second: T) -> <U as Add<T>>::Output
|
fn add_parameter<U, T>(first: U, second: T) -> <U as Add<T>>::Output
|
||||||
where
|
where
|
||||||
U: Add<T>,
|
U: Add<T>,
|
||||||
|
@ -30,6 +30,24 @@ where
|
||||||
first + second
|
first + second
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[automatically_derived]
|
||||||
|
impl<'input, U: 'input, T: 'input, S0: 'input> Node<'input, U> for AddParameterNode<S0>
|
||||||
|
where
|
||||||
|
U: Add<T>,
|
||||||
|
S0: Node<'input, (), Output = T>,
|
||||||
|
{
|
||||||
|
type Output = <U as Add<T>>::Output;
|
||||||
|
#[inline]
|
||||||
|
fn eval(&'input self, first: U) -> Self::Output {
|
||||||
|
let second = self.second.eval(());
|
||||||
|
{
|
||||||
|
{
|
||||||
|
first + second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct MulParameterNode<Second> {
|
pub struct MulParameterNode<Second> {
|
||||||
second: Second,
|
second: Second,
|
||||||
}
|
}
|
||||||
|
@ -181,7 +199,7 @@ pub struct MapResultNode<I, E, Mn> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(MapResultNode<_I, _E>)]
|
#[node_macro::node_fn(MapResultNode<_I, _E>)]
|
||||||
fn flat_map<_I, _E, N>(input: Result<_I, _E>, node: &'any_input N) -> Result<<N as Node<'input, _I>>::Output, _E>
|
fn flat_map<_I, _E, N>(input: Result<_I, _E>, node: &'input N) -> Result<<N as Node<'input, _I>>::Output, _E>
|
||||||
where
|
where
|
||||||
N: for<'a> Node<'a, _I>,
|
N: for<'a> Node<'a, _I>,
|
||||||
{
|
{
|
||||||
|
@ -195,7 +213,7 @@ pub struct FlatMapResultNode<I, O, E, Mn> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(FlatMapResultNode<_I, _O, _E>)]
|
#[node_macro::node_fn(FlatMapResultNode<_I, _O, _E>)]
|
||||||
fn flat_map<_I, _O, _E, N>(input: Result<_I, _E>, node: &'any_input N) -> Result<_O, _E>
|
fn flat_map<_I, _O, _E, N>(input: Result<_I, _E>, node: &'input N) -> Result<_O, _E>
|
||||||
where
|
where
|
||||||
N: for<'a> Node<'a, _I, Output = Result<_O, _E>>,
|
N: for<'a> Node<'a, _I, Output = Result<_O, _E>>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -221,7 +221,7 @@ pub struct MapNode<MapFn> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(MapNode)]
|
#[node_macro::node_fn(MapNode)]
|
||||||
fn map_node<_Iter: Iterator, MapFnNode>(input: _Iter, map_fn: &'any_input MapFnNode) -> MapFnIterator<'input, _Iter, MapFnNode>
|
fn map_node<_Iter: Iterator, MapFnNode>(input: _Iter, map_fn: &'input MapFnNode) -> MapFnIterator<'input, _Iter, MapFnNode>
|
||||||
where
|
where
|
||||||
MapFnNode: for<'any_input> Node<'any_input, _Iter::Item>,
|
MapFnNode: for<'any_input> Node<'any_input, _Iter::Item>,
|
||||||
{
|
{
|
||||||
|
@ -425,7 +425,7 @@ pub struct MapSndNode<First, Second, MapFn> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(MapSndNode< _First, _Second>)]
|
#[node_macro::node_fn(MapSndNode< _First, _Second>)]
|
||||||
fn map_snd_node<MapFn, _First, _Second>(input: (_First, _Second), map_fn: &'any_input MapFn) -> (_First, <MapFn as Node<'input, _Second>>::Output)
|
fn map_snd_node<MapFn, _First, _Second>(input: (_First, _Second), map_fn: &'input MapFn) -> (_First, <MapFn as Node<'input, _Second>>::Output)
|
||||||
where
|
where
|
||||||
MapFn: for<'any_input> Node<'any_input, _Second>,
|
MapFn: for<'any_input> Node<'any_input, _Second>,
|
||||||
{
|
{
|
||||||
|
@ -449,7 +449,7 @@ pub struct ForEachNode<MapNode> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(ForEachNode)]
|
#[node_macro::node_fn(ForEachNode)]
|
||||||
fn map_node<_Iter: Iterator, MapNode>(input: _Iter, map_node: &'any_input MapNode) -> ()
|
fn map_node<_Iter: Iterator, MapNode>(input: _Iter, map_node: &'input MapNode) -> ()
|
||||||
where
|
where
|
||||||
MapNode: for<'any_input> Node<'any_input, _Iter::Item, Output = ()> + 'input,
|
MapNode: for<'any_input> Node<'any_input, _Iter::Item, Output = ()> + 'input,
|
||||||
{
|
{
|
||||||
|
|
|
@ -329,12 +329,13 @@ impl<'a> AsRef<EditorApi<'a>> for EditorApi<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct ExtractImageFrame;
|
pub struct ExtractImageFrame;
|
||||||
|
|
||||||
impl<'a: 'input, 'input> Node<'input, EditorApi<'a>> for ExtractImageFrame {
|
impl<'a: 'input, 'input> Node<'input, &'a EditorApi<'a>> for ExtractImageFrame {
|
||||||
type Output = ImageFrame<Color>;
|
type Output = ImageFrame<Color>;
|
||||||
fn eval(&'input self, mut editor_api: EditorApi<'a>) -> Self::Output {
|
fn eval(&'input self, editor_api: &'a EditorApi<'a>) -> Self::Output {
|
||||||
editor_api.image_frame.take().unwrap_or(ImageFrame::identity())
|
editor_api.image_frame.clone().unwrap_or(ImageFrame::identity())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ struct SetNode<S, I, Storage, Index> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(SetNode<_S, _I>)]
|
#[node_macro::node_fn(SetNode<_S, _I>)]
|
||||||
fn set_node<T, _S, _I>(value: T, storage: &'any_input mut _S, index: _I)
|
fn set_node<T, _S, _I>(value: T, storage: &'input mut _S, index: _I)
|
||||||
where
|
where
|
||||||
_S: IndexMut<_I>,
|
_S: IndexMut<_I>,
|
||||||
_S::Output: DerefMut<Target = T> + Sized,
|
_S::Output: DerefMut<Target = T> + Sized,
|
||||||
|
@ -25,7 +25,7 @@ struct GetNode<S, Storage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(GetNode<_S>)]
|
#[node_macro::node_fn(GetNode<_S>)]
|
||||||
fn get_node<_S, I>(index: I, storage: &'any_input _S) -> &'input _S::Output
|
fn get_node<_S, I>(index: I, storage: &'input _S) -> &'input _S::Output
|
||||||
where
|
where
|
||||||
_S: Index<I>,
|
_S: Index<I>,
|
||||||
_S::Output: Sized,
|
_S::Output: Sized,
|
||||||
|
|
|
@ -32,6 +32,39 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AsyncComposeNode<First, Second, I> {
|
||||||
|
first: First,
|
||||||
|
second: Second,
|
||||||
|
phantom: PhantomData<I>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'i, 'f: 'i, 's: 'i, Input: 'static, First, Second> Node<'i, Input> for AsyncComposeNode<First, Second, Input>
|
||||||
|
where
|
||||||
|
First: Node<'i, Input>,
|
||||||
|
First::Output: core::future::Future,
|
||||||
|
Second: Node<'i, <<First as Node<'i, Input>>::Output as core::future::Future>::Output> + 'i,
|
||||||
|
{
|
||||||
|
type Output = core::pin::Pin<Box<dyn core::future::Future<Output = <Second as Node<'i, <<First as Node<'i, Input>>::Output as core::future::Future>::Output>>::Output> + 'i>>;
|
||||||
|
fn eval(&'i self, input: Input) -> Self::Output {
|
||||||
|
Box::pin(async move {
|
||||||
|
let arg = self.first.eval(input).await;
|
||||||
|
self.second.eval(arg)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'i, First, Second, Input: 'i> AsyncComposeNode<First, Second, Input>
|
||||||
|
where
|
||||||
|
First: Node<'i, Input>,
|
||||||
|
First::Output: core::future::Future,
|
||||||
|
Second: Node<'i, <<First as Node<'i, Input>>::Output as core::future::Future>::Output> + 'i,
|
||||||
|
{
|
||||||
|
pub const fn new(first: First, second: Second) -> Self {
|
||||||
|
AsyncComposeNode::<First, Second, Input> { first, second, phantom: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Then<'i, Input: 'i>: Sized {
|
pub trait Then<'i, Input: 'i>: Sized {
|
||||||
fn then<Second>(self, second: Second) -> ComposeNode<Self, Second, Input>
|
fn then<Second>(self, second: Second) -> ComposeNode<Self, Second, Input>
|
||||||
where
|
where
|
||||||
|
@ -44,6 +77,19 @@ pub trait Then<'i, Input: 'i>: Sized {
|
||||||
|
|
||||||
impl<'i, First: Node<'i, Input>, Input: 'i> Then<'i, Input> for First {}
|
impl<'i, First: Node<'i, Input>, Input: 'i> Then<'i, Input> for First {}
|
||||||
|
|
||||||
|
pub trait AndThen<'i, Input: 'i>: Sized {
|
||||||
|
fn and_then<Second>(self, second: Second) -> AsyncComposeNode<Self, Second, Input>
|
||||||
|
where
|
||||||
|
Self: Node<'i, Input>,
|
||||||
|
Self::Output: core::future::Future,
|
||||||
|
Second: Node<'i, <<Self as Node<'i, Input>>::Output as core::future::Future>::Output> + 'i,
|
||||||
|
{
|
||||||
|
AsyncComposeNode::new(self, second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'i, First: Node<'i, Input>, Input: 'i> AndThen<'i, Input> for First {}
|
||||||
|
|
||||||
pub struct ConsNode<I: From<()>, Root>(pub Root, PhantomData<I>);
|
pub struct ConsNode<I: From<()>, Root>(pub Root, PhantomData<I>);
|
||||||
|
|
||||||
impl<'i, Root, Input: 'i, I: 'i + From<()>> Node<'i, Input> for ConsNode<I, Root>
|
impl<'i, Root, Input: 'i, I: 'i + From<()>> Node<'i, Input> for ConsNode<I, Root>
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub struct TextGenerator<Text, FontName, Size> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_fn(TextGenerator)]
|
#[node_fn(TextGenerator)]
|
||||||
fn generate_text<'a: 'input>(editor: EditorApi<'a>, text: String, font_name: Font, font_size: f64) -> crate::vector::VectorData {
|
fn generate_text<'a: 'input>(editor: &'a EditorApi<'a>, text: String, font_name: Font, font_size: f64) -> crate::vector::VectorData {
|
||||||
let buzz_face = editor.font_cache.and_then(|cache| cache.get(&font_name)).map(|data| load_face(data));
|
let buzz_face = editor.font_cache.and_then(|cache| cache.get(&font_name)).map(|data| load_face(data));
|
||||||
crate::vector::VectorData::from_subpaths(to_path(&text, buzz_face, font_size, None))
|
crate::vector::VectorData::from_subpaths(to_path(&text, buzz_face, font_size, None))
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,6 +158,7 @@ mod test {
|
||||||
assert_eq!(node.eval(()), 0);
|
assert_eq!(node.eval(()), 0);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(clippy::unit_cmp)]
|
||||||
fn test_unit_node() {
|
fn test_unit_node() {
|
||||||
let node = ForgetNode::new();
|
let node = ForgetNode::new();
|
||||||
assert_eq!(node.eval(()), ());
|
assert_eq!(node.eval(()), ());
|
||||||
|
|
|
@ -10,6 +10,7 @@ pub fn compile_spirv(request: &CompileRequest, compile_dir: Option<&str>, manife
|
||||||
io: request.shader_io.clone(),
|
io: request.shader_io.clone(),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "profiling"))]
|
||||||
let features = "";
|
let features = "";
|
||||||
#[cfg(feature = "profiling")]
|
#[cfg(feature = "profiling")]
|
||||||
let features = "profiling";
|
let features = "profiling";
|
||||||
|
|
|
@ -168,7 +168,7 @@ pub struct UniformNode<Executor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(UniformNode)]
|
#[node_macro::node_fn(UniformNode)]
|
||||||
fn uniform_node<T: ToUniformBuffer, E: GpuExecutor>(data: T, executor: &'any_input E) -> ShaderInput<E::BufferHandle> {
|
fn uniform_node<T: ToUniformBuffer, E: GpuExecutor>(data: T, executor: &'input E) -> ShaderInput<E::BufferHandle> {
|
||||||
executor.create_uniform_buffer(data).unwrap()
|
executor.create_uniform_buffer(data).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +177,7 @@ pub struct StorageNode<Executor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(StorageNode)]
|
#[node_macro::node_fn(StorageNode)]
|
||||||
fn storage_node<T: ToStorageBuffer, E: GpuExecutor>(data: T, executor: &'any_input E) -> ShaderInput<E::BufferHandle> {
|
fn storage_node<T: ToStorageBuffer, E: GpuExecutor>(data: T, executor: &'input E) -> ShaderInput<E::BufferHandle> {
|
||||||
executor
|
executor
|
||||||
.create_storage_buffer(
|
.create_storage_buffer(
|
||||||
data,
|
data,
|
||||||
|
@ -205,7 +205,7 @@ pub struct CreateOutputBufferNode<Executor, Ty> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(CreateOutputBufferNode)]
|
#[node_macro::node_fn(CreateOutputBufferNode)]
|
||||||
fn create_output_buffer_node<E: GpuExecutor>(size: usize, executor: &'any_input E, ty: Type) -> ShaderInput<E::BufferHandle> {
|
fn create_output_buffer_node<E: GpuExecutor>(size: usize, executor: &'input E, ty: Type) -> ShaderInput<E::BufferHandle> {
|
||||||
executor.create_output_buffer(size, ty, true).unwrap()
|
executor.create_output_buffer(size, ty, true).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +216,7 @@ pub struct CreateComputePassNode<Executor, Output, Instances> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(CreateComputePassNode)]
|
#[node_macro::node_fn(CreateComputePassNode)]
|
||||||
fn create_compute_pass_node<E: GpuExecutor>(layout: PipelineLayout<E>, executor: &'any_input E, output: ShaderInput<E::BufferHandle>, instances: u32) -> E::CommandBuffer {
|
fn create_compute_pass_node<E: GpuExecutor>(layout: PipelineLayout<E>, executor: &'input E, output: ShaderInput<E::BufferHandle>, instances: u32) -> E::CommandBuffer {
|
||||||
executor.create_compute_pass(&layout, Some(output), instances).unwrap()
|
executor.create_compute_pass(&layout, Some(output), instances).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +242,7 @@ pub struct ExecuteComputePipelineNode<Executor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(ExecuteComputePipelineNode)]
|
#[node_macro::node_fn(ExecuteComputePipelineNode)]
|
||||||
fn execute_compute_pipeline_node<E: GpuExecutor>(encoder: E::CommandBuffer, executor: &'any_input mut E) {
|
fn execute_compute_pipeline_node<E: GpuExecutor>(encoder: E::CommandBuffer, executor: &'input mut E) {
|
||||||
executor.execute_compute_pipeline(encoder).unwrap();
|
executor.execute_compute_pipeline(encoder).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,6 +251,6 @@ fn execute_compute_pipeline_node<E: GpuExecutor>(encoder: E::CommandBuffer, exec
|
||||||
// executor: Executor,
|
// executor: Executor,
|
||||||
// }
|
// }
|
||||||
// #[node_macro::node_fn(ReadOutputBufferNode)]
|
// #[node_macro::node_fn(ReadOutputBufferNode)]
|
||||||
// fn read_output_buffer_node<E: GpuExecutor>(buffer: E::BufferHandle, executor: &'any_input mut E) -> Vec<u8> {
|
// fn read_output_buffer_node<E: GpuExecutor>(buffer: E::BufferHandle, executor: &'input mut E) -> Vec<u8> {
|
||||||
// executor.read_output_buffer(buffer).await.unwrap()
|
// executor.read_output_buffer(buffer).await.unwrap()
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -295,7 +295,7 @@ impl NodeNetwork {
|
||||||
self.previous_outputs.as_ref().unwrap_or(&self.outputs)
|
self.previous_outputs.as_ref().unwrap_or(&self.outputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input_types<'a>(&'a self) -> impl Iterator<Item = Type> + 'a {
|
pub fn input_types(&self) -> impl Iterator<Item = Type> + '_ {
|
||||||
self.inputs.iter().map(move |id| self.nodes[id].inputs.get(0).map(|i| i.ty()).unwrap_or(concrete!(())))
|
self.inputs.iter().map(move |id| self.nodes[id].inputs.get(0).map(|i| i.ty()).unwrap_or(concrete!(())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use super::DocumentNode;
|
use super::DocumentNode;
|
||||||
use crate::executor::Any;
|
use crate::executor::Any;
|
||||||
pub use crate::imaginate_input::{ImaginateMaskStartingFill, ImaginateSamplingMethod, ImaginateStatus};
|
pub use crate::imaginate_input::{ImaginateMaskStartingFill, ImaginateSamplingMethod, ImaginateStatus};
|
||||||
|
use crate::proto::{Any as DAny, FutureAny};
|
||||||
|
|
||||||
use graphene_core::raster::{BlendMode, LuminanceCalculation};
|
use graphene_core::raster::{BlendMode, LuminanceCalculation};
|
||||||
use graphene_core::{Color, Node, Type};
|
use graphene_core::{Color, Node, Type};
|
||||||
|
@ -305,11 +306,11 @@ impl<'a> TaggedValue {
|
||||||
pub struct UpcastNode {
|
pub struct UpcastNode {
|
||||||
value: TaggedValue,
|
value: TaggedValue,
|
||||||
}
|
}
|
||||||
impl<'input> Node<'input, Box<dyn DynAny<'input> + 'input>> for UpcastNode {
|
impl<'input> Node<'input, DAny<'input>> for UpcastNode {
|
||||||
type Output = Box<dyn DynAny<'input> + 'input>;
|
type Output = FutureAny<'input>;
|
||||||
|
|
||||||
fn eval(&'input self, _: Box<dyn DynAny<'input> + 'input>) -> Self::Output {
|
fn eval(&'input self, _: DAny<'input>) -> Self::Output {
|
||||||
self.value.clone().to_any()
|
Box::pin(async move { self.value.clone().to_any() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl UpcastNode {
|
impl UpcastNode {
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::error::Error;
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
|
|
||||||
use crate::document::NodeNetwork;
|
use crate::document::NodeNetwork;
|
||||||
use crate::proto::ProtoNetwork;
|
use crate::proto::{LocalFuture, ProtoNetwork};
|
||||||
|
|
||||||
pub struct Compiler {}
|
pub struct Compiler {}
|
||||||
|
|
||||||
|
@ -37,5 +37,5 @@ impl Compiler {
|
||||||
pub type Any<'a> = Box<dyn DynAny<'a> + 'a>;
|
pub type Any<'a> = Box<dyn DynAny<'a> + 'a>;
|
||||||
|
|
||||||
pub trait Executor {
|
pub trait Executor {
|
||||||
fn execute<'a, 's: 'a>(&'s self, input: Any<'a>) -> Result<Any<'a>, Box<dyn Error>>;
|
fn execute<'a>(&'a self, input: Any<'a>) -> LocalFuture<Result<Any<'a>, Box<dyn Error>>>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use xxhash_rust::xxh3::Xxh3;
|
use xxhash_rust::xxh3::Xxh3;
|
||||||
|
|
||||||
|
@ -11,12 +12,15 @@ use graphene_core::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
pub type DynFuture<'n, T> = Pin<Box<dyn core::future::Future<Output = T> + 'n>>;
|
||||||
|
pub type LocalFuture<'n, T> = Pin<Box<dyn core::future::Future<Output = T> + 'n>>;
|
||||||
pub type Any<'n> = Box<dyn DynAny<'n> + 'n>;
|
pub type Any<'n> = Box<dyn DynAny<'n> + 'n>;
|
||||||
pub type TypeErasedNode<'n> = dyn for<'i> NodeIO<'i, Any<'i>, Output = Any<'i>> + 'n + Send + Sync;
|
pub type FutureAny<'n> = DynFuture<'n, Any<'n>>;
|
||||||
pub type TypeErasedPinnedRef<'n> = Pin<&'n (dyn for<'i> NodeIO<'i, Any<'i>, Output = Any<'i>> + 'n + Send + Sync)>;
|
pub type TypeErasedNode<'n> = dyn for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n;
|
||||||
pub type TypeErasedPinned<'n> = Pin<Box<dyn for<'i> NodeIO<'i, Any<'i>, Output = Any<'i>> + 'n + Send + Sync>>;
|
pub type TypeErasedPinnedRef<'n> = Pin<&'n (dyn for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n)>;
|
||||||
|
pub type TypeErasedPinned<'n> = Pin<Box<dyn for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n>>;
|
||||||
|
|
||||||
pub type NodeConstructor = for<'a> fn(Vec<TypeErasedPinnedRef<'static>>) -> TypeErasedPinned<'static>;
|
pub type NodeConstructor = for<'a> fn(Vec<TypeErasedPinnedRef<'static>>) -> DynFuture<'static, TypeErasedPinned<'static>>;
|
||||||
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[derive(Debug, Default, PartialEq, Clone)]
|
#[derive(Debug, Default, PartialEq, Clone)]
|
||||||
|
|
|
@ -59,6 +59,8 @@ node-macro = { path = "../node-macro" }
|
||||||
boxcar = "0.1.0"
|
boxcar = "0.1.0"
|
||||||
xxhash-rust = { workspace = true }
|
xxhash-rust = { workspace = true }
|
||||||
serde_json = "1.0.96"
|
serde_json = "1.0.96"
|
||||||
|
reqwest = { version = "0.11.17", features = ["rustls", "rustls-tls"] }
|
||||||
|
futures = "0.3.28"
|
||||||
|
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use dyn_any::StaticType;
|
use dyn_any::StaticType;
|
||||||
pub use graph_craft::proto::{Any, TypeErasedNode, TypeErasedPinned, TypeErasedPinnedRef};
|
pub use graph_craft::proto::{Any, TypeErasedNode, TypeErasedPinned, TypeErasedPinnedRef};
|
||||||
|
use graph_craft::proto::{DynFuture, FutureAny};
|
||||||
use graphene_core::NodeIO;
|
use graphene_core::NodeIO;
|
||||||
pub use graphene_core::{generic, ops, Node};
|
pub use graphene_core::{generic, ops, Node};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
@ -12,18 +13,20 @@ pub struct DynAnyNode<I, O, Node> {
|
||||||
|
|
||||||
impl<'input, _I: 'input + StaticType, _O: 'input + StaticType, N: 'input, S0: 'input> Node<'input, Any<'input>> for DynAnyNode<_I, _O, S0>
|
impl<'input, _I: 'input + StaticType, _O: 'input + StaticType, N: 'input, S0: 'input> Node<'input, Any<'input>> for DynAnyNode<_I, _O, S0>
|
||||||
where
|
where
|
||||||
N: for<'any_input> Node<'any_input, _I, Output = _O>,
|
N: for<'any_input> Node<'any_input, _I, Output = DynFuture<'any_input, _O>>,
|
||||||
S0: for<'any_input> Node<'any_input, (), Output = &'any_input N>,
|
S0: for<'any_input> Node<'any_input, (), Output = &'any_input N>,
|
||||||
{
|
{
|
||||||
type Output = Any<'input>;
|
type Output = FutureAny<'input>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eval(&'input self, input: Any<'input>) -> Self::Output {
|
fn eval(&'input self, input: Any<'input>) -> Self::Output {
|
||||||
let node = self.node.eval(());
|
let node = self.node.eval(());
|
||||||
{
|
let node_name = core::any::type_name::<N>();
|
||||||
let node_name = core::any::type_name::<N>();
|
let input: Box<_I> = dyn_any::downcast(input).unwrap_or_else(|e| panic!("DynAnyNode Input, {0} in:\n{1}", e, node_name));
|
||||||
let input: Box<_I> = dyn_any::downcast(input).unwrap_or_else(|e| panic!("DynAnyNode Input, {0} in:\n{1}", e, node_name));
|
let output = async move {
|
||||||
Box::new(node.eval(*input))
|
let result = node.eval(*input).await;
|
||||||
}
|
Box::new(result) as Any<'input>
|
||||||
|
};
|
||||||
|
Box::pin(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset(self: std::pin::Pin<&mut Self>) {
|
fn reset(self: std::pin::Pin<&mut Self>) {
|
||||||
|
@ -56,11 +59,13 @@ impl<'input, _I: 'input + StaticType, _O: 'input + StaticType, N: 'input> Node<'
|
||||||
where
|
where
|
||||||
N: for<'any_input> Node<'any_input, _I, Output = &'any_input _O>,
|
N: for<'any_input> Node<'any_input, _I, Output = &'any_input _O>,
|
||||||
{
|
{
|
||||||
type Output = Any<'input>;
|
type Output = FutureAny<'input>;
|
||||||
fn eval(&'input self, input: Any<'input>) -> Self::Output {
|
fn eval(&'input self, input: Any<'input>) -> Self::Output {
|
||||||
let node_name = core::any::type_name::<N>();
|
let node_name = core::any::type_name::<N>();
|
||||||
let input: Box<_I> = dyn_any::downcast(input).unwrap_or_else(|e| panic!("DynAnyRefNode Input, {e} in:\n{node_name}"));
|
let input: Box<_I> = dyn_any::downcast(input).unwrap_or_else(|e| panic!("DynAnyRefNode Input, {e} in:\n{node_name}"));
|
||||||
Box::new(self.node.eval(*input))
|
let result = self.node.eval(*input);
|
||||||
|
let output = async move { Box::new(result) as Any<'input> };
|
||||||
|
Box::pin(output)
|
||||||
}
|
}
|
||||||
fn reset(self: std::pin::Pin<&mut Self>) {
|
fn reset(self: std::pin::Pin<&mut Self>) {
|
||||||
let wrapped_node = unsafe { self.map_unchecked_mut(|e| &mut e.node) };
|
let wrapped_node = unsafe { self.map_unchecked_mut(|e| &mut e.node) };
|
||||||
|
@ -79,14 +84,15 @@ pub struct DynAnyInRefNode<I, O, Node> {
|
||||||
}
|
}
|
||||||
impl<'input, _I: 'input + StaticType, _O: 'input + StaticType, N: 'input> Node<'input, Any<'input>> for DynAnyInRefNode<_I, _O, N>
|
impl<'input, _I: 'input + StaticType, _O: 'input + StaticType, N: 'input> Node<'input, Any<'input>> for DynAnyInRefNode<_I, _O, N>
|
||||||
where
|
where
|
||||||
N: for<'any_input> Node<'any_input, &'any_input _I, Output = _O>,
|
N: for<'any_input> Node<'any_input, &'any_input _I, Output = DynFuture<'any_input, _O>>,
|
||||||
{
|
{
|
||||||
type Output = Any<'input>;
|
type Output = FutureAny<'input>;
|
||||||
fn eval(&'input self, input: Any<'input>) -> Self::Output {
|
fn eval(&'input self, input: Any<'input>) -> Self::Output {
|
||||||
{
|
{
|
||||||
let node_name = core::any::type_name::<N>();
|
let node_name = core::any::type_name::<N>();
|
||||||
let input: Box<&_I> = dyn_any::downcast(input).unwrap_or_else(|e| panic!("DynAnyInRefNode Input, {e} in:\n{node_name}"));
|
let input: Box<&_I> = dyn_any::downcast(input).unwrap_or_else(|e| panic!("DynAnyInRefNode Input, {e} in:\n{node_name}"));
|
||||||
Box::new(self.node.eval(*input))
|
let result = self.node.eval(*input);
|
||||||
|
Box::pin(async move { Box::new(result.await) as Any<'_> })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,13 +102,37 @@ impl<_I, _O, S0> DynAnyInRefNode<_I, _O, S0> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct FutureWrapperNode<Node> {
|
||||||
|
node: Node,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'i, T: 'i, N: Node<'i, T>> Node<'i, T> for FutureWrapperNode<N>
|
||||||
|
where
|
||||||
|
N: Node<'i, T>,
|
||||||
|
{
|
||||||
|
type Output = DynFuture<'i, N::Output>;
|
||||||
|
fn eval(&'i self, input: T) -> Self::Output {
|
||||||
|
Box::pin(async move { self.node.eval(input) })
|
||||||
|
}
|
||||||
|
fn reset(self: std::pin::Pin<&mut Self>) {
|
||||||
|
let wrapped_node = unsafe { self.map_unchecked_mut(|e| &mut e.node) };
|
||||||
|
Node::reset(wrapped_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'i, N> FutureWrapperNode<N> {
|
||||||
|
pub const fn new(node: N) -> Self {
|
||||||
|
Self { node }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait IntoTypeErasedNode<'n> {
|
pub trait IntoTypeErasedNode<'n> {
|
||||||
fn into_type_erased(self) -> TypeErasedPinned<'n>;
|
fn into_type_erased(self) -> TypeErasedPinned<'n>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'n, N: 'n> IntoTypeErasedNode<'n> for N
|
impl<'n, N: 'n> IntoTypeErasedNode<'n> for N
|
||||||
where
|
where
|
||||||
N: for<'i> NodeIO<'i, Any<'i>, Output = Any<'i>> + Send + Sync + 'n,
|
N: for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n,
|
||||||
{
|
{
|
||||||
fn into_type_erased(self) -> TypeErasedPinned<'n> {
|
fn into_type_erased(self) -> TypeErasedPinned<'n> {
|
||||||
Box::pin(self)
|
Box::pin(self)
|
||||||
|
@ -139,13 +169,17 @@ pub struct DowncastBothNode<'a, I, O> {
|
||||||
_o: PhantomData<O>,
|
_o: PhantomData<O>,
|
||||||
}
|
}
|
||||||
impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'input, I> for DowncastBothNode<'n, I, O> {
|
impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'input, I> for DowncastBothNode<'n, I, O> {
|
||||||
type Output = O;
|
type Output = DynFuture<'input, O>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eval(&'input self, input: I) -> Self::Output {
|
fn eval(&'input self, input: I) -> Self::Output {
|
||||||
{
|
{
|
||||||
|
let node_name = self.node.node_name();
|
||||||
let input = Box::new(input);
|
let input = Box::new(input);
|
||||||
let out = dyn_any::downcast(self.node.eval(input)).unwrap_or_else(|e| panic!("DowncastBothNode Input {e}"));
|
let future = self.node.eval(input);
|
||||||
*out
|
Box::pin(async move {
|
||||||
|
let out = dyn_any::downcast(future.await).unwrap_or_else(|e| panic!("DowncastBothNode Input {e} in: \n{node_name}"));
|
||||||
|
*out
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,13 +200,15 @@ pub struct DowncastBothRefNode<'a, I, O> {
|
||||||
_i: PhantomData<(I, O)>,
|
_i: PhantomData<(I, O)>,
|
||||||
}
|
}
|
||||||
impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'input, I> for DowncastBothRefNode<'n, I, O> {
|
impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'input, I> for DowncastBothRefNode<'n, I, O> {
|
||||||
type Output = &'input O;
|
type Output = DynFuture<'input, &'input O>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eval(&'input self, input: I) -> Self::Output {
|
fn eval(&'input self, input: I) -> Self::Output {
|
||||||
{
|
{
|
||||||
let input = Box::new(input);
|
let input = Box::new(input);
|
||||||
let out: Box<&_> = dyn_any::downcast::<&O>(self.node.eval(input)).unwrap_or_else(|e| panic!("DowncastBothRefNode Input {e}"));
|
Box::pin(async move {
|
||||||
*out
|
let out: Box<&_> = dyn_any::downcast::<&O>(self.node.eval(input).await).unwrap_or_else(|e| panic!("DowncastBothRefNode Input {e}"));
|
||||||
|
*out
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,10 +224,12 @@ pub struct ComposeTypeErased<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'i, 'a: 'i> Node<'i, Any<'i>> for ComposeTypeErased<'a> {
|
impl<'i, 'a: 'i> Node<'i, Any<'i>> for ComposeTypeErased<'a> {
|
||||||
type Output = Any<'i>;
|
type Output = DynFuture<'i, Any<'i>>;
|
||||||
fn eval(&'i self, input: Any<'i>) -> Self::Output {
|
fn eval(&'i self, input: Any<'i>) -> Self::Output {
|
||||||
let arg = self.first.eval(input);
|
Box::pin(async move {
|
||||||
self.second.eval(arg)
|
let arg = self.first.eval(input).await;
|
||||||
|
self.second.eval(arg).await
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,6 +243,21 @@ pub fn input_node<O: StaticType>(n: TypeErasedPinnedRef) -> DowncastBothNode<(),
|
||||||
DowncastBothNode::new(n)
|
DowncastBothNode::new(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PanicNode<I, O>(PhantomData<I>, PhantomData<O>);
|
||||||
|
|
||||||
|
impl<'i, I: 'i, O: 'i> Node<'i, I> for PanicNode<I, O> {
|
||||||
|
type Output = O;
|
||||||
|
fn eval(&'i self, _: I) -> Self::Output {
|
||||||
|
unimplemented!("This node should never be evaluated")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, O> PanicNode<I, O> {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self(PhantomData, PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -215,8 +268,8 @@ mod test {
|
||||||
pub fn dyn_input_invalid_eval_panic() {
|
pub fn dyn_input_invalid_eval_panic() {
|
||||||
//let add = DynAnyNode::new(AddNode::new()).into_type_erased();
|
//let add = DynAnyNode::new(AddNode::new()).into_type_erased();
|
||||||
//add.eval(Box::new(&("32", 32u32)));
|
//add.eval(Box::new(&("32", 32u32)));
|
||||||
let dyn_any = DynAnyNode::<(u32, u32), u32, _>::new(ValueNode::new(AddNode::new()));
|
let dyn_any = DynAnyNode::<(u32, u32), u32, _>::new(ValueNode::new(FutureWrapperNode { node: AddNode::new() }));
|
||||||
let type_erased = dyn_any.into_type_erased();
|
let type_erased = Box::pin(dyn_any) as TypeErasedPinned;
|
||||||
let _ref_type_erased = type_erased.as_ref();
|
let _ref_type_erased = type_erased.as_ref();
|
||||||
//let type_erased = Box::pin(dyn_any) as TypeErasedPinned<'_>;
|
//let type_erased = Box::pin(dyn_any) as TypeErasedPinned<'_>;
|
||||||
type_erased.eval(Box::new(&("32", 32u32)));
|
type_erased.eval(Box::new(&("32", 32u32)));
|
||||||
|
@ -226,10 +279,10 @@ mod test {
|
||||||
pub fn dyn_input_invalid_eval_panic_() {
|
pub fn dyn_input_invalid_eval_panic_() {
|
||||||
//let add = DynAnyNode::new(AddNode::new()).into_type_erased();
|
//let add = DynAnyNode::new(AddNode::new()).into_type_erased();
|
||||||
//add.eval(Box::new(&("32", 32u32)));
|
//add.eval(Box::new(&("32", 32u32)));
|
||||||
let dyn_any = DynAnyNode::<(u32, u32), u32, _>::new(ValueNode::new(AddNode::new()));
|
let dyn_any = DynAnyNode::<(u32, u32), u32, _>::new(ValueNode::new(FutureWrapperNode { node: AddNode::new() }));
|
||||||
let type_erased = Box::pin(dyn_any) as TypeErasedPinned<'_>;
|
let type_erased = Box::pin(dyn_any) as TypeErasedPinned<'_>;
|
||||||
type_erased.eval(Box::new((4u32, 2u32)));
|
type_erased.eval(Box::new((4u32, 2u32)));
|
||||||
let id_node = IdNode::new();
|
let id_node = FutureWrapperNode::new(IdNode::new());
|
||||||
let type_erased_id = Box::pin(id_node) as TypeErasedPinned;
|
let type_erased_id = Box::pin(id_node) as TypeErasedPinned;
|
||||||
let type_erased = ComposeTypeErased::new(type_erased.as_ref(), type_erased_id.as_ref());
|
let type_erased = ComposeTypeErased::new(type_erased.as_ref(), type_erased_id.as_ref());
|
||||||
type_erased.eval(Box::new((4u32, 2u32)));
|
type_erased.eval(Box::new((4u32, 2u32)));
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub struct ReduceNode<Initial, Lambda> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_fn(ReduceNode)]
|
#[node_fn(ReduceNode)]
|
||||||
fn reduce<I: Iterator, Lambda, T>(iter: I, initial: T, lambda: &'any_input Lambda) -> T
|
fn reduce<I: Iterator, Lambda, T>(iter: I, initial: T, lambda: &'input Lambda) -> T
|
||||||
where
|
where
|
||||||
Lambda: for<'a> Node<'a, (T, I::Item), Output = T>,
|
Lambda: for<'a> Node<'a, (T, I::Item), Output = T>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub struct GpuCompiler<TypingContext, ShaderIO> {
|
||||||
|
|
||||||
// TODO: Move to graph-craft
|
// TODO: Move to graph-craft
|
||||||
#[node_macro::node_fn(GpuCompiler)]
|
#[node_macro::node_fn(GpuCompiler)]
|
||||||
fn compile_gpu(node: &'input DocumentNode, mut typing_context: TypingContext, io: ShaderIO) -> compilation_client::Shader {
|
async fn compile_gpu(node: &'input DocumentNode, mut typing_context: TypingContext, io: ShaderIO) -> compilation_client::Shader {
|
||||||
let compiler = graph_craft::executor::Compiler {};
|
let compiler = graph_craft::executor::Compiler {};
|
||||||
let DocumentNodeImplementation::Network(network) = node.implementation;
|
let DocumentNodeImplementation::Network(network) = node.implementation;
|
||||||
let proto_network = compiler.compile_single(network, true).unwrap();
|
let proto_network = compiler.compile_single(network, true).unwrap();
|
||||||
|
@ -25,7 +25,7 @@ fn compile_gpu(node: &'input DocumentNode, mut typing_context: TypingContext, io
|
||||||
let input_types = proto_network.inputs.iter().map(|id| typing_context.get_type(*id).unwrap()).map(|node_io| node_io.output).collect();
|
let input_types = proto_network.inputs.iter().map(|id| typing_context.get_type(*id).unwrap()).map(|node_io| node_io.output).collect();
|
||||||
let output_type = typing_context.get_type(proto_network.output).unwrap().output;
|
let output_type = typing_context.get_type(proto_network.output).unwrap().output;
|
||||||
|
|
||||||
let bytes = compilation_client::compile_sync(proto_network, input_types, output_type, io).unwrap();
|
let bytes = compilation_client::compile(proto_network, input_types, output_type, io).await.unwrap();
|
||||||
bytes
|
bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ pub struct MapGpuNode<Shader> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(MapGpuNode)]
|
#[node_macro::node_fn(MapGpuNode)]
|
||||||
fn map_gpu(inputs: Vec<ShaderInput<<NewExecutor as GpuExecutor>::BufferHandle>>, shader: &'any_input compilation_client::Shader) {
|
async fn map_gpu(inputs: Vec<ShaderInput<<NewExecutor as GpuExecutor>::BufferHandle>>, shader: &'any_input compilation_client::Shader) {
|
||||||
use graph_craft::executor::Executor;
|
use graph_craft::executor::Executor;
|
||||||
let executor = NewExecutor::new().unwrap();
|
let executor = NewExecutor::new().unwrap();
|
||||||
for input in shader.inputs.iter() {
|
for input in shader.inputs.iter() {
|
||||||
|
@ -42,11 +42,13 @@ fn map_gpu(inputs: Vec<ShaderInput<<NewExecutor as GpuExecutor>::BufferHandle>>,
|
||||||
executor.write_buffer(buffer, input.data).unwrap();
|
executor.write_buffer(buffer, input.data).unwrap();
|
||||||
}
|
}
|
||||||
todo!();
|
todo!();
|
||||||
let executor: GpuExecutor = GpuExecutor::new(Context::new_sync().unwrap(), shader.into(), "gpu::eval".into()).unwrap();
|
/*
|
||||||
|
let executor: GpuExecutor = GpuExecutor::new(Context::new().await.unwrap(), shader.into(), "gpu::eval".into()).unwrap();
|
||||||
let data: Vec<_> = input.into_iter().collect();
|
let data: Vec<_> = input.into_iter().collect();
|
||||||
let result = executor.execute(Box::new(data)).unwrap();
|
let result = executor.execute(Box::new(data)).unwrap();
|
||||||
let result = dyn_any::downcast::<Vec<_O>>(result).unwrap();
|
let result = dyn_any::downcast::<Vec<_O>>(result).unwrap();
|
||||||
*result
|
*result
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MapGpuSingleImageNode<N> {
|
pub struct MapGpuSingleImageNode<N> {
|
||||||
|
|
32
node-graph/gstd/src/http.rs
Normal file
32
node-graph/gstd/src/http.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use std::future::Future;
|
||||||
|
|
||||||
|
use crate::Node;
|
||||||
|
|
||||||
|
pub struct GetNode;
|
||||||
|
|
||||||
|
#[node_macro::node_fn(GetNode)]
|
||||||
|
async fn get_node(url: String) -> reqwest::Response {
|
||||||
|
reqwest::get(url).await.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PostNode<Body> {
|
||||||
|
body: Body,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[node_macro::node_fn(PostNode)]
|
||||||
|
async fn post_node(url: String, body: String) -> reqwest::Response {
|
||||||
|
reqwest::Client::new().post(url).body(body).send().await.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct EvalSyncNode {}
|
||||||
|
|
||||||
|
#[node_macro::node_fn(EvalSyncNode)]
|
||||||
|
fn eval_sync<F: Future + 'input>(future: F) -> F::Output {
|
||||||
|
let future = futures::future::maybe_done(future);
|
||||||
|
futures::pin_mut!(future);
|
||||||
|
match future.as_mut().take_output() {
|
||||||
|
Some(value) => value,
|
||||||
|
_ => panic!("Node construction future returned pending"),
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,8 @@ pub mod memo;
|
||||||
|
|
||||||
pub mod raster;
|
pub mod raster;
|
||||||
|
|
||||||
|
pub mod http;
|
||||||
|
|
||||||
pub mod any;
|
pub mod any;
|
||||||
|
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use futures::Future;
|
||||||
|
|
||||||
use graphene_core::Node;
|
use graphene_core::Node;
|
||||||
|
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
@ -15,25 +17,30 @@ pub struct CacheNode<T, CachedNode> {
|
||||||
cache: boxcar::Vec<(u64, T, AtomicBool)>,
|
cache: boxcar::Vec<(u64, T, AtomicBool)>,
|
||||||
node: CachedNode,
|
node: CachedNode,
|
||||||
}
|
}
|
||||||
impl<'i, T: 'i, I: 'i + Hash, CachedNode: 'i> Node<'i, I> for CacheNode<T, CachedNode>
|
impl<'i, T: 'i + Clone, I: 'i + Hash, CachedNode: 'i> Node<'i, I> for CacheNode<T, CachedNode>
|
||||||
where
|
where
|
||||||
CachedNode: for<'any_input> Node<'any_input, I, Output = T>,
|
CachedNode: for<'any_input> Node<'any_input, I>,
|
||||||
|
for<'a> <CachedNode as Node<'a, I>>::Output: core::future::Future<Output = T> + 'a,
|
||||||
{
|
{
|
||||||
type Output = &'i T;
|
// TODO: This should return a reference to the cached cached_value
|
||||||
|
// but that requires a lot of lifetime magic <- This was suggested by copilot but is pretty acurate xD
|
||||||
|
type Output = Pin<Box<dyn Future<Output = T> + 'i>>;
|
||||||
fn eval(&'i self, input: I) -> Self::Output {
|
fn eval(&'i self, input: I) -> Self::Output {
|
||||||
let mut hasher = Xxh3::new();
|
Box::pin(async move {
|
||||||
input.hash(&mut hasher);
|
let mut hasher = Xxh3::new();
|
||||||
let hash = hasher.finish();
|
input.hash(&mut hasher);
|
||||||
|
let hash = hasher.finish();
|
||||||
|
|
||||||
if let Some((_, cached_value, keep)) = self.cache.iter().find(|(h, _, _)| *h == hash) {
|
if let Some((_, cached_value, keep)) = self.cache.iter().find(|(h, _, _)| *h == hash) {
|
||||||
keep.store(true, std::sync::atomic::Ordering::Relaxed);
|
keep.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
cached_value
|
cached_value.clone()
|
||||||
} else {
|
} else {
|
||||||
trace!("Cache miss");
|
trace!("Cache miss");
|
||||||
let output = self.node.eval(input);
|
let output = self.node.eval(input).await;
|
||||||
let index = self.cache.push((hash, output, AtomicBool::new(true)));
|
let index = self.cache.push((hash, output, AtomicBool::new(true)));
|
||||||
&self.cache[index].1
|
self.cache[index].1.clone()
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset(mut self: Pin<&mut Self>) {
|
fn reset(mut self: Pin<&mut Self>) {
|
||||||
|
@ -151,11 +158,12 @@ pub struct RefNode<T, Let> {
|
||||||
let_node: Let,
|
let_node: Let,
|
||||||
_t: PhantomData<T>,
|
_t: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'i, T: 'i, Let> Node<'i, ()> for RefNode<T, Let>
|
impl<'i, T: 'i, Let> Node<'i, ()> for RefNode<T, Let>
|
||||||
where
|
where
|
||||||
Let: for<'a> Node<'a, Option<T>, Output = &'a T>,
|
Let: for<'a> Node<'a, Option<T>>,
|
||||||
{
|
{
|
||||||
type Output = &'i T;
|
type Output = <Let as Node<'i, Option<T>>>::Output;
|
||||||
fn eval(&'i self, _: ()) -> Self::Output {
|
fn eval(&'i self, _: ()) -> Self::Output {
|
||||||
self.let_node.eval(None)
|
self.let_node.eval(None)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub struct GenerateQuantizationNode<N, M> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(GenerateQuantizationNode)]
|
#[node_macro::node_fn(GenerateQuantizationNode)]
|
||||||
fn generate_quantization_fn(image_frame: ImageFrame, samples: u32, function: u32) -> [Quantization; 4] {
|
fn generate_quantization_fn(image_frame: ImageFrame<Color>, samples: u32, function: u32) -> [Quantization; 4] {
|
||||||
let image = image_frame.image;
|
let image = image_frame.image;
|
||||||
|
|
||||||
let len = image.data.len().min(10000);
|
let len = image.data.len().min(10000);
|
||||||
|
|
|
@ -85,7 +85,7 @@ pub struct MapImageNode<P, MapFn> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(MapImageNode<_P>)]
|
#[node_macro::node_fn(MapImageNode<_P>)]
|
||||||
fn map_image<MapFn, _P, Img: RasterMut<Pixel = _P>>(image: Img, map_fn: &'any_input MapFn) -> Img
|
fn map_image<MapFn, _P, Img: RasterMut<Pixel = _P>>(image: Img, map_fn: &'input MapFn) -> Img
|
||||||
where
|
where
|
||||||
MapFn: for<'any_input> Node<'any_input, _P, Output = _P> + 'input,
|
MapFn: for<'any_input> Node<'any_input, _P, Output = _P> + 'input,
|
||||||
{
|
{
|
||||||
|
@ -282,7 +282,7 @@ pub struct BlendImageTupleNode<P, Fg, MapFn> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(BlendImageTupleNode<_P, _Fg>)]
|
#[node_macro::node_fn(BlendImageTupleNode<_P, _Fg>)]
|
||||||
fn blend_image_tuple<_P: Alpha + Pixel + Debug, MapFn, _Fg: Sample<Pixel = _P> + Transform>(images: (ImageFrame<_P>, _Fg), map_fn: &'any_input MapFn) -> ImageFrame<_P>
|
fn blend_image_tuple<_P: Alpha + Pixel + Debug, MapFn, _Fg: Sample<Pixel = _P> + Transform>(images: (ImageFrame<_P>, _Fg), map_fn: &'input MapFn) -> ImageFrame<_P>
|
||||||
where
|
where
|
||||||
MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'input + Clone,
|
MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'input + Clone,
|
||||||
{
|
{
|
||||||
|
@ -299,7 +299,7 @@ pub struct BlendImageNode<P, Background, MapFn> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(BlendImageNode<_P>)]
|
#[node_macro::node_fn(BlendImageNode<_P>)]
|
||||||
fn blend_image_node<_P: Alpha + Pixel + Debug, MapFn, Forground: Sample<Pixel = _P> + Transform>(foreground: Forground, background: ImageFrame<_P>, map_fn: &'any_input MapFn) -> ImageFrame<_P>
|
async fn blend_image_node<_P: Alpha + Pixel + Debug, MapFn, Forground: Sample<Pixel = _P> + Transform>(foreground: Forground, background: ImageFrame<_P>, map_fn: &'input MapFn) -> ImageFrame<_P>
|
||||||
where
|
where
|
||||||
MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'input,
|
MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'input,
|
||||||
{
|
{
|
||||||
|
@ -314,7 +314,7 @@ pub struct BlendReverseImageNode<P, Background, MapFn> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(BlendReverseImageNode<_P>)]
|
#[node_macro::node_fn(BlendReverseImageNode<_P>)]
|
||||||
fn blend_image_node<_P: Alpha + Pixel + Debug, MapFn, Background: Transform + Sample<Pixel = _P>>(foreground: ImageFrame<_P>, background: Background, map_fn: &'any_input MapFn) -> ImageFrame<_P>
|
fn blend_image_node<_P: Alpha + Pixel + Debug, MapFn, Background: Transform + Sample<Pixel = _P>>(foreground: ImageFrame<_P>, background: Background, map_fn: &'input MapFn) -> ImageFrame<_P>
|
||||||
where
|
where
|
||||||
MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'input,
|
MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'input,
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,3 +24,7 @@ log = "0.4"
|
||||||
serde = { version = "1", features = ["derive"], optional = true }
|
serde = { version = "1", features = ["derive"], optional = true }
|
||||||
glam = { version = "0.22" }
|
glam = { version = "0.22" }
|
||||||
once_cell = "1.17.0"
|
once_cell = "1.17.0"
|
||||||
|
futures = "0.3.28"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tokio = { version = "1.12", features = ["rt", "macros"] }
|
||||||
|
|
|
@ -6,7 +6,7 @@ use dyn_any::StaticType;
|
||||||
use graph_craft::document::value::UpcastNode;
|
use graph_craft::document::value::UpcastNode;
|
||||||
use graph_craft::document::NodeId;
|
use graph_craft::document::NodeId;
|
||||||
use graph_craft::executor::Executor;
|
use graph_craft::executor::Executor;
|
||||||
use graph_craft::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, TypingContext};
|
use graph_craft::proto::{ConstructionArgs, LocalFuture, ProtoNetwork, ProtoNode, TypingContext};
|
||||||
use graph_craft::Type;
|
use graph_craft::Type;
|
||||||
use graphene_std::any::{Any, TypeErasedPinned, TypeErasedPinnedRef};
|
use graphene_std::any::{Any, TypeErasedPinned, TypeErasedPinnedRef};
|
||||||
|
|
||||||
|
@ -33,11 +33,11 @@ impl Default for DynamicExecutor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DynamicExecutor {
|
impl DynamicExecutor {
|
||||||
pub fn new(proto_network: ProtoNetwork) -> Result<Self, String> {
|
pub async fn new(proto_network: ProtoNetwork) -> Result<Self, String> {
|
||||||
let mut typing_context = TypingContext::new(&node_registry::NODE_REGISTRY);
|
let mut typing_context = TypingContext::new(&node_registry::NODE_REGISTRY);
|
||||||
typing_context.update(&proto_network)?;
|
typing_context.update(&proto_network)?;
|
||||||
let output = proto_network.output;
|
let output = proto_network.output;
|
||||||
let tree = BorrowTree::new(proto_network, &typing_context)?;
|
let tree = BorrowTree::new(proto_network, &typing_context).await?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
tree,
|
tree,
|
||||||
|
@ -47,11 +47,11 @@ impl DynamicExecutor {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, proto_network: ProtoNetwork) -> Result<(), String> {
|
pub async fn update(&mut self, proto_network: ProtoNetwork) -> Result<(), String> {
|
||||||
self.output = proto_network.output;
|
self.output = proto_network.output;
|
||||||
self.typing_context.update(&proto_network)?;
|
self.typing_context.update(&proto_network)?;
|
||||||
trace!("setting output to {}", self.output);
|
trace!("setting output to {}", self.output);
|
||||||
let mut orphans = self.tree.update(proto_network, &self.typing_context)?;
|
let mut orphans = self.tree.update(proto_network, &self.typing_context).await?;
|
||||||
core::mem::swap(&mut self.orphaned_nodes, &mut orphans);
|
core::mem::swap(&mut self.orphaned_nodes, &mut orphans);
|
||||||
for node_id in orphans {
|
for node_id in orphans {
|
||||||
if self.orphaned_nodes.contains(&node_id) {
|
if self.orphaned_nodes.contains(&node_id) {
|
||||||
|
@ -75,8 +75,8 @@ impl DynamicExecutor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Executor for DynamicExecutor {
|
impl Executor for DynamicExecutor {
|
||||||
fn execute<'a, 's: 'a>(&'s self, input: Any<'a>) -> Result<Any<'a>, Box<dyn Error>> {
|
fn execute<'a>(&'a self, input: Any<'a>) -> LocalFuture<Result<Any<'a>, Box<dyn Error>>> {
|
||||||
self.tree.eval_any(self.output, input).ok_or_else(|| "Failed to execute".into())
|
Box::pin(async move { self.tree.eval_any(self.output, input).await.ok_or_else(|| "Failed to execute".into()) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,20 +118,20 @@ pub struct BorrowTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BorrowTree {
|
impl BorrowTree {
|
||||||
pub fn new(proto_network: ProtoNetwork, typing_context: &TypingContext) -> Result<Self, String> {
|
pub async fn new(proto_network: ProtoNetwork, typing_context: &TypingContext) -> Result<Self, String> {
|
||||||
let mut nodes = BorrowTree::default();
|
let mut nodes = BorrowTree::default();
|
||||||
for (id, node) in proto_network.nodes {
|
for (id, node) in proto_network.nodes {
|
||||||
nodes.push_node(id, node, typing_context)?
|
nodes.push_node(id, node, typing_context).await?
|
||||||
}
|
}
|
||||||
Ok(nodes)
|
Ok(nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pushes new nodes into the tree and return orphaned nodes
|
/// Pushes new nodes into the tree and return orphaned nodes
|
||||||
pub fn update(&mut self, proto_network: ProtoNetwork, typing_context: &TypingContext) -> Result<Vec<NodeId>, String> {
|
pub async fn update(&mut self, proto_network: ProtoNetwork, typing_context: &TypingContext) -> Result<Vec<NodeId>, String> {
|
||||||
let mut old_nodes: HashSet<_> = self.nodes.keys().copied().collect();
|
let mut old_nodes: HashSet<_> = self.nodes.keys().copied().collect();
|
||||||
for (id, node) in proto_network.nodes {
|
for (id, node) in proto_network.nodes {
|
||||||
if !self.nodes.contains_key(&id) {
|
if !self.nodes.contains_key(&id) {
|
||||||
self.push_node(id, node, typing_context)?;
|
self.push_node(id, node, typing_context).await?;
|
||||||
} else {
|
} else {
|
||||||
let Some(node_container) = self.nodes.get_mut(&id) else { continue };
|
let Some(node_container) = self.nodes.get_mut(&id) else { continue };
|
||||||
let mut node_container_writer = node_container.write().unwrap();
|
let mut node_container_writer = node_container.write().unwrap();
|
||||||
|
@ -168,25 +168,25 @@ impl BorrowTree {
|
||||||
self.nodes.get(&id).cloned()
|
self.nodes.get(&id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval<'i, I: StaticType + 'i, O: StaticType + 'i>(&'i self, id: NodeId, input: I) -> Option<O> {
|
pub async fn eval<'i, I: StaticType + 'i + Send + Sync, O: StaticType + Send + Sync + 'i>(&'i self, id: NodeId, input: I) -> Option<O> {
|
||||||
let node = self.nodes.get(&id).cloned()?;
|
let node = self.nodes.get(&id).cloned()?;
|
||||||
let reader = node.read().unwrap();
|
let reader = node.read().unwrap();
|
||||||
let output = reader.node.eval(Box::new(input));
|
let output = reader.node.eval(Box::new(input));
|
||||||
dyn_any::downcast::<O>(output).ok().map(|o| *o)
|
dyn_any::downcast::<O>(output.await).ok().map(|o| *o)
|
||||||
}
|
}
|
||||||
pub fn eval_any<'i>(&'i self, id: NodeId, input: Any<'i>) -> Option<Any<'i>> {
|
pub async fn eval_any<'i>(&'i self, id: NodeId, input: Any<'i>) -> Option<Any<'i>> {
|
||||||
let node = self.nodes.get(&id)?;
|
let node = self.nodes.get(&id)?;
|
||||||
// TODO: Comments by @TrueDoctor before this was merged:
|
// TODO: Comments by @TrueDoctor before this was merged:
|
||||||
// TODO: Oof I dislike the evaluation being an unsafe operation but I guess its fine because it only is a lifetime extension
|
// TODO: Oof I dislike the evaluation being an unsafe operation but I guess its fine because it only is a lifetime extension
|
||||||
// TODO: We should ideally let miri run on a test that evaluates the nodegraph multiple times to check if this contains any subtle UB but this looks fine for now
|
// TODO: We should ideally let miri run on a test that evaluates the nodegraph multiple times to check if this contains any subtle UB but this looks fine for now
|
||||||
Some(unsafe { (*((&*node.read().unwrap()) as *const NodeContainer)).node.eval(input) })
|
Some(unsafe { (*((&*node.read().unwrap()) as *const NodeContainer)).node.eval(input).await })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn free_node(&mut self, id: NodeId) {
|
pub fn free_node(&mut self, id: NodeId) {
|
||||||
self.nodes.remove(&id);
|
self.nodes.remove(&id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_node(&mut self, id: NodeId, proto_node: ProtoNode, typing_context: &TypingContext) -> Result<(), String> {
|
pub async fn push_node(&mut self, id: NodeId, proto_node: ProtoNode, typing_context: &TypingContext) -> Result<(), String> {
|
||||||
let ProtoNode {
|
let ProtoNode {
|
||||||
construction_args,
|
construction_args,
|
||||||
identifier,
|
identifier,
|
||||||
|
@ -207,7 +207,7 @@ impl BorrowTree {
|
||||||
let ids: Vec<_> = ids.iter().map(|(id, _)| *id).collect();
|
let ids: Vec<_> = ids.iter().map(|(id, _)| *id).collect();
|
||||||
let construction_nodes = self.node_refs(&ids);
|
let construction_nodes = self.node_refs(&ids);
|
||||||
let constructor = typing_context.constructor(id).ok_or(format!("No constructor found for node {:?}", identifier))?;
|
let constructor = typing_context.constructor(id).ok_or(format!("No constructor found for node {:?}", identifier))?;
|
||||||
let node = constructor(construction_nodes);
|
let node = constructor(construction_nodes).await;
|
||||||
let node = NodeContainer {
|
let node = NodeContainer {
|
||||||
node,
|
node,
|
||||||
_dependencies: self.node_deps(&ids),
|
_dependencies: self.node_deps(&ids),
|
||||||
|
@ -226,12 +226,12 @@ mod test {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn push_node() {
|
async fn push_node() {
|
||||||
let mut tree = BorrowTree::default();
|
let mut tree = BorrowTree::default();
|
||||||
let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32)), vec![]);
|
let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32)), vec![]);
|
||||||
tree.push_node(0, val_1_protonode, &TypingContext::default()).unwrap();
|
tree.push_node(0, val_1_protonode, &TypingContext::default()).await.unwrap();
|
||||||
let _node = tree.get(0).unwrap();
|
let _node = tree.get(0).unwrap();
|
||||||
assert_eq!(tree.eval(0, ()), Some(2u32));
|
assert_eq!(tree.eval(0, ()).await, Some(2u32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,8 +44,8 @@ mod tests {
|
||||||
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);
|
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn execute_add() {
|
async fn execute_add() {
|
||||||
use graph_craft::document::*;
|
use graph_craft::document::*;
|
||||||
|
|
||||||
use graph_craft::*;
|
use graph_craft::*;
|
||||||
|
@ -109,15 +109,15 @@ mod tests {
|
||||||
let compiler = Compiler {};
|
let compiler = Compiler {};
|
||||||
let protograph = compiler.compile_single(network, true).expect("Graph should be generated");
|
let protograph = compiler.compile_single(network, true).expect("Graph should be generated");
|
||||||
|
|
||||||
let exec = DynamicExecutor::new(protograph).unwrap_or_else(|e| panic!("Failed to create executor: {}", e));
|
let exec = DynamicExecutor::new(protograph).await.unwrap_or_else(|e| panic!("Failed to create executor: {}", e));
|
||||||
|
|
||||||
let result = exec.execute(32_u32.into_dyn()).unwrap();
|
let result = exec.execute(32_u32.into_dyn()).await.unwrap();
|
||||||
let val = *dyn_any::downcast::<u32>(result).unwrap();
|
let val = *dyn_any::downcast::<u32>(result).unwrap();
|
||||||
assert_eq!(val, 33_u32);
|
assert_eq!(val, 33_u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn double_number() {
|
async fn double_number() {
|
||||||
use graph_craft::document::*;
|
use graph_craft::document::*;
|
||||||
|
|
||||||
use graph_craft::*;
|
use graph_craft::*;
|
||||||
|
@ -158,6 +158,6 @@ mod tests {
|
||||||
let compiler = Compiler {};
|
let compiler = Compiler {};
|
||||||
let protograph = compiler.compile_single(network, true).expect("Graph should be generated");
|
let protograph = compiler.compile_single(network, true).expect("Graph should be generated");
|
||||||
|
|
||||||
let _exec = DynamicExecutor::new(protograph).map(|e| panic!("The network should not type check: {:#?}", e)).unwrap_err();
|
let _exec = DynamicExecutor::new(protograph).await.map(|e| panic!("The network should not type check: {:#?}", e)).unwrap_err();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +1,46 @@
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
use graph_craft::imaginate_input::{ImaginateMaskStartingFill, ImaginateSamplingMethod, ImaginateStatus};
|
|
||||||
use graphene_core::ops::{CloneNode, IdNode, TypeNode};
|
use graphene_core::ops::IdNode;
|
||||||
use graphene_core::vector::VectorData;
|
use graphene_core::vector::VectorData;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use graphene_core::raster::color::Color;
|
use graphene_core::raster::color::Color;
|
||||||
use graphene_core::raster::*;
|
|
||||||
use graphene_core::structural::Then;
|
use graphene_core::structural::Then;
|
||||||
use graphene_core::value::{ClonedNode, CopiedNode, ForgetNode, ValueNode};
|
use graphene_core::value::{ClonedNode, CopiedNode, ValueNode};
|
||||||
|
use graphene_core::{fn_type, raster::*};
|
||||||
use graphene_core::{Node, NodeIO, NodeIOTypes};
|
use graphene_core::{Node, NodeIO, NodeIOTypes};
|
||||||
use graphene_std::brush::*;
|
use graphene_std::brush::*;
|
||||||
use graphene_std::raster::*;
|
use graphene_std::raster::*;
|
||||||
|
|
||||||
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DowncastBothRefNode, DynAnyInRefNode, DynAnyNode, DynAnyRefNode, IntoTypeErasedNode, TypeErasedPinnedRef};
|
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyInRefNode, DynAnyNode, FutureWrapperNode, IntoTypeErasedNode, TypeErasedPinnedRef};
|
||||||
|
|
||||||
use graphene_core::{Cow, NodeIdentifier, Type, TypeDescriptor};
|
use graphene_core::{Cow, NodeIdentifier, Type, TypeDescriptor};
|
||||||
|
|
||||||
use graph_craft::proto::NodeConstructor;
|
use graph_craft::proto::{NodeConstructor, TypeErasedPinned};
|
||||||
|
|
||||||
use graphene_core::{concrete, fn_type, generic, value_fn};
|
use graphene_core::{concrete, generic, value_fn};
|
||||||
use graphene_std::memo::{CacheNode, LetNode};
|
use graphene_std::memo::{CacheNode, LetNode};
|
||||||
use graphene_std::raster::BlendImageTupleNode;
|
use graphene_std::raster::BlendImageTupleNode;
|
||||||
|
|
||||||
use crate::executor::NodeContainer;
|
|
||||||
|
|
||||||
use dyn_any::StaticType;
|
use dyn_any::StaticType;
|
||||||
|
|
||||||
use graphene_core::quantization::QuantizationChannels;
|
use graphene_core::quantization::QuantizationChannels;
|
||||||
|
|
||||||
macro_rules! construct_node {
|
macro_rules! construct_node {
|
||||||
($args: ident, $path:ty, [$($type:tt),*]) => {{
|
($args: ident, $path:ty, [$($type:tt),*]) => { async move {
|
||||||
let mut args: Vec<TypeErasedPinnedRef<'static>> = $args.clone();
|
let mut args: Vec<TypeErasedPinnedRef<'static>> = $args.clone();
|
||||||
args.reverse();
|
args.reverse();
|
||||||
<$path>::new($(graphene_core::value::ClonedNode::new(
|
let node = <$path>::new($(
|
||||||
graphene_std::any::input_node::<$type>(args.pop()
|
{
|
||||||
.expect("Not enough arguments provided to construct node")).eval(()))
|
let node = graphene_std::any::input_node::<$type>(args.pop().expect("Not enough arguments provided to construct node"));
|
||||||
|
let value = node.eval(()).await;
|
||||||
|
graphene_core::value::ClonedNode::new(value)
|
||||||
|
}
|
||||||
),*
|
),*
|
||||||
)
|
);
|
||||||
|
node
|
||||||
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,16 +50,16 @@ macro_rules! register_node {
|
||||||
(
|
(
|
||||||
NodeIdentifier::new(stringify!($path)),
|
NodeIdentifier::new(stringify!($path)),
|
||||||
|args| {
|
|args| {
|
||||||
let node = construct_node!(args, $path, [$($type),*]);
|
Box::pin(async move {
|
||||||
|
let node = construct_node!(args, $path, [$($type),*]).await;
|
||||||
|
let node = graphene_std::any::FutureWrapperNode::new(node);
|
||||||
let any: DynAnyNode<$input, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
let any: DynAnyNode<$input, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||||
Box::pin(any)
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
let node = IdNode::new().into_type_erased();
|
|
||||||
let node = NodeContainer::new(node, vec![]);
|
|
||||||
let _node = unsafe { node.erase_lifetime().static_ref() };
|
|
||||||
let node = <$path>::new($(
|
let node = <$path>::new($(
|
||||||
graphene_std::any::input_node::<$type>(_node)
|
graphene_std::any::PanicNode::<(), $type>::new()
|
||||||
),*);
|
),*);
|
||||||
let params = vec![$(value_fn!($type)),*];
|
let params = vec![$(value_fn!($type)),*];
|
||||||
let mut node_io = <$path as NodeIO<'_, $input>>::to_node_io(&node, params);
|
let mut node_io = <$path as NodeIO<'_, $input>>::to_node_io(&node, params);
|
||||||
|
@ -82,9 +85,12 @@ macro_rules! raster_node {
|
||||||
(
|
(
|
||||||
NodeIdentifier::new(stringify!($path)),
|
NodeIdentifier::new(stringify!($path)),
|
||||||
|args| {
|
|args| {
|
||||||
let node = construct_node!(args, $path, [$($type),*]);
|
Box::pin(async move {
|
||||||
let any: DynAnyNode<Color, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
let node = construct_node!(args, $path, [$($type),*]).await;
|
||||||
Box::pin(any)
|
let node = graphene_std::any::FutureWrapperNode::new(node);
|
||||||
|
let any: DynAnyNode<Color, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||||
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
let params = vec![$(value_fn!($type)),*];
|
let params = vec![$(value_fn!($type)),*];
|
||||||
|
@ -94,10 +100,13 @@ macro_rules! raster_node {
|
||||||
(
|
(
|
||||||
NodeIdentifier::new(stringify!($path)),
|
NodeIdentifier::new(stringify!($path)),
|
||||||
|args| {
|
|args| {
|
||||||
let node = construct_node!(args, $path, [$($type),*]);
|
Box::pin(async move {
|
||||||
let map_node = graphene_std::raster::MapImageNode::new(graphene_core::value::ValueNode::new(node));
|
let node = construct_node!(args, $path, [$($type),*]).await;
|
||||||
let any: DynAnyNode<Image<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(map_node));
|
let map_node = graphene_std::raster::MapImageNode::new(graphene_core::value::ValueNode::new(node));
|
||||||
Box::pin(any)
|
let map_node = graphene_std::any::FutureWrapperNode::new(map_node);
|
||||||
|
let any: DynAnyNode<Image<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(map_node));
|
||||||
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
let params = vec![$(value_fn!($type)),*];
|
let params = vec![$(value_fn!($type)),*];
|
||||||
|
@ -107,10 +116,13 @@ macro_rules! raster_node {
|
||||||
(
|
(
|
||||||
NodeIdentifier::new(stringify!($path)),
|
NodeIdentifier::new(stringify!($path)),
|
||||||
|args| {
|
|args| {
|
||||||
let node = construct_node!(args, $path, [$($type),*]);
|
Box::pin(async move {
|
||||||
let map_node = graphene_std::raster::MapImageNode::new(graphene_core::value::ValueNode::new(node));
|
let node = construct_node!(args, $path, [$($type),*]).await;
|
||||||
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(map_node));
|
let map_node = graphene_std::raster::MapImageNode::new(graphene_core::value::ValueNode::new(node));
|
||||||
Box::pin(any)
|
let map_node = graphene_std::any::FutureWrapperNode::new(map_node);
|
||||||
|
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(map_node));
|
||||||
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
let params = vec![$(value_fn!($type)),*];
|
let params = vec![$(value_fn!($type)),*];
|
||||||
|
@ -129,7 +141,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
||||||
//register_node!(graphene_core::ops::IdNode, input: Any<'_>, params: []),
|
//register_node!(graphene_core::ops::IdNode, input: Any<'_>, params: []),
|
||||||
vec![(
|
vec![(
|
||||||
NodeIdentifier::new("graphene_core::ops::IdNode"),
|
NodeIdentifier::new("graphene_core::ops::IdNode"),
|
||||||
|_| IdNode::new().into_type_erased(),
|
|_| Box::pin(async move { Box::pin(FutureWrapperNode::new(IdNode::new())) as TypeErasedPinned }),
|
||||||
NodeIOTypes::new(generic!(I), generic!(I), vec![]),
|
NodeIOTypes::new(generic!(I), generic!(I), vec![]),
|
||||||
)],
|
)],
|
||||||
// TODO: create macro to impl for all types
|
// TODO: create macro to impl for all types
|
||||||
|
@ -158,37 +170,39 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
||||||
vec![(
|
vec![(
|
||||||
NodeIdentifier::new("graphene_std::raster::CombineChannelsNode"),
|
NodeIdentifier::new("graphene_std::raster::CombineChannelsNode"),
|
||||||
|args| {
|
|args| {
|
||||||
use graphene_core::raster::*;
|
Box::pin(async move {
|
||||||
use graphene_core::value::*;
|
use graphene_core::raster::*;
|
||||||
|
use graphene_core::value::*;
|
||||||
|
|
||||||
let channel_r: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
let channel_r: ImageFrame<Color> = DowncastBothNode::new(args[0]).eval(()).await;
|
||||||
let channel_g: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[1]);
|
let channel_g: ImageFrame<Color> = DowncastBothNode::new(args[1]).eval(()).await;
|
||||||
let channel_b: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[2]);
|
let channel_b: ImageFrame<Color> = DowncastBothNode::new(args[2]).eval(()).await;
|
||||||
let channel_a: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[3]);
|
let channel_a: ImageFrame<Color> = DowncastBothNode::new(args[3]).eval(()).await;
|
||||||
|
|
||||||
let insert_r = InsertChannelNode::new(channel_r.clone(), CopiedNode::new(RedGreenBlue::Red));
|
let insert_r = InsertChannelNode::new(ClonedNode::new(channel_r.clone()), CopiedNode::new(RedGreenBlue::Red));
|
||||||
let insert_g = InsertChannelNode::new(channel_g.clone(), CopiedNode::new(RedGreenBlue::Green));
|
let insert_g = InsertChannelNode::new(ClonedNode::new(channel_g.clone()), CopiedNode::new(RedGreenBlue::Green));
|
||||||
let insert_b = InsertChannelNode::new(channel_b.clone(), CopiedNode::new(RedGreenBlue::Blue));
|
let insert_b = InsertChannelNode::new(ClonedNode::new(channel_b.clone()), CopiedNode::new(RedGreenBlue::Blue));
|
||||||
let complete_node = insert_r.then(insert_g).then(insert_b);
|
let complete_node = insert_r.then(insert_g).then(insert_b);
|
||||||
let complete_node = complete_node.then(MaskImageNode::new(channel_a.clone()));
|
let complete_node = complete_node.then(MaskImageNode::new(ClonedNode::new(channel_a.clone())));
|
||||||
|
|
||||||
// TODO: Move to FN Node for better performance
|
// TODO: Move to FN Node for better performance
|
||||||
let (mut transform, mut bounds) = (DAffine2::ZERO, glam::UVec2::ZERO);
|
let (mut transform, mut bounds) = (DAffine2::ZERO, glam::UVec2::ZERO);
|
||||||
for imf in [channel_a, channel_r, channel_g, channel_b] {
|
for image in [channel_a, channel_r, channel_g, channel_b] {
|
||||||
let image = imf.eval(());
|
if image.image.width() > bounds.x {
|
||||||
if image.image.width() > bounds.x {
|
bounds = glam::UVec2::new(image.image.width(), image.image.height());
|
||||||
bounds = glam::UVec2::new(image.image.width(), image.image.height());
|
transform = image.transform;
|
||||||
transform = image.transform;
|
}
|
||||||
}
|
}
|
||||||
}
|
let empty_image = ImageFrame {
|
||||||
let empty_image = ImageFrame {
|
image: Image::new(bounds.x, bounds.y, Color::BLACK),
|
||||||
image: Image::new(bounds.x, bounds.y, Color::BLACK),
|
transform,
|
||||||
transform,
|
};
|
||||||
};
|
let final_image = ClonedNode::new(empty_image).then(complete_node);
|
||||||
let final_image = ClonedNode::new(empty_image).then(complete_node);
|
let final_image = FutureWrapperNode::new(final_image);
|
||||||
|
|
||||||
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(final_image));
|
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(final_image));
|
||||||
Box::pin(any)
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(
|
NodeIOTypes::new(
|
||||||
concrete!(()),
|
concrete!(()),
|
||||||
|
@ -200,12 +214,26 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
||||||
register_node!(graphene_std::memo::MonitorNode<_>, input: ImageFrame<Color>, params: []),
|
register_node!(graphene_std::memo::MonitorNode<_>, input: ImageFrame<Color>, params: []),
|
||||||
register_node!(graphene_std::memo::MonitorNode<_>, input: graphene_core::GraphicGroup, params: []),
|
register_node!(graphene_std::memo::MonitorNode<_>, input: graphene_core::GraphicGroup, params: []),
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
register_node!(graphene_std::executor::MapGpuSingleImageNode<_>, input: Image<Color>, params: [String]),
|
vec![(
|
||||||
|
NodeIdentifier::new("graphene_std::executor::MapGpuSingleImageNode<_>"),
|
||||||
|
|args| {
|
||||||
|
Box::pin(async move {
|
||||||
|
let document_node: DowncastBothNode<(), DocumentNode> = DowncastBothNode::new(args[0]);
|
||||||
|
let document_node = ClonedNode::new(document_node.eval(()).await);
|
||||||
|
let node = graphene_std::executor::MapGpuNode::new(document_node);
|
||||||
|
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||||
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
|
},
|
||||||
|
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(DocumentNode)]),
|
||||||
|
)],
|
||||||
vec![(
|
vec![(
|
||||||
NodeIdentifier::new("graphene_core::structural::ComposeNode<_, _, _>"),
|
NodeIdentifier::new("graphene_core::structural::ComposeNode<_, _, _>"),
|
||||||
|args| {
|
|args| {
|
||||||
let node = ComposeTypeErased::new(args[0], args[1]);
|
Box::pin(async move {
|
||||||
node.into_type_erased()
|
let node = ComposeTypeErased::new(args[0], args[1]);
|
||||||
|
node.into_type_erased()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(
|
NodeIOTypes::new(
|
||||||
generic!(T),
|
generic!(T),
|
||||||
|
@ -213,8 +241,6 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
||||||
vec![Type::Fn(Box::new(generic!(T)), Box::new(generic!(V))), Type::Fn(Box::new(generic!(V)), Box::new(generic!(U)))],
|
vec![Type::Fn(Box::new(generic!(T)), Box::new(generic!(V))), Type::Fn(Box::new(generic!(V)), Box::new(generic!(U)))],
|
||||||
),
|
),
|
||||||
)],
|
)],
|
||||||
//register_node!(graphene_std::brush::ReduceNode<_, _>, input: core::slice::Iter<ImageFrame<Color>>, params: [ImageFrame<Color>, &ValueNode<BlendImageTupleNode<ValueNode<BlendNode<ClonedNode<BlendMode>, ClonedNode<f64>>>>>]),
|
|
||||||
//register_node!(graphene_std::brush::ReduceNode<_, _>, input: core::slice::Iter<ImageFrame<Color>>, params: [AxisAlignedBbox, &MergeBoundingBoxNode]),
|
|
||||||
register_node!(graphene_std::brush::IntoIterNode<_>, input: &Vec<DVec2>, params: []),
|
register_node!(graphene_std::brush::IntoIterNode<_>, input: &Vec<DVec2>, params: []),
|
||||||
vec![(
|
vec![(
|
||||||
NodeIdentifier::new("graphene_std::brush::BrushNode"),
|
NodeIdentifier::new("graphene_std::brush::BrushNode"),
|
||||||
|
@ -223,42 +249,45 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
||||||
use graphene_core::value::*;
|
use graphene_core::value::*;
|
||||||
use graphene_std::brush::*;
|
use graphene_std::brush::*;
|
||||||
|
|
||||||
let image: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
Box::pin(async move {
|
||||||
let bounds: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[1]);
|
let image: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||||
let trace: DowncastBothNode<(), Vec<DVec2>> = DowncastBothNode::new(args[2]);
|
let bounds: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[1]);
|
||||||
let diameter: DowncastBothNode<(), f64> = DowncastBothNode::new(args[3]);
|
let trace: DowncastBothNode<(), Vec<DVec2>> = DowncastBothNode::new(args[2]);
|
||||||
let hardness: DowncastBothNode<(), f64> = DowncastBothNode::new(args[4]);
|
let diameter: DowncastBothNode<(), f64> = DowncastBothNode::new(args[3]);
|
||||||
let flow: DowncastBothNode<(), f64> = DowncastBothNode::new(args[5]);
|
let hardness: DowncastBothNode<(), f64> = DowncastBothNode::new(args[4]);
|
||||||
let color: DowncastBothNode<(), Color> = DowncastBothNode::new(args[6]);
|
let flow: DowncastBothNode<(), f64> = DowncastBothNode::new(args[5]);
|
||||||
|
let color: DowncastBothNode<(), Color> = DowncastBothNode::new(args[6]);
|
||||||
|
|
||||||
let stamp = BrushStampGeneratorNode::new(color, CopiedNode::new(hardness.eval(())), CopiedNode::new(flow.eval(())));
|
let stamp = BrushStampGeneratorNode::new(CopiedNode::new(color.eval(()).await), CopiedNode::new(hardness.eval(()).await), CopiedNode::new(flow.eval(()).await));
|
||||||
let stamp = stamp.eval(diameter.eval(()));
|
let stamp = stamp.eval(diameter.eval(()).await);
|
||||||
|
|
||||||
let frames = TranslateNode::new(CopiedNode::new(stamp));
|
let frames = TranslateNode::new(CopiedNode::new(stamp));
|
||||||
let frames = MapNode::new(ValueNode::new(frames));
|
let frames = MapNode::new(ValueNode::new(frames));
|
||||||
let frames = frames.eval(trace.eval(()).into_iter()).collect::<Vec<_>>();
|
let frames = frames.eval(trace.eval(()).await.into_iter()).collect::<Vec<_>>();
|
||||||
|
|
||||||
let background_bounds = ReduceNode::new(ClonedNode::new(None), ValueNode::new(MergeBoundingBoxNode::new()));
|
let background_bounds = ReduceNode::new(ClonedNode::new(None), ValueNode::new(MergeBoundingBoxNode::new()));
|
||||||
let background_bounds = background_bounds.eval(frames.clone().into_iter());
|
let background_bounds = background_bounds.eval(frames.clone().into_iter());
|
||||||
let background_bounds = MergeBoundingBoxNode::new().eval((background_bounds, image.eval(())));
|
let background_bounds = MergeBoundingBoxNode::new().eval((background_bounds, image.eval(()).await));
|
||||||
let mut background_bounds = CopiedNode::new(background_bounds.unwrap().to_transform());
|
let mut background_bounds = CopiedNode::new(background_bounds.unwrap().to_transform());
|
||||||
|
|
||||||
let bounds_transform = bounds.eval(()).transform;
|
let bounds_transform = bounds.eval(()).await.transform;
|
||||||
if bounds_transform != DAffine2::ZERO {
|
if bounds_transform != DAffine2::ZERO {
|
||||||
background_bounds = CopiedNode::new(bounds_transform);
|
background_bounds = CopiedNode::new(bounds_transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
let background_image = background_bounds.then(EmptyImageNode::new(CopiedNode::new(Color::TRANSPARENT)));
|
let background_image = background_bounds.then(EmptyImageNode::new(CopiedNode::new(Color::TRANSPARENT)));
|
||||||
let blend_node = graphene_core::raster::BlendNode::new(CopiedNode::new(BlendMode::Normal), CopiedNode::new(100.));
|
let blend_node = graphene_core::raster::BlendNode::new(CopiedNode::new(BlendMode::Normal), CopiedNode::new(100.));
|
||||||
|
|
||||||
let background = ExtendImageNode::new(background_image);
|
let background = ExtendImageNode::new(background_image);
|
||||||
let background_image = image.then(background);
|
let background_image = image.and_then(background);
|
||||||
|
|
||||||
let final_image = ReduceNode::new(background_image, ValueNode::new(BlendImageTupleNode::new(ValueNode::new(blend_node))));
|
let final_image = ReduceNode::new(ClonedNode::new(background_image.eval(()).await), ValueNode::new(BlendImageTupleNode::new(ValueNode::new(blend_node))));
|
||||||
let final_image = ClonedNode::new(frames.into_iter()).then(final_image);
|
let final_image = ClonedNode::new(frames.into_iter()).then(final_image);
|
||||||
|
|
||||||
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(final_image));
|
let final_image = FutureWrapperNode::new(final_image);
|
||||||
Box::pin(any)
|
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(final_image));
|
||||||
|
any.into_type_erased()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(
|
NodeIOTypes::new(
|
||||||
concrete!(()),
|
concrete!(()),
|
||||||
|
@ -277,14 +306,17 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
||||||
vec![(
|
vec![(
|
||||||
NodeIdentifier::new("graphene_std::brush::ReduceNode<_, _>"),
|
NodeIdentifier::new("graphene_std::brush::ReduceNode<_, _>"),
|
||||||
|args| {
|
|args| {
|
||||||
let acc: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
Box::pin(async move {
|
||||||
let image = acc.eval(());
|
let acc: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||||
let blend_node = graphene_core::raster::BlendNode::new(ClonedNode::new(BlendMode::Normal), ClonedNode::new(1.0));
|
let image = acc.eval(()).await;
|
||||||
let _ = &blend_node as &dyn for<'i> Node<'i, (Color, Color), Output = Color>;
|
let blend_node = graphene_core::raster::BlendNode::new(ClonedNode::new(BlendMode::Normal), ClonedNode::new(1.0));
|
||||||
let node = ReduceNode::new(ClonedNode::new(image), ValueNode::new(BlendImageTupleNode::new(ValueNode::new(blend_node))));
|
let _ = &blend_node as &dyn for<'i> Node<'i, (Color, Color), Output = Color>;
|
||||||
//let _ = &node as &dyn for<'i> Node<'i, core::slice::Iter<ImageFrame<Color>>, Output = ImageFrame<Color>>;
|
let node = ReduceNode::new(ClonedNode::new(image), ValueNode::new(BlendImageTupleNode::new(ValueNode::new(blend_node))));
|
||||||
let any: DynAnyNode<Box<dyn Iterator<Item = ImageFrame<Color>> + Sync + Send>, _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(node));
|
//let _ = &node as &dyn for<'i> Node<'i, core::slice::Iter<ImageFrame<Color>>, Output = ImageFrame<Color>>;
|
||||||
Box::pin(any)
|
let node = FutureWrapperNode::new(node);
|
||||||
|
let any: DynAnyNode<Box<dyn Iterator<Item = ImageFrame<Color>> + Sync + Send>, _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(node));
|
||||||
|
any.into_type_erased()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(
|
NodeIOTypes::new(
|
||||||
concrete!(Box<dyn Iterator<Item = &ImageFrame<Color>> + Sync + Send>),
|
concrete!(Box<dyn Iterator<Item = &ImageFrame<Color>> + Sync + Send>),
|
||||||
|
@ -299,39 +331,25 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
||||||
raster_node!(graphene_core::raster::LevelsNode<_, _, _, _, _>, params: [f64, f64, f64, f64, f64]),
|
raster_node!(graphene_core::raster::LevelsNode<_, _, _, _, _>, params: [f64, f64, f64, f64, f64]),
|
||||||
register_node!(graphene_std::image_segmentation::ImageSegmentationNode<_>, input: ImageFrame<Color>, params: [ImageFrame<Color>]),
|
register_node!(graphene_std::image_segmentation::ImageSegmentationNode<_>, input: ImageFrame<Color>, params: [ImageFrame<Color>]),
|
||||||
register_node!(graphene_core::raster::IndexNode<_>, input: Vec<ImageFrame<Color>>, params: [u32]),
|
register_node!(graphene_core::raster::IndexNode<_>, input: Vec<ImageFrame<Color>>, params: [u32]),
|
||||||
vec![
|
vec![(
|
||||||
(
|
NodeIdentifier::new("graphene_core::raster::BlendNode<_, _, _, _>"),
|
||||||
NodeIdentifier::new("graphene_core::raster::BlendNode<_, _, _, _>"),
|
|args| {
|
||||||
|args| {
|
Box::pin(async move {
|
||||||
let image: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
let image: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||||
let blend_mode: DowncastBothNode<(), BlendMode> = DowncastBothNode::new(args[1]);
|
let blend_mode: DowncastBothNode<(), BlendMode> = DowncastBothNode::new(args[1]);
|
||||||
let opacity: DowncastBothNode<(), f64> = DowncastBothNode::new(args[2]);
|
let opacity: DowncastBothNode<(), f64> = DowncastBothNode::new(args[2]);
|
||||||
let blend_node = graphene_core::raster::BlendNode::new(CopiedNode::new(blend_mode.eval(())), CopiedNode::new(opacity.eval(())));
|
let blend_node = graphene_core::raster::BlendNode::new(CopiedNode::new(blend_mode.eval(()).await), CopiedNode::new(opacity.eval(()).await));
|
||||||
let node = graphene_std::raster::BlendImageNode::new(image, ValueNode::new(blend_node));
|
let node = graphene_std::raster::BlendImageNode::new(image, FutureWrapperNode::new(ValueNode::new(blend_node)));
|
||||||
let _ = &node as &dyn for<'i> Node<'i, ImageFrame<Color>, Output = ImageFrame<Color>>;
|
|
||||||
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||||
any.into_type_erased()
|
Box::pin(any) as TypeErasedPinned
|
||||||
},
|
})
|
||||||
NodeIOTypes::new(
|
},
|
||||||
concrete!(ImageFrame<Color>),
|
NodeIOTypes::new(
|
||||||
concrete!(ImageFrame<Color>),
|
concrete!(ImageFrame<Color>),
|
||||||
vec![value_fn!(ImageFrame<Color>), value_fn!(BlendMode), value_fn!(f64)],
|
concrete!(ImageFrame<Color>),
|
||||||
),
|
vec![value_fn!(ImageFrame<Color>), value_fn!(BlendMode), value_fn!(f64)],
|
||||||
),
|
),
|
||||||
(
|
)],
|
||||||
NodeIdentifier::new("graphene_core::raster::EraseNode<_, _>"),
|
|
||||||
|args| {
|
|
||||||
let image: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
|
||||||
let opacity: DowncastBothNode<(), f64> = DowncastBothNode::new(args[1]);
|
|
||||||
let blend_node = graphene_std::brush::EraseNode::new(ClonedNode::new(opacity.eval(())));
|
|
||||||
let node = graphene_std::raster::BlendImageNode::new(image, ValueNode::new(blend_node));
|
|
||||||
let _ = &node as &dyn for<'i> Node<'i, ImageFrame<Color>, Output = ImageFrame<Color>>;
|
|
||||||
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
|
||||||
any.into_type_erased()
|
|
||||||
},
|
|
||||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(ImageFrame<Color>), value_fn!(f64)]),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
raster_node!(graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>, params: [Color, f64, f64, f64, f64, f64, f64]),
|
raster_node!(graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>, params: [Color, f64, f64, f64, f64, f64, f64]),
|
||||||
raster_node!(graphene_core::raster::HueSaturationNode<_, _, _>, params: [f64, f64, f64]),
|
raster_node!(graphene_core::raster::HueSaturationNode<_, _, _>, params: [f64, f64, f64]),
|
||||||
raster_node!(graphene_core::raster::InvertRGBNode, params: []),
|
raster_node!(graphene_core::raster::InvertRGBNode, params: []),
|
||||||
|
@ -348,25 +366,29 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
||||||
vec![(
|
vec![(
|
||||||
NodeIdentifier::new("graphene_core::raster::BrightnessContrastNode<_, _, _>"),
|
NodeIdentifier::new("graphene_core::raster::BrightnessContrastNode<_, _, _>"),
|
||||||
|args| {
|
|args| {
|
||||||
use graphene_core::raster::brightness_contrast::*;
|
Box::pin(async move {
|
||||||
|
use graphene_core::raster::brightness_contrast::*;
|
||||||
|
|
||||||
let brightness: DowncastBothNode<(), f64> = DowncastBothNode::new(args[0]);
|
let brightness: DowncastBothNode<(), f64> = DowncastBothNode::new(args[0]);
|
||||||
let brightness = ClonedNode::new(brightness.eval(()) as f32);
|
let brightness = ClonedNode::new(brightness.eval(()).await as f32);
|
||||||
let contrast: DowncastBothNode<(), f64> = DowncastBothNode::new(args[1]);
|
let contrast: DowncastBothNode<(), f64> = DowncastBothNode::new(args[1]);
|
||||||
let contrast = ClonedNode::new(contrast.eval(()) as f32);
|
let contrast = ClonedNode::new(contrast.eval(()).await as f32);
|
||||||
let use_legacy: DowncastBothNode<(), bool> = DowncastBothNode::new(args[2]);
|
let use_legacy: DowncastBothNode<(), bool> = DowncastBothNode::new(args[2]);
|
||||||
|
|
||||||
if use_legacy.eval(()) {
|
if use_legacy.eval(()).await {
|
||||||
let generate_brightness_contrast_legacy_mapper_node = GenerateBrightnessContrastLegacyMapperNode::new(brightness, contrast);
|
let generate_brightness_contrast_legacy_mapper_node = GenerateBrightnessContrastLegacyMapperNode::new(brightness, contrast);
|
||||||
let map_image_frame_node = graphene_std::raster::MapImageNode::new(ValueNode::new(generate_brightness_contrast_legacy_mapper_node.eval(())));
|
let map_image_frame_node = graphene_std::raster::MapImageNode::new(ValueNode::new(generate_brightness_contrast_legacy_mapper_node.eval(())));
|
||||||
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(map_image_frame_node));
|
let map_image_frame_node = FutureWrapperNode::new(map_image_frame_node);
|
||||||
Box::pin(any)
|
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(map_image_frame_node));
|
||||||
} else {
|
Box::pin(any) as TypeErasedPinned
|
||||||
let generate_brightness_contrast_mapper_node = GenerateBrightnessContrastMapperNode::new(brightness, contrast);
|
} else {
|
||||||
let map_image_frame_node = graphene_std::raster::MapImageNode::new(ValueNode::new(generate_brightness_contrast_mapper_node.eval(())));
|
let generate_brightness_contrast_mapper_node = GenerateBrightnessContrastMapperNode::new(brightness, contrast);
|
||||||
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(map_image_frame_node));
|
let map_image_frame_node = graphene_std::raster::MapImageNode::new(ValueNode::new(generate_brightness_contrast_mapper_node.eval(())));
|
||||||
Box::pin(any)
|
let map_image_frame_node = FutureWrapperNode::new(map_image_frame_node);
|
||||||
}
|
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(map_image_frame_node));
|
||||||
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(f64), value_fn!(f64), value_fn!(bool)]),
|
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(f64), value_fn!(f64), value_fn!(bool)]),
|
||||||
)],
|
)],
|
||||||
|
@ -377,88 +399,102 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
||||||
(
|
(
|
||||||
NodeIdentifier::new("graphene_std::memo::LetNode<_>"),
|
NodeIdentifier::new("graphene_std::memo::LetNode<_>"),
|
||||||
|_| {
|
|_| {
|
||||||
let node: LetNode<ImageFrame<Color>> = graphene_std::memo::LetNode::new();
|
Box::pin(async move {
|
||||||
let any = graphene_std::any::DynAnyRefNode::new(node);
|
let node: LetNode<ImageFrame<Color>> = graphene_std::memo::LetNode::new();
|
||||||
any.into_type_erased()
|
let any = graphene_std::any::DynAnyRefNode::new(node);
|
||||||
|
any.into_type_erased()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(concrete!(Option<ImageFrame<Color>>), concrete!(&ImageFrame<Color>), vec![]),
|
NodeIOTypes::new(concrete!(Option<ImageFrame<Color>>), concrete!(&ImageFrame<Color>), vec![]),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
NodeIdentifier::new("graphene_std::memo::LetNode<_>"),
|
NodeIdentifier::new("graphene_std::memo::LetNode<_>"),
|
||||||
|_| {
|
|_| {
|
||||||
let node: LetNode<graphene_core::EditorApi> = graphene_std::memo::LetNode::new();
|
Box::pin(async move {
|
||||||
let any = graphene_std::any::DynAnyRefNode::new(node);
|
let node: LetNode<graphene_core::EditorApi> = graphene_std::memo::LetNode::new();
|
||||||
any.into_type_erased()
|
let any = graphene_std::any::DynAnyRefNode::new(node);
|
||||||
|
any.into_type_erased()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(concrete!(Option<graphene_core::EditorApi>), concrete!(&graphene_core::EditorApi), vec![]),
|
NodeIOTypes::new(concrete!(Option<graphene_core::EditorApi>), concrete!(&graphene_core::EditorApi), vec![]),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||||
|args| {
|
|args| {
|
||||||
let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
Box::pin(async move {
|
||||||
let node = graphene_std::memo::EndLetNode::new(input);
|
let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
let node = graphene_std::memo::EndLetNode::new(input);
|
||||||
any.into_type_erased()
|
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||||
|
Box::pin(any) as TypeErasedPinned<'_>
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(generic!(T), concrete!(graphene_core::EditorApi), vec![value_fn!(ImageFrame<Color>)]),
|
NodeIOTypes::new(generic!(T), concrete!(ImageFrame<Color>), vec![value_fn!(ImageFrame<Color>)]),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||||
|args| {
|
|args| {
|
||||||
let input: DowncastBothNode<(), VectorData> = DowncastBothNode::new(args[0]);
|
Box::pin(async move {
|
||||||
let node = graphene_std::memo::EndLetNode::new(input);
|
let input: DowncastBothNode<(), VectorData> = DowncastBothNode::new(args[0]);
|
||||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
let node = graphene_std::memo::EndLetNode::new(input);
|
||||||
any.into_type_erased()
|
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||||
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(generic!(T), concrete!(graphene_core::EditorApi), vec![value_fn!(VectorData)]),
|
NodeIOTypes::new(generic!(T), concrete!(VectorData), vec![value_fn!(VectorData)]),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||||
|args| {
|
|args| {
|
||||||
let input: DowncastBothNode<(), graphene_core::GraphicGroup> = DowncastBothNode::new(args[0]);
|
Box::pin(async move {
|
||||||
let node = graphene_std::memo::EndLetNode::new(input);
|
let input: DowncastBothNode<(), graphene_core::GraphicGroup> = DowncastBothNode::new(args[0]);
|
||||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
let node = graphene_std::memo::EndLetNode::new(input);
|
||||||
any.into_type_erased()
|
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||||
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(generic!(T), concrete!(graphene_core::EditorApi), vec![value_fn!(graphene_core::GraphicGroup)]),
|
NodeIOTypes::new(generic!(T), concrete!(graphene_core::GraphicGroup), vec![value_fn!(graphene_core::GraphicGroup)]),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||||
|args| {
|
|args| {
|
||||||
let input: DowncastBothNode<(), graphene_core::Artboard> = DowncastBothNode::new(args[0]);
|
Box::pin(async move {
|
||||||
let node = graphene_std::memo::EndLetNode::new(input);
|
let input: DowncastBothNode<(), graphene_core::Artboard> = DowncastBothNode::new(args[0]);
|
||||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
let node = graphene_std::memo::EndLetNode::new(input);
|
||||||
any.into_type_erased()
|
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||||
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(generic!(T), concrete!(graphene_core::EditorApi), vec![value_fn!(graphene_core::Artboard)]),
|
NodeIOTypes::new(generic!(T), concrete!(graphene_core::Artboard), vec![value_fn!(graphene_core::Artboard)]),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
NodeIdentifier::new("graphene_std::memo::RefNode<_, _>"),
|
NodeIdentifier::new("graphene_std::memo::RefNode<_, _>"),
|
||||||
|args| {
|
|args| {
|
||||||
let map_fn: DowncastBothRefNode<Option<graphene_core::EditorApi>, graphene_core::EditorApi> = DowncastBothRefNode::new(args[0]);
|
Box::pin(async move {
|
||||||
let node = graphene_std::memo::RefNode::new(map_fn);
|
let map_fn: DowncastBothNode<Option<graphene_core::EditorApi>, &graphene_core::EditorApi> = DowncastBothNode::new(args[0]);
|
||||||
let any = graphene_std::any::DynAnyRefNode::new(node);
|
//let map_fn = map_fn.then(EvalSyncNode::new());
|
||||||
any.into_type_erased()
|
let node = graphene_std::memo::RefNode::new(map_fn);
|
||||||
|
let any = graphene_std::any::DynAnyNode::new(ValueNode::new(node));
|
||||||
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(concrete!(()), concrete!(&graphene_core::EditorApi), vec![]),
|
NodeIOTypes::new(
|
||||||
),
|
concrete!(()),
|
||||||
(
|
concrete!(&graphene_core::EditorApi),
|
||||||
NodeIdentifier::new("graphene_core::structural::MapImageNode"),
|
vec![fn_type!(Option<graphene_core::EditorApi>, &graphene_core::EditorApi)],
|
||||||
|args| {
|
),
|
||||||
let map_fn: DowncastBothNode<Color, Color> = DowncastBothNode::new(args[0]);
|
|
||||||
let node = graphene_std::raster::MapImageNode::new(ValueNode::new(map_fn));
|
|
||||||
let any: DynAnyNode<Image<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
|
||||||
any.into_type_erased()
|
|
||||||
},
|
|
||||||
NodeIOTypes::new(concrete!(Image<Color>), concrete!(Image<Color>), vec![]),
|
|
||||||
),
|
),
|
||||||
|
/*
|
||||||
(
|
(
|
||||||
NodeIdentifier::new("graphene_std::raster::ImaginateNode<_>"),
|
NodeIdentifier::new("graphene_std::raster::ImaginateNode<_>"),
|
||||||
|args| {
|
|args| {
|
||||||
let cached = graphene_std::any::input_node::<Option<std::sync::Arc<Image<Color>>>>(args[15]);
|
Box::pin(async move {
|
||||||
let node = graphene_std::raster::ImaginateNode::new(cached);
|
let cached = graphene_std::any::input_node::<Option<std::sync::Arc<Image<Color>>>>(args[15]);
|
||||||
let any = DynAnyNode::new(ValueNode::new(node));
|
let cached = cached.then(EvalSyncNode::new());
|
||||||
any.into_type_erased()
|
let node = graphene_std::raster::ImaginateNode::new(cached);
|
||||||
|
let node = FutureWrapperNode::new(node);
|
||||||
|
let any = DynAnyNode::new(ValueNode::new(node));
|
||||||
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(
|
NodeIOTypes::new(
|
||||||
concrete!(ImageFrame<Color>),
|
concrete!(ImageFrame<Color>),
|
||||||
|
@ -485,12 +521,15 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
*/
|
||||||
|
/*
|
||||||
(
|
(
|
||||||
NodeIdentifier::new("graphene_core::raster::BlurNode"),
|
NodeIdentifier::new("graphene_core::raster::BlurNode"),
|
||||||
|args| {
|
|args| {
|
||||||
let radius = DowncastBothNode::<(), u32>::new(args[0]);
|
let radius = DowncastBothNode::<(), u32>::new(args[0]);
|
||||||
let sigma = DowncastBothNode::<(), f64>::new(args[1]);
|
let sigma = DowncastBothNode::<(), f64>::new(args[1]);
|
||||||
let image = DowncastBothRefNode::<Image<Color>, Image<Color>>::new(args[2]);
|
let image = DowncastBothRefNode::<Image<Color>, Image<Color>>::new(args[2]);
|
||||||
|
let image = image.then(EvalSyncNode::new());
|
||||||
let empty_image: ValueNode<Image<Color>> = ValueNode::new(Image::empty());
|
let empty_image: ValueNode<Image<Color>> = ValueNode::new(Image::empty());
|
||||||
let empty: TypeNode<_, (), Image<Color>> = TypeNode::new(empty_image.then(CloneNode::new()));
|
let empty: TypeNode<_, (), Image<Color>> = TypeNode::new(empty_image.then(CloneNode::new()));
|
||||||
use graphene_core::Node;
|
use graphene_core::Node;
|
||||||
|
@ -517,61 +556,73 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
||||||
let dimensions: TypeNode<_, (), (u32, u32)> = TypeNode::new(dimensions);
|
let dimensions: TypeNode<_, (), (u32, u32)> = TypeNode::new(dimensions);
|
||||||
let new_image = dimensions.then(new_image);
|
let new_image = dimensions.then(new_image);
|
||||||
let new_image = ForgetNode::new().then(new_image);
|
let new_image = ForgetNode::new().then(new_image);
|
||||||
|
let new_image = FutureWrapperNode::new(new_image);
|
||||||
let node: DynAnyNode<&Image<Color>, _, _> = DynAnyNode::new(ValueNode::new(new_image));
|
let node: DynAnyNode<&Image<Color>, _, _> = DynAnyNode::new(ValueNode::new(new_image));
|
||||||
node.into_type_erased()
|
Box::pin(node)
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(concrete!(Image<Color>), concrete!(Image<Color>), vec![value_fn!(u32), value_fn!(f64)]),
|
NodeIOTypes::new(concrete!(Image<Color>), concrete!(Image<Color>), vec![value_fn!(u32), value_fn!(f64)]),
|
||||||
),
|
),
|
||||||
//register_node!(graphene_std::memo::CacheNode<_>, input: Image<Color>, params: []),
|
//register_node!(graphene_std::memo::CacheNode<_>, input: Image<Color>, params: []),
|
||||||
|
*/
|
||||||
(
|
(
|
||||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||||
|args| {
|
|args| {
|
||||||
let input: DowncastBothNode<(), Image<Color>> = DowncastBothNode::new(args[0]);
|
Box::pin(async move {
|
||||||
let node: CacheNode<Image<Color>, _> = graphene_std::memo::CacheNode::new(input);
|
let input: DowncastBothNode<(), Image<Color>> = DowncastBothNode::new(args[0]);
|
||||||
let any = DynAnyRefNode::new(node);
|
let node: CacheNode<Image<Color>, _> = graphene_std::memo::CacheNode::new(input);
|
||||||
any.into_type_erased()
|
let any = DynAnyNode::new(ValueNode::new(node));
|
||||||
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(concrete!(()), concrete!(&Image<Color>), vec![value_fn!(Image<Color>)]),
|
NodeIOTypes::new(concrete!(()), concrete!(Image<Color>), vec![value_fn!(Image<Color>)]),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||||
|args| {
|
|args| {
|
||||||
let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
Box::pin(async move {
|
||||||
let node: CacheNode<ImageFrame<Color>, _> = graphene_std::memo::CacheNode::new(input);
|
let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||||
let any = DynAnyRefNode::new(node);
|
let node: CacheNode<ImageFrame<Color>, _> = graphene_std::memo::CacheNode::new(input);
|
||||||
any.into_type_erased()
|
let any = DynAnyNode::new(ValueNode::new(node));
|
||||||
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(concrete!(()), concrete!(&ImageFrame<Color>), vec![value_fn!(ImageFrame<Color>)]),
|
NodeIOTypes::new(concrete!(()), concrete!(ImageFrame<Color>), vec![value_fn!(ImageFrame<Color>)]),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||||
|args| {
|
|args| {
|
||||||
let input: DowncastBothNode<ImageFrame<Color>, ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
Box::pin(async move {
|
||||||
let node: CacheNode<ImageFrame<Color>, _> = graphene_std::memo::CacheNode::new(input);
|
let input: DowncastBothNode<ImageFrame<Color>, ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||||
let any = DynAnyRefNode::new(node);
|
let node: CacheNode<ImageFrame<Color>, _> = graphene_std::memo::CacheNode::new(input);
|
||||||
any.into_type_erased()
|
let any = DynAnyNode::new(ValueNode::new(node));
|
||||||
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(&ImageFrame<Color>), vec![fn_type!(ImageFrame<Color>, ImageFrame<Color>)]),
|
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![fn_type!(ImageFrame<Color>, ImageFrame<Color>)]),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||||
|args| {
|
|args| {
|
||||||
let input: DowncastBothNode<(), QuantizationChannels> = DowncastBothNode::new(args[0]);
|
Box::pin(async move {
|
||||||
let node: CacheNode<QuantizationChannels, _> = graphene_std::memo::CacheNode::new(input);
|
let input: DowncastBothNode<(), QuantizationChannels> = DowncastBothNode::new(args[0]);
|
||||||
let any = DynAnyRefNode::new(node);
|
let node: CacheNode<QuantizationChannels, _> = graphene_std::memo::CacheNode::new(input);
|
||||||
any.into_type_erased()
|
let any = DynAnyNode::new(ValueNode::new(node));
|
||||||
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(concrete!(()), concrete!(&QuantizationChannels), vec![value_fn!(QuantizationChannels)]),
|
NodeIOTypes::new(concrete!(()), concrete!(QuantizationChannels), vec![value_fn!(QuantizationChannels)]),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||||
|args| {
|
|args| {
|
||||||
let input: DowncastBothNode<(), Vec<DVec2>> = DowncastBothNode::new(args[0]);
|
Box::pin(async move {
|
||||||
let node: CacheNode<Vec<DVec2>, _> = graphene_std::memo::CacheNode::new(input);
|
let input: DowncastBothNode<(), Vec<DVec2>> = DowncastBothNode::new(args[0]);
|
||||||
let any = DynAnyRefNode::new(node);
|
let node: CacheNode<Vec<DVec2>, _> = graphene_std::memo::CacheNode::new(input);
|
||||||
any.into_type_erased()
|
let any = DynAnyNode::new(ValueNode::new(node));
|
||||||
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(concrete!(()), concrete!(&Vec<DVec2>), vec![value_fn!(Vec<DVec2>)]),
|
NodeIOTypes::new(concrete!(()), concrete!(Vec<DVec2>), vec![value_fn!(Vec<DVec2>)]),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
register_node!(graphene_core::structural::ConsNode<_, _>, input: Image<Color>, params: [&str]),
|
register_node!(graphene_core::structural::ConsNode<_, _>, input: Image<Color>, params: [&str]),
|
||||||
|
@ -595,9 +646,9 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
||||||
input: Vec<graphene_core::vector::bezier_rs::Subpath<graphene_core::uuid::ManipulatorGroupId>>,
|
input: Vec<graphene_core::vector::bezier_rs::Subpath<graphene_core::uuid::ManipulatorGroupId>>,
|
||||||
params: [Vec<graphene_core::uuid::ManipulatorGroupId>]
|
params: [Vec<graphene_core::uuid::ManipulatorGroupId>]
|
||||||
),
|
),
|
||||||
register_node!(graphene_core::text::TextGenerator<_, _, _>, input: graphene_core::EditorApi, params: [String, graphene_core::text::Font, f64]),
|
register_node!(graphene_core::text::TextGenerator<_, _, _>, input: &graphene_core::EditorApi, params: [String, graphene_core::text::Font, f64]),
|
||||||
register_node!(graphene_std::brush::VectorPointsNode, input: VectorData, params: []),
|
register_node!(graphene_std::brush::VectorPointsNode, input: VectorData, params: []),
|
||||||
register_node!(graphene_core::ExtractImageFrame, input: graphene_core::EditorApi, params: []),
|
register_node!(graphene_core::ExtractImageFrame, input: &graphene_core::EditorApi, params: []),
|
||||||
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::vector::VectorData, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
|
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::vector::VectorData, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
|
||||||
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: ImageFrame<Color>, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
|
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: ImageFrame<Color>, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
|
||||||
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::GraphicGroup, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
|
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::GraphicGroup, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::Span;
|
use proc_macro2::Span;
|
||||||
use quote::{format_ident, ToTokens};
|
use quote::{format_ident, quote, ToTokens};
|
||||||
use syn::{
|
use syn::{
|
||||||
parse_macro_input, punctuated::Punctuated, token::Comma, FnArg, GenericParam, Ident, ItemFn, Lifetime, Pat, PatIdent, PathArguments, PredicateType, ReturnType, Token, TraitBound, Type, TypeParam,
|
parse_macro_input, punctuated::Punctuated, token::Comma, FnArg, GenericParam, Ident, ItemFn, Lifetime, Pat, PatIdent, PathArguments, PredicateType, ReturnType, Token, TraitBound, Type, TypeParam,
|
||||||
TypeParamBound, WhereClause, WherePredicate,
|
TypeParamBound, WhereClause, WherePredicate,
|
||||||
|
@ -8,14 +8,69 @@ use syn::{
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
//let node_name = parse_macro_input!(attr as Ident);
|
let mut imp = node_impl_proxy(attr.clone(), item.clone());
|
||||||
|
let new = node_new_impl(attr, item);
|
||||||
|
imp.extend(new);
|
||||||
|
imp
|
||||||
|
}
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn node_new(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
node_new_impl(attr, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn node_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
node_impl_proxy(attr, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn node_new_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
let node = parse_macro_input!(attr as syn::PathSegment);
|
let node = parse_macro_input!(attr as syn::PathSegment);
|
||||||
|
|
||||||
let function = parse_macro_input!(item as ItemFn);
|
let function = parse_macro_input!(item as ItemFn);
|
||||||
|
|
||||||
let node = &node;
|
let node = &node;
|
||||||
let node_name = &node.ident;
|
let node_name = &node.ident;
|
||||||
let mut args = match node.arguments.clone() {
|
let mut args = args(node);
|
||||||
|
|
||||||
|
let arg_idents = args
|
||||||
|
.iter()
|
||||||
|
.filter(|x| x.to_token_stream().to_string().starts_with('_'))
|
||||||
|
.map(|arg| Ident::new(arg.to_token_stream().to_string().to_lowercase().as_str(), Span::call_site()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let (_, _, parameter_pat_ident_patterns) = parse_inputs(&function);
|
||||||
|
let parameter_idents = parameter_pat_ident_patterns.iter().map(|pat_ident| &pat_ident.ident).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Extract the output type of the entire node - `()` by default
|
||||||
|
let struct_generics = (0..parameter_pat_ident_patterns.len())
|
||||||
|
.map(|x| {
|
||||||
|
let ident = format_ident!("S{x}");
|
||||||
|
ident
|
||||||
|
})
|
||||||
|
.collect::<Punctuated<_, Comma>>();
|
||||||
|
|
||||||
|
for ident in struct_generics.iter() {
|
||||||
|
args.push(Type::Verbatim(quote::quote!(#ident)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let struct_generics_iter = struct_generics.iter();
|
||||||
|
quote::quote! {
|
||||||
|
#[automatically_derived]
|
||||||
|
impl <#(#args),*> #node_name<#(#args),*>
|
||||||
|
{
|
||||||
|
pub const fn new(#(#parameter_idents: #struct_generics_iter),*) -> Self{
|
||||||
|
Self{
|
||||||
|
#(#parameter_idents,)*
|
||||||
|
#(#arg_idents: core::marker::PhantomData,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn args(node: &syn::PathSegment) -> Vec<Type> {
|
||||||
|
match node.arguments.clone() {
|
||||||
PathArguments::AngleBracketed(args) => args
|
PathArguments::AngleBracketed(args) => args
|
||||||
.args
|
.args
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -25,53 +80,59 @@ pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
_ => Default::default(),
|
_ => Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn node_impl_proxy(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
let fn_item = item.clone();
|
||||||
|
let function = parse_macro_input!(fn_item as ItemFn);
|
||||||
|
let sync_input = if function.sig.asyncness.is_some() {
|
||||||
|
node_impl_impl(attr, item, Asyncness::AllAsync)
|
||||||
|
} else {
|
||||||
|
node_impl_impl(attr, item, Asyncness::Sync)
|
||||||
};
|
};
|
||||||
let arg_idents = args
|
sync_input
|
||||||
.iter()
|
}
|
||||||
.filter(|x| x.to_token_stream().to_string().starts_with('_'))
|
enum Asyncness {
|
||||||
.map(|arg| Ident::new(arg.to_token_stream().to_string().to_lowercase().as_str(), Span::call_site()))
|
Sync,
|
||||||
.collect::<Vec<_>>();
|
AsyncOut,
|
||||||
|
AllAsync,
|
||||||
|
}
|
||||||
|
|
||||||
let mut function_inputs = function.sig.inputs.iter().filter_map(|arg| if let FnArg::Typed(typed_arg) = arg { Some(typed_arg) } else { None });
|
fn node_impl_impl(attr: TokenStream, item: TokenStream, asyncness: Asyncness) -> TokenStream {
|
||||||
|
//let node_name = parse_macro_input!(attr as Ident);
|
||||||
|
let node = parse_macro_input!(attr as syn::PathSegment);
|
||||||
|
|
||||||
|
let function = parse_macro_input!(item as ItemFn);
|
||||||
|
|
||||||
|
let node = &node;
|
||||||
|
let node_name = &node.ident;
|
||||||
|
let mut args = args(node);
|
||||||
|
|
||||||
|
let async_out = match asyncness {
|
||||||
|
Asyncness::Sync => false,
|
||||||
|
Asyncness::AsyncOut | Asyncness::AllAsync => true,
|
||||||
|
};
|
||||||
|
let async_in = matches!(asyncness, Asyncness::AllAsync);
|
||||||
|
|
||||||
|
let body = &function.block;
|
||||||
let mut type_generics = function.sig.generics.params.clone();
|
let mut type_generics = function.sig.generics.params.clone();
|
||||||
let mut where_clause = function.sig.generics.where_clause.clone().unwrap_or(WhereClause {
|
let mut where_clause = function.sig.generics.where_clause.clone().unwrap_or(WhereClause {
|
||||||
where_token: Token),
|
where_token: Token),
|
||||||
predicates: Default::default(),
|
predicates: Default::default(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Extract primary input as first argument
|
type_generics.iter_mut().for_each(|x| {
|
||||||
let primary_input = function_inputs.next().expect("Primary input required - set to `()` if not needed.");
|
if let GenericParam::Type(t) = x {
|
||||||
|
t.bounds.insert(0, TypeParamBound::Lifetime(Lifetime::new("'input", Span::call_site())));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let (primary_input, parameter_inputs, parameter_pat_ident_patterns) = parse_inputs(&function);
|
||||||
|
let primary_input_ty = &primary_input.ty;
|
||||||
let Pat::Ident(PatIdent{ident: primary_input_ident, mutability: primary_input_mutability,..} ) =&*primary_input.pat else {
|
let Pat::Ident(PatIdent{ident: primary_input_ident, mutability: primary_input_mutability,..} ) =&*primary_input.pat else {
|
||||||
panic!("Expected ident as primary input.");
|
panic!("Expected ident as primary input.");
|
||||||
};
|
};
|
||||||
let primary_input_ty = &primary_input.ty;
|
|
||||||
let aux_type_generics = type_generics
|
|
||||||
.iter()
|
|
||||||
.filter(|gen| {
|
|
||||||
if let GenericParam::Type(ty) = gen {
|
|
||||||
!function.sig.inputs.iter().take(1).any(|param_ty| match param_ty {
|
|
||||||
FnArg::Typed(pat_ty) => ty.ident == pat_ty.ty.to_token_stream().to_string(),
|
|
||||||
_ => false,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let body = function.block;
|
|
||||||
|
|
||||||
// Extract secondary inputs as all other arguments
|
|
||||||
let parameter_inputs = function_inputs.collect::<Vec<_>>();
|
|
||||||
let parameter_pat_ident_patterns = parameter_inputs
|
|
||||||
.iter()
|
|
||||||
.map(|input| {
|
|
||||||
let Pat::Ident(pat_ident) = &*input.pat else { panic!("Expected ident for secondary input."); };
|
|
||||||
pat_ident
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let parameter_idents = parameter_pat_ident_patterns.iter().map(|pat_ident| &pat_ident.ident).collect::<Vec<_>>();
|
let parameter_idents = parameter_pat_ident_patterns.iter().map(|pat_ident| &pat_ident.ident).collect::<Vec<_>>();
|
||||||
let parameter_mutability = parameter_pat_ident_patterns.iter().map(|pat_ident| &pat_ident.mutability);
|
let parameter_mutability = parameter_pat_ident_patterns.iter().map(|pat_ident| &pat_ident.mutability);
|
||||||
|
|
||||||
|
@ -82,20 +143,94 @@ pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
quote::quote!(())
|
quote::quote!(())
|
||||||
};
|
};
|
||||||
|
|
||||||
let struct_generics = (0..parameter_inputs.len())
|
let struct_generics = (0..parameter_pat_ident_patterns.len()).map(|x| format_ident!("S{x}")).collect::<Vec<_>>();
|
||||||
.map(|x| {
|
let future_generics = (0..parameter_pat_ident_patterns.len()).map(|x| format_ident!("F{x}")).collect::<Vec<_>>();
|
||||||
let ident = format_ident!("S{x}");
|
let future_types = future_generics.iter().map(|x| Type::Verbatim(x.to_token_stream())).collect::<Vec<_>>();
|
||||||
ident
|
let parameter_types = parameter_inputs.iter().map(|x| *x.ty.clone()).collect::<Vec<Type>>();
|
||||||
})
|
|
||||||
.collect::<Punctuated<_, Comma>>();
|
|
||||||
let struct_generics_iter = struct_generics.iter();
|
|
||||||
|
|
||||||
for ident in struct_generics.iter() {
|
for ident in struct_generics.iter() {
|
||||||
args.push(Type::Verbatim(quote::quote!(#ident)));
|
args.push(Type::Verbatim(quote::quote!(#ident)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generics are simply `S0` through to `Sn-1` where n is the number of secondary inputs
|
// Generics are simply `S0` through to `Sn-1` where n is the number of secondary inputs
|
||||||
let node_generics = struct_generics
|
let node_generics = construct_node_generics(&struct_generics);
|
||||||
|
let future_generic_params = construct_node_generics(&future_generics);
|
||||||
|
|
||||||
|
let generics = if async_in {
|
||||||
|
type_generics
|
||||||
|
.into_iter()
|
||||||
|
.chain(node_generics.iter().cloned())
|
||||||
|
.chain(future_generic_params.iter().cloned())
|
||||||
|
.collect::<Punctuated<_, Comma>>()
|
||||||
|
} else {
|
||||||
|
type_generics.into_iter().chain(node_generics.iter().cloned()).collect::<Punctuated<_, Comma>>()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bindings for all of the above generics to a node with an input of `()` and an output of the type in the function
|
||||||
|
let node_bounds = if async_in {
|
||||||
|
let mut node_bounds = input_node_bounds(future_types, node_generics, |ty| quote! {Node<'input, (), Output = #ty>});
|
||||||
|
let future_bounds = input_node_bounds(parameter_types, future_generic_params, |ty| quote! { core::future::Future<Output = #ty>});
|
||||||
|
node_bounds.extend(future_bounds);
|
||||||
|
node_bounds
|
||||||
|
} else {
|
||||||
|
input_node_bounds(parameter_types, node_generics, |ty| quote! {Node<'input, (), Output = #ty>})
|
||||||
|
};
|
||||||
|
where_clause.predicates.extend(node_bounds);
|
||||||
|
|
||||||
|
let output = if async_out {
|
||||||
|
quote::quote!(core::pin::Pin<Box<dyn core::future::Future< Output = #output> + 'input>>)
|
||||||
|
} else {
|
||||||
|
quote::quote!(#output)
|
||||||
|
};
|
||||||
|
|
||||||
|
let parameters = if matches!(asyncness, Asyncness::AllAsync) {
|
||||||
|
quote::quote!(#(let #parameter_mutability #parameter_idents = self.#parameter_idents.eval(()).await;)*)
|
||||||
|
} else {
|
||||||
|
quote::quote!(#(let #parameter_mutability #parameter_idents = self.#parameter_idents.eval(());)*)
|
||||||
|
};
|
||||||
|
let mut body_with_inputs = quote::quote!(
|
||||||
|
#parameters
|
||||||
|
{#body}
|
||||||
|
);
|
||||||
|
if async_out {
|
||||||
|
body_with_inputs = quote::quote!(Box::pin(async move { #body_with_inputs }));
|
||||||
|
}
|
||||||
|
|
||||||
|
quote::quote! {
|
||||||
|
#[automatically_derived]
|
||||||
|
impl <'input, #generics> Node<'input, #primary_input_ty> for #node_name<#(#args),*>
|
||||||
|
#where_clause
|
||||||
|
{
|
||||||
|
type Output = #output;
|
||||||
|
#[inline]
|
||||||
|
fn eval(&'input self, #primary_input_mutability #primary_input_ident: #primary_input_ty) -> Self::Output {
|
||||||
|
#body_with_inputs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_inputs(function: &ItemFn) -> (&syn::PatType, Vec<&syn::PatType>, Vec<&PatIdent>) {
|
||||||
|
let mut function_inputs = function.sig.inputs.iter().filter_map(|arg| if let FnArg::Typed(typed_arg) = arg { Some(typed_arg) } else { None });
|
||||||
|
|
||||||
|
// Extract primary input as first argument
|
||||||
|
let primary_input = function_inputs.next().expect("Primary input required - set to `()` if not needed.");
|
||||||
|
|
||||||
|
// Extract secondary inputs as all other arguments
|
||||||
|
let parameter_inputs = function_inputs.collect::<Vec<_>>();
|
||||||
|
let parameter_pat_ident_patterns = parameter_inputs
|
||||||
|
.iter()
|
||||||
|
.map(|input| {
|
||||||
|
let Pat::Ident(pat_ident) = &*input.pat else { panic!("Expected ident for secondary input."); };
|
||||||
|
pat_ident
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
(primary_input, parameter_inputs, parameter_pat_ident_patterns)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn construct_node_generics(struct_generics: &[Ident]) -> Vec<GenericParam> {
|
||||||
|
struct_generics
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|ident| {
|
.map(|ident| {
|
||||||
|
@ -108,22 +243,17 @@ pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
default: None,
|
default: None,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Punctuated<_, Comma>>();
|
.collect()
|
||||||
type_generics.iter_mut().for_each(|x| {
|
}
|
||||||
if let GenericParam::Type(t) = x {
|
|
||||||
t.bounds.insert(0, TypeParamBound::Lifetime(Lifetime::new("'input", Span::call_site())));
|
fn input_node_bounds(parameter_inputs: Vec<Type>, node_generics: Vec<GenericParam>, trait_bound: impl Fn(Type) -> proc_macro2::TokenStream) -> Vec<WherePredicate> {
|
||||||
}
|
parameter_inputs
|
||||||
});
|
|
||||||
let generics = type_generics.into_iter().chain(node_generics.iter().cloned()).collect::<Punctuated<_, Comma>>();
|
|
||||||
let new_fn_generics = aux_type_generics.into_iter().chain(node_generics.iter().cloned()).collect::<Punctuated<_, Comma>>();
|
|
||||||
// Bindings for all of the above generics to a node with an input of `()` and an output of the type in the function
|
|
||||||
let extra_where_clause = parameter_inputs
|
|
||||||
.iter()
|
.iter()
|
||||||
.zip(&node_generics)
|
.zip(&node_generics)
|
||||||
.map(|(ty, name)| {
|
.map(|(ty, name)| {
|
||||||
let ty = &ty.ty;
|
|
||||||
let GenericParam::Type(generic_ty) = name else { panic!("Expected type generic."); };
|
let GenericParam::Type(generic_ty) = name else { panic!("Expected type generic."); };
|
||||||
let ident = &generic_ty.ident;
|
let ident = &generic_ty.ident;
|
||||||
|
let bound = trait_bound(ty.clone());
|
||||||
WherePredicate::Type(PredicateType {
|
WherePredicate::Type(PredicateType {
|
||||||
lifetimes: None,
|
lifetimes: None,
|
||||||
bounded_ty: Type::Verbatim(ident.to_token_stream()),
|
bounded_ty: Type::Verbatim(ident.to_token_stream()),
|
||||||
|
@ -131,43 +261,10 @@ pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
bounds: Punctuated::from_iter([TypeParamBound::Trait(TraitBound {
|
bounds: Punctuated::from_iter([TypeParamBound::Trait(TraitBound {
|
||||||
paren_token: None,
|
paren_token: None,
|
||||||
modifier: syn::TraitBoundModifier::None,
|
modifier: syn::TraitBoundModifier::None,
|
||||||
lifetimes: syn::parse_quote!(for<'any_input>),
|
lifetimes: None, //syn::parse_quote!(for<'any_input>),
|
||||||
path: syn::parse_quote!(Node<'any_input, (), Output = #ty>),
|
path: syn::parse_quote!(#bound),
|
||||||
})]),
|
})]),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect()
|
||||||
where_clause.predicates.extend(extra_where_clause.clone());
|
|
||||||
|
|
||||||
let input_lifetime = if generics.is_empty() { quote::quote!() } else { quote::quote!('input,) };
|
|
||||||
|
|
||||||
quote::quote! {
|
|
||||||
|
|
||||||
impl <'input, #generics> Node<'input, #primary_input_ty> for #node_name<#(#args),*>
|
|
||||||
#where_clause
|
|
||||||
{
|
|
||||||
type Output = #output;
|
|
||||||
#[inline]
|
|
||||||
fn eval(&'input self, #primary_input_mutability #primary_input_ident: #primary_input_ty) -> Self::Output {
|
|
||||||
#(
|
|
||||||
let #parameter_mutability #parameter_idents = self.#parameter_idents.eval(());
|
|
||||||
)*
|
|
||||||
|
|
||||||
#body
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <#input_lifetime #new_fn_generics> #node_name<#(#args),*>
|
|
||||||
where #(#extra_where_clause),*
|
|
||||||
{
|
|
||||||
pub const fn new(#(#parameter_idents: #struct_generics_iter),*) -> Self{
|
|
||||||
Self{
|
|
||||||
#(#parameter_idents,)*
|
|
||||||
#(#arg_idents: core::marker::PhantomData,)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ use super::context::Context;
|
||||||
|
|
||||||
use graph_craft::executor::{Any, Executor};
|
use graph_craft::executor::{Any, Executor};
|
||||||
|
|
||||||
|
use graph_craft::proto::LocalFuture;
|
||||||
use graphene_core::gpu::PushConstants;
|
use graphene_core::gpu::PushConstants;
|
||||||
|
|
||||||
use bytemuck::Pod;
|
use bytemuck::Pod;
|
||||||
|
@ -38,7 +39,7 @@ impl<I: StaticTypeSized, O> GpuExecutor<I, O> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync + Pod> Executor for GpuExecutor<I, O> {
|
impl<I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync + Pod> Executor for GpuExecutor<I, O> {
|
||||||
fn execute<'i, 's: 'i>(&'s self, input: Any<'i>) -> Result<Any<'i>, Box<dyn std::error::Error>> {
|
fn execute<'i>(&'i self, input: Any<'i>) -> LocalFuture<Result<Any<'i>, Box<dyn std::error::Error>>> {
|
||||||
let input = dyn_any::downcast::<Vec<I>>(input).expect("Wrong input type");
|
let input = dyn_any::downcast::<Vec<I>>(input).expect("Wrong input type");
|
||||||
let context = &self.context;
|
let context = &self.context;
|
||||||
let result: Vec<O> = execute_shader(
|
let result: Vec<O> = execute_shader(
|
||||||
|
@ -49,10 +50,11 @@ impl<I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync +
|
||||||
&context.command_buffer_allocator,
|
&context.command_buffer_allocator,
|
||||||
*input,
|
*input,
|
||||||
);
|
);
|
||||||
Ok(Box::new(result))
|
Box::pin(async move { Ok(Box::new(result) as Any) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: make async
|
||||||
fn execute_shader<I: Pod + Send + Sync, O: Pod + Send + Sync>(
|
fn execute_shader<I: Pod + Send + Sync, O: Pod + Send + Sync>(
|
||||||
device: std::sync::Arc<Device>,
|
device: std::sync::Arc<Device>,
|
||||||
queue: std::sync::Arc<vulkano::device::Queue>,
|
queue: std::sync::Arc<vulkano::device::Queue>,
|
||||||
|
|
|
@ -5,7 +5,10 @@ use wgpu::util::DeviceExt;
|
||||||
use super::context::Context;
|
use super::context::Context;
|
||||||
use bytemuck::Pod;
|
use bytemuck::Pod;
|
||||||
use dyn_any::StaticTypeSized;
|
use dyn_any::StaticTypeSized;
|
||||||
use graph_craft::executor::{Any, Executor};
|
use graph_craft::{
|
||||||
|
executor::{Any, Executor},
|
||||||
|
proto::LocalFuture,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GpuExecutor<'a, I: StaticTypeSized, O> {
|
pub struct GpuExecutor<'a, I: StaticTypeSized, O> {
|
||||||
|
@ -27,14 +30,16 @@ impl<'a, I: StaticTypeSized, O> GpuExecutor<'a, I, O> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync + Pod> Executor for GpuExecutor<'a, I, O> {
|
impl<'a, I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync + Pod> Executor for GpuExecutor<'a, I, O> {
|
||||||
fn execute<'i, 's: 'i>(&'s self, input: Any<'i>) -> Result<Any<'i>, Box<dyn std::error::Error>> {
|
fn execute<'i>(&'i self, input: Any<'i>) -> LocalFuture<Result<Any<'i>, Box<dyn std::error::Error>>> {
|
||||||
let input = dyn_any::downcast::<Vec<I>>(input).expect("Wrong input type");
|
let input = dyn_any::downcast::<Vec<I>>(input).expect("Wrong input type");
|
||||||
let context = &self.context;
|
let context = &self.context;
|
||||||
let future = execute_shader(context.device.clone(), context.queue.clone(), self.shader.to_vec(), *input, self.entry_point.clone());
|
let future = execute_shader(context.device.clone(), context.queue.clone(), self.shader.to_vec(), *input, self.entry_point.clone());
|
||||||
let result = future_executor::block_on(future);
|
Box::pin(async move {
|
||||||
|
let result = future.await;
|
||||||
|
|
||||||
let result: Vec<O> = result.ok_or_else(|| String::from("Failed to execute shader"))?;
|
let result: Vec<O> = result.ok_or_else(|| String::from("Failed to execute shader"))?;
|
||||||
Ok(Box::new(result))
|
Ok(Box::new(result) as Any)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue