mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-07-08 00:05:00 +00:00
Test using slotmap
This commit is contained in:
parent
95b23ce1af
commit
f5fd0a8bd7
20 changed files with 395 additions and 386 deletions
13
Cargo.lock
generated
13
Cargo.lock
generated
|
@ -1014,6 +1014,7 @@ name = "dyn-any"
|
|||
version = "0.3.1"
|
||||
dependencies = [
|
||||
"dyn-any-derive",
|
||||
"ghost-cell",
|
||||
"glam",
|
||||
"log",
|
||||
]
|
||||
|
@ -1424,6 +1425,12 @@ dependencies = [
|
|||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ghost-cell"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5fdd3f2182d5fad2c97a25af8992c30e844a775f8fc7339dae5328377d164e6"
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.27.2"
|
||||
|
@ -1652,11 +1659,14 @@ dependencies = [
|
|||
"bytemuck",
|
||||
"dyn-any",
|
||||
"dyn-clone",
|
||||
"futures",
|
||||
"ghost-cell",
|
||||
"glam",
|
||||
"graphene-core",
|
||||
"log",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"slotmap",
|
||||
"specta",
|
||||
"xxhash-rust",
|
||||
]
|
||||
|
@ -1670,6 +1680,7 @@ dependencies = [
|
|||
"bezier-rs",
|
||||
"bytemuck",
|
||||
"dyn-any",
|
||||
"ghost-cell",
|
||||
"glam",
|
||||
"js-sys",
|
||||
"kurbo",
|
||||
|
@ -1681,6 +1692,7 @@ dependencies = [
|
|||
"rand_chacha 0.3.1",
|
||||
"rustybuzz",
|
||||
"serde",
|
||||
"slotmap",
|
||||
"specta",
|
||||
"spin 0.9.8",
|
||||
"spirv-std",
|
||||
|
@ -1699,6 +1711,7 @@ dependencies = [
|
|||
"dyn-any",
|
||||
"dyn-clone",
|
||||
"futures",
|
||||
"ghost-cell",
|
||||
"glam",
|
||||
"gpu-compiler-bin-wrapper",
|
||||
"gpu-executor",
|
||||
|
|
|
@ -7,9 +7,9 @@ use crate::messages::prelude::*;
|
|||
use document_legacy::layers::layer_info::LayerDataType;
|
||||
use document_legacy::{LayerId, Operation};
|
||||
|
||||
use graph_craft::compiler::Compiler;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{generate_uuid, DocumentNodeImplementation, NodeId, NodeNetwork};
|
||||
use graph_craft::executor::Compiler;
|
||||
use graph_craft::{concrete, Type, TypeDescriptor};
|
||||
use graphene_core::application_io::ApplicationIo;
|
||||
use graphene_core::raster::{Image, ImageFrame};
|
||||
|
@ -19,7 +19,7 @@ use graphene_core::vector::style::ViewMode;
|
|||
|
||||
use graphene_core::wasm_application_io::WasmApplicationIo;
|
||||
use graphene_core::{Color, EditorApi, SurfaceFrame, SurfaceId};
|
||||
use interpreted_executor::executor::DynamicExecutor;
|
||||
use interpreted_executor::dynamic_executor::DynamicExecutor;
|
||||
|
||||
use glam::{DAffine2, DVec2};
|
||||
use std::borrow::Cow;
|
||||
|
@ -147,7 +147,7 @@ impl NodeRuntime {
|
|||
return Err(e);
|
||||
}
|
||||
|
||||
use graph_craft::executor::Executor;
|
||||
use graph_craft::compiler::Executor;
|
||||
|
||||
let result = match self.executor.input_type() {
|
||||
Some(t) if t == concrete!(EditorApi) => (&self.executor).execute(editor_api).await.map_err(|e| e.to_string()),
|
||||
|
|
|
@ -15,6 +15,7 @@ documentation = "https://docs.rs/dyn-any"
|
|||
dyn-any-derive = { path = "derive", version = "0.3.0", optional = true }
|
||||
log = { version = "0.4", optional = true }
|
||||
glam = { version = "0.22", optional = true, default-features = false }
|
||||
ghost-cell = "0.2.3"
|
||||
|
||||
[features]
|
||||
derive = ["dyn-any-derive"]
|
||||
|
|
|
@ -205,6 +205,12 @@ unsafe impl<T: StaticTypeSized> StaticType for dyn core::future::Future<Output =
|
|||
unsafe impl<T: StaticTypeSized> StaticType for dyn core::future::Future<Output = T> + '_ {
|
||||
type Static = dyn core::future::Future<Output = T::Static>;
|
||||
}
|
||||
unsafe impl<T: StaticType> StaticType for ghost_cell::GhostCell<'_, T> {
|
||||
type Static = ghost_cell::GhostCell<'static, T::Static>;
|
||||
}
|
||||
unsafe impl StaticType for ghost_cell::GhostToken<'_> {
|
||||
type Static = ghost_cell::GhostToken<'static>;
|
||||
}
|
||||
#[cfg(feature = "alloc")]
|
||||
pub trait IntoDynAny<'n>: Sized + StaticType + 'n {
|
||||
fn into_dyn(self) -> Box<dyn DynAny<'n> + 'n> {
|
||||
|
|
|
@ -14,7 +14,7 @@ fn main() {
|
|||
let client = reqwest::blocking::Client::new();
|
||||
|
||||
let network = add_network();
|
||||
let compiler = graph_craft::executor::Compiler {};
|
||||
let compiler = graph_craft::compiler::Compiler {};
|
||||
let proto_network = compiler.compile_single(network, true).unwrap();
|
||||
|
||||
let io = ShaderIO {
|
||||
|
|
|
@ -9,24 +9,10 @@ license = "MIT OR Apache-2.0"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
std = [
|
||||
"dyn-any",
|
||||
"dyn-any/std",
|
||||
"alloc",
|
||||
"glam/std",
|
||||
"specta",
|
||||
"num-traits/std",
|
||||
"rustybuzz",
|
||||
]
|
||||
std = ["dyn-any", "dyn-any/std", "alloc", "glam/std", "specta", "num-traits/std", "rustybuzz"]
|
||||
default = ["async", "serde", "kurbo", "log", "std", "rand_chacha", "wasm"]
|
||||
log = ["dep:log"]
|
||||
serde = [
|
||||
"dep:serde",
|
||||
"glam/serde",
|
||||
"bezier-rs/serde",
|
||||
"bezier-rs/serde",
|
||||
"base64",
|
||||
]
|
||||
serde = ["dep:serde", "glam/serde", "bezier-rs/serde", "bezier-rs/serde", "base64"]
|
||||
gpu = ["spirv-std", "glam/bytemuck", "dyn-any", "glam/libm"]
|
||||
async = ["async-trait", "alloc"]
|
||||
nightly = []
|
||||
|
@ -73,6 +59,8 @@ num-traits = { version = "0.2.15", default-features = false, features = [
|
|||
|
||||
wasm-bindgen = { version = "0.2.84", optional = true }
|
||||
js-sys = { version = "0.3.55", optional = true }
|
||||
ghost-cell = "0.2.3"
|
||||
slotmap = { version = "1.0.6", default-features = false }
|
||||
|
||||
[dependencies.web-sys]
|
||||
version = "0.3.4"
|
||||
|
|
|
@ -58,6 +58,7 @@ mod types;
|
|||
#[cfg(feature = "alloc")]
|
||||
pub use types::*;
|
||||
|
||||
use dyn_any::StaticTypeSized;
|
||||
pub trait NodeIO<'i, Input: 'i>: 'i + Node<'i, Input>
|
||||
where
|
||||
Self::Output: 'i + StaticTypeSized,
|
||||
|
@ -96,54 +97,81 @@ where
|
|||
{
|
||||
}
|
||||
|
||||
/*impl<'i, I: 'i, O: 'i> Node<'i, I> for &'i dyn for<'n> Node<'n, I, Output = O> {
|
||||
use ghost_cell::{GhostCell, GhostToken};
|
||||
impl<'i, 'brand, I: 'i, N: Node<'i, I>> Node<'i, (I, &'i GhostToken<'brand>)> for GhostCell<'brand, N> {
|
||||
type Output = N::Output;
|
||||
|
||||
fn eval(&'i self, input: (I, &'i GhostToken<'brand>)) -> Self::Output {
|
||||
self.borrow(input.1).eval(input.0)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod dyn_exec {
|
||||
use super::{Node, NodeIO};
|
||||
use alloc::boxed::Box;
|
||||
use core::pin::Pin;
|
||||
use dyn_any::{DynAny, StaticType, StaticTypeSized};
|
||||
use slotmap::{DefaultKey, SlotMap};
|
||||
|
||||
pub type DynFuture<'n, T> = Pin<Box<dyn core::future::Future<Output = T> + 'n>>;
|
||||
pub type Any<'n> = Box<dyn DynAny<'n> + 'n>;
|
||||
pub type FutureAny<'n> = DynFuture<'n, Any<'n>>;
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SlotInput<'i, T>(pub T, pub &'i SlotMap<DefaultKey, Box<TypeErasedNode<'i>>>);
|
||||
impl<'i, T> SlotInput<'i, T> {
|
||||
pub fn new(&self, arg: T) -> SlotInput<'i, T> {
|
||||
SlotInput(arg, self.1)
|
||||
}
|
||||
}
|
||||
unsafe impl<'i, T: StaticTypeSized> StaticType for SlotInput<'i, T> {
|
||||
type Static = SlotInput<'static, T::Static>;
|
||||
}
|
||||
pub type AnySlotInput<'i> = SlotInput<'i, Any<'i>>;
|
||||
//pub type SlotInput<'i> = (Any<'i>, &'i SlotMap<DefaultKey, Box<TypeErasedNode>>);
|
||||
pub type TypeErasedNode<'n> = dyn for<'i> NodeIO<'i, AnySlotInput<'i>, Output = FutureAny<'i>> + 'n;
|
||||
|
||||
impl<'i> Node<'i, AnySlotInput<'i>> for DefaultKey {
|
||||
type Output = FutureAny<'i>;
|
||||
|
||||
fn eval(&'i self, input: AnySlotInput<'i>) -> Self::Output {
|
||||
input.1[*self].eval(input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<'i, 's: 'i, I: 'i, O: 'i, N: Node<'i, I, Output = O>> Node<'i, I> for alloc::sync::Arc<N> {
|
||||
type Output = O;
|
||||
|
||||
fn eval(&'i self, input: I) -> Self::Output {
|
||||
(*self.as_ref()).eval(input)
|
||||
}
|
||||
}
|
||||
impl<'i, 's: 'i, I: 'i, O: 'i, N: Node<'i, I, Output = O>> Node<'i, I> for &'i N {
|
||||
type Output = O;
|
||||
|
||||
fn eval(&'i self, input: I) -> Self::Output {
|
||||
(**self).eval(input)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<'i, I: 'i, O: 'i, N: Node<'i, I, Output = O>> Node<'i, I> for Box<N> {
|
||||
type Output = O;
|
||||
|
||||
fn eval(&'i self, input: I) -> Self::Output {
|
||||
(**self).eval(input)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Specifically implement for trait objects because they would otherwise evaluated as unsized objetcs
|
||||
impl<'i, I: 'i, O: 'i> Node<'i, I> for &'i dyn Node<'i, I, Output = O> {
|
||||
type Output = O;
|
||||
|
||||
fn eval(&'i self, input: I) -> Self::Output {
|
||||
(**self).eval(input)
|
||||
}
|
||||
}*/
|
||||
impl<'i, 's: 'i, I: 'i, O: 'i, N: Node<'i, I, Output = O>> Node<'i, I> for &'s N {
|
||||
type Output = O;
|
||||
|
||||
fn eval(&'i self, input: I) -> Self::Output {
|
||||
(**self).eval(input)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<'i, 's: 'i, I: 'i, O: 'i, N: Node<'i, I, Output = O>> Node<'i, I> for Box<N> {
|
||||
type Output = O;
|
||||
|
||||
fn eval(&'i self, input: I) -> Self::Output {
|
||||
(**self).eval(input)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'i, I: 'i, O: 'i> Node<'i, I> for &'i dyn for<'a> Node<'a, I, Output = O> {
|
||||
type Output = O;
|
||||
|
||||
fn eval(&'i self, input: I) -> Self::Output {
|
||||
(**self).eval(input)
|
||||
}
|
||||
}
|
||||
use core::pin::Pin;
|
||||
|
||||
use dyn_any::StaticTypeSized;
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<'i, I: 'i, O: 'i> Node<'i, I> for Pin<Box<dyn for<'a> Node<'a, I, Output = O> + 'i>> {
|
||||
type Output = O;
|
||||
|
||||
fn eval(&'i self, input: I) -> Self::Output {
|
||||
(**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)
|
||||
}
|
||||
}
|
||||
|
||||
pub use crate::application_io::{ExtractImageFrame, SurfaceFrame, SurfaceId};
|
||||
#[cfg(feature = "wasm")]
|
||||
|
|
|
@ -304,5 +304,7 @@ mod test {
|
|||
assert_eq!(fnn.eval((1u32, 2u32)), (2, 1));
|
||||
let result: u32 = fns.eval(());
|
||||
assert_eq!(result, 42);
|
||||
|
||||
AddParameterNode::new(IntNode::<42>).eval(2u32);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,3 +27,4 @@ anyhow = "1.0.66"
|
|||
xxhash-rust = {workspace = true}
|
||||
ghost-cell = "0.2.3"
|
||||
futures = "0.3.28"
|
||||
slotmap = "1.0.6"
|
||||
|
|
|
@ -13,13 +13,10 @@ 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 Any<'n> = Box<dyn DynAny<'n> + 'n>;
|
||||
pub type FutureAny<'n> = DynFuture<'n, Any<'n>>;
|
||||
pub type TypeErasedNode<'n> = dyn for<'i> NodeIO<Any<'i>, Output = FutureAny<'i>> + 'n;
|
||||
pub type TypeErasedCell<'n> = Arc<TypeErasedNode<'n>>;
|
||||
pub use graphene_core::dyn_exec::*;
|
||||
pub type TypeErasedCell<'n> = Box<TypeErasedNode<'n>>;
|
||||
|
||||
pub type NodeConstructor = for<'i> fn(Vec<TypeErasedCell<'i>>) -> DynFuture<'i, TypeErasedCell<'i>>;
|
||||
pub type NodeConstructor = fn(Vec<TypeErasedCell>) -> DynFuture<'static, TypeErasedCell>;
|
||||
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Default, PartialEq, Clone, Hash, Eq)]
|
||||
|
|
|
@ -10,12 +10,7 @@ license = "MIT OR Apache-2.0"
|
|||
|
||||
[features]
|
||||
default = ["wgpu"]
|
||||
gpu = [
|
||||
"graphene-core/gpu",
|
||||
"gpu-compiler-bin-wrapper",
|
||||
"compilation-client",
|
||||
"gpu-executor",
|
||||
]
|
||||
gpu = ["graphene-core/gpu", "gpu-compiler-bin-wrapper", "compilation-client", "gpu-executor"]
|
||||
vulkan = ["gpu", "vulkan-executor"]
|
||||
wgpu = ["gpu", "wgpu-executor"]
|
||||
quantization = ["autoquant"]
|
||||
|
@ -53,6 +48,7 @@ xxhash-rust = { workspace = true }
|
|||
serde_json = "1.0.96"
|
||||
reqwest = { version = "0.11.17", features = ["rustls", "rustls-tls"] }
|
||||
futures = "0.3.28"
|
||||
ghost-cell = "0.2.3"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use dyn_any::StaticType;
|
||||
pub use graph_craft::proto::{Any, TypeErasedNode, TypeErasedPinned, TypeErasedPinnedRef};
|
||||
use graph_craft::proto::{DynFuture, FutureAny};
|
||||
use dyn_any::{StaticType, StaticTypeSized};
|
||||
use gpu_executor::ShaderInput;
|
||||
pub use graph_craft::proto::{Any, TypeErasedCell, TypeErasedNode};
|
||||
use graph_craft::proto::{AnySlotInput, DynFuture, FutureAny, SlotInput};
|
||||
use graphene_core::NodeIO;
|
||||
pub use graphene_core::{generic, ops, Node};
|
||||
use std::marker::PhantomData;
|
||||
use std::{marker::PhantomData, sync::Arc};
|
||||
|
||||
pub struct DynAnyNode<I, O, Node> {
|
||||
node: Node,
|
||||
|
@ -124,15 +125,15 @@ impl<'i, N> FutureWrapperNode<N> {
|
|||
}
|
||||
|
||||
pub trait IntoTypeErasedNode<'n> {
|
||||
fn into_type_erased(self) -> TypeErasedPinned<'n>;
|
||||
fn into_type_erased(self) -> TypeErasedCell<'n>;
|
||||
}
|
||||
|
||||
impl<'n, N: 'n> IntoTypeErasedNode<'n> for N
|
||||
where
|
||||
N: for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n,
|
||||
N: for<'i> NodeIO<'i, AnySlotInput<'i>, Output = FutureAny<'i>> + 'n,
|
||||
{
|
||||
fn into_type_erased(self) -> TypeErasedPinned<'n> {
|
||||
Box::pin(self)
|
||||
fn into_type_erased(self) -> TypeErasedCell<'n> {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,32 +148,22 @@ impl<N: Clone, O: StaticType> Clone for DowncastNode<O, N> {
|
|||
}
|
||||
impl<N: Copy, O: StaticType> Copy for DowncastNode<O, N> {}
|
||||
|
||||
#[node_macro::node_fn(DowncastNode<_O>)]
|
||||
fn downcast<N: 'input, _O: StaticType>(input: Any<'input>, node: &'input N) -> _O
|
||||
where
|
||||
N: for<'any_input> Node<'any_input, Any<'any_input>, Output = Any<'any_input>> + 'input,
|
||||
{
|
||||
let node_name = core::any::type_name::<N>();
|
||||
let out = dyn_any::downcast(node.eval(input)).unwrap_or_else(|e| panic!("DowncastNode Input {e} in:\n{node_name}"));
|
||||
*out
|
||||
}
|
||||
|
||||
/// 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 DowncastBothNode<'a, I, O> {
|
||||
node: TypeErasedPinnedRef<'a>,
|
||||
pub struct DowncastBothNode<'n, I, O> {
|
||||
node: TypeErasedCell<'n>,
|
||||
_i: PhantomData<I>,
|
||||
_o: PhantomData<O>,
|
||||
}
|
||||
impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'input, I> for DowncastBothNode<'n, I, O> {
|
||||
impl<'n: 'input, 'i: 'input, 't, 'input, O: 'input + StaticType, I: 'input + StaticTypeSized> Node<'input, SlotInput<'i, I>> for DowncastBothNode<'n, I, O> {
|
||||
type Output = DynFuture<'input, O>;
|
||||
#[inline]
|
||||
fn eval(&'input self, input: I) -> Self::Output {
|
||||
fn eval(&'input self, input: SlotInput<'input, I>) -> Self::Output {
|
||||
{
|
||||
let node_name = self.node.node_name();
|
||||
let input = Box::new(input);
|
||||
let future = self.node.eval(input);
|
||||
let slotmap = input.1;
|
||||
let box_input = Box::new(input);
|
||||
let future = self.node.eval(SlotInput(box_input, slotmap));
|
||||
Box::pin(async move {
|
||||
let out = dyn_any::downcast(future.await).unwrap_or_else(|e| panic!("DowncastBothNode Input {e} in: \n{node_name}"));
|
||||
*out
|
||||
|
@ -181,7 +172,7 @@ impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'i
|
|||
}
|
||||
}
|
||||
impl<'n, I, O> DowncastBothNode<'n, I, O> {
|
||||
pub const fn new(node: TypeErasedPinnedRef<'n>) -> Self {
|
||||
pub const fn new(node: TypeErasedCell<'n>) -> Self {
|
||||
Self {
|
||||
node,
|
||||
_i: core::marker::PhantomData,
|
||||
|
@ -191,53 +182,54 @@ impl<'n, I, O> DowncastBothNode<'n, I, O> {
|
|||
}
|
||||
/// 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 DowncastBothRefNode<'a, I, O> {
|
||||
node: TypeErasedPinnedRef<'a>,
|
||||
node: TypeErasedCell<'a>,
|
||||
_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 + StaticTypeSized> Node<'input, SlotInput<'input, I>> for DowncastBothRefNode<'n, I, O> {
|
||||
type Output = DynFuture<'input, &'input O>;
|
||||
#[inline]
|
||||
fn eval(&'input self, input: I) -> Self::Output {
|
||||
fn eval(&'input self, input: SlotInput<'input, I>) -> Self::Output {
|
||||
{
|
||||
let slotmap = input.1;
|
||||
let node_name = self.node.node_name();
|
||||
let input = Box::new(input);
|
||||
Box::pin(async move {
|
||||
let out: Box<&_> = dyn_any::downcast::<&O>(self.node.eval(input).await).unwrap_or_else(|e| panic!("DowncastBothRefNode Input {e} in {node_name}"));
|
||||
let box_input = Box::new(input);
|
||||
let out: Box<&_> = dyn_any::downcast::<&O>(self.node.eval(SlotInput(box_input, slotmap)).await).unwrap_or_else(|e| panic!("DowncastBothRefNode Input {e}"));
|
||||
*out
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'n, I, O> DowncastBothRefNode<'n, I, O> {
|
||||
pub const fn new(node: TypeErasedPinnedRef<'n>) -> Self {
|
||||
pub const fn new(node: TypeErasedCell<'n>) -> Self {
|
||||
Self { node, _i: core::marker::PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ComposeTypeErased<'a> {
|
||||
first: TypeErasedPinnedRef<'a>,
|
||||
second: TypeErasedPinnedRef<'a>,
|
||||
first: TypeErasedCell<'a>,
|
||||
second: TypeErasedCell<'a>,
|
||||
}
|
||||
|
||||
impl<'i, 'a: 'i> Node<'i, Any<'i>> for ComposeTypeErased<'a> {
|
||||
impl<'i, 'a, 't> Node<'i, AnySlotInput<'i>> for ComposeTypeErased<'i> {
|
||||
type Output = DynFuture<'i, Any<'i>>;
|
||||
fn eval(&'i self, input: Any<'i>) -> Self::Output {
|
||||
fn eval(&'i self, input: AnySlotInput<'i>) -> Self::Output {
|
||||
let slotmap = input.1;
|
||||
Box::pin(async move {
|
||||
let arg = self.first.eval(input).await;
|
||||
self.second.eval(arg).await
|
||||
self.second.eval(SlotInput(arg, slotmap)).await
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ComposeTypeErased<'a> {
|
||||
pub const fn new(first: TypeErasedPinnedRef<'a>, second: TypeErasedPinnedRef<'a>) -> Self {
|
||||
pub const fn new(first: TypeErasedCell<'a>, second: TypeErasedCell<'a>) -> Self {
|
||||
ComposeTypeErased { first, second }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn input_node<O: StaticType>(n: TypeErasedPinnedRef) -> DowncastBothNode<(), O> {
|
||||
pub fn input_node<'n, O: StaticType>(n: TypeErasedCell<'n>) -> DowncastBothNode<'n, (), O> {
|
||||
DowncastBothNode::new(n)
|
||||
}
|
||||
|
||||
|
@ -267,9 +259,9 @@ mod test {
|
|||
//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(FutureWrapperNode { node: AddNode::new() }));
|
||||
let type_erased = Box::pin(dyn_any) as TypeErasedPinned;
|
||||
let type_erased = Box::pin(dyn_any) as TypeErasedCell;
|
||||
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 TypeErasedCell<'_>;
|
||||
type_erased.eval(Box::new(&("32", 32u32)));
|
||||
}
|
||||
|
||||
|
@ -278,10 +270,10 @@ mod test {
|
|||
//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(FutureWrapperNode { node: AddNode::new() }));
|
||||
let type_erased = Box::pin(dyn_any) as TypeErasedPinned<'_>;
|
||||
let type_erased = Box::pin(dyn_any) as TypeErasedCell<'_>;
|
||||
type_erased.eval(Box::new((4u32, 2u32)));
|
||||
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 TypeErasedCell;
|
||||
let type_erased = ComposeTypeErased::new(type_erased.as_ref(), type_erased_id.as_ref());
|
||||
type_erased.eval(Box::new((4u32, 2u32)));
|
||||
//let downcast: DowncastBothNode<(u32, u32), u32> = DowncastBothNode::new(type_erased.as_ref());
|
||||
|
|
|
@ -18,7 +18,7 @@ pub struct GpuCompiler<TypingContext, ShaderIO> {
|
|||
// TODO: Move to graph-craft
|
||||
#[node_macro::node_fn(GpuCompiler)]
|
||||
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::compiler::Compiler {};
|
||||
let DocumentNodeImplementation::Network(ref network) = node.implementation else { panic!() };
|
||||
let proto_networks: Vec<_> = compiler.compile(network.clone(), true).collect();
|
||||
|
||||
|
@ -44,7 +44,7 @@ pub struct MapGpuNode<Node> {
|
|||
#[node_macro::node_fn(MapGpuNode)]
|
||||
async fn map_gpu(image: ImageFrame<Color>, node: DocumentNode) -> ImageFrame<Color> {
|
||||
log::debug!("Executing gpu node");
|
||||
let compiler = graph_craft::executor::Compiler {};
|
||||
let compiler = graph_craft::compiler::Compiler {};
|
||||
let inner_network = NodeNetwork::value_network(node);
|
||||
|
||||
log::debug!("inner_network: {:?}", inner_network);
|
||||
|
@ -262,7 +262,7 @@ async fn blend_gpu_image(foreground: ImageFrame<Color>, background: ImageFrame<C
|
|||
let translation: Vec2 = bg_to_fg.translation.as_vec2();
|
||||
|
||||
log::debug!("Executing gpu blend node!");
|
||||
let compiler = graph_craft::executor::Compiler {};
|
||||
let compiler = graph_craft::compiler::Compiler {};
|
||||
|
||||
let network = NodeNetwork {
|
||||
inputs: vec![],
|
||||
|
|
99
node-graph/interpreted-executor/src/dynamic_executor.rs
Normal file
99
node-graph/interpreted-executor/src/dynamic_executor.rs
Normal file
|
@ -0,0 +1,99 @@
|
|||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
use dyn_any::StaticType;
|
||||
use graph_craft::compiler::Executor;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::NodeId;
|
||||
use graph_craft::proto::{DynFuture, ProtoNetwork, TypingContext};
|
||||
use graph_craft::Type;
|
||||
|
||||
use crate::node_registry;
|
||||
|
||||
mod borrow_tree;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DynamicExecutor {
|
||||
output: NodeId,
|
||||
tree: borrow_tree::BorrowTree,
|
||||
typing_context: TypingContext,
|
||||
// This allows us to keep the nodes around for one more frame which is used for introspection
|
||||
orphaned_nodes: Vec<NodeId>,
|
||||
}
|
||||
|
||||
impl Default for DynamicExecutor {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
output: Default::default(),
|
||||
tree: Default::default(),
|
||||
typing_context: TypingContext::new(&node_registry::NODE_REGISTRY),
|
||||
orphaned_nodes: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DynamicExecutor {
|
||||
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 = borrow_tree::BorrowTree::new(proto_network, &typing_context).await?;
|
||||
|
||||
Ok(Self {
|
||||
tree,
|
||||
output,
|
||||
typing_context,
|
||||
orphaned_nodes: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn update(&mut self, proto_network: ProtoNetwork) -> Result<(), String> {
|
||||
self.output = proto_network.output;
|
||||
self.typing_context.update(&proto_network)?;
|
||||
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) {
|
||||
self.tree.free_node(node_id)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn introspect(&self, node_path: &[NodeId]) -> Option<Option<Arc<dyn std::any::Any>>> {
|
||||
self.tree.introspect(node_path)
|
||||
}
|
||||
|
||||
pub fn input_type(&self) -> Option<Type> {
|
||||
self.typing_context.type_of(self.output).map(|node_io| node_io.input.clone())
|
||||
}
|
||||
|
||||
pub fn output_type(&self) -> Option<Type> {
|
||||
self.typing_context.type_of(self.output).map(|node_io| node_io.output.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, I: StaticType + 'a> Executor<I, TaggedValue> for &'a DynamicExecutor {
|
||||
fn execute(&self, input: I) -> DynFuture<Result<TaggedValue, Box<dyn Error>>> {
|
||||
Box::pin(async move { self.tree.eval_tagged_value(self.output, input).await.map_err(|e| e.into()) })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn push_node_sync() {
|
||||
let mut tree = borrow_tree::BorrowTree::default();
|
||||
let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32)), vec![]);
|
||||
let context = TypingContext::default();
|
||||
let future = tree.push_node(0, val_1_protonode, &context); //.await.unwrap();
|
||||
futures::executor::block_on(future).unwrap();
|
||||
let _node = tree.get(0).unwrap();
|
||||
let result = futures::executor::block_on(tree.eval(0, ()));
|
||||
assert_eq!(result, Some(2u32));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
use dyn_any::StaticType;
|
||||
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::value::UpcastNode;
|
||||
use graph_craft::document::NodeId;
|
||||
use graph_craft::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, TypingContext};
|
||||
|
||||
use graphene_std::any::TypeErasedCell;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
use std::sync::RwLock;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct NodeContainer<'n> {
|
||||
pub node: TypeErasedCell<'n>,
|
||||
}
|
||||
|
||||
impl<'a> core::fmt::Debug for NodeContainer<'a> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("NodeContainer").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> NodeContainer<'a> {
|
||||
pub fn new(node: TypeErasedCell<'a>) -> Self {
|
||||
Self { node }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct BorrowTree {
|
||||
pub(crate) nodes: HashMap<NodeId, NodeContainer<'static>>,
|
||||
pub(crate) source_map: HashMap<Vec<NodeId>, NodeId>,
|
||||
}
|
||||
|
||||
impl BorrowTree {
|
||||
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).await?
|
||||
}
|
||||
Ok(nodes)
|
||||
}
|
||||
|
||||
/// Pushes new nodes into the tree and return orphaned nodes
|
||||
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).await?;
|
||||
} else {
|
||||
let Some(node_container) = self.nodes.get_mut(&id) else { continue };
|
||||
node_container.node.reset();
|
||||
}
|
||||
old_nodes.remove(&id);
|
||||
}
|
||||
self.source_map.retain(|_, nid| !old_nodes.contains(nid));
|
||||
Ok(old_nodes.into_iter().collect())
|
||||
}
|
||||
|
||||
pub(crate) fn node_deps(&self, nodes: &[NodeId]) -> Vec<NodeContainer<'static>> {
|
||||
nodes.iter().map(|node| self.nodes.get(node).unwrap().clone()).collect()
|
||||
}
|
||||
|
||||
pub(crate) fn store_node(&mut self, node: NodeContainer<'static>, id: NodeId) -> NodeContainer<'static> {
|
||||
self.nodes.insert(id, node.clone());
|
||||
node
|
||||
}
|
||||
|
||||
pub fn introspect(&self, node_path: &[NodeId]) -> Option<Option<Arc<dyn std::any::Any>>> {
|
||||
let id = self.source_map.get(node_path)?;
|
||||
let node = self.nodes.get(id)?;
|
||||
Some(node.node.serialize())
|
||||
}
|
||||
|
||||
pub fn get(&self, id: NodeId) -> Option<NodeContainer<'static>> {
|
||||
self.nodes.get(&id).cloned()
|
||||
}
|
||||
|
||||
pub async fn eval<'i, I: StaticType + 'i, O: StaticType + 'i>(&'i self, id: NodeId, input: I) -> Option<O> {
|
||||
let node = self.nodes.get(&id).cloned()?;
|
||||
let output = node.node.eval(Box::new(input));
|
||||
dyn_any::downcast::<O>(output.await).ok().map(|o| *o)
|
||||
}
|
||||
pub async fn eval_tagged_value<'i, I: StaticType + 'i>(&'i self, id: NodeId, input: I) -> Result<TaggedValue, String> {
|
||||
let node = self.nodes.get(&id).cloned().ok_or_else(|| "Output node not found in executor")?;
|
||||
let output = node.node.eval(Box::new(input));
|
||||
TaggedValue::try_from_any(output.await)
|
||||
}
|
||||
|
||||
pub fn free_node(&mut self, id: NodeId) {
|
||||
self.nodes.remove(&id);
|
||||
}
|
||||
|
||||
pub async fn push_node(&mut self, id: NodeId, proto_node: ProtoNode, typing_context: &TypingContext) -> Result<(), String> {
|
||||
let ProtoNode {
|
||||
construction_args,
|
||||
identifier,
|
||||
document_node_path,
|
||||
..
|
||||
} = proto_node;
|
||||
self.source_map.insert(document_node_path, id);
|
||||
|
||||
match construction_args {
|
||||
ConstructionArgs::Value(value) => {
|
||||
let upcasted = UpcastNode::new(value);
|
||||
let node = Arc::new(upcasted) as TypeErasedCell<'_>;
|
||||
let node = NodeContainer { node };
|
||||
self.store_node(node.into(), id);
|
||||
}
|
||||
ConstructionArgs::Inline(_) => unimplemented!("Inline nodes are not supported yet"),
|
||||
ConstructionArgs::Nodes(ids) => {
|
||||
let ids: Vec<_> = ids.iter().map(|(id, _)| *id).collect();
|
||||
let construction_nodes = self.node_deps(&ids);
|
||||
let constructor = typing_context.constructor(id).ok_or(format!("No constructor found for node {:?}", identifier))?;
|
||||
let node = constructor(construction_nodes).await;
|
||||
let node = NodeContainer { node };
|
||||
self.store_node(node.into(), id);
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,239 +0,0 @@
|
|||
use std::collections::{HashMap, HashSet};
|
||||
use std::error::Error;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use dyn_any::StaticType;
|
||||
use graph_craft::document::value::{TaggedValue, UpcastNode};
|
||||
use graph_craft::document::NodeId;
|
||||
use graph_craft::executor::Executor;
|
||||
use graph_craft::proto::{ConstructionArgs, LocalFuture, ProtoNetwork, ProtoNode, TypingContext};
|
||||
use graph_craft::Type;
|
||||
use graphene_std::any::{TypeErasedPinned, TypeErasedPinnedRef};
|
||||
|
||||
use crate::node_registry;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DynamicExecutor {
|
||||
output: NodeId,
|
||||
tree: BorrowTree,
|
||||
typing_context: TypingContext,
|
||||
// This allows us to keep the nodes around for one more frame which is used for introspection
|
||||
orphaned_nodes: Vec<NodeId>,
|
||||
}
|
||||
|
||||
impl Default for DynamicExecutor {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
output: Default::default(),
|
||||
tree: Default::default(),
|
||||
typing_context: TypingContext::new(&node_registry::NODE_REGISTRY),
|
||||
orphaned_nodes: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DynamicExecutor {
|
||||
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).await?;
|
||||
|
||||
Ok(Self {
|
||||
tree,
|
||||
output,
|
||||
typing_context,
|
||||
orphaned_nodes: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn update(&mut self, proto_network: ProtoNetwork) -> Result<(), String> {
|
||||
self.output = proto_network.output;
|
||||
self.typing_context.update(&proto_network)?;
|
||||
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) {
|
||||
self.tree.free_node(node_id)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn introspect(&self, node_path: &[NodeId]) -> Option<Option<Arc<dyn std::any::Any>>> {
|
||||
self.tree.introspect(node_path)
|
||||
}
|
||||
|
||||
pub fn input_type(&self) -> Option<Type> {
|
||||
self.typing_context.type_of(self.output).map(|node_io| node_io.input.clone())
|
||||
}
|
||||
|
||||
pub fn output_type(&self) -> Option<Type> {
|
||||
self.typing_context.type_of(self.output).map(|node_io| node_io.output.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, I: StaticType + 'a> Executor<I, TaggedValue> for &'a DynamicExecutor {
|
||||
fn execute(&self, input: I) -> LocalFuture<Result<TaggedValue, Box<dyn Error>>> {
|
||||
Box::pin(async move { self.tree.eval_tagged_value(self.output, input).await.map_err(|e| e.into()) })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NodeContainer<'n> {
|
||||
pub node: TypeErasedPinned<'n>,
|
||||
// the dependencies are only kept to ensure that the nodes are not dropped while still in use
|
||||
_dependencies: Vec<Arc<RwLock<NodeContainer<'static>>>>,
|
||||
}
|
||||
|
||||
impl<'a> core::fmt::Debug for NodeContainer<'a> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("NodeContainer").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> NodeContainer<'a> {
|
||||
pub fn new(node: TypeErasedPinned<'a>, _dependencies: Vec<Arc<RwLock<NodeContainer<'static>>>>) -> Self {
|
||||
Self { node, _dependencies }
|
||||
}
|
||||
|
||||
/// Return a static reference to the TypeErasedNode
|
||||
/// # Safety
|
||||
/// This is unsafe because the returned reference is only valid as long as the NodeContainer is alive
|
||||
pub unsafe fn erase_lifetime(self) -> NodeContainer<'static> {
|
||||
std::mem::transmute(self)
|
||||
}
|
||||
}
|
||||
impl NodeContainer<'static> {
|
||||
pub unsafe fn static_ref(&self) -> TypeErasedPinnedRef<'static> {
|
||||
let s = &*(self as *const Self);
|
||||
*(&s.node.as_ref() as *const TypeErasedPinnedRef<'static>)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct BorrowTree {
|
||||
nodes: HashMap<NodeId, Arc<RwLock<NodeContainer<'static>>>>,
|
||||
source_map: HashMap<Vec<NodeId>, NodeId>,
|
||||
}
|
||||
|
||||
impl BorrowTree {
|
||||
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).await?
|
||||
}
|
||||
Ok(nodes)
|
||||
}
|
||||
|
||||
/// Pushes new nodes into the tree and return orphaned nodes
|
||||
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).await?;
|
||||
} else {
|
||||
let Some(node_container) = self.nodes.get_mut(&id) else { continue };
|
||||
let mut node_container_writer = node_container.write().unwrap();
|
||||
let node = node_container_writer.node.as_mut();
|
||||
node.reset();
|
||||
}
|
||||
old_nodes.remove(&id);
|
||||
}
|
||||
self.source_map.retain(|_, nid| !old_nodes.contains(nid));
|
||||
Ok(old_nodes.into_iter().collect())
|
||||
}
|
||||
|
||||
fn node_refs(&self, nodes: &[NodeId]) -> Vec<TypeErasedPinnedRef<'static>> {
|
||||
self.node_deps(nodes).into_iter().map(|node| unsafe { node.read().unwrap().static_ref() }).collect()
|
||||
}
|
||||
fn node_deps(&self, nodes: &[NodeId]) -> Vec<Arc<RwLock<NodeContainer<'static>>>> {
|
||||
nodes.iter().map(|node| self.nodes.get(node).unwrap().clone()).collect()
|
||||
}
|
||||
|
||||
fn store_node(&mut self, node: Arc<RwLock<NodeContainer<'static>>>, id: NodeId) -> Arc<RwLock<NodeContainer<'static>>> {
|
||||
self.nodes.insert(id, node.clone());
|
||||
node
|
||||
}
|
||||
|
||||
pub fn introspect(&self, node_path: &[NodeId]) -> Option<Option<Arc<dyn std::any::Any>>> {
|
||||
let id = self.source_map.get(node_path)?;
|
||||
let node = self.nodes.get(id)?;
|
||||
let reader = node.read().unwrap();
|
||||
let node = reader.node.as_ref();
|
||||
Some(node.serialize())
|
||||
}
|
||||
|
||||
pub fn get(&self, id: NodeId) -> Option<Arc<RwLock<NodeContainer<'static>>>> {
|
||||
self.nodes.get(&id).cloned()
|
||||
}
|
||||
|
||||
pub async fn eval<'i, I: StaticType + 'i, O: StaticType + '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.await).ok().map(|o| *o)
|
||||
}
|
||||
pub async fn eval_tagged_value<'i, I: StaticType + 'i>(&'i self, id: NodeId, input: I) -> Result<TaggedValue, String> {
|
||||
let node = self.nodes.get(&id).cloned().ok_or_else(|| "Output node not found in executor")?;
|
||||
let reader = node.read().unwrap();
|
||||
let output = reader.node.eval(Box::new(input));
|
||||
TaggedValue::try_from_any(output.await)
|
||||
}
|
||||
|
||||
pub fn free_node(&mut self, id: NodeId) {
|
||||
self.nodes.remove(&id);
|
||||
}
|
||||
|
||||
pub async fn push_node(&mut self, id: NodeId, proto_node: ProtoNode, typing_context: &TypingContext) -> Result<(), String> {
|
||||
let ProtoNode {
|
||||
construction_args,
|
||||
identifier,
|
||||
document_node_path,
|
||||
..
|
||||
} = proto_node;
|
||||
self.source_map.insert(document_node_path, id);
|
||||
|
||||
match construction_args {
|
||||
ConstructionArgs::Value(value) => {
|
||||
let upcasted = UpcastNode::new(value);
|
||||
let node = Box::pin(upcasted) as TypeErasedPinned<'_>;
|
||||
let node = NodeContainer { node, _dependencies: vec![] };
|
||||
let node = unsafe { node.erase_lifetime() };
|
||||
self.store_node(Arc::new(node.into()), id);
|
||||
}
|
||||
ConstructionArgs::Inline(_) => unimplemented!("Inline nodes are not supported yet"),
|
||||
ConstructionArgs::Nodes(ids) => {
|
||||
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).await;
|
||||
let node = NodeContainer {
|
||||
node,
|
||||
_dependencies: self.node_deps(&ids),
|
||||
};
|
||||
let node = unsafe { node.erase_lifetime() };
|
||||
self.store_node(Arc::new(node.into()), id);
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn push_node_sync() {
|
||||
let mut tree = BorrowTree::default();
|
||||
let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32)), vec![]);
|
||||
let context = TypingContext::default();
|
||||
let future = tree.push_node(0, val_1_protonode, &context); //.await.unwrap();
|
||||
futures::executor::block_on(future).unwrap();
|
||||
let _node = tree.get(0).unwrap();
|
||||
let result = futures::executor::block_on(tree.eval(0, ()));
|
||||
assert_eq!(result, Some(2u32));
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
pub mod executor;
|
||||
pub mod dynamic_executor;
|
||||
pub mod node_registry;
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -72,8 +72,8 @@ mod tests {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
use crate::executor::DynamicExecutor;
|
||||
use graph_craft::executor::{Compiler, Executor};
|
||||
use crate::dynamic_executor::DynamicExecutor;
|
||||
use graph_craft::compiler::{Compiler, Executor};
|
||||
|
||||
let compiler = Compiler {};
|
||||
let protograph = compiler.compile_single(network, true).expect("Graph should be generated");
|
||||
|
@ -120,8 +120,8 @@ mod tests {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
use crate::executor::DynamicExecutor;
|
||||
use graph_craft::executor::Compiler;
|
||||
use crate::dynamic_executor::DynamicExecutor;
|
||||
use graph_craft::compiler::Compiler;
|
||||
|
||||
let compiler = Compiler {};
|
||||
let protograph = compiler.compile_single(network, true).expect("Graph should be generated");
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use graph_craft::proto::{NodeConstructor, TypeErasedPinned};
|
||||
use graph_craft::proto::{NodeConstructor, TypeErasedCell};
|
||||
use graphene_core::ops::IdNode;
|
||||
use graphene_core::quantization::QuantizationChannels;
|
||||
use graphene_core::raster::bbox::AxisAlignedBbox;
|
||||
|
@ -50,7 +50,7 @@ macro_rules! register_node {
|
|||
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) as TypeErasedPinned
|
||||
Arc::new(any) as TypeErasedCell
|
||||
})
|
||||
},
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ macro_rules! register_node {
|
|||
graphene_std::any::PanicNode::<(), $type>::new()
|
||||
),*);
|
||||
let params = vec![$(fn_type!((), $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);
|
||||
node_io.input = concrete!(<$input as StaticType>::Static);
|
||||
node_io
|
||||
},
|
||||
|
@ -76,7 +76,7 @@ macro_rules! async_node {
|
|||
args.reverse();
|
||||
let node = <$path>::new($(graphene_std::any::input_node::<$type>(args.pop().expect("Not enough arguments provided to construct node"))),*);
|
||||
let any: DynAnyNode<$input, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
Arc::new(any) as TypeErasedCell
|
||||
})
|
||||
},
|
||||
{
|
||||
|
@ -111,7 +111,7 @@ macro_rules! raster_node {
|
|||
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
|
||||
Arc::new(any) as TypeErasedCell
|
||||
})
|
||||
},
|
||||
{
|
||||
|
@ -127,7 +127,7 @@ macro_rules! raster_node {
|
|||
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
|
||||
Arc::new(any) as TypeErasedCell
|
||||
})
|
||||
},
|
||||
{
|
||||
|
@ -143,7 +143,7 @@ macro_rules! raster_node {
|
|||
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
|
||||
Arc::new(any) as TypeErasedCell
|
||||
})
|
||||
},
|
||||
{
|
||||
|
@ -163,7 +163,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"),
|
||||
|_| Box::pin(async move { Box::pin(FutureWrapperNode::new(IdNode::new())) as TypeErasedPinned }),
|
||||
|_| Box::pin(async move { Box::pin(FutureWrapperNode::new(IdNode::new())) as TypeErasedCell }),
|
||||
NodeIOTypes::new(generic!(I), generic!(I), vec![]),
|
||||
)],
|
||||
// TODO: create macro to impl for all types
|
||||
|
@ -225,7 +225,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
let final_image = FutureWrapperNode::new(final_image);
|
||||
|
||||
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(final_image));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
Arc::new(any) as TypeErasedCell
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(
|
||||
|
@ -248,7 +248,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
//let document_node = ClonedNode::new(document_node.eval(()));
|
||||
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
|
||||
Arc::new(any) as TypeErasedCell
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![fn_type!(graph_craft::document::DocumentNode)]),
|
||||
|
@ -264,7 +264,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
let node = graphene_std::executor::BlendGpuImageNode::new(background, blend_mode, opacity);
|
||||
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
Arc::new(any) as TypeErasedCell
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(
|
||||
|
@ -333,7 +333,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
let node = ClonedNode::new(blits.into_iter()).then(all_blits);
|
||||
|
||||
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
Arc::new(any) as TypeErasedCell
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(
|
||||
|
@ -359,7 +359,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
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, FutureWrapperNode::new(ValueNode::new(blend_node)));
|
||||
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
Arc::new(any) as TypeErasedCell
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(
|
||||
|
@ -398,13 +398,13 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
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) as TypeErasedPinned
|
||||
Arc::new(any) as TypeErasedCell
|
||||
} 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) as TypeErasedPinned
|
||||
Arc::new(any) as TypeErasedCell
|
||||
}
|
||||
})
|
||||
},
|
||||
|
@ -427,7 +427,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
let node: DowncastBothNode<Option<graphene_core::EditorApi>, graphene_core::EditorApi> = graphene_std::any::DowncastBothNode::new(args[0]);
|
||||
let node = <graphene_core::memo::RefNode<_, _>>::new(node);
|
||||
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
Arc::new(any) as TypeErasedCell
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(
|
||||
|
|
|
@ -2,9 +2,9 @@ use std::error::Error;
|
|||
|
||||
use super::context::Context;
|
||||
|
||||
use graph_craft::executor::Executor;
|
||||
use graph_craft::compiler::Executor;
|
||||
|
||||
use graph_craft::proto::LocalFuture;
|
||||
use graph_craft::proto::DynFuture;
|
||||
use graphene_core::gpu::PushConstants;
|
||||
|
||||
use bytemuck::Pod;
|
||||
|
@ -41,7 +41,7 @@ impl<I: StaticTypeSized, O> GpuExecutor<I, O> {
|
|||
}
|
||||
|
||||
impl<'a, I: StaticTypeSized + Sync + Pod + Send + 'a, O: StaticTypeSized + Send + Sync + Pod + 'a> Executor<Vec<I>, Vec<O>> for &'a GpuExecutor<I, O> {
|
||||
fn execute(&self, input: Vec<I>) -> LocalFuture<Result<Vec<O>, Box<dyn Error>>> {
|
||||
fn execute(&self, input: Vec<I>) -> DynFuture<Result<Vec<O>, Box<dyn Error>>> {
|
||||
let context = &self.context;
|
||||
let result: Vec<O> = execute_shader(
|
||||
context.device.clone(),
|
||||
|
|
|
@ -5,7 +5,7 @@ use wgpu::util::DeviceExt;
|
|||
use super::context::Context;
|
||||
use bytemuck::Pod;
|
||||
use dyn_any::StaticTypeSized;
|
||||
use graph_craft::{executor::Executor, proto::LocalFuture};
|
||||
use graph_craft::{compiler::Executor, proto::DynFuture};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GpuExecutor<'a, I: StaticTypeSized, O> {
|
||||
|
@ -27,7 +27,7 @@ impl<'a, I: StaticTypeSized, O> GpuExecutor<'a, I, O> {
|
|||
}
|
||||
|
||||
impl<'a, I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync + Pod> Executor<Vec<I>, Vec<O>> for GpuExecutor<'a, I, O> {
|
||||
fn execute(&self, input: Vec<I>) -> LocalFuture<Result<Vec<O>, Box<dyn Error>>> {
|
||||
fn execute(&self, input: Vec<I>) -> DynFuture<Result<Vec<O>, Box<dyn Error>>> {
|
||||
let context = &self.context;
|
||||
let future = execute_shader(context.device.clone(), context.queue.clone(), self.shader.to_vec(), input, self.entry_point.clone());
|
||||
Box::pin(async move {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue