mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-03 21:08:18 +00:00
Bundle Graphite using Tauri (#873)
* Setup tauri component for graphite editor Integrate graphite into tauri app Split interpreted-executor out of graph-craft * Add gpu execution node * General Cleanup
This commit is contained in:
parent
52cc770a1e
commit
7d8f94462a
109 changed files with 5661 additions and 544 deletions
|
@ -9,17 +9,26 @@ 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"]
|
||||
default = ["async", "serde"]
|
||||
gpu = ["spirv-std", "bytemuck"]
|
||||
async = ["async-trait"]
|
||||
std = ["dyn-any", "dyn-any/std"]
|
||||
default = ["async", "serde", "kurbo", "log"]
|
||||
log = ["dep:log"]
|
||||
serde = ["dep:serde", "glam/serde"]
|
||||
gpu = ["spirv-std", "bytemuck", "glam/bytemuck", "dyn-any"]
|
||||
async = ["async-trait", "alloc"]
|
||||
nightly = []
|
||||
serde = ["dep:serde"]
|
||||
alloc = ["dyn-any", "bezier-rs"]
|
||||
|
||||
[dependencies]
|
||||
dyn-any = {path = "../../libraries/dyn-any", features = ["derive"], optional = true}
|
||||
dyn-any = {path = "../../libraries/dyn-any", features = ["derive"], optional = true, default-features = false }
|
||||
|
||||
spirv-std = { git = "https://github.com/EmbarkStudios/rust-gpu", features = ["glam"] , optional = true}
|
||||
bytemuck = {version = "1.8", features = ["derive"], optional = true}
|
||||
async-trait = {version = "0.1", optional = true}
|
||||
serde = {version = "1.0", features = ["derive"], optional = true}
|
||||
serde = {version = "1.0", features = ["derive"], optional = true, default-features = false }
|
||||
log = {version = "0.4", optional = true}
|
||||
|
||||
bezier-rs = { path = "../../libraries/bezier-rs", optional = true }
|
||||
kurbo = { git = "https://github.com/linebender/kurbo.git", features = [
|
||||
"serde",
|
||||
], optional = true }
|
||||
glam = { version = "^0.22", default-features = false, features = ["scalar-math", "libm"]}
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
#![no_std]
|
||||
#[cfg(feature = "async")]
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg_attr(feature = "log", macro_use)]
|
||||
#[cfg(feature = "log")]
|
||||
extern crate log;
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
use alloc::boxed::Box;
|
||||
#[cfg(feature = "async")]
|
||||
|
@ -17,6 +22,9 @@ pub mod gpu;
|
|||
|
||||
pub mod raster;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod vector;
|
||||
|
||||
pub trait Node<T> {
|
||||
type Output;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::Node;
|
||||
|
||||
pub mod color;
|
||||
use self::color::Color;
|
||||
pub use self::color::Color;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct GrayscaleColorNode;
|
||||
|
@ -21,6 +21,12 @@ impl<'n> Node<Color> for &'n GrayscaleColorNode {
|
|||
}
|
||||
}
|
||||
|
||||
impl GrayscaleColorNode {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct BrightenColorNode<N: Node<(), Output = f32>>(N);
|
||||
|
||||
|
@ -48,8 +54,10 @@ impl<N: Node<(), Output = f32> + Copy> BrightenColorNode<N> {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
pub struct HueShiftColorNode<N: Node<(), Output = f32>>(N);
|
||||
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
impl<N: Node<(), Output = f32>> Node<Color> for HueShiftColorNode<N> {
|
||||
type Output = Color;
|
||||
fn eval(self, color: Color) -> Color {
|
||||
|
@ -58,6 +66,7 @@ impl<N: Node<(), Output = f32>> Node<Color> for HueShiftColorNode<N> {
|
|||
Color::from_hsla(hue + hue_shift / 360., saturation, lightness, alpha)
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
impl<N: Node<(), Output = f32> + Copy> Node<Color> for &HueShiftColorNode<N> {
|
||||
type Output = Color;
|
||||
fn eval(self, color: Color) -> Color {
|
||||
|
@ -67,6 +76,7 @@ impl<N: Node<(), Output = f32> + Copy> Node<Color> for &HueShiftColorNode<N> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
impl<N: Node<(), Output = f32> + Copy> HueShiftColorNode<N> {
|
||||
pub fn new(node: N) -> Self {
|
||||
Self(node)
|
||||
|
@ -85,6 +95,48 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use image::Image;
|
||||
#[cfg(feature = "alloc")]
|
||||
mod image {
|
||||
use super::Color;
|
||||
use alloc::vec::Vec;
|
||||
use dyn_any::{DynAny, StaticType};
|
||||
#[derive(Clone, Debug, PartialEq, DynAny, Default)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct Image {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub data: Vec<Color>,
|
||||
}
|
||||
|
||||
impl Image {
|
||||
pub const fn empty() -> Self {
|
||||
Self {
|
||||
width: 0,
|
||||
height: 0,
|
||||
data: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Image {
|
||||
type Item = Color;
|
||||
type IntoIter = alloc::vec::IntoIter<Color>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.data.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a Image {
|
||||
type Item = &'a Color;
|
||||
type IntoIter = alloc::slice::Iter<'a, Color>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.data.iter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*pub struct MutWrapper<N>(pub N);
|
||||
|
||||
impl<'n, T: Clone, N> Node<&'n mut T> for &'n MutWrapper<N>
|
||||
|
|
|
@ -3,13 +3,23 @@ use dyn_any::{DynAny, StaticType};
|
|||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(target_arch = "spirv")]
|
||||
use spirv_std::num_traits::float::Float;
|
||||
|
||||
#[cfg(target_arch = "spirv")]
|
||||
use spirv_std::num_traits::Euclid;
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
|
||||
/// Structure that represents a color.
|
||||
/// Internally alpha is stored as `f32` that ranges from `0.0` (transparent) to `1.0` (opaque).
|
||||
/// The other components (RGB) are stored as `f32` that range from `0.0` up to `f32::MAX`,
|
||||
/// the values encode the brightness of each channel proportional to the light intensity in cd/m² (nits) in HDR, and `0.0` (black) to `1.0` (white) in SDR color.
|
||||
#[repr(C)]
|
||||
#[cfg_attr(feature = "std", derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize, DynAny))]
|
||||
#[cfg_attr(not(feature = "std"), derive(Debug, Clone, Copy, PartialEq, Default))]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, DynAny))]
|
||||
#[cfg_attr(feature = "gpu", derive(Pod, Zeroable))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Default)]
|
||||
pub struct Color {
|
||||
red: f32,
|
||||
green: f32,
|
||||
|
@ -92,6 +102,7 @@ impl Color {
|
|||
/// use graphene_core::raster::color::Color;
|
||||
/// let color = Color::from_hsla(0.5, 0.2, 0.3, 1.);
|
||||
/// ```
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
pub fn from_hsla(hue: f32, saturation: f32, lightness: f32, alpha: f32) -> Color {
|
||||
let temp1 = if lightness < 0.5 {
|
||||
lightness * (saturation + 1.)
|
||||
|
@ -219,7 +230,10 @@ impl Color {
|
|||
} else {
|
||||
4. + (self.red - self.green) / (max_channel - min_channel)
|
||||
} / 6.;
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
let hue = hue.rem_euclid(1.);
|
||||
#[cfg(target_arch = "spirv")]
|
||||
let hue = hue.rem_euclid(&1.);
|
||||
|
||||
[hue, saturation, lightness, self.alpha]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::ops::{Index, IndexMut};
|
||||
use core::ops::{Index, IndexMut};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::Node;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphene_core::Node;
|
||||
|
||||
use super::subpath::Subpath;
|
||||
|
||||
|
@ -40,8 +38,10 @@ impl Node<()> for &UnitSquareGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: I removed the Arc requirement we shouuld think about when it makes sense to use its
|
||||
// vs making a generic value node
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PathGenerator(Arc<Subpath>);
|
||||
pub struct PathGenerator(Subpath);
|
||||
|
||||
impl Node<()> for PathGenerator {
|
||||
type Output = VectorData;
|
||||
|
@ -53,7 +53,7 @@ impl Node<()> for PathGenerator {
|
|||
impl Node<()> for &PathGenerator {
|
||||
type Output = VectorData;
|
||||
fn eval(self, _input: ()) -> Self::Output {
|
||||
(*self.0).clone()
|
||||
(self.0).clone()
|
||||
}
|
||||
}
|
||||
use crate::raster::Image;
|
||||
|
@ -65,7 +65,7 @@ impl<N: Node<(), Output = Subpath>> Node<Image> for BlitSubpath<N> {
|
|||
type Output = Image;
|
||||
fn eval(self, input: Image) -> Self::Output {
|
||||
let subpath = self.0.eval(());
|
||||
info!("Blitting subpath {subpath:?}");
|
||||
log::info!("Blitting subpath {subpath:?}");
|
||||
input
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ impl<N: Node<(), Output = Subpath> + Copy> Node<Image> for &BlitSubpath<N> {
|
|||
type Output = Image;
|
||||
fn eval(self, input: Image) -> Self::Output {
|
||||
let subpath = self.0.eval(());
|
||||
info!("Blitting subpath {subpath:?}");
|
||||
log::info!("Blitting subpath {subpath:?}");
|
||||
input
|
||||
}
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
use core::ops::{Deref, DerefMut};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
/// Brief description: A vec that allows indexing elements by both index and an assigned unique ID
|
||||
/// Goals of this Data Structure:
|
||||
|
@ -121,7 +124,7 @@ impl<T> IdBackedVec<T> {
|
|||
}
|
||||
|
||||
/// Enumerate the ids and elements in this container `(&ElementId, &T)`
|
||||
pub fn enumerate(&self) -> std::iter::Zip<core::slice::Iter<u64>, core::slice::Iter<T>> {
|
||||
pub fn enumerate(&self) -> core::iter::Zip<core::slice::Iter<u64>, core::slice::Iter<T>> {
|
||||
self.element_ids.iter().zip(self.elements.iter())
|
||||
}
|
||||
|
|
@ -3,6 +3,9 @@ use super::id_vec::IdBackedVec;
|
|||
use super::manipulator_group::ManipulatorGroup;
|
||||
use super::manipulator_point::ManipulatorPoint;
|
||||
|
||||
use alloc::string::String;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use dyn_any::{DynAny, StaticType};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use kurbo::{BezPath, PathEl, Shape};
|
||||
|
@ -92,7 +95,7 @@ impl Subpath {
|
|||
pub fn new_ngon(center: DVec2, sides: u64, radius: f64) -> Self {
|
||||
let mut manipulator_groups = vec![];
|
||||
for i in 0..sides {
|
||||
let angle = (i as f64) * std::f64::consts::TAU / (sides as f64);
|
||||
let angle = (i as f64) * core::f64::consts::TAU / (sides as f64);
|
||||
let center = center + DVec2::ONE * radius;
|
||||
let position = ManipulatorGroup::new_with_anchor(DVec2::new(center.x + radius * f64::cos(angle), center.y + radius * f64::sin(angle)) * 0.5);
|
||||
|
||||
|
@ -346,7 +349,7 @@ impl Subpath {
|
|||
/// Generate an SVG `path` elements's `d` attribute: `<path d="...">`.
|
||||
pub fn to_svg(&mut self) -> String {
|
||||
fn write_positions(result: &mut String, values: [Option<DVec2>; 3]) {
|
||||
use std::fmt::Write;
|
||||
use core::fmt::Write;
|
||||
let count = values.into_iter().flatten().count();
|
||||
for (index, pos) in values.into_iter().flatten().enumerate() {
|
||||
write!(result, "{},{}", pos.x, pos.y).unwrap();
|
||||
|
@ -442,7 +445,7 @@ impl BezierId {
|
|||
|
||||
/// An iterator over [`bezier_rs::Bezier`] segments constructable via [`Subpath::bezier_iter`].
|
||||
pub struct PathIter<'a> {
|
||||
path: std::iter::Zip<core::slice::Iter<'a, u64>, core::slice::Iter<'a, ManipulatorGroup>>,
|
||||
path: core::iter::Zip<core::slice::Iter<'a, u64>, core::slice::Iter<'a, ManipulatorGroup>>,
|
||||
|
||||
last_anchor: Option<DVec2>,
|
||||
last_out_handle: Option<DVec2>,
|
|
@ -8,13 +8,12 @@ license = "MIT OR Apache-2.0"
|
|||
default = []
|
||||
profiling = ["nvtx", "gpu"]
|
||||
gpu = ["serde", "vulkano", "spirv-builder", "tera", "graphene-core/gpu"]
|
||||
serde = ["dep:serde", "graphene-std/serde", "glam/serde"]
|
||||
serde = ["dep:serde", "graphene-core/serde", "glam/serde"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
graphene-core = { path = "../gcore", features = ["async", "std" ] }
|
||||
graphene-std = { path = "../gstd" }
|
||||
graphene-core = { path = "../gcore", features = ["async", "std", "alloc"] }
|
||||
dyn-any = { path = "../../libraries/dyn-any", features = ["log-bad-types", "rc", "glam"] }
|
||||
num-traits = "0.2"
|
||||
borrow_stack = { path = "../borrow_stack" }
|
||||
|
@ -22,7 +21,7 @@ dyn-clone = "1.0"
|
|||
rand_chacha = "0.3.1"
|
||||
log = "0.4"
|
||||
serde = { version = "1", features = ["derive", "rc"], optional = true }
|
||||
glam = { version = "0.17" }
|
||||
glam = { version = "0.22" }
|
||||
|
||||
vulkano = {git = "https://github.com/GraphiteEditor/vulkano", branch = "fix_rust_gpu", optional = true}
|
||||
bytemuck = {version = "1.8" }
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::sync::Mutex;
|
|||
|
||||
pub mod value;
|
||||
|
||||
use dyn_any::{DynAny, StaticType};
|
||||
use rand_chacha::{
|
||||
rand_core::{RngCore, SeedableRng},
|
||||
ChaCha20Rng,
|
||||
|
@ -138,7 +139,7 @@ pub enum DocumentNodeImplementation {
|
|||
Unresolved(NodeIdentifier),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, PartialEq, DynAny)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct NodeNetwork {
|
||||
pub inputs: Vec<NodeId>,
|
||||
|
|
|
@ -15,10 +15,10 @@ pub enum TaggedValue {
|
|||
F64(f64),
|
||||
Bool(bool),
|
||||
DVec2(DVec2),
|
||||
Image(graphene_std::raster::Image),
|
||||
Image(graphene_core::raster::Image),
|
||||
Color(graphene_core::raster::color::Color),
|
||||
Subpath(graphene_std::vector::subpath::Subpath),
|
||||
RcSubpath(Arc<graphene_std::vector::subpath::Subpath>),
|
||||
Subpath(graphene_core::vector::subpath::Subpath),
|
||||
RcSubpath(Arc<graphene_core::vector::subpath::Subpath>),
|
||||
}
|
||||
|
||||
impl TaggedValue {
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
use std::error::Error;
|
||||
|
||||
use borrow_stack::{BorrowStack, FixedSizeStack};
|
||||
use graphene_core::Node;
|
||||
use graphene_std::any::{Any, TypeErasedNode};
|
||||
use dyn_any::DynAny;
|
||||
|
||||
use crate::{document::NodeNetwork, node_registry::push_node, proto::ProtoNetwork};
|
||||
use crate::{document::NodeNetwork, proto::ProtoNetwork};
|
||||
|
||||
pub struct Compiler {}
|
||||
|
||||
|
@ -25,30 +23,8 @@ impl Compiler {
|
|||
proto_network
|
||||
}
|
||||
}
|
||||
pub type Any<'a> = Box<dyn DynAny<'a> + 'a>;
|
||||
|
||||
pub trait Executor {
|
||||
fn execute(&self, input: Any<'static>) -> Result<Any<'static>, Box<dyn Error>>;
|
||||
}
|
||||
|
||||
pub struct DynamicExecutor {
|
||||
stack: FixedSizeStack<TypeErasedNode<'static>>,
|
||||
}
|
||||
|
||||
impl DynamicExecutor {
|
||||
pub fn new(proto_network: ProtoNetwork) -> Self {
|
||||
assert_eq!(proto_network.inputs.len(), 1);
|
||||
let node_count = proto_network.nodes.len();
|
||||
let stack = FixedSizeStack::new(node_count);
|
||||
for (_id, node) in proto_network.nodes {
|
||||
push_node(node, &stack);
|
||||
}
|
||||
Self { stack }
|
||||
}
|
||||
}
|
||||
|
||||
impl Executor for DynamicExecutor {
|
||||
fn execute(&self, input: Any<'static>) -> Result<Any<'static>, Box<dyn Error>> {
|
||||
let result = unsafe { self.stack.get().last().unwrap().eval(input) };
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,10 @@ pub fn create_files(matadata: &Metadata, network: &ProtoNetwork, compile_dir: &P
|
|||
let cargo_toml = create_cargo_toml(matadata)?;
|
||||
std::fs::write(cargo_file, cargo_toml)?;
|
||||
|
||||
let toolchain_file = compile_dir.join("rust-toolchain");
|
||||
let toolchain = include_str!("templates/rust-toolchain");
|
||||
std::fs::write(toolchain_file, toolchain)?;
|
||||
|
||||
// create src dir
|
||||
match std::fs::create_dir(&src) {
|
||||
Ok(_) => {}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::path::Path;
|
||||
|
||||
use super::{compiler::Metadata, context::Context};
|
||||
use crate::gpu::compiler;
|
||||
use crate::{executor::Any, gpu::compiler};
|
||||
use bytemuck::Pod;
|
||||
use dyn_any::StaticTypeSized;
|
||||
use vulkano::{
|
||||
|
@ -44,7 +44,7 @@ impl<I: StaticTypeSized, O> GpuExecutor<I, O> {
|
|||
}
|
||||
|
||||
impl<I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync + Pod> crate::executor::Executor for GpuExecutor<I, O> {
|
||||
fn execute(&self, input: graphene_std::any::Any<'static>) -> Result<graphene_std::any::Any<'static>, Box<dyn std::error::Error>> {
|
||||
fn execute(&self, input: Any<'static>) -> Result<Any<'static>, 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(
|
||||
|
@ -91,7 +91,7 @@ fn execute_shader<I: Pod + Send + Sync, O: Pod + Send + Sync>(
|
|||
.bind_pipeline_compute(compute_pipeline.clone())
|
||||
.bind_descriptor_sets(PipelineBindPoint::Compute, compute_pipeline.layout().clone(), 0, set)
|
||||
.push_constants(compute_pipeline.layout().clone(), 0, constants)
|
||||
.dispatch([1024, 1, 1])
|
||||
.dispatch([((constants.n as isize - 1) / 1024 + 1) as u32 * 1024, 1, 1])
|
||||
.unwrap();
|
||||
let command_buffer = builder.build().unwrap();
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
pub mod node_registry;
|
||||
|
||||
pub mod document;
|
||||
pub mod proto;
|
||||
|
||||
|
@ -10,124 +8,3 @@ pub mod executor;
|
|||
|
||||
#[cfg(feature = "gpu")]
|
||||
pub mod gpu;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use graphene_core::value::ValueNode;
|
||||
use graphene_core::{structural::*, RefNode};
|
||||
|
||||
use borrow_stack::BorrowStack;
|
||||
use dyn_any::{downcast, IntoDynAny};
|
||||
use graphene_std::any::{Any, DowncastNode, DynAnyNode, TypeErasedNode};
|
||||
use graphene_std::ops::AddNode;
|
||||
|
||||
#[test]
|
||||
fn borrow_stack() {
|
||||
let stack = borrow_stack::FixedSizeStack::new(256);
|
||||
unsafe {
|
||||
let dynanynode: DynAnyNode<ValueNode<u32>, (), _, _> = DynAnyNode::new(ValueNode(2_u32));
|
||||
stack.push(dynanynode.into_box());
|
||||
}
|
||||
stack.push_fn(|nodes| {
|
||||
let pre_node = nodes.get(0).unwrap();
|
||||
let downcast: DowncastNode<&TypeErasedNode, &u32> = DowncastNode::new(pre_node);
|
||||
let dynanynode: DynAnyNode<ConsNode<_, Any<'_>>, u32, _, _> = DynAnyNode::new(ConsNode(downcast, PhantomData));
|
||||
dynanynode.into_box()
|
||||
});
|
||||
stack.push_fn(|_| {
|
||||
let dynanynode: DynAnyNode<_, (u32, &u32), _, _> = DynAnyNode::new(AddNode);
|
||||
dynanynode.into_box()
|
||||
});
|
||||
stack.push_fn(|nodes| {
|
||||
let compose_node = nodes[1].after(&nodes[2]);
|
||||
TypeErasedNode(Box::new(compose_node))
|
||||
});
|
||||
|
||||
let result = unsafe { &stack.get()[0] }.eval_ref(().into_dyn());
|
||||
assert_eq!(*downcast::<&u32>(result).unwrap(), &2_u32);
|
||||
let result = unsafe { &stack.get()[1] }.eval_ref(4_u32.into_dyn());
|
||||
assert_eq!(*downcast::<(u32, &u32)>(result).unwrap(), (4_u32, &2_u32));
|
||||
let result = unsafe { &stack.get()[1] }.eval_ref(4_u32.into_dyn());
|
||||
let add = unsafe { &stack.get()[2] }.eval_ref(result);
|
||||
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);
|
||||
let add = unsafe { &stack.get()[3] }.eval_ref(4_u32.into_dyn());
|
||||
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute_add() {
|
||||
use crate::document::*;
|
||||
use crate::proto::*;
|
||||
|
||||
fn add_network() -> NodeNetwork {
|
||||
NodeNetwork {
|
||||
inputs: vec![0, 0],
|
||||
output: 1,
|
||||
nodes: [
|
||||
(
|
||||
0,
|
||||
DocumentNode {
|
||||
name: "Cons".into(),
|
||||
inputs: vec![NodeInput::Network, NodeInput::Network],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new(
|
||||
"graphene_core::structural::ConsNode",
|
||||
&[Type::Concrete(std::borrow::Cow::Borrowed("u32")), Type::Concrete(std::borrow::Cow::Borrowed("u32"))],
|
||||
)),
|
||||
metadata: DocumentNodeMetadata::default(),
|
||||
},
|
||||
),
|
||||
(
|
||||
1,
|
||||
DocumentNode {
|
||||
name: "Add".into(),
|
||||
inputs: vec![NodeInput::Node(0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new(
|
||||
"graphene_core::ops::AddNode",
|
||||
&[Type::Concrete(std::borrow::Cow::Borrowed("u32")), Type::Concrete(std::borrow::Cow::Borrowed("u32"))],
|
||||
)),
|
||||
metadata: DocumentNodeMetadata::default(),
|
||||
},
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
let network = NodeNetwork {
|
||||
inputs: vec![0],
|
||||
output: 0,
|
||||
nodes: [(
|
||||
0,
|
||||
DocumentNode {
|
||||
name: "Inc".into(),
|
||||
inputs: vec![
|
||||
NodeInput::Network,
|
||||
NodeInput::Value {
|
||||
tagged_value: value::TaggedValue::U32(1),
|
||||
exposed: false,
|
||||
},
|
||||
],
|
||||
implementation: DocumentNodeImplementation::Network(add_network()),
|
||||
metadata: DocumentNodeMetadata::default(),
|
||||
},
|
||||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
};
|
||||
|
||||
use crate::executor::{Compiler, DynamicExecutor, Executor};
|
||||
|
||||
let compiler = Compiler {};
|
||||
let protograph = compiler.compile(network, false);
|
||||
|
||||
let exec = DynamicExecutor::new(protograph);
|
||||
|
||||
let result = exec.execute(32_u32.into_dyn()).unwrap();
|
||||
let val = *dyn_any::downcast::<u32>(result).unwrap();
|
||||
assert_eq!(val, 33_u32);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -321,17 +321,12 @@ impl ProtoNetwork {
|
|||
}
|
||||
|
||||
fn replace_node_references(&mut self, lookup: &HashMap<u64, u64>) {
|
||||
self.nodes.iter_mut().for_each(|(sid, node)| {
|
||||
self.nodes.iter_mut().for_each(|(_, node)| {
|
||||
node.map_ids(|id| *lookup.get(&id).expect("node not found in lookup table"));
|
||||
});
|
||||
self.inputs = self.inputs.iter().map(|id| *lookup.get(id).unwrap()).collect();
|
||||
self.output = *lookup.get(&self.output).unwrap();
|
||||
}
|
||||
|
||||
fn replace_ids_with_lookup(&mut self, lookup: HashMap<u64, u64>) {
|
||||
self.nodes.iter_mut().for_each(|(id, _)| *id = *lookup.get(id).unwrap());
|
||||
self.replace_node_references(&lookup);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -12,13 +12,17 @@ license = "MIT OR Apache-2.0"
|
|||
derive = ["graph-proc-macros"]
|
||||
memoization = ["once_cell"]
|
||||
default = ["derive", "memoization"]
|
||||
gpu = ["graph-craft/gpu", "graphene-core/gpu"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
graphene-core = {path = "../gcore", features = ["async", "std"], default-features = false}
|
||||
graphene-core = {path = "../gcore", features = ["async", "std" ], default-features = false}
|
||||
borrow_stack = {path = "../borrow_stack"}
|
||||
dyn-any = {path = "../../libraries/dyn-any", features = ["derive"]}
|
||||
graph-proc-macros = {path = "../proc-macro", optional = true}
|
||||
graph-craft = {path = "../graph-craft"}
|
||||
bytemuck = {version = "1.8" }
|
||||
tempfile = "3"
|
||||
once_cell = {version= "1.10", optional = true}
|
||||
#pretty-token-stream = {path = "../../pretty-token-stream"}
|
||||
syn = {version = "1.0", default-features = false, features = ["parsing", "printing"]}
|
||||
|
@ -32,7 +36,7 @@ bezier-rs = { path = "../../libraries/bezier-rs" }
|
|||
kurbo = { git = "https://github.com/linebender/kurbo.git", features = [
|
||||
"serde",
|
||||
] }
|
||||
glam = { version = "0.17", features = ["serde"] }
|
||||
glam = { version = "0.22", features = ["serde"] }
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
|
|
|
@ -30,7 +30,9 @@ where
|
|||
input.borrow().hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
|
||||
self.map.get_or_create_with(&hash, || CacheNode::new(self.node))
|
||||
self.map.get_or_create_with(&hash, ||{
|
||||
trace!("Creating new cache node");
|
||||
CacheNode::new(self.node)})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
135
node-graph/gstd/src/executor.rs
Normal file
135
node-graph/gstd/src/executor.rs
Normal file
|
@ -0,0 +1,135 @@
|
|||
use bytemuck::Pod;
|
||||
use core::marker::PhantomData;
|
||||
use dyn_any::StaticTypeSized;
|
||||
use graph_craft::document::*;
|
||||
use graph_craft::proto::*;
|
||||
use graphene_core::{raster::Image, value::ValueNode, Node};
|
||||
|
||||
pub struct MapGpuNode<NN: Node<()>, I: IntoIterator<Item = S>, S: StaticTypeSized + Sync + Send + Pod, O: StaticTypeSized + Sync + Send + Pod>(pub NN, PhantomData<(S, I, O)>);
|
||||
|
||||
impl<'n, I: IntoIterator<Item = S>, NN: Node<(), Output = &'n NodeNetwork> + Copy, S: StaticTypeSized + Sync + Send + Pod, O: StaticTypeSized + Sync + Send + Pod> Node<I>
|
||||
for &MapGpuNode<NN, I, S, O>
|
||||
{
|
||||
type Output = Vec<O>;
|
||||
fn eval(self, input: I) -> Self::Output {
|
||||
let network = self.0.eval(());
|
||||
|
||||
use graph_craft::executor::Compiler;
|
||||
use graph_craft::executor::Executor;
|
||||
use graph_craft::gpu::compiler::Metadata;
|
||||
let compiler = Compiler {};
|
||||
let proto_network = compiler.compile(network.clone(), true);
|
||||
|
||||
let m = Metadata::new("project".to_owned(), vec!["test@example.com".to_owned()]);
|
||||
let temp_dir = tempfile::tempdir().expect("failed to create tempdir");
|
||||
|
||||
use graph_craft::gpu::context::Context;
|
||||
use graph_craft::gpu::executor::GpuExecutor;
|
||||
let executor: GpuExecutor<S, O> = GpuExecutor::new(Context::new(), proto_network, m, temp_dir.path()).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
|
||||
}
|
||||
}
|
||||
impl<'n, I: IntoIterator<Item = S>, NN: Node<(), Output = &'n NodeNetwork> + Copy, S: StaticTypeSized + Sync + Send + Pod, O: StaticTypeSized + Sync + Send + Pod> Node<I> for MapGpuNode<NN, I, S, O> {
|
||||
type Output = Vec<O>;
|
||||
fn eval(self, input: I) -> Self::Output {
|
||||
let network = self.0.eval(());
|
||||
|
||||
use graph_craft::executor::Compiler;
|
||||
use graph_craft::executor::Executor;
|
||||
use graph_craft::gpu::compiler::Metadata;
|
||||
let compiler = Compiler {};
|
||||
let proto_network = compiler.compile(network.clone(), true);
|
||||
|
||||
let m = Metadata::new("project".to_owned(), vec!["test@example.com".to_owned()]);
|
||||
let temp_dir = tempfile::tempdir().expect("failed to create tempdir");
|
||||
|
||||
use graph_craft::gpu::context::Context;
|
||||
use graph_craft::gpu::executor::GpuExecutor;
|
||||
let executor: GpuExecutor<S, O> = GpuExecutor::new(Context::new(), proto_network, m, temp_dir.path()).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
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: IntoIterator<Item = S>, NN: Node<()>, S: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Sync + Send + Pod> MapGpuNode<NN, I, S, O> {
|
||||
pub const fn new(network: NN) -> Self {
|
||||
MapGpuNode(network, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MapGpuSingleImageNode<NN: Node<(), Output = String>>(pub NN);
|
||||
|
||||
impl<NN: Node<(), Output = String> + Copy> Node<Image> for MapGpuSingleImageNode<NN> {
|
||||
type Output = Image;
|
||||
fn eval(self, input: Image) -> Self::Output {
|
||||
let node = self.0.eval(());
|
||||
use graph_craft::document::*;
|
||||
|
||||
let identifier = NodeIdentifier {
|
||||
name: std::borrow::Cow::Owned(node),
|
||||
types: std::borrow::Cow::Borrowed(&[]),
|
||||
};
|
||||
|
||||
let network = NodeNetwork {
|
||||
inputs: vec![0],
|
||||
output: 0,
|
||||
nodes: [(
|
||||
0,
|
||||
DocumentNode {
|
||||
name: "Image filter Node".into(),
|
||||
inputs: vec![NodeInput::Network],
|
||||
implementation: DocumentNodeImplementation::Unresolved(identifier),
|
||||
metadata: DocumentNodeMetadata::default(),
|
||||
},
|
||||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let value_network = ValueNode::new(network);
|
||||
let map_node = MapGpuNode::new(&value_network);
|
||||
let data = map_node.eval(input.data.clone());
|
||||
Image { data, ..input }
|
||||
}
|
||||
}
|
||||
|
||||
impl<NN: Node<(), Output = String> + Copy> Node<Image> for &MapGpuSingleImageNode<NN> {
|
||||
type Output = Image;
|
||||
fn eval(self, input: Image) -> Self::Output {
|
||||
let node = self.0.eval(());
|
||||
use graph_craft::document::*;
|
||||
|
||||
let identifier = NodeIdentifier {
|
||||
name: std::borrow::Cow::Owned(node),
|
||||
types: std::borrow::Cow::Borrowed(&[]),
|
||||
};
|
||||
|
||||
let network = NodeNetwork {
|
||||
inputs: vec![0],
|
||||
output: 0,
|
||||
nodes: [(
|
||||
0,
|
||||
DocumentNode {
|
||||
name: "Image filter Node".into(),
|
||||
inputs: vec![NodeInput::Network],
|
||||
implementation: DocumentNodeImplementation::Unresolved(identifier),
|
||||
metadata: DocumentNodeMetadata::default(),
|
||||
},
|
||||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let value_network = ValueNode::new(network);
|
||||
let map_node = MapGpuNode::new(&value_network);
|
||||
let data = map_node.eval(input.data.clone());
|
||||
Image { data, ..input }
|
||||
}
|
||||
}
|
|
@ -9,8 +9,10 @@ extern crate log;
|
|||
pub mod memo;
|
||||
|
||||
pub mod raster;
|
||||
pub mod vector;
|
||||
|
||||
pub mod any;
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
pub mod executor;
|
||||
|
||||
pub use graphene_core::*;
|
||||
|
|
|
@ -9,7 +9,10 @@ pub struct CacheNode<CachedNode: Node<I>, I> {
|
|||
impl<'n, CashedNode: Node<I> + Copy, I> Node<I> for &'n CacheNode<CashedNode, I> {
|
||||
type Output = &'n CashedNode::Output;
|
||||
fn eval(self, input: I) -> Self::Output {
|
||||
self.cache.get_or_init(|| self.node.eval(input))
|
||||
self.cache.get_or_init(|| {
|
||||
trace!("Creating new cache node");
|
||||
self.node.eval(input)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use core::marker::PhantomData;
|
||||
use dyn_any::{DynAny, StaticType};
|
||||
use graphene_core::ops::FlatMapResultNode;
|
||||
use graphene_core::raster::color::Color;
|
||||
use graphene_core::raster::{Color, Image};
|
||||
use graphene_core::structural::{ComposeNode, ConsNode};
|
||||
use graphene_core::{generic::FnNode, ops::MapResultNode, structural::Then, value::ValueNode, Node};
|
||||
use image::Pixel;
|
||||
|
@ -98,40 +98,6 @@ impl<Reader: std::io::Read> Node<Reader> for BufferNode {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DynAny, Default)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct Image {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub data: Vec<Color>,
|
||||
}
|
||||
|
||||
impl Image {
|
||||
pub const fn empty() -> Self {
|
||||
Self {
|
||||
width: 0,
|
||||
height: 0,
|
||||
data: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Image {
|
||||
type Item = Color;
|
||||
type IntoIter = std::vec::IntoIter<Color>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.data.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a Image {
|
||||
type Item = &'a Color;
|
||||
type IntoIter = std::slice::Iter<'a, Color>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.data.iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn file_node<'n, P: AsRef<Path> + 'n>() -> impl Node<P, Output = Result<Vec<u8>, Error>> {
|
||||
let fs = ValueNode(StdFs).clone();
|
||||
let fs = ConsNode::new(fs);
|
||||
|
|
25
node-graph/interpreted-executor/Cargo.toml
Normal file
25
node-graph/interpreted-executor/Cargo.toml
Normal file
|
@ -0,0 +1,25 @@
|
|||
[package]
|
||||
name = "interpreted-executor"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
serde = ["dep:serde", "graphene-std/serde", "glam/serde"]
|
||||
gpu = ["graphene-std/gpu"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
graphene-core = { path = "../gcore", features = ["async", "std" ] }
|
||||
graphene-std = { path = "../gstd" }
|
||||
graph-craft = { path = "../graph-craft" }
|
||||
dyn-any = { path = "../../libraries/dyn-any", features = ["log-bad-types"] }
|
||||
num-traits = "0.2"
|
||||
borrow_stack = { path = "../borrow_stack" }
|
||||
dyn-clone = "1.0"
|
||||
rand_chacha = "0.3.1"
|
||||
log = "0.4"
|
||||
serde = { version = "1", features = ["derive"], optional = true }
|
||||
glam = { version = "0.22" }
|
31
node-graph/interpreted-executor/src/executor.rs
Normal file
31
node-graph/interpreted-executor/src/executor.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
use std::error::Error;
|
||||
|
||||
use borrow_stack::{BorrowStack, FixedSizeStack};
|
||||
use graphene_core::Node;
|
||||
use graphene_std::any::{Any, TypeErasedNode};
|
||||
|
||||
use crate::node_registry::push_node;
|
||||
use graph_craft::{executor::Executor, proto::ProtoNetwork};
|
||||
|
||||
pub struct DynamicExecutor {
|
||||
stack: FixedSizeStack<TypeErasedNode<'static>>,
|
||||
}
|
||||
|
||||
impl DynamicExecutor {
|
||||
pub fn new(proto_network: ProtoNetwork) -> Self {
|
||||
assert_eq!(proto_network.inputs.len(), 1);
|
||||
let node_count = proto_network.nodes.len();
|
||||
let stack = FixedSizeStack::new(node_count);
|
||||
for (_id, node) in proto_network.nodes {
|
||||
push_node(node, &stack);
|
||||
}
|
||||
Self { stack }
|
||||
}
|
||||
}
|
||||
|
||||
impl Executor for DynamicExecutor {
|
||||
fn execute(&self, input: Any<'static>) -> Result<Any<'static>, Box<dyn Error>> {
|
||||
let result = unsafe { self.stack.get().last().unwrap().eval(input) };
|
||||
Ok(result)
|
||||
}
|
||||
}
|
127
node-graph/interpreted-executor/src/lib.rs
Normal file
127
node-graph/interpreted-executor/src/lib.rs
Normal file
|
@ -0,0 +1,127 @@
|
|||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
pub mod executor;
|
||||
pub mod node_registry;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use graphene_core::value::ValueNode;
|
||||
use graphene_core::{structural::*, RefNode};
|
||||
|
||||
use borrow_stack::BorrowStack;
|
||||
use dyn_any::{downcast, IntoDynAny};
|
||||
use graphene_std::any::{Any, DowncastNode, DynAnyNode, TypeErasedNode};
|
||||
use graphene_std::ops::AddNode;
|
||||
|
||||
#[test]
|
||||
fn borrow_stack() {
|
||||
let stack = borrow_stack::FixedSizeStack::new(256);
|
||||
unsafe {
|
||||
let dynanynode: DynAnyNode<ValueNode<u32>, (), _, _> = DynAnyNode::new(ValueNode(2_u32));
|
||||
stack.push(dynanynode.into_box());
|
||||
}
|
||||
stack.push_fn(|nodes| {
|
||||
let pre_node = nodes.get(0).unwrap();
|
||||
let downcast: DowncastNode<&TypeErasedNode, &u32> = DowncastNode::new(pre_node);
|
||||
let dynanynode: DynAnyNode<ConsNode<_, Any<'_>>, u32, _, _> = DynAnyNode::new(ConsNode(downcast, PhantomData));
|
||||
dynanynode.into_box()
|
||||
});
|
||||
stack.push_fn(|_| {
|
||||
let dynanynode: DynAnyNode<_, (u32, &u32), _, _> = DynAnyNode::new(AddNode);
|
||||
dynanynode.into_box()
|
||||
});
|
||||
stack.push_fn(|nodes| {
|
||||
let compose_node = nodes[1].after(&nodes[2]);
|
||||
TypeErasedNode(Box::new(compose_node))
|
||||
});
|
||||
|
||||
let result = unsafe { &stack.get()[0] }.eval_ref(().into_dyn());
|
||||
assert_eq!(*downcast::<&u32>(result).unwrap(), &2_u32);
|
||||
let result = unsafe { &stack.get()[1] }.eval_ref(4_u32.into_dyn());
|
||||
assert_eq!(*downcast::<(u32, &u32)>(result).unwrap(), (4_u32, &2_u32));
|
||||
let result = unsafe { &stack.get()[1] }.eval_ref(4_u32.into_dyn());
|
||||
let add = unsafe { &stack.get()[2] }.eval_ref(result);
|
||||
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);
|
||||
let add = unsafe { &stack.get()[3] }.eval_ref(4_u32.into_dyn());
|
||||
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute_add() {
|
||||
use graph_craft::document::*;
|
||||
use graph_craft::proto::*;
|
||||
|
||||
fn add_network() -> NodeNetwork {
|
||||
NodeNetwork {
|
||||
inputs: vec![0, 0],
|
||||
output: 1,
|
||||
nodes: [
|
||||
(
|
||||
0,
|
||||
DocumentNode {
|
||||
name: "Cons".into(),
|
||||
inputs: vec![NodeInput::Network, NodeInput::Network],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new(
|
||||
"graphene_core::structural::ConsNode",
|
||||
&[Type::Concrete(std::borrow::Cow::Borrowed("u32")), Type::Concrete(std::borrow::Cow::Borrowed("u32"))],
|
||||
)),
|
||||
metadata: DocumentNodeMetadata::default(),
|
||||
},
|
||||
),
|
||||
(
|
||||
1,
|
||||
DocumentNode {
|
||||
name: "Add".into(),
|
||||
inputs: vec![NodeInput::Node(0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new(
|
||||
"graphene_core::ops::AddNode",
|
||||
&[Type::Concrete(std::borrow::Cow::Borrowed("u32")), Type::Concrete(std::borrow::Cow::Borrowed("u32"))],
|
||||
)),
|
||||
metadata: DocumentNodeMetadata::default(),
|
||||
},
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
let network = NodeNetwork {
|
||||
inputs: vec![0],
|
||||
output: 0,
|
||||
nodes: [(
|
||||
0,
|
||||
DocumentNode {
|
||||
name: "Inc".into(),
|
||||
inputs: vec![
|
||||
NodeInput::Network,
|
||||
NodeInput::Value {
|
||||
tagged_value: value::TaggedValue::U32(1),
|
||||
exposed: false,
|
||||
},
|
||||
],
|
||||
implementation: DocumentNodeImplementation::Network(add_network()),
|
||||
metadata: DocumentNodeMetadata::default(),
|
||||
},
|
||||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
};
|
||||
|
||||
use crate::executor::DynamicExecutor;
|
||||
use graph_craft::executor::{Compiler, Executor};
|
||||
|
||||
let compiler = Compiler {};
|
||||
let protograph = compiler.compile(network, false);
|
||||
|
||||
let exec = DynamicExecutor::new(protograph);
|
||||
|
||||
let result = exec.execute(32_u32.into_dyn()).unwrap();
|
||||
let val = *dyn_any::downcast::<u32>(result).unwrap();
|
||||
assert_eq!(val, 33_u32);
|
||||
}
|
||||
}
|
|
@ -3,19 +3,19 @@ use glam::DVec2;
|
|||
use graphene_core::generic::FnNode;
|
||||
use graphene_core::ops::{AddNode, IdNode};
|
||||
use graphene_core::raster::color::Color;
|
||||
use graphene_core::raster::Image;
|
||||
use graphene_core::structural::{ConsNode, Then};
|
||||
use graphene_core::vector::subpath::Subpath;
|
||||
use graphene_core::Node;
|
||||
use graphene_std::any::DowncastBothNode;
|
||||
use graphene_std::any::{Any, DowncastNode, DynAnyNode, IntoTypeErasedNode, TypeErasedNode};
|
||||
use graphene_std::raster::Image;
|
||||
use graphene_std::vector::subpath::Subpath;
|
||||
|
||||
use crate::proto::Type;
|
||||
use crate::proto::{ConstructionArgs, NodeIdentifier, ProtoNode, ProtoNodeInput};
|
||||
use graph_craft::proto::Type;
|
||||
use graph_craft::proto::{ConstructionArgs, NodeIdentifier, ProtoNode, ProtoNodeInput};
|
||||
|
||||
type NodeConstructor = fn(ProtoNode, &FixedSizeStack<TypeErasedNode<'static>>);
|
||||
|
||||
use crate::{concrete, generic};
|
||||
use graph_craft::{concrete, generic};
|
||||
|
||||
//TODO: turn into hasmap
|
||||
static NODE_REGISTRY: &[(NodeIdentifier, NodeConstructor)] = &[
|
||||
|
@ -25,7 +25,7 @@ static NODE_REGISTRY: &[(NodeIdentifier, NodeConstructor)] = &[
|
|||
let pre_node = nodes.get(pre_id as usize).unwrap();
|
||||
pre_node.into_type_erased()
|
||||
} else {
|
||||
graphene_core::ops::IdNode.into_type_erased()
|
||||
IdNode.into_type_erased()
|
||||
}
|
||||
})
|
||||
}),
|
||||
|
@ -35,7 +35,7 @@ static NODE_REGISTRY: &[(NodeIdentifier, NodeConstructor)] = &[
|
|||
let pre_node = nodes.get(pre_id as usize).unwrap();
|
||||
pre_node.into_type_erased()
|
||||
} else {
|
||||
graphene_core::ops::IdNode.into_type_erased()
|
||||
IdNode.into_type_erased()
|
||||
}
|
||||
})
|
||||
}),
|
||||
|
@ -221,6 +221,54 @@ static NODE_REGISTRY: &[(NodeIdentifier, NodeConstructor)] = &[
|
|||
}
|
||||
})
|
||||
}),
|
||||
#[cfg(feature = "gpu")]
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::executor::MapGpuNode", &[concrete!("&TypeErasedNode"), concrete!("Color"), concrete!("Color")]),
|
||||
|proto_node, stack| {
|
||||
if let ConstructionArgs::Nodes(operation_node_id) = proto_node.construction_args {
|
||||
stack.push_fn(move |nodes| {
|
||||
info!("Map image Depending upon id {:?}", operation_node_id);
|
||||
let operation_node = nodes.get(operation_node_id[0] as usize).unwrap();
|
||||
let input_node: DowncastBothNode<_, (), &graph_craft::document::NodeNetwork> = DowncastBothNode::new(operation_node);
|
||||
let map_node: graphene_std::executor::MapGpuNode<_, Vec<u32>, u32, u32> = graphene_std::executor::MapGpuNode::new(input_node);
|
||||
let map_node = DynAnyNode::new(map_node);
|
||||
|
||||
if let ProtoNodeInput::Node(node_id) = proto_node.input {
|
||||
let pre_node = nodes.get(node_id as usize).unwrap();
|
||||
(pre_node).then(map_node).into_type_erased()
|
||||
} else {
|
||||
map_node.into_type_erased()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
unimplemented!()
|
||||
}
|
||||
},
|
||||
),
|
||||
#[cfg(feature = "gpu")]
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::executor::MapGpuSingleImageNode", &[concrete!("&TypeErasedNode")]),
|
||||
|proto_node, stack| {
|
||||
if let ConstructionArgs::Nodes(operation_node_id) = proto_node.construction_args {
|
||||
stack.push_fn(move |nodes| {
|
||||
info!("Map image Depending upon id {:?}", operation_node_id);
|
||||
let operation_node = nodes.get(operation_node_id[0] as usize).unwrap();
|
||||
let input_node: DowncastBothNode<_, (), String> = DowncastBothNode::new(operation_node);
|
||||
let map_node = graphene_std::executor::MapGpuSingleImageNode(input_node);
|
||||
let map_node = DynAnyNode::new(map_node);
|
||||
|
||||
if let ProtoNodeInput::Node(node_id) = proto_node.input {
|
||||
let pre_node = nodes.get(node_id as usize).unwrap();
|
||||
(pre_node).then(map_node).into_type_erased()
|
||||
} else {
|
||||
map_node.into_type_erased()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
unimplemented!()
|
||||
}
|
||||
},
|
||||
),
|
||||
(NodeIdentifier::new("graphene_std::raster::MapImageNode", &[]), |proto_node, stack| {
|
||||
if let ConstructionArgs::Nodes(operation_node_id) = proto_node.construction_args {
|
||||
stack.push_fn(move |nodes| {
|
||||
|
@ -442,7 +490,7 @@ pub fn push_node<'a>(proto_node: ProtoNode, stack: &'a FixedSizeStack<TypeErased
|
|||
.filter(|id| id.name.as_ref() == proto_node.identifier.name.as_ref())
|
||||
.collect::<Vec<_>>();
|
||||
panic!(
|
||||
"NodeImplementation: {:?} not found in Registry types for which the node is implemented:\n {:#?}",
|
||||
"NodeImplementation: {:?} not found in Registry. Types for which the node is implemented:\n {:#?}",
|
||||
proto_node.identifier, other_types
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue