mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-04 13:30:48 +00:00
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
This commit is contained in:
parent
0c7b55949d
commit
b62ce1d03c
30 changed files with 545 additions and 239 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -1659,6 +1659,7 @@ dependencies = [
|
|||
"compilation-client",
|
||||
"dyn-any",
|
||||
"dyn-clone",
|
||||
"futures",
|
||||
"glam",
|
||||
"gpu-compiler-bin-wrapper",
|
||||
"gpu-executor",
|
||||
|
@ -1671,6 +1672,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 1.0.109",
|
||||
|
@ -2140,6 +2142,7 @@ dependencies = [
|
|||
"borrow_stack",
|
||||
"dyn-any",
|
||||
"dyn-clone",
|
||||
"futures",
|
||||
"glam",
|
||||
"graph-craft",
|
||||
"graphene-core",
|
||||
|
@ -2148,6 +2151,7 @@ dependencies = [
|
|||
"num-traits",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[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).
|
||||
///
|
||||
/// This function updates the insert index so that it points to the same place after the specified `layers` are deleted.
|
||||
fn update_insert_index<'a>(&self, layers: &[&'a [LayerId]], path: &[LayerId], insert_index: isize, reverse_index: bool) -> Result<isize, DocumentError> {
|
||||
fn update_insert_index(&self, layers: &[&[LayerId]], path: &[LayerId], insert_index: isize, reverse_index: bool) -> Result<isize, DocumentError> {
|
||||
let folder = self.document_legacy.folder(path)?;
|
||||
let insert_index = if reverse_index { folder.layer_ids.len() as isize - insert_index } else { insert_index };
|
||||
let layer_ids_above = if insert_index < 0 { &folder.layer_ids } else { &folder.layer_ids[..(insert_index as usize)] };
|
||||
|
|
|
@ -24,7 +24,7 @@ struct ManipulatorGroupOverlays {
|
|||
pub out_line: Option<Vec<LayerId>>,
|
||||
}
|
||||
impl ManipulatorGroupOverlays {
|
||||
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a Option<Vec<LayerId>>> {
|
||||
pub fn iter(&self) -> impl Iterator<Item = &'_ Option<Vec<LayerId>>> {
|
||||
[&self.anchor, &self.in_handle, &self.in_line, &self.out_handle, &self.out_line].into_iter()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ impl ShapeState {
|
|||
}
|
||||
|
||||
/// Provide the currently selected points by reference.
|
||||
pub fn selected_points<'a>(&'a self) -> impl Iterator<Item = &'a ManipulatorPointId> {
|
||||
pub fn selected_points(&self) -> impl Iterator<Item = &'_ ManipulatorPointId> {
|
||||
self.selected_shape_state.values().flat_map(|state| &state.selected_points)
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ use interpreted_executor::executor::DynamicExecutor;
|
|||
use glam::{DAffine2, DVec2};
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::sync::mpsc::{Receiver, Sender};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -58,7 +59,7 @@ pub(crate) struct GenerationResponse {
|
|||
}
|
||||
|
||||
thread_local! {
|
||||
static NODE_RUNTIME: RefCell<Option<NodeRuntime>> = RefCell::new(None);
|
||||
pub(crate) static NODE_RUNTIME: Rc<RefCell<Option<NodeRuntime>>> = Rc::new(RefCell::new(None));
|
||||
}
|
||||
|
||||
impl NodeRuntime {
|
||||
|
@ -72,7 +73,7 @@ impl NodeRuntime {
|
|||
thumbnails: Default::default(),
|
||||
}
|
||||
}
|
||||
pub fn run(&mut self) {
|
||||
pub async fn run(&mut self) {
|
||||
let mut requests = self.receiver.try_iter().collect::<Vec<_>>();
|
||||
// TODO: Currently we still render the document after we submit the node graph execution request.
|
||||
// This should be avoided in the future.
|
||||
|
@ -94,7 +95,7 @@ impl NodeRuntime {
|
|||
}) => {
|
||||
let (network, monitor_nodes) = Self::wrap_network(graph);
|
||||
|
||||
let result = self.execute_network(network, image_frame);
|
||||
let result = self.execute_network(network, image_frame).await;
|
||||
let mut responses = VecDeque::new();
|
||||
self.update_thumbnails(&path, monitor_nodes, &mut responses);
|
||||
let response = GenerationResponse {
|
||||
|
@ -125,7 +126,7 @@ impl NodeRuntime {
|
|||
(scoped_network, monitor_nodes)
|
||||
}
|
||||
|
||||
fn execute_network<'a>(&'a mut self, scoped_network: NodeNetwork, image_frame: Option<ImageFrame<Color>>) -> Result<TaggedValue, String> {
|
||||
async fn execute_network<'a>(&'a mut self, scoped_network: NodeNetwork, image_frame: Option<ImageFrame<Color>>) -> Result<TaggedValue, String> {
|
||||
let editor_api = EditorApi {
|
||||
font_cache: Some(&self.font_cache),
|
||||
image_frame,
|
||||
|
@ -137,7 +138,7 @@ impl NodeRuntime {
|
|||
let proto_network = c.compile_single(scoped_network, true)?;
|
||||
|
||||
assert_ne!(proto_network.nodes.len(), 0, "No protonodes exist?");
|
||||
if let Err(e) = self.executor.update(proto_network) {
|
||||
if let Err(e) = self.executor.update(proto_network).await {
|
||||
error!("Failed to update executor:\n{}", e);
|
||||
return Err(e);
|
||||
}
|
||||
|
@ -146,8 +147,8 @@ impl NodeRuntime {
|
|||
use graph_craft::executor::Executor;
|
||||
|
||||
let result = match self.executor.input_type() {
|
||||
Some(t) if t == concrete!(EditorApi) => self.executor.execute(editor_api.into_dyn()).map_err(|e| e.to_string()),
|
||||
Some(t) if t == concrete!(()) => self.executor.execute(().into_dyn()).map_err(|e| e.to_string()),
|
||||
Some(t) if t == concrete!(EditorApi) => self.executor.execute(editor_api.into_dyn()).await.map_err(|e| e.to_string()),
|
||||
Some(t) if t == concrete!(()) => self.executor.execute(().into_dyn()).await.map_err(|e| e.to_string()),
|
||||
_ => Err("Invalid input type".to_string()),
|
||||
};
|
||||
match result {
|
||||
|
@ -200,13 +201,21 @@ impl NodeRuntime {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn run_node_graph() {
|
||||
NODE_RUNTIME.with(|runtime| {
|
||||
let mut runtime = runtime.borrow_mut();
|
||||
if let Some(runtime) = runtime.as_mut() {
|
||||
runtime.run();
|
||||
pub async fn run_node_graph() {
|
||||
let result = NODE_RUNTIME.try_with(|runtime| {
|
||||
let runtime = runtime.clone();
|
||||
async move {
|
||||
let mut runtime = runtime.try_borrow_mut();
|
||||
if let Ok(ref mut runtime) = runtime {
|
||||
if let Some(ref mut runtime) = runtime.as_mut() {
|
||||
runtime.run().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if let Ok(result) = result {
|
||||
result.await;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -231,8 +240,7 @@ impl Default for NodeGraphExecutor {
|
|||
let (request_sender, request_reciever) = std::sync::mpsc::channel();
|
||||
let (response_sender, response_reciever) = std::sync::mpsc::channel();
|
||||
NODE_RUNTIME.with(|runtime| {
|
||||
let mut runtime = runtime.borrow_mut();
|
||||
*runtime = Some(NodeRuntime::new(request_reciever, response_sender));
|
||||
runtime.borrow_mut().replace(NodeRuntime::new(request_reciever, response_sender));
|
||||
});
|
||||
|
||||
Self {
|
||||
|
|
|
@ -12,12 +12,15 @@ use axum::routing::get;
|
|||
use axum::Router;
|
||||
use fern::colors::{Color, ColoredLevelConfig};
|
||||
use http::{Response, StatusCode};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
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 {
|
||||
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());
|
||||
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));
|
||||
|
||||
// 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 {
|
||||
panic!("Error parsing message: {}", message)
|
||||
};
|
||||
let mut guard = EDITOR.lock().unwrap();
|
||||
let editor = (*guard).as_mut().unwrap();
|
||||
let responses = editor.handle_message(message);
|
||||
let responses = EDITOR.with(|editor| {
|
||||
let mut editor = editor.borrow_mut();
|
||||
editor.as_mut().unwrap().handle_message(message)
|
||||
});
|
||||
|
||||
// Sends a FrontendMessage to JavaScript
|
||||
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()>) {
|
||||
window().request_animation_frame(f.as_ref().unchecked_ref()).expect("should register `requestAnimationFrame` OK");
|
||||
window().request_idle_callback(f.as_ref().unchecked_ref()).unwrap();
|
||||
//window().request_animation_frame(f.as_ref().unchecked_ref()).expect("should register `requestAnimationFrame` OK");
|
||||
}
|
||||
|
||||
// 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
|
||||
if EDITOR_HAS_CRASHED.load(Ordering::SeqCst) {
|
||||
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
|
||||
EDITOR_INSTANCES.with(|instances| {
|
||||
|
@ -218,7 +219,7 @@ impl JsEditorHandle {
|
|||
let g = f.clone();
|
||||
|
||||
*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.
|
||||
request_animation_frame(f.borrow().as_ref().unwrap());
|
||||
|
@ -788,7 +789,7 @@ impl JsEditorHandle {
|
|||
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;
|
||||
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]
|
||||
|
|
|
@ -193,9 +193,18 @@ unsafe impl<T: StaticTypeSized, const N: usize> StaticType for [T; 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>;
|
||||
}
|
||||
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")]
|
||||
pub trait IntoDynAny<'n>: Sized + StaticType + 'n {
|
||||
fn into_dyn(self) -> Box<dyn DynAny<'n> + 'n> {
|
||||
|
@ -228,13 +237,14 @@ use core::{
|
|||
mem::{ManuallyDrop, MaybeUninit},
|
||||
num::Wrapping,
|
||||
ops::Range,
|
||||
pin::Pin,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
impl_type!(
|
||||
Option<T>, Result<T, E>, Cell<T>, UnsafeCell<T>, RefCell<T>, MaybeUninit<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,
|
||||
i8, AtomicI8, i16, AtomicI16, i32, AtomicI32, i64, isize, AtomicIsize,
|
||||
i128, u128, AtomicBool, AtomicPtr<T>
|
||||
|
|
|
@ -329,6 +329,7 @@ impl<'a> AsRef<EditorApi<'a>> for EditorApi<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct ExtractImageFrame;
|
||||
|
||||
impl<'a: 'input, 'input> Node<'input, EditorApi<'a>> for ExtractImageFrame {
|
||||
|
|
|
@ -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 {
|
||||
fn then<Second>(self, second: Second) -> ComposeNode<Self, Second, Input>
|
||||
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 {}
|
||||
|
||||
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>);
|
||||
|
||||
impl<'i, Root, Input: 'i, I: 'i + From<()>> Node<'i, Input> for ConsNode<I, Root>
|
||||
|
|
|
@ -158,6 +158,7 @@ mod test {
|
|||
assert_eq!(node.eval(()), 0);
|
||||
}
|
||||
#[test]
|
||||
#[allow(clippy::unit_cmp)]
|
||||
fn test_unit_node() {
|
||||
let node = ForgetNode::new();
|
||||
assert_eq!(node.eval(()), ());
|
||||
|
|
|
@ -10,6 +10,7 @@ pub fn compile_spirv(request: &CompileRequest, compile_dir: Option<&str>, manife
|
|||
io: request.shader_io.clone(),
|
||||
})?;
|
||||
|
||||
#[cfg(not(feature = "profiling"))]
|
||||
let features = "";
|
||||
#[cfg(feature = "profiling")]
|
||||
let features = "profiling";
|
||||
|
|
|
@ -295,7 +295,7 @@ impl NodeNetwork {
|
|||
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!(())))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::DocumentNode;
|
||||
use crate::executor::Any;
|
||||
pub use crate::imaginate_input::{ImaginateMaskStartingFill, ImaginateSamplingMethod, ImaginateStatus};
|
||||
use crate::proto::{Any as DAny, FutureAny};
|
||||
|
||||
use graphene_core::raster::{BlendMode, LuminanceCalculation};
|
||||
use graphene_core::{Color, Node, Type};
|
||||
|
@ -305,11 +306,11 @@ impl<'a> TaggedValue {
|
|||
pub struct UpcastNode {
|
||||
value: TaggedValue,
|
||||
}
|
||||
impl<'input> Node<'input, Box<dyn DynAny<'input> + 'input>> for UpcastNode {
|
||||
type Output = Box<dyn DynAny<'input> + 'input>;
|
||||
impl<'input> Node<'input, DAny<'input>> for UpcastNode {
|
||||
type Output = FutureAny<'input>;
|
||||
|
||||
fn eval(&'input self, _: Box<dyn DynAny<'input> + 'input>) -> Self::Output {
|
||||
self.value.clone().to_any()
|
||||
fn eval(&'input self, _: DAny<'input>) -> Self::Output {
|
||||
Box::pin(async move { self.value.clone().to_any() })
|
||||
}
|
||||
}
|
||||
impl UpcastNode {
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::error::Error;
|
|||
use dyn_any::DynAny;
|
||||
|
||||
use crate::document::NodeNetwork;
|
||||
use crate::proto::ProtoNetwork;
|
||||
use crate::proto::{LocalFuture, ProtoNetwork};
|
||||
|
||||
pub struct Compiler {}
|
||||
|
||||
|
@ -37,5 +37,5 @@ impl Compiler {
|
|||
pub type Any<'a> = Box<dyn DynAny<'a> + 'a>;
|
||||
|
||||
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::collections::{HashMap, HashSet};
|
||||
|
||||
use std::hash::Hash;
|
||||
use xxhash_rust::xxh3::Xxh3;
|
||||
|
||||
|
@ -11,12 +12,15 @@ use graphene_core::*;
|
|||
use serde::{Deserialize, Serialize};
|
||||
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 TypeErasedNode<'n> = 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 = Any<'i>> + 'n + Send + Sync)>;
|
||||
pub type TypeErasedPinned<'n> = Pin<Box<dyn for<'i> NodeIO<'i, Any<'i>, Output = Any<'i>> + 'n + Send + Sync>>;
|
||||
pub type FutureAny<'n> = DynFuture<'n, Any<'n>>;
|
||||
pub type TypeErasedNode<'n> = dyn for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n;
|
||||
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))]
|
||||
#[derive(Debug, Default, PartialEq, Clone)]
|
||||
|
|
|
@ -59,6 +59,8 @@ node-macro = { path = "../node-macro" }
|
|||
boxcar = "0.1.0"
|
||||
xxhash-rust = { workspace = true }
|
||||
serde_json = "1.0.96"
|
||||
reqwest = { version = "0.11.17", features = ["rustls", "rustls-tls"] }
|
||||
futures = "0.3.28"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
use dyn_any::StaticType;
|
||||
pub use graph_craft::proto::{Any, TypeErasedNode, TypeErasedPinned, TypeErasedPinnedRef};
|
||||
use graph_craft::proto::{DynFuture, FutureAny};
|
||||
use graphene_core::NodeIO;
|
||||
pub use graphene_core::{generic, ops, Node};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::http::EvalSyncNode;
|
||||
|
||||
pub struct DynAnyNode<I, O, Node> {
|
||||
node: Node,
|
||||
_i: PhantomData<I>,
|
||||
|
@ -12,18 +15,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>
|
||||
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>,
|
||||
{
|
||||
type Output = Any<'input>;
|
||||
type Output = FutureAny<'input>;
|
||||
#[inline]
|
||||
fn eval(&'input self, input: Any<'input>) -> Self::Output {
|
||||
let node = self.node.eval(());
|
||||
{
|
||||
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));
|
||||
Box::new(node.eval(*input))
|
||||
}
|
||||
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 output = async move {
|
||||
let result = node.eval(*input).await;
|
||||
Box::new(result) as Any<'input>
|
||||
};
|
||||
Box::pin(output)
|
||||
}
|
||||
|
||||
fn reset(self: std::pin::Pin<&mut Self>) {
|
||||
|
@ -56,11 +61,13 @@ impl<'input, _I: 'input + StaticType, _O: 'input + StaticType, N: 'input> Node<'
|
|||
where
|
||||
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 {
|
||||
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}"));
|
||||
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>) {
|
||||
let wrapped_node = unsafe { self.map_unchecked_mut(|e| &mut e.node) };
|
||||
|
@ -79,14 +86,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>
|
||||
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 {
|
||||
{
|
||||
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}"));
|
||||
Box::new(self.node.eval(*input))
|
||||
let result = self.node.eval(*input);
|
||||
Box::pin(async move { Box::new(result.await) as Any<'_> })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -96,13 +104,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> {
|
||||
fn into_type_erased(self) -> TypeErasedPinned<'n>;
|
||||
}
|
||||
|
||||
impl<'n, N: 'n> IntoTypeErasedNode<'n> for N
|
||||
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> {
|
||||
Box::pin(self)
|
||||
|
@ -139,17 +171,51 @@ pub struct DowncastBothNode<'a, I, O> {
|
|||
_o: PhantomData<O>,
|
||||
}
|
||||
impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'input, I> for DowncastBothNode<'n, I, O> {
|
||||
type Output = DynFuture<'input, O>;
|
||||
#[inline]
|
||||
fn eval(&'input self, input: I) -> Self::Output {
|
||||
{
|
||||
let input = Box::new(input);
|
||||
let future = self.node.eval(input);
|
||||
Box::pin(async move {
|
||||
let out = dyn_any::downcast(future.await).unwrap_or_else(|e| panic!("DowncastBothNode Input {e}"));
|
||||
*out
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'n, I, O> DowncastBothNode<'n, I, O> {
|
||||
pub const fn new(node: TypeErasedPinnedRef<'n>) -> Self {
|
||||
Self {
|
||||
node,
|
||||
_i: core::marker::PhantomData,
|
||||
_o: core::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Boxes the input and downcasts the output.
|
||||
/// Wraps around a node taking Box<dyn DynAny> and returning Box<dyn DynAny>
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct DowncastBothSyncNode<'a, I, O> {
|
||||
node: TypeErasedPinnedRef<'a>,
|
||||
_i: PhantomData<I>,
|
||||
_o: PhantomData<O>,
|
||||
}
|
||||
impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'input, I> for DowncastBothSyncNode<'n, I, O> {
|
||||
type Output = O;
|
||||
#[inline]
|
||||
fn eval(&'input self, input: I) -> Self::Output {
|
||||
{
|
||||
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);
|
||||
|
||||
let value = EvalSyncNode::new().eval(future);
|
||||
let out = dyn_any::downcast(value).unwrap_or_else(|e| panic!("DowncastBothNode Input {e}"));
|
||||
*out
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'n, I, O> DowncastBothNode<'n, I, O> {
|
||||
impl<'n, I, O> DowncastBothSyncNode<'n, I, O> {
|
||||
pub const fn new(node: TypeErasedPinnedRef<'n>) -> Self {
|
||||
Self {
|
||||
node,
|
||||
|
@ -166,13 +232,15 @@ pub struct DowncastBothRefNode<'a, I, O> {
|
|||
_i: PhantomData<(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]
|
||||
fn eval(&'input self, input: I) -> Self::Output {
|
||||
{
|
||||
let input = Box::new(input);
|
||||
let out: Box<&_> = dyn_any::downcast::<&O>(self.node.eval(input)).unwrap_or_else(|e| panic!("DowncastBothRefNode Input {e}"));
|
||||
*out
|
||||
Box::pin(async move {
|
||||
let out: Box<&_> = dyn_any::downcast::<&O>(self.node.eval(input).await).unwrap_or_else(|e| panic!("DowncastBothRefNode Input {e}"));
|
||||
*out
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,10 +256,12 @@ pub struct 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 {
|
||||
let arg = self.first.eval(input);
|
||||
self.second.eval(arg)
|
||||
Box::pin(async move {
|
||||
let arg = self.first.eval(input).await;
|
||||
self.second.eval(arg).await
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,6 +275,21 @@ pub fn input_node<O: StaticType>(n: TypeErasedPinnedRef) -> DowncastBothNode<(),
|
|||
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)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
@ -215,8 +300,8 @@ mod test {
|
|||
pub fn dyn_input_invalid_eval_panic() {
|
||||
//let add = DynAnyNode::new(AddNode::new()).into_type_erased();
|
||||
//add.eval(Box::new(&("32", 32u32)));
|
||||
let dyn_any = DynAnyNode::<(u32, u32), u32, _>::new(ValueNode::new(AddNode::new()));
|
||||
let type_erased = dyn_any.into_type_erased();
|
||||
let dyn_any = DynAnyNode::<(u32, u32), u32, _>::new(ValueNode::new(FutureWrapperNode { node: AddNode::new() }));
|
||||
let type_erased = Box::pin(dyn_any) as TypeErasedPinned;
|
||||
let _ref_type_erased = type_erased.as_ref();
|
||||
//let type_erased = Box::pin(dyn_any) as TypeErasedPinned<'_>;
|
||||
type_erased.eval(Box::new(&("32", 32u32)));
|
||||
|
@ -226,10 +311,10 @@ mod test {
|
|||
pub fn dyn_input_invalid_eval_panic_() {
|
||||
//let add = DynAnyNode::new(AddNode::new()).into_type_erased();
|
||||
//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<'_>;
|
||||
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 = ComposeTypeErased::new(type_erased.as_ref(), type_erased_id.as_ref());
|
||||
type_erased.eval(Box::new((4u32, 2u32)));
|
||||
|
|
|
@ -17,7 +17,7 @@ pub struct GpuCompiler<TypingContext, ShaderIO> {
|
|||
|
||||
// TODO: Move to graph-craft
|
||||
#[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 DocumentNodeImplementation::Network(network) = node.implementation;
|
||||
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 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
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ pub struct MapGpuNode<Shader> {
|
|||
}
|
||||
|
||||
#[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;
|
||||
let executor = NewExecutor::new().unwrap();
|
||||
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();
|
||||
}
|
||||
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 result = executor.execute(Box::new(data)).unwrap();
|
||||
let result = dyn_any::downcast::<Vec<_O>>(result).unwrap();
|
||||
*result
|
||||
*/
|
||||
}
|
||||
|
||||
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 http;
|
||||
|
||||
pub mod any;
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
|
|
|
@ -12,7 +12,7 @@ pub struct GenerateQuantizationNode<N, M> {
|
|||
}
|
||||
|
||||
#[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 len = image.data.len().min(10000);
|
||||
|
|
|
@ -24,3 +24,7 @@ log = "0.4"
|
|||
serde = { version = "1", features = ["derive"], optional = true }
|
||||
glam = { version = "0.22" }
|
||||
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::NodeId;
|
||||
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 graphene_std::any::{Any, TypeErasedPinned, TypeErasedPinnedRef};
|
||||
|
||||
|
@ -33,11 +33,11 @@ impl Default for 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);
|
||||
typing_context.update(&proto_network)?;
|
||||
let output = proto_network.output;
|
||||
let tree = BorrowTree::new(proto_network, &typing_context)?;
|
||||
let tree = BorrowTree::new(proto_network, &typing_context).await?;
|
||||
|
||||
Ok(Self {
|
||||
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.typing_context.update(&proto_network)?;
|
||||
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);
|
||||
for node_id in orphans {
|
||||
if self.orphaned_nodes.contains(&node_id) {
|
||||
|
@ -75,8 +75,8 @@ impl DynamicExecutor {
|
|||
}
|
||||
|
||||
impl Executor for DynamicExecutor {
|
||||
fn execute<'a, 's: 'a>(&'s self, input: Any<'a>) -> Result<Any<'a>, Box<dyn Error>> {
|
||||
self.tree.eval_any(self.output, input).ok_or_else(|| "Failed to execute".into())
|
||||
fn execute<'a>(&'a self, input: Any<'a>) -> LocalFuture<Result<Any<'a>, Box<dyn Error>>> {
|
||||
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 {
|
||||
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();
|
||||
for (id, node) in proto_network.nodes {
|
||||
nodes.push_node(id, node, typing_context)?
|
||||
nodes.push_node(id, node, typing_context).await?
|
||||
}
|
||||
Ok(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();
|
||||
for (id, node) in proto_network.nodes {
|
||||
if !self.nodes.contains_key(&id) {
|
||||
self.push_node(id, node, typing_context)?;
|
||||
self.push_node(id, node, typing_context).await?;
|
||||
} else {
|
||||
let Some(node_container) = self.nodes.get_mut(&id) else { continue };
|
||||
let mut node_container_writer = node_container.write().unwrap();
|
||||
|
@ -168,25 +168,25 @@ impl BorrowTree {
|
|||
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 reader = node.read().unwrap();
|
||||
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)?;
|
||||
// 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: 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) {
|
||||
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 {
|
||||
construction_args,
|
||||
identifier,
|
||||
|
@ -207,7 +207,7 @@ impl BorrowTree {
|
|||
let ids: Vec<_> = ids.iter().map(|(id, _)| *id).collect();
|
||||
let construction_nodes = self.node_refs(&ids);
|
||||
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 {
|
||||
node,
|
||||
_dependencies: self.node_deps(&ids),
|
||||
|
@ -226,12 +226,12 @@ mod test {
|
|||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn push_node() {
|
||||
#[tokio::test]
|
||||
async fn push_node() {
|
||||
let mut tree = BorrowTree::default();
|
||||
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();
|
||||
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);
|
||||
}*/
|
||||
|
||||
#[test]
|
||||
fn execute_add() {
|
||||
#[tokio::test]
|
||||
async fn execute_add() {
|
||||
use graph_craft::document::*;
|
||||
|
||||
use graph_craft::*;
|
||||
|
@ -109,15 +109,15 @@ mod tests {
|
|||
let compiler = Compiler {};
|
||||
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();
|
||||
assert_eq!(val, 33_u32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn double_number() {
|
||||
#[tokio::test]
|
||||
async fn double_number() {
|
||||
use graph_craft::document::*;
|
||||
|
||||
use graph_craft::*;
|
||||
|
@ -158,6 +158,6 @@ mod tests {
|
|||
let compiler = Compiler {};
|
||||
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,6 +1,6 @@
|
|||
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 once_cell::sync::Lazy;
|
||||
use std::collections::HashMap;
|
||||
|
@ -8,36 +8,40 @@ use std::collections::HashMap;
|
|||
use graphene_core::raster::color::Color;
|
||||
use graphene_core::raster::*;
|
||||
use graphene_core::structural::Then;
|
||||
use graphene_core::value::{ClonedNode, CopiedNode, ForgetNode, ValueNode};
|
||||
use graphene_core::value::{ClonedNode, ValueNode};
|
||||
use graphene_core::{Node, NodeIO, NodeIOTypes};
|
||||
use graphene_std::brush::*;
|
||||
use graphene_std::raster::*;
|
||||
|
||||
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DowncastBothRefNode, DynAnyInRefNode, DynAnyNode, DynAnyRefNode, IntoTypeErasedNode, TypeErasedPinnedRef};
|
||||
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DowncastBothRefNode, DynAnyInRefNode, DynAnyNode, FutureWrapperNode, IntoTypeErasedNode, TypeErasedPinnedRef};
|
||||
|
||||
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_std::memo::{CacheNode, LetNode};
|
||||
use graphene_core::{concrete, generic, value_fn};
|
||||
use graphene_std::http::EvalSyncNode;
|
||||
use graphene_std::memo::LetNode;
|
||||
use graphene_std::raster::BlendImageTupleNode;
|
||||
|
||||
use crate::executor::NodeContainer;
|
||||
|
||||
use dyn_any::StaticType;
|
||||
|
||||
use graphene_core::quantization::QuantizationChannels;
|
||||
|
||||
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();
|
||||
args.reverse();
|
||||
<$path>::new($(graphene_core::value::ClonedNode::new(
|
||||
graphene_std::any::input_node::<$type>(args.pop()
|
||||
.expect("Not enough arguments provided to construct node")).eval(()))
|
||||
let node = <$path>::new($(
|
||||
{
|
||||
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 +51,16 @@ macro_rules! register_node {
|
|||
(
|
||||
NodeIdentifier::new(stringify!($path)),
|
||||
|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));
|
||||
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($(
|
||||
graphene_std::any::input_node::<$type>(_node)
|
||||
graphene_std::any::PanicNode::<(), $type>::new()
|
||||
),*);
|
||||
let params = vec![$(value_fn!($type)),*];
|
||||
let mut node_io = <$path as NodeIO<'_, $input>>::to_node_io(&node, params);
|
||||
|
@ -82,9 +86,12 @@ macro_rules! raster_node {
|
|||
(
|
||||
NodeIdentifier::new(stringify!($path)),
|
||||
|args| {
|
||||
let node = construct_node!(args, $path, [$($type),*]);
|
||||
let any: DynAnyNode<Color, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||
Box::pin(any)
|
||||
Box::pin(async move {
|
||||
let node = construct_node!(args, $path, [$($type),*]).await;
|
||||
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)),*];
|
||||
|
@ -94,10 +101,13 @@ macro_rules! raster_node {
|
|||
(
|
||||
NodeIdentifier::new(stringify!($path)),
|
||||
|args| {
|
||||
let node = construct_node!(args, $path, [$($type),*]);
|
||||
let map_node = graphene_std::raster::MapImageNode::new(graphene_core::value::ValueNode::new(node));
|
||||
let any: DynAnyNode<Image<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(map_node));
|
||||
Box::pin(any)
|
||||
Box::pin(async move {
|
||||
let node = construct_node!(args, $path, [$($type),*]).await;
|
||||
let map_node = graphene_std::raster::MapImageNode::new(graphene_core::value::ValueNode::new(node));
|
||||
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)),*];
|
||||
|
@ -107,10 +117,13 @@ macro_rules! raster_node {
|
|||
(
|
||||
NodeIdentifier::new(stringify!($path)),
|
||||
|args| {
|
||||
let node = construct_node!(args, $path, [$($type),*]);
|
||||
let map_node = graphene_std::raster::MapImageNode::new(graphene_core::value::ValueNode::new(node));
|
||||
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(map_node));
|
||||
Box::pin(any)
|
||||
Box::pin(async move {
|
||||
let node = construct_node!(args, $path, [$($type),*]).await;
|
||||
let map_node = graphene_std::raster::MapImageNode::new(graphene_core::value::ValueNode::new(node));
|
||||
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)),*];
|
||||
|
@ -129,7 +142,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
//register_node!(graphene_core::ops::IdNode, input: Any<'_>, params: []),
|
||||
vec![(
|
||||
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![]),
|
||||
)],
|
||||
// TODO: create macro to impl for all types
|
||||
|
@ -204,8 +217,10 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
vec![(
|
||||
NodeIdentifier::new("graphene_core::structural::ComposeNode<_, _, _>"),
|
||||
|args| {
|
||||
let node = ComposeTypeErased::new(args[0], args[1]);
|
||||
node.into_type_erased()
|
||||
Box::pin(async move {
|
||||
let node = ComposeTypeErased::new(args[0], args[1]);
|
||||
node.into_type_erased()
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(
|
||||
generic!(T),
|
||||
|
@ -223,42 +238,47 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
use graphene_core::value::*;
|
||||
use graphene_std::brush::*;
|
||||
|
||||
let image: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let bounds: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[1]);
|
||||
let trace: DowncastBothNode<(), Vec<DVec2>> = DowncastBothNode::new(args[2]);
|
||||
let diameter: DowncastBothNode<(), f64> = DowncastBothNode::new(args[3]);
|
||||
let hardness: DowncastBothNode<(), f64> = DowncastBothNode::new(args[4]);
|
||||
let flow: DowncastBothNode<(), f64> = DowncastBothNode::new(args[5]);
|
||||
let color: DowncastBothNode<(), Color> = DowncastBothNode::new(args[6]);
|
||||
Box::pin(async move {
|
||||
let image: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let bounds: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[1]);
|
||||
let trace: DowncastBothNode<(), Vec<DVec2>> = DowncastBothNode::new(args[2]);
|
||||
let diameter: DowncastBothNode<(), f64> = DowncastBothNode::new(args[3]);
|
||||
let hardness: DowncastBothNode<(), f64> = DowncastBothNode::new(args[4]);
|
||||
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 = stamp.eval(diameter.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(()).await);
|
||||
|
||||
let frames = TranslateNode::new(CopiedNode::new(stamp));
|
||||
let frames = MapNode::new(ValueNode::new(frames));
|
||||
let frames = frames.eval(trace.eval(()).into_iter()).collect::<Vec<_>>();
|
||||
let frames = TranslateNode::new(CopiedNode::new(stamp));
|
||||
let frames = MapNode::new(ValueNode::new(frames));
|
||||
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 = background_bounds.eval(frames.clone().into_iter());
|
||||
let background_bounds = MergeBoundingBoxNode::new().eval((background_bounds, image.eval(())));
|
||||
let mut background_bounds = CopiedNode::new(background_bounds.unwrap().to_transform());
|
||||
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 = MergeBoundingBoxNode::new().eval((background_bounds, image.eval(()).await));
|
||||
let mut background_bounds = CopiedNode::new(background_bounds.unwrap().to_transform());
|
||||
let http_node = graphene_std::http::GetNode::new();
|
||||
log::info!("http node: {:?}", http_node.eval("http://localhost:8080".to_string()).await);
|
||||
|
||||
let bounds_transform = bounds.eval(()).transform;
|
||||
if bounds_transform != DAffine2::ZERO {
|
||||
background_bounds = CopiedNode::new(bounds_transform);
|
||||
}
|
||||
let bounds_transform = bounds.eval(()).await.transform;
|
||||
if bounds_transform != DAffine2::ZERO {
|
||||
background_bounds = CopiedNode::new(bounds_transform);
|
||||
}
|
||||
|
||||
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 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 background = ExtendImageNode::new(background_image);
|
||||
let background_image = image.then(background);
|
||||
let background = ExtendImageNode::new(background_image);
|
||||
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 = ClonedNode::new(frames.into_iter()).then(final_image);
|
||||
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 any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(final_image));
|
||||
Box::pin(any)
|
||||
let final_image = FutureWrapperNode::new(final_image);
|
||||
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(final_image));
|
||||
any.into_type_erased()
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(
|
||||
concrete!(()),
|
||||
|
@ -277,14 +297,17 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
vec![(
|
||||
NodeIdentifier::new("graphene_std::brush::ReduceNode<_, _>"),
|
||||
|args| {
|
||||
let acc: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let image = acc.eval(());
|
||||
let blend_node = graphene_core::raster::BlendNode::new(ClonedNode::new(BlendMode::Normal), ClonedNode::new(1.0));
|
||||
let _ = &blend_node as &dyn for<'i> Node<'i, (Color, Color), Output = Color>;
|
||||
let node = ReduceNode::new(ClonedNode::new(image), ValueNode::new(BlendImageTupleNode::new(ValueNode::new(blend_node))));
|
||||
//let _ = &node as &dyn for<'i> Node<'i, core::slice::Iter<ImageFrame<Color>>, Output = ImageFrame<Color>>;
|
||||
let any: DynAnyNode<Box<dyn Iterator<Item = ImageFrame<Color>> + Sync + Send>, _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any)
|
||||
Box::pin(async move {
|
||||
let acc: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let image = acc.eval(()).await;
|
||||
let blend_node = graphene_core::raster::BlendNode::new(ClonedNode::new(BlendMode::Normal), ClonedNode::new(1.0));
|
||||
let _ = &blend_node as &dyn for<'i> Node<'i, (Color, Color), Output = Color>;
|
||||
let node = ReduceNode::new(ClonedNode::new(image), ValueNode::new(BlendImageTupleNode::new(ValueNode::new(blend_node))));
|
||||
//let _ = &node as &dyn for<'i> Node<'i, core::slice::Iter<ImageFrame<Color>>, Output = ImageFrame<Color>>;
|
||||
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(
|
||||
concrete!(Box<dyn Iterator<Item = &ImageFrame<Color>> + Sync + Send>),
|
||||
|
@ -299,18 +322,22 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
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_core::raster::IndexNode<_>, input: Vec<ImageFrame<Color>>, params: [u32]),
|
||||
/*
|
||||
vec![
|
||||
(
|
||||
NodeIdentifier::new("graphene_core::raster::BlendNode<_, _, _, _>"),
|
||||
|args| {
|
||||
let image: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let blend_mode: DowncastBothNode<(), BlendMode> = DowncastBothNode::new(args[1]);
|
||||
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 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()
|
||||
Box::pin(async move {
|
||||
let image: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let blend_mode: DowncastBothNode<(), BlendMode> = DowncastBothNode::new(args[1]);
|
||||
let opacity: DowncastBothNode<(), f64> = DowncastBothNode::new(args[2]);
|
||||
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 as &dyn for<'i> Node<'i, ImageFrame<Color>, Output = ImageFrame<Color>>;
|
||||
let node = FutureWrapperNode::new(node);
|
||||
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>),
|
||||
|
@ -321,17 +348,21 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
(
|
||||
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()
|
||||
Box::pin(async move {
|
||||
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(()).await));
|
||||
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 node = FutureWrapperNode::new(node);
|
||||
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::HueSaturationNode<_, _, _>, params: [f64, f64, f64]),
|
||||
raster_node!(graphene_core::raster::InvertRGBNode, params: []),
|
||||
|
@ -345,6 +376,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
graphene_core::raster::SelectiveColorNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>,
|
||||
params: [RelativeAbsolute, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64]
|
||||
),
|
||||
/*
|
||||
vec![(
|
||||
NodeIdentifier::new("graphene_core::raster::BrightnessContrastNode<_, _, _>"),
|
||||
|args| {
|
||||
|
@ -359,17 +391,20 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
if use_legacy.eval(()) {
|
||||
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 = 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)
|
||||
} else {
|
||||
let generate_brightness_contrast_mapper_node = GenerateBrightnessContrastMapperNode::new(brightness, contrast);
|
||||
let map_image_frame_node = graphene_std::raster::MapImageNode::new(ValueNode::new(generate_brightness_contrast_mapper_node.eval(())));
|
||||
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)
|
||||
}
|
||||
},
|
||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(f64), value_fn!(f64), value_fn!(bool)]),
|
||||
)],
|
||||
*/
|
||||
raster_node!(graphene_core::raster::OpacityNode<_>, params: [f64]),
|
||||
raster_node!(graphene_core::raster::PosterizeNode<_>, params: [f64]),
|
||||
raster_node!(graphene_core::raster::ExposureNode<_, _, _>, params: [f64, f64, f64]),
|
||||
|
@ -377,88 +412,112 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
(
|
||||
NodeIdentifier::new("graphene_std::memo::LetNode<_>"),
|
||||
|_| {
|
||||
let node: LetNode<ImageFrame<Color>> = graphene_std::memo::LetNode::new();
|
||||
let any = graphene_std::any::DynAnyRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
Box::pin(async move {
|
||||
let node: LetNode<ImageFrame<Color>> = graphene_std::memo::LetNode::new();
|
||||
let any = graphene_std::any::DynAnyRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(Option<ImageFrame<Color>>), concrete!(&ImageFrame<Color>), vec![]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::LetNode<_>"),
|
||||
|_| {
|
||||
let node: LetNode<graphene_core::EditorApi> = graphene_std::memo::LetNode::new();
|
||||
let any = graphene_std::any::DynAnyRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
Box::pin(async move {
|
||||
let node: LetNode<graphene_core::EditorApi> = graphene_std::memo::LetNode::new();
|
||||
let any = graphene_std::any::DynAnyRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(Option<graphene_core::EditorApi>), concrete!(&graphene_core::EditorApi), vec![]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||
|args| {
|
||||
let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
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>)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||
|args| {
|
||||
let input: DowncastBothNode<(), VectorData> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), VectorData> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
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)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||
|args| {
|
||||
let input: DowncastBothNode<(), graphene_core::GraphicGroup> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), graphene_core::GraphicGroup> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
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)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||
|args| {
|
||||
let input: DowncastBothNode<(), graphene_core::Artboard> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), graphene_core::Artboard> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
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)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::RefNode<_, _>"),
|
||||
|args| {
|
||||
let map_fn: DowncastBothRefNode<Option<graphene_core::EditorApi>, graphene_core::EditorApi> = DowncastBothRefNode::new(args[0]);
|
||||
let node = graphene_std::memo::RefNode::new(map_fn);
|
||||
let any = graphene_std::any::DynAnyRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
Box::pin(async move {
|
||||
let map_fn: DowncastBothRefNode<Option<graphene_core::EditorApi>, graphene_core::EditorApi> = DowncastBothRefNode::new(args[0]);
|
||||
let map_fn = map_fn.then(EvalSyncNode::new());
|
||||
let node = graphene_std::memo::RefNode::new(map_fn);
|
||||
let any = graphene_std::any::DynAnyRefNode::new(node);
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(()), concrete!(&graphene_core::EditorApi), vec![]),
|
||||
),
|
||||
/*
|
||||
(
|
||||
NodeIdentifier::new("graphene_core::structural::MapImageNode"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let map_fn: DowncastBothNode<Color, Color> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::raster::MapImageNode::new(ValueNode::new(map_fn));
|
||||
let node = FutureWrapperNode::new(node);
|
||||
let any: DynAnyNode<Image<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||
any.into_type_erased()
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(Image<Color>), concrete!(Image<Color>), vec![]),
|
||||
),
|
||||
*/
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::raster::ImaginateNode<_>"),
|
||||
|args| {
|
||||
let cached = graphene_std::any::input_node::<Option<std::sync::Arc<Image<Color>>>>(args[15]);
|
||||
let node = graphene_std::raster::ImaginateNode::new(cached);
|
||||
let any = DynAnyNode::new(ValueNode::new(node));
|
||||
any.into_type_erased()
|
||||
Box::pin(async move {
|
||||
let cached = graphene_std::any::input_node::<Option<std::sync::Arc<Image<Color>>>>(args[15]);
|
||||
let cached = cached.then(EvalSyncNode::new());
|
||||
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(
|
||||
concrete!(ImageFrame<Color>),
|
||||
|
@ -485,12 +544,14 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
],
|
||||
),
|
||||
),
|
||||
/*
|
||||
(
|
||||
NodeIdentifier::new("graphene_core::raster::BlurNode"),
|
||||
|args| {
|
||||
let radius = DowncastBothNode::<(), u32>::new(args[0]);
|
||||
let sigma = DowncastBothNode::<(), f64>::new(args[1]);
|
||||
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: TypeNode<_, (), Image<Color>> = TypeNode::new(empty_image.then(CloneNode::new()));
|
||||
use graphene_core::Node;
|
||||
|
@ -517,8 +578,9 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
let dimensions: TypeNode<_, (), (u32, u32)> = TypeNode::new(dimensions);
|
||||
let new_image = dimensions.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));
|
||||
node.into_type_erased()
|
||||
Box::pin(node)
|
||||
},
|
||||
NodeIOTypes::new(concrete!(Image<Color>), concrete!(Image<Color>), vec![value_fn!(u32), value_fn!(f64)]),
|
||||
),
|
||||
|
@ -529,7 +591,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
let input: DowncastBothNode<(), Image<Color>> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<Image<Color>, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
Box::pin(any)
|
||||
},
|
||||
NodeIOTypes::new(concrete!(()), concrete!(&Image<Color>), vec![value_fn!(Image<Color>)]),
|
||||
),
|
||||
|
@ -539,7 +601,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<ImageFrame<Color>, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
Box::pin(any)
|
||||
},
|
||||
NodeIOTypes::new(concrete!(()), concrete!(&ImageFrame<Color>), vec![value_fn!(ImageFrame<Color>)]),
|
||||
),
|
||||
|
@ -549,7 +611,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
let input: DowncastBothNode<ImageFrame<Color>, ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<ImageFrame<Color>, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
Box::pin(any)
|
||||
},
|
||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(&ImageFrame<Color>), vec![fn_type!(ImageFrame<Color>, ImageFrame<Color>)]),
|
||||
),
|
||||
|
@ -559,7 +621,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
let input: DowncastBothNode<(), QuantizationChannels> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<QuantizationChannels, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
Box::pin(any)
|
||||
},
|
||||
NodeIOTypes::new(concrete!(()), concrete!(&QuantizationChannels), vec![value_fn!(QuantizationChannels)]),
|
||||
),
|
||||
|
@ -569,10 +631,10 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
let input: DowncastBothNode<(), Vec<DVec2>> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<Vec<DVec2>, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
Box::pin(any)
|
||||
},
|
||||
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_std::raster::ImageFrameNode<_, _>, input: Image<Color>, params: [DAffine2]),
|
||||
|
|
|
@ -26,6 +26,9 @@ pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||
.collect::<Vec<_>>(),
|
||||
_ => Default::default(),
|
||||
};
|
||||
|
||||
let asyncness = function.sig.asyncness.is_some();
|
||||
|
||||
let arg_idents = args
|
||||
.iter()
|
||||
.filter(|x| x.to_token_stream().to_string().starts_with('_'))
|
||||
|
@ -141,21 +144,43 @@ pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||
|
||||
let input_lifetime = if generics.is_empty() { quote::quote!() } else { quote::quote!('input,) };
|
||||
|
||||
quote::quote! {
|
||||
let node_impl = if asyncness {
|
||||
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(());
|
||||
)*
|
||||
impl <'input, #generics> Node<'input, #primary_input_ty> for #node_name<#(#args),*>
|
||||
#where_clause
|
||||
{
|
||||
type Output = core::pin::Pin<Box<dyn core::future::Future< Output = #output> + 'input>>;
|
||||
#[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
|
||||
Box::pin(async move {#body})
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let new_fn = quote::quote! {
|
||||
|
||||
impl <#input_lifetime #new_fn_generics> #node_name<#(#args),*>
|
||||
where #(#extra_where_clause),*
|
||||
|
@ -168,6 +193,10 @@ pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
};
|
||||
quote::quote! {
|
||||
#node_impl
|
||||
#new_fn
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use super::context::Context;
|
|||
|
||||
use graph_craft::executor::{Any, Executor};
|
||||
|
||||
use graph_craft::proto::LocalFuture;
|
||||
use graphene_core::gpu::PushConstants;
|
||||
|
||||
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> {
|
||||
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 context = &self.context;
|
||||
let result: Vec<O> = execute_shader(
|
||||
|
@ -49,10 +50,11 @@ impl<I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync +
|
|||
&context.command_buffer_allocator,
|
||||
*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>(
|
||||
device: std::sync::Arc<Device>,
|
||||
queue: std::sync::Arc<vulkano::device::Queue>,
|
||||
|
|
|
@ -5,7 +5,10 @@ use wgpu::util::DeviceExt;
|
|||
use super::context::Context;
|
||||
use bytemuck::Pod;
|
||||
use dyn_any::StaticTypeSized;
|
||||
use graph_craft::executor::{Any, Executor};
|
||||
use graph_craft::{
|
||||
executor::{Any, Executor},
|
||||
proto::LocalFuture,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
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> {
|
||||
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 context = &self.context;
|
||||
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"))?;
|
||||
Ok(Box::new(result))
|
||||
let result: Vec<O> = result.ok_or_else(|| String::from("Failed to execute shader"))?;
|
||||
Ok(Box::new(result) as Any)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue