mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-07-08 00:05:00 +00:00
Remove unsafe code and clean up the code base in general (#1263)
* Remove unsafe code * Make node graph test syncronous * Add miri step to ci * Remove unsafe from node graph evaluation * Replace operation pseudo_hash with hash based on discriminant * Fix test * Move memo module to core and make it safe * Fix formatting * Remove unused stuff from gstd * Use safe casting for creating key variants * Fix memo node types * Fix ref node * "fix" ub * Use correct input types for ExtractImageFrame * Fix types for async nodes * Fix missing implementation * Manually override output type for async nodes * Fix types for EditorApi * Fix output type for WasmSurfaceHandle * Remove unused miri.yml * Fix incorrect type for cache node
This commit is contained in:
parent
259dcdc628
commit
4e1bfddcd8
43 changed files with 520 additions and 1252 deletions
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
|
@ -107,6 +107,16 @@ jobs:
|
|||
run: |
|
||||
mold -run cargo nextest run
|
||||
|
||||
miri:
|
||||
runs-on: self-hosted
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: 🧪 Run Rust miri
|
||||
run: |
|
||||
mold -run cargo +nightly miri nextest run -j32
|
||||
|
||||
cargo-deny:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
|
|
48
Cargo.lock
generated
48
Cargo.lock
generated
|
@ -390,19 +390,6 @@ dependencies = [
|
|||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "borrow_stack"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dyn-any",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "boxcar"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38c99613cb3cd7429889a08dfcf651721ca971c86afa30798461f8eee994de47"
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "3.3.4"
|
||||
|
@ -1707,8 +1694,6 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"autoquant",
|
||||
"bezier-rs",
|
||||
"borrow_stack",
|
||||
"boxcar",
|
||||
"bytemuck",
|
||||
"compilation-client",
|
||||
"dyn-any",
|
||||
|
@ -1723,13 +1708,9 @@ dependencies = [
|
|||
"kurbo",
|
||||
"log",
|
||||
"node-macro",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 1.0.109",
|
||||
"tempfile",
|
||||
"vulkan-executor",
|
||||
"wgpu-executor",
|
||||
|
@ -1778,7 +1759,6 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"bezier-rs",
|
||||
"bitflags 1.3.2",
|
||||
"borrow_stack",
|
||||
"derivative",
|
||||
"dyn-any",
|
||||
"env_logger",
|
||||
|
@ -1792,6 +1772,7 @@ dependencies = [
|
|||
"interpreted-executor",
|
||||
"kurbo",
|
||||
"log",
|
||||
"num_enum 0.6.1",
|
||||
"once_cell",
|
||||
"remain",
|
||||
"serde",
|
||||
|
@ -2214,7 +2195,6 @@ dependencies = [
|
|||
name = "interpreted-executor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"borrow_stack",
|
||||
"dyn-any",
|
||||
"dyn-clone",
|
||||
"futures",
|
||||
|
@ -2226,7 +2206,6 @@ dependencies = [
|
|||
"num-traits",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2706,7 +2685,7 @@ dependencies = [
|
|||
"bitflags 1.3.2",
|
||||
"jni-sys",
|
||||
"ndk-sys",
|
||||
"num_enum",
|
||||
"num_enum 0.5.11",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
@ -2873,7 +2852,16 @@ version = "0.5.11"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
|
||||
dependencies = [
|
||||
"num_enum_derive",
|
||||
"num_enum_derive 0.5.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1"
|
||||
dependencies = [
|
||||
"num_enum_derive 0.6.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2888,6 +2876,18 @@ dependencies = [
|
|||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_threads"
|
||||
version = "0.1.6"
|
||||
|
|
|
@ -9,7 +9,6 @@ members = [
|
|||
"node-graph/gstd",
|
||||
"node-graph/graph-craft",
|
||||
"node-graph/interpreted-executor",
|
||||
"node-graph/borrow_stack",
|
||||
"node-graph/node-macro",
|
||||
"node-graph/compilation-server",
|
||||
"node-graph/compilation-client",
|
||||
|
|
|
@ -167,22 +167,9 @@ pub enum Operation {
|
|||
}
|
||||
|
||||
impl Operation {
|
||||
/// Returns the byte representation of the message.
|
||||
///
|
||||
/// # Safety
|
||||
/// This function reads from uninitialized memory!!!
|
||||
/// Only use if you know what you are doing
|
||||
unsafe fn as_slice(&self) -> &[u8] {
|
||||
core::slice::from_raw_parts(self as *const Operation as *const u8, std::mem::size_of::<Operation>())
|
||||
}
|
||||
/// Returns a pseudo hash that should uniquely identify the operation.
|
||||
/// This is needed because `Hash` is not implemented for f64s
|
||||
///
|
||||
/// # Safety
|
||||
/// This function reads from uninitialized memory but the generated value should be fine.
|
||||
pub fn pseudo_hash(&self) -> u64 {
|
||||
let mut s = DefaultHasher::new();
|
||||
unsafe { self.as_slice() }.hash(&mut s);
|
||||
std::mem::discriminant(self).hash(&mut s);
|
||||
s.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,10 +12,7 @@ license = "Apache-2.0"
|
|||
|
||||
[features]
|
||||
gpu = ["interpreted-executor/gpu", "graphene-std/gpu", "graphene-core/gpu"]
|
||||
quantization = [
|
||||
"graphene-std/quantization",
|
||||
"interpreted-executor/quantization",
|
||||
]
|
||||
quantization = ["graphene-std/quantization", "interpreted-executor/quantization"]
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
|
@ -41,10 +38,10 @@ image = { version = "0.24", default-features = false, features = [
|
|||
] }
|
||||
graph-craft = { path = "../node-graph/graph-craft" }
|
||||
interpreted-executor = { path = "../node-graph/interpreted-executor" }
|
||||
borrow_stack = { path = "../node-graph/borrow_stack" }
|
||||
dyn-any = { path = "../libraries/dyn-any" }
|
||||
graphene-core = { path = "../node-graph/gcore" }
|
||||
graphene-std = { path = "../node-graph/gstd" }
|
||||
num_enum = "0.6.1"
|
||||
|
||||
[dependencies.document-legacy]
|
||||
path = "../document-legacy"
|
||||
|
|
|
@ -323,6 +323,7 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
/// - create rect, shape and ellipse
|
||||
/// - select shape
|
||||
/// - copy
|
||||
|
@ -362,6 +363,7 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn copy_paste_folder() {
|
||||
let mut editor = create_editor_with_three_layers();
|
||||
|
||||
|
@ -450,6 +452,7 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
/// - create rect, shape and ellipse
|
||||
/// - select ellipse and rect
|
||||
/// - copy
|
||||
|
|
|
@ -37,9 +37,9 @@ impl InputMapperMessageHandler {
|
|||
.filter_map(|(i, m)| {
|
||||
let ma = m.0.iter().find_map(|m| actions.find_map(|a| (a == m.action.to_discriminant()).then(|| m.action.to_discriminant())));
|
||||
|
||||
ma.map(|a| unsafe { (std::mem::transmute_copy::<usize, Key>(&i), a) })
|
||||
ma.map(|a| ((i as u8).try_into().unwrap(), a))
|
||||
})
|
||||
.for_each(|(k, a)| {
|
||||
.for_each(|(k, a): (Key, _)| {
|
||||
let _ = write!(output, "{}: {}, ", k.to_discriminant().local_name(), a.local_name().split('.').last().unwrap());
|
||||
});
|
||||
output.replace("Key", "")
|
||||
|
@ -72,7 +72,7 @@ impl InputMapperMessageHandler {
|
|||
"Attempting to convert a Key with enum index {}, which is larger than the number of Key enums",
|
||||
i
|
||||
);
|
||||
unsafe { std::mem::transmute_copy::<usize, Key>(&i) }
|
||||
(i as u8).try_into().unwrap()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
|
|
@ -50,7 +50,8 @@ bitflags! {
|
|||
// (although we ignore the shift key, so the user doesn't have to press `Ctrl Shift +` on a US keyboard), even if the keyboard layout
|
||||
// is for a different locale where the `+` key is somewhere entirely different, shifted or not. This would then also work for numpad `+`.
|
||||
#[impl_message(Message, InputMapperMessage, KeyDown)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize, specta::Type)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize, specta::Type, num_enum::TryFromPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum Key {
|
||||
// Writing system keys
|
||||
Digit0,
|
||||
|
|
|
@ -41,28 +41,6 @@ pub enum Message {
|
|||
Workspace(WorkspaceMessage),
|
||||
}
|
||||
|
||||
impl Message {
|
||||
/// Returns the byte representation of the message.
|
||||
///
|
||||
/// # Safety
|
||||
/// This function reads from uninitialized memory!!!
|
||||
/// Only use if you know what you are doing.
|
||||
unsafe fn as_slice(&self) -> &[u8] {
|
||||
core::slice::from_raw_parts(self as *const Message as *const u8, std::mem::size_of::<Message>())
|
||||
}
|
||||
|
||||
/// Returns a pseudo hash that should uniquely identify the message.
|
||||
/// This is needed because `Hash` is not implemented for `f64`s
|
||||
///
|
||||
/// # Safety
|
||||
/// This function reads from uninitialized memory but the generated value should be fine.
|
||||
pub fn pseudo_hash(&self) -> u64 {
|
||||
let mut s = DefaultHasher::new();
|
||||
unsafe { self.as_slice() }.hash(&mut s);
|
||||
s.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides an impl of `specta::Type` for `MessageDiscriminant`, the struct created by `impl_message`.
|
||||
/// Specta isn't integrated with `impl_message`, so a remote impl must be provided using this
|
||||
/// struct.
|
||||
|
|
|
@ -1001,6 +1001,10 @@ impl DocumentMessageHandler {
|
|||
// Calculate the size of the region to be exported and generate an SVG of the artwork below this layer within that region
|
||||
let transform = self.document_legacy.multiply_transforms(&layer_path).unwrap();
|
||||
let size = DVec2::new(transform.transform_vector2(DVec2::new(1., 0.)).length(), transform.transform_vector2(DVec2::new(0., 1.)).length());
|
||||
// TODO: Fix this hack
|
||||
// This is a hack to prevent the compiler from optimizing out the size calculation which likely is due
|
||||
// to undefined behavior. THIS IS NOT A FIX.
|
||||
log::trace!("size: {:?}", size);
|
||||
let svg = self.render_document(size, transform.inverse(), persistent_data, DocumentRenderMode::OnlyBelowLayerInFolder(&layer_path));
|
||||
|
||||
self.restore_document_transform(old_transforms);
|
||||
|
|
|
@ -148,7 +148,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
1,
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(0, 0)],
|
||||
implementation: DocumentNodeImplementation::proto("graphene_std::memo::MonitorNode<_>"),
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode<_>"),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
|
@ -198,7 +198,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(0, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")),
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
// We currently just clone by default
|
||||
|
@ -262,7 +262,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(0, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")),
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
|
@ -305,7 +305,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(1, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")),
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
|
@ -355,13 +355,13 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
DocumentNode {
|
||||
name: "LetNode".to_string(),
|
||||
inputs: vec![NodeInput::node(0, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::LetNode<_>")),
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::LetNode<_>")),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
name: "RefNode".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::lambda(1, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::RefNode<_, _>")),
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::RefNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
|
@ -392,7 +392,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
DocumentNodeType {
|
||||
name: "End Scope",
|
||||
category: "Ignore",
|
||||
identifier: NodeImplementation::proto("graphene_std::memo::EndLetNode<_>"),
|
||||
identifier: NodeImplementation::proto("graphene_core::memo::EndLetNode<_>"),
|
||||
inputs: vec![
|
||||
DocumentInputType {
|
||||
name: "Scope",
|
||||
|
@ -666,47 +666,6 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
],
|
||||
properties: node_properties::no_properties,
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Gaussian Blur",
|
||||
category: "Ignore",
|
||||
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
||||
inputs: vec![0, 1, 1],
|
||||
outputs: vec![NodeOutput::new(1, 0)],
|
||||
nodes: vec![
|
||||
(
|
||||
0,
|
||||
DocumentNode {
|
||||
name: "CacheNode".to_string(),
|
||||
inputs: vec![NodeInput::Network(concrete!(Image<Color>))],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
(
|
||||
1,
|
||||
DocumentNode {
|
||||
name: "BlurNode".to_string(),
|
||||
inputs: vec![NodeInput::node(0, 0), NodeInput::Network(concrete!(u32)), NodeInput::Network(concrete!(f64)), NodeInput::node(0, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::raster::BlurNode")),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
DocumentInputType::value("Radius", TaggedValue::U32(3), false),
|
||||
DocumentInputType::value("Sigma", TaggedValue::F64(1.), false),
|
||||
],
|
||||
outputs: vec![DocumentOutputType {
|
||||
name: "Image",
|
||||
data_type: FrontendGraphDataType::Raster,
|
||||
}],
|
||||
properties: node_properties::blur_image_properties,
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Brush",
|
||||
category: "Brush",
|
||||
|
@ -735,34 +694,9 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
properties: node_properties::no_properties,
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Cache",
|
||||
name: "Memoize",
|
||||
category: "Structural",
|
||||
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
||||
inputs: vec![0],
|
||||
outputs: vec![NodeOutput::new(1, 0)],
|
||||
nodes: [
|
||||
(
|
||||
0,
|
||||
DocumentNode {
|
||||
name: "CacheNode".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::Network(concrete!(ImageFrame<Color>))],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
(
|
||||
1,
|
||||
DocumentNode {
|
||||
name: "CloneNode".to_string(),
|
||||
inputs: vec![NodeInput::node(0, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::CloneNode<_>")),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
]
|
||||
.into(),
|
||||
..Default::default()
|
||||
}),
|
||||
identifier: NodeImplementation::proto("graphene_core::memo::MemoNode<_, _>"),
|
||||
inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true)],
|
||||
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
|
||||
properties: node_properties::no_properties,
|
||||
|
@ -778,7 +712,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
DocumentNodeType {
|
||||
name: "Ref",
|
||||
category: "Structural",
|
||||
identifier: NodeImplementation::proto("graphene_std::memo::CacheNode"),
|
||||
identifier: NodeImplementation::proto("graphene_core::memo::MemoNode<_, _>"),
|
||||
inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true)],
|
||||
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
|
||||
properties: node_properties::no_properties,
|
||||
|
@ -1330,7 +1264,7 @@ pub fn wrap_network_in_scope(mut network: NodeNetwork) -> NodeNetwork {
|
|||
let mut network_inputs = Vec::new();
|
||||
let mut input_type = None;
|
||||
for (id, node) in network.nodes.iter() {
|
||||
for (index, input) in node.inputs.iter().enumerate() {
|
||||
for input in node.inputs.iter() {
|
||||
if let NodeInput::Network(_) = input {
|
||||
if input_type.is_none() {
|
||||
input_type = Some(input.clone());
|
||||
|
|
|
@ -1222,9 +1222,7 @@ fn edit_layer_deepest_manipulation(intersect: &Layer, responses: &mut VecDeque<M
|
|||
fn recursive_search(document: &DocumentMessageHandler, layer_path: &Vec<u64>, incoming_layer_path_vector: &Vec<u64>) -> bool {
|
||||
let layer_paths = document.document_legacy.folder_children_paths(layer_path);
|
||||
for path in layer_paths {
|
||||
if path == *incoming_layer_path_vector {
|
||||
return true;
|
||||
} else if document.document_legacy.is_folder(path.clone()) && recursive_search(document, &path, incoming_layer_path_vector) {
|
||||
if path == *incoming_layer_path_vector || document.document_legacy.is_folder(path.clone()) && recursive_search(document, &path, incoming_layer_path_vector) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ use crate::messages::prelude::*;
|
|||
use document_legacy::layers::layer_info::LayerDataType;
|
||||
use document_legacy::{LayerId, Operation};
|
||||
|
||||
use dyn_any::DynAny;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{generate_uuid, DocumentNodeImplementation, NodeId, NodeNetwork};
|
||||
use graph_craft::executor::Compiler;
|
||||
|
@ -18,7 +17,7 @@ use graphene_core::renderer::{SvgSegment, SvgSegmentList};
|
|||
use graphene_core::text::FontCache;
|
||||
use graphene_core::vector::style::ViewMode;
|
||||
|
||||
use graphene_core::wasm_application_io::{WasmApplicationIo, WasmSurfaceHandleFrame};
|
||||
use graphene_core::wasm_application_io::WasmApplicationIo;
|
||||
use graphene_core::{Color, EditorApi, SurfaceFrame, SurfaceId};
|
||||
use interpreted_executor::executor::DynamicExecutor;
|
||||
|
||||
|
@ -110,7 +109,7 @@ impl NodeRuntime {
|
|||
updates: responses,
|
||||
new_thumbnails: self.thumbnails.clone(),
|
||||
};
|
||||
self.sender.send(response);
|
||||
self.sender.send(response).expect("Failed to send response");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,7 +117,7 @@ impl NodeRuntime {
|
|||
|
||||
/// Wraps a network in a scope and returns the new network and the paths to the monitor nodes.
|
||||
fn wrap_network(network: NodeNetwork) -> (NodeNetwork, Vec<Vec<NodeId>>) {
|
||||
let mut scoped_network = wrap_network_in_scope(network);
|
||||
let scoped_network = wrap_network_in_scope(network);
|
||||
|
||||
//scoped_network.generate_node_paths(&[]);
|
||||
let monitor_nodes = scoped_network
|
||||
|
@ -126,7 +125,6 @@ impl NodeRuntime {
|
|||
.filter(|(node, _, _)| node.implementation == DocumentNodeImplementation::proto("graphene_std::memo::MonitorNode<_>"))
|
||||
.map(|(_, _, path)| path)
|
||||
.collect();
|
||||
//scoped_network.remove_dead_nodes();
|
||||
|
||||
(scoped_network, monitor_nodes)
|
||||
}
|
||||
|
@ -149,40 +147,23 @@ impl NodeRuntime {
|
|||
return Err(e);
|
||||
}
|
||||
|
||||
use dyn_any::IntoDynAny;
|
||||
use graph_craft::executor::Executor;
|
||||
|
||||
let result = match self.executor.input_type() {
|
||||
Some(t) if t == concrete!(EditorApi) => self.executor.execute(editor_api.into_dyn()).await.map_err(|e| e.to_string()),
|
||||
Some(t) if t == concrete!(()) => self.executor.execute(().into_dyn()).await.map_err(|e| e.to_string()),
|
||||
Some(t) if t == concrete!(EditorApi) => (&self.executor).execute(editor_api).await.map_err(|e| e.to_string()),
|
||||
Some(t) if t == concrete!(()) => (&self.executor).execute(()).await.map_err(|e| e.to_string()),
|
||||
_ => Err("Invalid input type".to_string()),
|
||||
};
|
||||
}?;
|
||||
|
||||
match result {
|
||||
Ok(result) => {
|
||||
if DynAny::type_id(result.as_ref()) == core::any::TypeId::of::<WasmSurfaceHandleFrame>() {
|
||||
let Ok(value) = dyn_any::downcast::<WasmSurfaceHandleFrame>(result) else { unreachable!()};
|
||||
let new_id = value.surface_handle.surface_id;
|
||||
let old_id = self.canvas_cache.insert(path.to_vec(), new_id);
|
||||
if let Some(old_id) = old_id {
|
||||
if old_id != new_id {
|
||||
self.wasm_io.destroy_surface(old_id);
|
||||
}
|
||||
}
|
||||
return Ok(TaggedValue::SurfaceFrame(SurfaceFrame {
|
||||
surface_id: new_id,
|
||||
transform: value.transform,
|
||||
}));
|
||||
}
|
||||
|
||||
let type_name = DynAny::type_name(result.as_ref());
|
||||
match TaggedValue::try_from_any(result) {
|
||||
Some(x) => Ok(x),
|
||||
None => Err(format!("Invalid output type: {}", type_name)),
|
||||
if let TaggedValue::SurfaceFrame(SurfaceFrame { surface_id, transform }) = result {
|
||||
let old_id = self.canvas_cache.insert(path.to_vec(), surface_id);
|
||||
if let Some(old_id) = old_id {
|
||||
if old_id != surface_id {
|
||||
self.wasm_io.destroy_surface(old_id);
|
||||
}
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Recomputes the thumbnails for the layers in the graph, modifying the state and updating the UI.
|
||||
|
@ -289,13 +270,13 @@ impl NodeGraphExecutor {
|
|||
image_frame,
|
||||
generation_id,
|
||||
};
|
||||
self.sender.send(NodeRuntimeMessage::GenerationRequest(request));
|
||||
self.sender.send(NodeRuntimeMessage::GenerationRequest(request)).expect("Failed to send generation request");
|
||||
|
||||
generation_id
|
||||
}
|
||||
|
||||
pub fn update_font_cache(&self, font_cache: FontCache) {
|
||||
self.sender.send(NodeRuntimeMessage::FontCacheUpdate(font_cache));
|
||||
self.sender.send(NodeRuntimeMessage::FontCacheUpdate(font_cache)).expect("Failed to send font cache update");
|
||||
}
|
||||
|
||||
pub fn introspect_node(&self, path: &[NodeId]) -> Option<Arc<dyn std::any::Any>> {
|
||||
|
|
|
@ -72,31 +72,33 @@ async fn poll_node_graph_evaluation() {
|
|||
editor::node_graph_executor::run_node_graph().await;
|
||||
|
||||
// Get the editor instances, dispatch the message, and store the `FrontendMessage` queue response
|
||||
EDITOR_INSTANCES.with(|instances| {
|
||||
JS_EDITOR_HANDLES.with(|handles| {
|
||||
// Mutably borrow the editors, and if successful, we can access them in the closure
|
||||
instances.try_borrow_mut().map(|mut editors| {
|
||||
// Get the editor instance for this editor ID, then dispatch the message to the backend, and return its response `FrontendMessage` queue
|
||||
for (id, editor) in editors.iter_mut() {
|
||||
let handles = handles.borrow_mut();
|
||||
let handle = handles.get(id).unwrap();
|
||||
let mut messages = VecDeque::new();
|
||||
editor.poll_node_graph_evaluation(&mut messages);
|
||||
// Send each `FrontendMessage` to the JavaScript frontend
|
||||
EDITOR_INSTANCES
|
||||
.with(|instances| {
|
||||
JS_EDITOR_HANDLES.with(|handles| {
|
||||
// Mutably borrow the editors, and if successful, we can access them in the closure
|
||||
instances.try_borrow_mut().map(|mut editors| {
|
||||
// Get the editor instance for this editor ID, then dispatch the message to the backend, and return its response `FrontendMessage` queue
|
||||
for (id, editor) in editors.iter_mut() {
|
||||
let handles = handles.borrow_mut();
|
||||
let handle = handles.get(id).unwrap();
|
||||
let mut messages = VecDeque::new();
|
||||
editor.poll_node_graph_evaluation(&mut messages);
|
||||
// Send each `FrontendMessage` to the JavaScript frontend
|
||||
|
||||
let mut responses = Vec::new();
|
||||
for message in messages.into_iter() {
|
||||
responses.extend(editor.handle_message(message));
|
||||
}
|
||||
let mut responses = Vec::new();
|
||||
for message in messages.into_iter() {
|
||||
responses.extend(editor.handle_message(message));
|
||||
}
|
||||
|
||||
for response in responses.into_iter() {
|
||||
handle.send_frontend_message_to_js(response);
|
||||
for response in responses.into_iter() {
|
||||
handle.send_frontend_message_to_js(response);
|
||||
}
|
||||
// If the editor cannot be borrowed then it has encountered a panic - we should just ignore new dispatches
|
||||
}
|
||||
// If the editor cannot be borrowed then it has encountered a panic - we should just ignore new dispatches
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
.unwrap_or_else(|_| log::error!("Failed to borrow editor instances"));
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
[package]
|
||||
name = "borrow_stack"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
dyn-any = {path = "../../libraries/dyn-any"}
|
|
@ -1,80 +0,0 @@
|
|||
use std::{
|
||||
mem::MaybeUninit,
|
||||
pin::Pin,
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
use dyn_any::StaticTypeSized;
|
||||
|
||||
pub trait BorrowStack<T: StaticTypeSized> {
|
||||
/// # Safety
|
||||
unsafe fn push(&self, value: T);
|
||||
/// # Safety
|
||||
unsafe fn pop(&self);
|
||||
/// # Safety
|
||||
unsafe fn get<'a>(&self) -> &'a [<T as StaticTypeSized>::Static];
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FixedSizeStack<T: dyn_any::StaticTypeSized> {
|
||||
data: Pin<Box<[MaybeUninit<T>]>>,
|
||||
capacity: usize,
|
||||
len: AtomicUsize,
|
||||
}
|
||||
|
||||
impl<'n, T: 'n + dyn_any::StaticTypeSized> FixedSizeStack<T> {
|
||||
pub fn new(capacity: usize) -> Self {
|
||||
let layout = std::alloc::Layout::array::<MaybeUninit<T>>(capacity).unwrap();
|
||||
let array = unsafe { std::alloc::alloc(layout) };
|
||||
let array = Box::into_pin(unsafe { Box::from_raw(core::ptr::slice_from_raw_parts_mut(array as *mut MaybeUninit<T>, capacity)) });
|
||||
|
||||
Self {
|
||||
data: array,
|
||||
capacity,
|
||||
len: AtomicUsize::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.len.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len.load(Ordering::SeqCst) == 0
|
||||
}
|
||||
pub fn push_fn<'a>(&self, f: impl FnOnce(&'a [<T as StaticTypeSized>::Static]) -> T) {
|
||||
assert_eq!(std::mem::size_of::<T>(), std::mem::size_of::<T::Static>());
|
||||
unsafe { self.push(f(self.get())) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: dyn_any::StaticTypeSized> BorrowStack<T> for FixedSizeStack<T> {
|
||||
unsafe fn push(&self, value: T) {
|
||||
let len = self.len.load(Ordering::SeqCst);
|
||||
assert!(len < self.capacity);
|
||||
let ptr = self.data[len].as_ptr();
|
||||
let static_value = std::mem::transmute_copy(&value);
|
||||
(ptr as *mut T::Static).write(static_value);
|
||||
std::mem::forget(value);
|
||||
self.len.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
unsafe fn pop(&self) {
|
||||
let ptr = self.data[self.len.load(Ordering::SeqCst)].as_ptr();
|
||||
let _ = Box::from_raw(ptr as *mut T);
|
||||
self.len.fetch_sub(1, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
unsafe fn get<'a>(&self) -> &'a [T::Static] {
|
||||
std::slice::from_raw_parts(self.data.as_ptr() as *const T::Static, self.len.load(Ordering::SeqCst))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = 2 + 2;
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ use graph_craft::concrete;
|
|||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::*;
|
||||
use graph_craft::*;
|
||||
use graphene_core::raster::adjustments::{BlendMode, BlendNode};
|
||||
use graphene_core::raster::adjustments::BlendMode;
|
||||
use graphene_core::Color;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
|
|
@ -36,34 +36,42 @@ unsafe impl StaticType for SurfaceFrame {
|
|||
type Static = SurfaceFrame;
|
||||
}
|
||||
|
||||
impl<S> From<SurfaceHandleFrame<S>> for SurfaceFrame {
|
||||
fn from(x: SurfaceHandleFrame<S>) -> Self {
|
||||
Self {
|
||||
surface_id: x.surface_handle.surface_id,
|
||||
transform: x.transform,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SurfaceHandle<'a, Surface> {
|
||||
pub struct SurfaceHandle<Surface> {
|
||||
pub surface_id: SurfaceId,
|
||||
pub surface: Surface,
|
||||
application_io: &'a dyn ApplicationIo<Surface = Surface>,
|
||||
}
|
||||
|
||||
unsafe impl<T: 'static> StaticType for SurfaceHandle<'_, T> {
|
||||
type Static = SurfaceHandle<'static, T>;
|
||||
unsafe impl<T: 'static> StaticType for SurfaceHandle<T> {
|
||||
type Static = SurfaceHandle<T>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SurfaceHandleFrame<'a, Surface> {
|
||||
pub surface_handle: Arc<SurfaceHandle<'a, Surface>>,
|
||||
pub struct SurfaceHandleFrame<Surface> {
|
||||
pub surface_handle: Arc<SurfaceHandle<Surface>>,
|
||||
pub transform: DAffine2,
|
||||
}
|
||||
|
||||
unsafe impl<T: 'static> StaticType for SurfaceHandleFrame<'_, T> {
|
||||
type Static = SurfaceHandleFrame<'static, T>;
|
||||
unsafe impl<T: 'static> StaticType for SurfaceHandleFrame<T> {
|
||||
type Static = SurfaceHandleFrame<T>;
|
||||
}
|
||||
|
||||
impl<T> Transform for SurfaceHandleFrame<'_, T> {
|
||||
impl<T> Transform for SurfaceHandleFrame<T> {
|
||||
fn transform(&self) -> DAffine2 {
|
||||
self.transform
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TransformMut for SurfaceHandleFrame<'_, T> {
|
||||
impl<T> TransformMut for SurfaceHandleFrame<T> {
|
||||
fn transform_mut(&mut self) -> &mut DAffine2 {
|
||||
&mut self.transform
|
||||
}
|
||||
|
@ -142,10 +150,10 @@ impl<'a, T> AsRef<EditorApi<'a, T>> for EditorApi<'a, T> {
|
|||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct ExtractImageFrame;
|
||||
|
||||
impl<'a: 'input, 'input, T> Node<'input, &'a EditorApi<'a, T>> for ExtractImageFrame {
|
||||
impl<'a: 'input, 'input, T> Node<'input, EditorApi<'a, T>> for ExtractImageFrame {
|
||||
type Output = ImageFrame<Color>;
|
||||
fn eval(&'input self, editor_api: &'a EditorApi<'a, T>) -> Self::Output {
|
||||
editor_api.image_frame.clone().unwrap_or(ImageFrame::identity())
|
||||
fn eval(&'input self, editor_api: EditorApi<'a, T>) -> Self::Output {
|
||||
editor_api.image_frame.unwrap_or(ImageFrame::identity())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::{cell::RefCell, collections::HashMap, sync::Mutex};
|
||||
use std::{cell::RefCell, collections::HashMap};
|
||||
|
||||
use super::{ApplicationIo, SurfaceHandle, SurfaceHandleFrame, SurfaceId};
|
||||
use crate::{
|
||||
raster::{color::SRGBA8, ImageFrame, Pixel},
|
||||
raster::{color::SRGBA8, ImageFrame},
|
||||
Node,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
|
@ -35,7 +35,7 @@ impl ApplicationIo for WasmApplicationIo {
|
|||
type Surface = CanvasRenderingContext2d;
|
||||
|
||||
fn create_surface(&self) -> SurfaceHandle<Self::Surface> {
|
||||
let mut wrapper = || {
|
||||
let wrapper = || {
|
||||
let document = window().expect("should have a window in this context").document().expect("window should have a document");
|
||||
|
||||
let canvas: HtmlCanvasElement = document.create_element("canvas")?.dyn_into::<HtmlCanvasElement>()?;
|
||||
|
@ -53,7 +53,7 @@ impl ApplicationIo for WasmApplicationIo {
|
|||
let image_canvases_key = JsValue::from_str("imageCanvases");
|
||||
|
||||
let mut canvases = Reflect::get(&window, &image_canvases_key);
|
||||
if let Err(e) = canvases {
|
||||
if let Err(_) = canvases {
|
||||
Reflect::set(&JsValue::from(web_sys::window().unwrap()), &image_canvases_key, &Object::new()).unwrap();
|
||||
canvases = Reflect::get(&window, &image_canvases_key);
|
||||
}
|
||||
|
@ -66,11 +66,7 @@ impl ApplicationIo for WasmApplicationIo {
|
|||
|
||||
// Use Reflect API to set property
|
||||
Reflect::set(&canvases, &js_key, &js_value)?;
|
||||
Ok::<_, JsValue>(SurfaceHandle {
|
||||
surface_id: id,
|
||||
surface: context,
|
||||
application_io: self,
|
||||
})
|
||||
Ok::<_, JsValue>(SurfaceHandle { surface_id: id, surface: context })
|
||||
};
|
||||
|
||||
wrapper().expect("should be able to set canvas in global scope")
|
||||
|
@ -99,13 +95,13 @@ impl ApplicationIo for WasmApplicationIo {
|
|||
}
|
||||
}
|
||||
|
||||
pub type WasmSurfaceHandle<'a> = SurfaceHandle<'a, CanvasRenderingContext2d>;
|
||||
pub type WasmSurfaceHandleFrame<'a> = SurfaceHandleFrame<'a, CanvasRenderingContext2d>;
|
||||
pub type WasmSurfaceHandle = SurfaceHandle<CanvasRenderingContext2d>;
|
||||
pub type WasmSurfaceHandleFrame = SurfaceHandleFrame<CanvasRenderingContext2d>;
|
||||
|
||||
pub struct CreateSurfaceNode {}
|
||||
|
||||
#[node_macro::node_fn(CreateSurfaceNode)]
|
||||
fn create_surface_node<'a: 'input>(editor: &'a WasmEditorApi<'a>) -> Arc<SurfaceHandle<'a, CanvasRenderingContext2d>> {
|
||||
fn create_surface_node<'a: 'input>(editor: WasmEditorApi<'a>) -> Arc<SurfaceHandle<CanvasRenderingContext2d>> {
|
||||
editor.application_io.create_surface().into()
|
||||
}
|
||||
|
||||
|
@ -114,7 +110,7 @@ pub struct DrawImageFrameNode<Surface> {
|
|||
}
|
||||
|
||||
#[node_macro::node_fn(DrawImageFrameNode)]
|
||||
async fn draw_image_frame_node<'a: 'input>(image: ImageFrame<SRGBA8>, surface_handle: Arc<SurfaceHandle<'a, CanvasRenderingContext2d>>) -> SurfaceHandleFrame<'a, CanvasRenderingContext2d> {
|
||||
async fn draw_image_frame_node<'a: 'input>(image: ImageFrame<SRGBA8>, surface_handle: Arc<SurfaceHandle<CanvasRenderingContext2d>>) -> SurfaceHandleFrame<CanvasRenderingContext2d> {
|
||||
let image_data = image.image.data;
|
||||
let array: Clamped<&[u8]> = Clamped(bytemuck::cast_slice(image_data.as_slice()));
|
||||
if image.image.width > 0 && image.image.height > 0 {
|
||||
|
|
|
@ -20,6 +20,7 @@ pub mod value;
|
|||
#[cfg(feature = "gpu")]
|
||||
pub mod gpu;
|
||||
|
||||
pub mod memo;
|
||||
pub mod storage;
|
||||
|
||||
pub mod raster;
|
||||
|
@ -44,7 +45,7 @@ pub use raster::Color;
|
|||
pub trait Node<'i, Input: 'i>: 'i {
|
||||
type Output: 'i;
|
||||
fn eval(&'i self, input: Input) -> Self::Output;
|
||||
fn reset(self: Pin<&mut Self>) {}
|
||||
fn reset(&self) {}
|
||||
#[cfg(feature = "std")]
|
||||
fn serialize(&self) -> Option<std::sync::Arc<dyn core::any::Any>> {
|
||||
log::warn!("Node::serialize not implemented for {}", core::any::type_name::<Self>());
|
||||
|
|
158
node-graph/gcore/src/memo.rs
Normal file
158
node-graph/gcore/src/memo.rs
Normal file
|
@ -0,0 +1,158 @@
|
|||
use crate::Node;
|
||||
use core::future::Future;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::sync::Arc;
|
||||
use core::cell::Cell;
|
||||
use core::pin::Pin;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// Caches the output of a given Node and acts as a proxy
|
||||
#[derive(Default)]
|
||||
pub struct MemoNode<T, CachedNode> {
|
||||
cache: Cell<Option<T>>,
|
||||
node: CachedNode,
|
||||
}
|
||||
impl<'i, 'o: 'i, T: 'i + Clone + 'o, CachedNode: 'i> Node<'i, ()> for MemoNode<T, CachedNode>
|
||||
where
|
||||
CachedNode: for<'any_input> Node<'any_input, ()>,
|
||||
for<'a> <CachedNode as Node<'a, ()>>::Output: core::future::Future<Output = T> + 'a,
|
||||
{
|
||||
// TODO: This should return a reference to the cached cached_value
|
||||
// but that requires a lot of lifetime magic <- This was suggested by copilot but is pretty acurate xD
|
||||
type Output = Pin<Box<dyn Future<Output = T> + 'i>>;
|
||||
fn eval(&'i self, input: ()) -> Self::Output {
|
||||
Box::pin(async move {
|
||||
if let Some(cached_value) = self.cache.take() {
|
||||
self.cache.set(Some(cached_value.clone()));
|
||||
cached_value
|
||||
} else {
|
||||
let value = self.node.eval(input).await;
|
||||
self.cache.set(Some(value.clone()));
|
||||
value
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn reset(&self) {
|
||||
self.cache.set(None);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, CachedNode> MemoNode<T, CachedNode> {
|
||||
pub const fn new(node: CachedNode) -> MemoNode<T, CachedNode> {
|
||||
MemoNode { cache: Cell::new(None), node }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
/// Caches the output of the last graph evaluation for introspection
|
||||
#[derive(Default)]
|
||||
pub struct MonitorNode<T> {
|
||||
output: Cell<Option<Arc<T>>>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<'i, T: 'static + Clone> Node<'i, T> for MonitorNode<T> {
|
||||
type Output = T;
|
||||
fn eval(&'i self, input: T) -> Self::Output {
|
||||
self.output.set(Some(Arc::new(input.clone())));
|
||||
input
|
||||
}
|
||||
|
||||
fn serialize(&self) -> Option<Arc<dyn core::any::Any>> {
|
||||
let out = self.output.take();
|
||||
self.output.set(out.clone());
|
||||
(out).as_ref().map(|output| output.clone() as Arc<dyn core::any::Any>)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<T> MonitorNode<T> {
|
||||
pub const fn new() -> MonitorNode<T> {
|
||||
MonitorNode { output: Cell::new(None) }
|
||||
}
|
||||
}
|
||||
|
||||
// Caches the output of a given Node and acts as a proxy
|
||||
/// It provides two modes of operation, it can either be set
|
||||
/// when calling the node with a `Some<T>` variant or the last
|
||||
/// value that was added is returned when calling it with `None`
|
||||
#[derive(Default)]
|
||||
pub struct LetNode<T> {
|
||||
// We have to use an append only data structure to make sure the references
|
||||
// to the cache entries are always valid
|
||||
// TODO: We only ever access the last value so there is not really a reason for us
|
||||
// to store the previous entries. This should be reworked in the future
|
||||
cache: Cell<Option<T>>,
|
||||
}
|
||||
impl<'i, T: 'i + Clone> Node<'i, Option<T>> for LetNode<T> {
|
||||
type Output = T;
|
||||
fn eval(&'i self, input: Option<T>) -> Self::Output {
|
||||
if let Some(input) = input {
|
||||
self.cache.set(Some(input.clone()));
|
||||
input
|
||||
} else {
|
||||
let value = self.cache.take();
|
||||
self.cache.set(value.clone());
|
||||
value.expect("LetNode was not initialized. This can happen if you try to evaluate a node that depends on the EditorApi in the node_registry")
|
||||
}
|
||||
}
|
||||
fn reset(&self) {
|
||||
self.cache.set(None);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::marker::Unpin for LetNode<T> {}
|
||||
|
||||
impl<T> LetNode<T> {
|
||||
pub fn new() -> LetNode<T> {
|
||||
LetNode { cache: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Caches the output of a given Node and acts as a proxy
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct EndLetNode<Input> {
|
||||
input: Input,
|
||||
}
|
||||
impl<'i, T: 'i, Input> Node<'i, T> for EndLetNode<Input>
|
||||
where
|
||||
Input: Node<'i, ()>,
|
||||
{
|
||||
type Output = <Input>::Output;
|
||||
fn eval(&'i self, _: T) -> Self::Output {
|
||||
let result = self.input.eval(());
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<Input> EndLetNode<Input> {
|
||||
pub const fn new(input: Input) -> EndLetNode<Input> {
|
||||
EndLetNode { input }
|
||||
}
|
||||
}
|
||||
|
||||
pub use crate::ops::SomeNode as InitNode;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
pub struct RefNode<T, Let> {
|
||||
let_node: Let,
|
||||
_t: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'i, T: 'i, Let> Node<'i, ()> for RefNode<T, Let>
|
||||
where
|
||||
Let: for<'a> Node<'a, Option<T>>,
|
||||
{
|
||||
type Output = <Let as Node<'i, Option<T>>>::Output;
|
||||
fn eval(&'i self, _: ()) -> Self::Output {
|
||||
self.let_node.eval(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Let, T> RefNode<T, Let> {
|
||||
pub const fn new(let_node: Let) -> RefNode<T, Let> {
|
||||
RefNode { let_node, _t: PhantomData }
|
||||
}
|
||||
}
|
|
@ -1,22 +1,10 @@
|
|||
use crate::Node;
|
||||
|
||||
use core::cell::RefMut;
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::{Deref, DerefMut, Index, IndexMut};
|
||||
|
||||
pub struct SetNode<Storage> {
|
||||
storage: Storage,
|
||||
}
|
||||
/*
|
||||
#[node_macro::node_fn(SetNode)]
|
||||
fn set_node<_T, _I, A: 'input>(input: (_T, _I), mut storage: RefMut<'input, A>)
|
||||
where
|
||||
A: DerefMut,
|
||||
A::Target: IndexMut<_I, Output = _T>,
|
||||
{
|
||||
let (value, index) = input;
|
||||
*storage.deref_mut().index_mut(index).deref_mut() = value;
|
||||
}*/
|
||||
impl<'input, T: 'input, I: 'input, A: 'input + 'input, S0: 'input> Node<'input, (T, I)> for SetNode<S0>
|
||||
where
|
||||
A: DerefMut,
|
||||
|
@ -94,7 +82,7 @@ where
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::value::{CopiedNode, OnceCellNode, RefCellMutNode, UnsafeMutValueNode, ValueNode};
|
||||
use crate::value::{CopiedNode, OnceCellNode};
|
||||
use crate::Node;
|
||||
|
||||
use super::*;
|
||||
|
|
|
@ -172,6 +172,7 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::unit_cmp)]
|
||||
fn test_apply() {
|
||||
let mut array = [1, 2, 3];
|
||||
let slice = &mut array;
|
||||
|
|
|
@ -15,7 +15,7 @@ pub struct TextGenerator<Text, FontName, Size> {
|
|||
}
|
||||
|
||||
#[node_fn(TextGenerator)]
|
||||
fn generate_text<'a: 'input>(editor: &'a EditorApi<'a>, text: String, font_name: Font, font_size: f64) -> crate::vector::VectorData {
|
||||
fn generate_text<'a: 'input>(editor: EditorApi<'a>, text: String, font_name: Font, font_size: f64) -> crate::vector::VectorData {
|
||||
let buzz_face = editor.font_cache.get(&font_name).map(|data| load_face(data));
|
||||
crate::vector::VectorData::from_subpaths(to_path(&text, buzz_face, font_size, None))
|
||||
}
|
||||
|
|
|
@ -56,15 +56,11 @@ macro_rules! generic {
|
|||
|
||||
#[macro_export]
|
||||
macro_rules! fn_type {
|
||||
($input:ty, $output:ty) => {
|
||||
Type::Fn(Box::new(concrete!($input)), Box::new(concrete!($output)))
|
||||
($type:ty) => {
|
||||
Type::Fn(Box::new(concrete!(())), Box::new(concrete!($type)))
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! value_fn {
|
||||
($output:ty) => {
|
||||
Type::Fn(Box::new(concrete!(())), Box::new(concrete!($output)))
|
||||
($in_type:ty, $type:ty) => {
|
||||
Type::Fn(Box::new(concrete!(($in_type))), Box::new(concrete!($type)))
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -109,6 +105,7 @@ pub enum Type {
|
|||
Generic(Cow<'static, str>),
|
||||
Concrete(TypeDescriptor),
|
||||
Fn(Box<Type>, Box<Type>),
|
||||
Future(Box<Type>),
|
||||
}
|
||||
|
||||
impl Type {
|
||||
|
@ -169,6 +166,7 @@ impl Type {
|
|||
Self::Generic(_) => None,
|
||||
Self::Concrete(ty) => Some(ty.size),
|
||||
Self::Fn(_, _) => None,
|
||||
Self::Future(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,6 +175,7 @@ impl Type {
|
|||
Self::Generic(_) => None,
|
||||
Self::Concrete(ty) => Some(ty.align),
|
||||
Self::Fn(_, _) => None,
|
||||
Self::Future(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -190,6 +189,7 @@ impl core::fmt::Debug for Type {
|
|||
#[cfg(not(feature = "type_id_logging"))]
|
||||
Self::Concrete(arg0) => write!(f, "Concrete({})", arg0.name),
|
||||
Self::Fn(arg0, arg1) => write!(f, "({:?} -> {:?})", arg0, arg1),
|
||||
Self::Future(arg0) => write!(f, "Future({:?})", arg0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -200,6 +200,7 @@ impl std::fmt::Display for Type {
|
|||
Type::Generic(name) => write!(f, "{}", name),
|
||||
Type::Concrete(ty) => write!(f, "{}", ty.name),
|
||||
Type::Fn(input, output) => write!(f, "({} -> {})", input, output),
|
||||
Type::Future(ty) => write!(f, "Future<{}>", ty),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use crate::Node;
|
||||
|
||||
use core::{
|
||||
borrow::BorrowMut,
|
||||
cell::{Cell, RefCell, RefMut},
|
||||
marker::PhantomData,
|
||||
};
|
||||
|
@ -47,10 +46,7 @@ impl<'i, T: 'i> Node<'i, ()> for RefCellMutNode<T> {
|
|||
type Output = RefMut<'i, T>;
|
||||
#[inline(always)]
|
||||
fn eval(&'i self, _input: ()) -> Self::Output {
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
let a = self.0.borrow_mut();
|
||||
#[cfg(target_arch = "spirv")]
|
||||
let a = unsafe { self.0.try_borrow_mut().unwrap_unchecked() };
|
||||
a
|
||||
}
|
||||
}
|
||||
|
@ -60,24 +56,6 @@ impl<T> RefCellMutNode<T> {
|
|||
RefCellMutNode(RefCell::new(value))
|
||||
}
|
||||
}
|
||||
/// #Safety: Never use this as it is unsound.
|
||||
#[derive(Default, Debug)]
|
||||
pub struct UnsafeMutValueNode<T>(pub T);
|
||||
|
||||
/// #Safety: Never use this as it is unsound.
|
||||
impl<'i, T: 'i> Node<'i, ()> for UnsafeMutValueNode<T> {
|
||||
type Output = &'i mut T;
|
||||
#[inline(always)]
|
||||
fn eval(&'i self, _input: ()) -> Self::Output {
|
||||
unsafe { &mut *(&self.0 as &T as *const T as *mut T) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> UnsafeMutValueNode<T> {
|
||||
pub const fn new(value: T) -> UnsafeMutValueNode<T> {
|
||||
UnsafeMutValueNode(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct OnceCellNode<T>(pub Cell<T>);
|
||||
|
|
|
@ -603,7 +603,6 @@ impl NodeNetwork {
|
|||
|
||||
fn replace_node_inputs(&mut self, old_input: NodeInput, new_input: NodeInput) {
|
||||
for node in self.nodes.values_mut() {
|
||||
let node_string = format!("{:?}", node);
|
||||
node.inputs.iter_mut().for_each(|input| {
|
||||
if *input == old_input {
|
||||
*input = new_input.clone();
|
||||
|
@ -893,16 +892,15 @@ impl<'a> Iterator for RecursiveNodeIter<'a> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::{cell::Cell, sync::atomic::AtomicU64};
|
||||
|
||||
use super::*;
|
||||
use crate::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, ProtoNodeInput};
|
||||
use graphene_core::NodeIdentifier;
|
||||
|
||||
fn gen_node_id() -> NodeId {
|
||||
static mut NODE_ID: NodeId = 3;
|
||||
unsafe {
|
||||
NODE_ID += 1;
|
||||
NODE_ID
|
||||
}
|
||||
static NODE_ID: AtomicU64 = AtomicU64::new(4);
|
||||
NODE_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst)
|
||||
}
|
||||
|
||||
fn add_network() -> NodeNetwork {
|
||||
|
|
|
@ -6,9 +6,8 @@ use crate::proto::{Any as DAny, FutureAny};
|
|||
use graphene_core::raster::{to_primtive_string, BlendMode, LuminanceCalculation};
|
||||
use graphene_core::{Color, Node, Type};
|
||||
|
||||
use dyn_any::DynAny;
|
||||
pub use dyn_any::StaticType;
|
||||
use dyn_any::{DynAny, Upcast};
|
||||
use dyn_clone::DynClone;
|
||||
pub use glam::{DAffine2, DVec2};
|
||||
use std::hash::Hash;
|
||||
pub use std::sync::Arc;
|
||||
|
@ -245,56 +244,60 @@ impl<'a> TaggedValue {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn try_from_any(input: Box<dyn DynAny<'a> + 'a>) -> Option<Self> {
|
||||
pub fn try_from_any(input: Box<dyn DynAny<'a> + 'a>) -> Result<Self, String> {
|
||||
use dyn_any::downcast;
|
||||
use std::any::TypeId;
|
||||
|
||||
match DynAny::type_id(input.as_ref()) {
|
||||
x if x == TypeId::of::<()>() => Some(TaggedValue::None),
|
||||
x if x == TypeId::of::<String>() => Some(TaggedValue::String(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<u32>() => Some(TaggedValue::U32(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<f32>() => Some(TaggedValue::F32(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<f64>() => Some(TaggedValue::F64(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<bool>() => Some(TaggedValue::Bool(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<DVec2>() => Some(TaggedValue::DVec2(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Option<DVec2>>() => Some(TaggedValue::OptionalDVec2(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::Image<Color>>() => Some(TaggedValue::Image(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Option<Arc<graphene_core::raster::Image<Color>>>>() => Some(TaggedValue::RcImage(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::ImageFrame<Color>>() => Some(TaggedValue::ImageFrame(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::Color>() => Some(TaggedValue::Color(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Vec<bezier_rs::Subpath<graphene_core::uuid::ManipulatorGroupId>>>() => Some(TaggedValue::Subpaths(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Arc<bezier_rs::Subpath<graphene_core::uuid::ManipulatorGroupId>>>() => Some(TaggedValue::RcSubpath(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<BlendMode>() => Some(TaggedValue::BlendMode(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<ImaginateSamplingMethod>() => Some(TaggedValue::ImaginateSamplingMethod(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<ImaginateMaskStartingFill>() => Some(TaggedValue::ImaginateMaskStartingFill(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<ImaginateStatus>() => Some(TaggedValue::ImaginateStatus(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Option<Vec<u64>>>() => Some(TaggedValue::LayerPath(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<DAffine2>() => Some(TaggedValue::DAffine2(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<LuminanceCalculation>() => Some(TaggedValue::LuminanceCalculation(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::vector::VectorData>() => Some(TaggedValue::VectorData(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::vector::style::Fill>() => Some(TaggedValue::Fill(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::vector::style::Stroke>() => Some(TaggedValue::Stroke(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Vec<f32>>() => Some(TaggedValue::VecF32(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::RedGreenBlue>() => Some(TaggedValue::RedGreenBlue(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::RelativeAbsolute>() => Some(TaggedValue::RelativeAbsolute(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::SelectiveColorChoice>() => Some(TaggedValue::SelectiveColorChoice(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::vector::style::LineCap>() => Some(TaggedValue::LineCap(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::vector::style::LineJoin>() => Some(TaggedValue::LineJoin(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::vector::style::FillType>() => Some(TaggedValue::FillType(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::vector::style::GradientType>() => Some(TaggedValue::GradientType(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Vec<(f64, Option<graphene_core::Color>)>>() => Some(TaggedValue::GradientPositions(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::quantization::QuantizationChannels>() => Some(TaggedValue::Quantization(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Option<graphene_core::Color>>() => Some(TaggedValue::OptionalColor(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Vec<graphene_core::uuid::ManipulatorGroupId>>() => Some(TaggedValue::ManipulatorGroupIds(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::text::Font>() => Some(TaggedValue::Font(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Vec<graphene_core::vector::brush_stroke::BrushStroke>>() => Some(TaggedValue::BrushStrokes(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::IndexNode<Vec<graphene_core::raster::ImageFrame<Color>>>>() => Some(TaggedValue::Segments(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<crate::document::DocumentNode>() => Some(TaggedValue::DocumentNode(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::GraphicGroup>() => Some(TaggedValue::GraphicGroup(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::Artboard>() => Some(TaggedValue::Artboard(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<glam::IVec2>() => Some(TaggedValue::IVec2(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::SurfaceFrame>() => Some(TaggedValue::SurfaceFrame(*downcast(input).unwrap())),
|
||||
_ => None,
|
||||
x if x == TypeId::of::<()>() => Ok(TaggedValue::None),
|
||||
x if x == TypeId::of::<String>() => Ok(TaggedValue::String(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<u32>() => Ok(TaggedValue::U32(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<f32>() => Ok(TaggedValue::F32(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<f64>() => Ok(TaggedValue::F64(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<bool>() => Ok(TaggedValue::Bool(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<DVec2>() => Ok(TaggedValue::DVec2(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Option<DVec2>>() => Ok(TaggedValue::OptionalDVec2(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::Image<Color>>() => Ok(TaggedValue::Image(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Option<Arc<graphene_core::raster::Image<Color>>>>() => Ok(TaggedValue::RcImage(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::ImageFrame<Color>>() => Ok(TaggedValue::ImageFrame(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::Color>() => Ok(TaggedValue::Color(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Vec<bezier_rs::Subpath<graphene_core::uuid::ManipulatorGroupId>>>() => Ok(TaggedValue::Subpaths(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Arc<bezier_rs::Subpath<graphene_core::uuid::ManipulatorGroupId>>>() => Ok(TaggedValue::RcSubpath(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<BlendMode>() => Ok(TaggedValue::BlendMode(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<ImaginateSamplingMethod>() => Ok(TaggedValue::ImaginateSamplingMethod(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<ImaginateMaskStartingFill>() => Ok(TaggedValue::ImaginateMaskStartingFill(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<ImaginateStatus>() => Ok(TaggedValue::ImaginateStatus(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Option<Vec<u64>>>() => Ok(TaggedValue::LayerPath(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<DAffine2>() => Ok(TaggedValue::DAffine2(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<LuminanceCalculation>() => Ok(TaggedValue::LuminanceCalculation(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::vector::VectorData>() => Ok(TaggedValue::VectorData(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::vector::style::Fill>() => Ok(TaggedValue::Fill(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::vector::style::Stroke>() => Ok(TaggedValue::Stroke(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Vec<f32>>() => Ok(TaggedValue::VecF32(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::RedGreenBlue>() => Ok(TaggedValue::RedGreenBlue(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::RelativeAbsolute>() => Ok(TaggedValue::RelativeAbsolute(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::SelectiveColorChoice>() => Ok(TaggedValue::SelectiveColorChoice(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::vector::style::LineCap>() => Ok(TaggedValue::LineCap(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::vector::style::LineJoin>() => Ok(TaggedValue::LineJoin(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::vector::style::FillType>() => Ok(TaggedValue::FillType(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::vector::style::GradientType>() => Ok(TaggedValue::GradientType(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Vec<(f64, Option<graphene_core::Color>)>>() => Ok(TaggedValue::GradientPositions(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::quantization::QuantizationChannels>() => Ok(TaggedValue::Quantization(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Option<graphene_core::Color>>() => Ok(TaggedValue::OptionalColor(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Vec<graphene_core::uuid::ManipulatorGroupId>>() => Ok(TaggedValue::ManipulatorGroupIds(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::text::Font>() => Ok(TaggedValue::Font(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Vec<graphene_core::vector::brush_stroke::BrushStroke>>() => Ok(TaggedValue::BrushStrokes(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::IndexNode<Vec<graphene_core::raster::ImageFrame<Color>>>>() => Ok(TaggedValue::Segments(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<crate::document::DocumentNode>() => Ok(TaggedValue::DocumentNode(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::GraphicGroup>() => Ok(TaggedValue::GraphicGroup(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::Artboard>() => Ok(TaggedValue::Artboard(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<glam::IVec2>() => Ok(TaggedValue::IVec2(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::SurfaceFrame>() => Ok(TaggedValue::SurfaceFrame(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::wasm_application_io::WasmSurfaceHandleFrame>() => {
|
||||
let frame = *downcast::<graphene_core::wasm_application_io::WasmSurfaceHandleFrame>(input).unwrap();
|
||||
Ok(TaggedValue::SurfaceFrame(frame.into()))
|
||||
}
|
||||
_ => Err(format!("Cannot convert {:?} to TaggedValue", DynAny::type_name(input.as_ref()))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -314,82 +317,3 @@ impl UpcastNode {
|
|||
Self { value }
|
||||
}
|
||||
}
|
||||
|
||||
pub type Value<'a> = Box<dyn for<'i> ValueTrait<'i> + 'a>;
|
||||
|
||||
pub trait ValueTrait<'a>: DynAny<'a> + Upcast<dyn DynAny<'a> + 'a> + std::fmt::Debug + DynClone + Sync + Send + 'a {}
|
||||
|
||||
pub trait IntoValue<'a>: Sized + for<'i> ValueTrait<'i> + 'a {
|
||||
fn into_any(self) -> Value<'a> {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a + StaticType + Upcast<dyn DynAny<'a> + 'a> + std::fmt::Debug + PartialEq + Clone + Sync + Send + 'a> ValueTrait<'a> for T {}
|
||||
|
||||
impl<'a, T: for<'i> ValueTrait<'i> + 'a> IntoValue<'a> for T {}
|
||||
|
||||
#[repr(C)]
|
||||
pub(crate) struct Vtable {
|
||||
pub(crate) destructor: unsafe fn(*mut ()),
|
||||
pub(crate) size: usize,
|
||||
pub(crate) align: usize,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub(crate) struct TraitObject {
|
||||
pub(crate) self_ptr: *mut u8,
|
||||
pub(crate) vtable: &'static Vtable,
|
||||
}
|
||||
|
||||
impl<'a> PartialEq for Box<dyn for<'i> ValueTrait<'i> + 'a> {
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if self.type_id() != other.type_id() {
|
||||
return false;
|
||||
}
|
||||
let self_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(self.as_ref()) };
|
||||
let other_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(other.as_ref()) };
|
||||
let size = self_trait_object.vtable.size;
|
||||
let self_mem = unsafe { std::slice::from_raw_parts(self_trait_object.self_ptr, size) };
|
||||
let other_mem = unsafe { std::slice::from_raw_parts(other_trait_object.self_ptr, size) };
|
||||
self_mem == other_mem
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Hash for Value<'a> {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
let self_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(self.as_ref()) };
|
||||
let size = self_trait_object.vtable.size;
|
||||
let self_mem = unsafe { std::slice::from_raw_parts(self_trait_object.self_ptr, size) };
|
||||
self_mem.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Clone for Value<'a> {
|
||||
fn clone(&self) -> Self {
|
||||
let self_trait_object = unsafe { std::mem::transmute::<&dyn ValueTrait, TraitObject>(self.as_ref()) };
|
||||
let size = self_trait_object.vtable.size;
|
||||
let self_mem = unsafe { std::slice::from_raw_parts(self_trait_object.self_ptr, size) }.to_owned();
|
||||
let ptr = Vec::leak(self_mem);
|
||||
unsafe {
|
||||
std::mem::transmute(TraitObject {
|
||||
self_ptr: ptr as *mut [u8] as *mut u8,
|
||||
vtable: self_trait_object.vtable,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn test_any_src() {
|
||||
assert!(2_u32.into_any() == 2_u32.into_any());
|
||||
assert!(2_u32.into_any() != 3_u32.into_any());
|
||||
assert!(2_u32.into_any() != 3_i32.into_any());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,6 @@ impl Compiler {
|
|||
}
|
||||
pub type Any<'a> = Box<dyn DynAny<'a> + 'a>;
|
||||
|
||||
pub trait Executor {
|
||||
fn execute<'a>(&'a self, input: Any<'a>) -> LocalFuture<Result<Any<'a>, Box<dyn Error>>>;
|
||||
pub trait Executor<I, O> {
|
||||
fn execute(&self, input: I) -> LocalFuture<Result<O, Box<dyn Error>>>;
|
||||
}
|
||||
|
|
|
@ -99,7 +99,6 @@ impl PartialEq for ConstructionArgs {
|
|||
(Self::Value(v1), Self::Value(v2)) => v1 == v2,
|
||||
_ => {
|
||||
use std::hash::Hasher;
|
||||
use xxhash_rust::xxh3::Xxh3;
|
||||
let hash = |input: &Self| {
|
||||
let mut hasher = Xxh3::new();
|
||||
input.hash(&mut hasher);
|
||||
|
|
|
@ -9,8 +9,7 @@ license = "MIT OR Apache-2.0"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
memoization = ["once_cell"]
|
||||
default = ["memoization", "wgpu"]
|
||||
default = ["wgpu"]
|
||||
gpu = [
|
||||
"graphene-core/gpu",
|
||||
"gpu-compiler-bin-wrapper",
|
||||
|
@ -31,7 +30,6 @@ graphene-core = { path = "../gcore", features = [
|
|||
"std",
|
||||
"serde",
|
||||
], default-features = false }
|
||||
borrow_stack = { path = "../borrow_stack" }
|
||||
dyn-any = { path = "../../libraries/dyn-any", features = ["derive"] }
|
||||
graph-craft = { path = "../graph-craft" }
|
||||
vulkan-executor = { path = "../vulkan-executor", optional = true }
|
||||
|
@ -41,16 +39,6 @@ gpu-compiler-bin-wrapper = { path = "../gpu-compiler/gpu-compiler-bin-wrapper",
|
|||
compilation-client = { path = "../compilation-client", optional = true }
|
||||
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",
|
||||
] }
|
||||
proc-macro2 = { version = "1.0", default-features = false, features = [
|
||||
"proc-macro",
|
||||
] }
|
||||
quote = { version = "1.0", default-features = false }
|
||||
image = { version = "*", default-features = false }
|
||||
dyn-clone = "1.0"
|
||||
|
||||
|
@ -61,7 +49,6 @@ kurbo = { git = "https://github.com/linebender/kurbo.git", features = [
|
|||
] }
|
||||
glam = { version = "0.22", features = ["serde"] }
|
||||
node-macro = { path = "../node-macro" }
|
||||
boxcar = "0.1.0"
|
||||
xxhash-rust = { workspace = true }
|
||||
serde_json = "1.0.96"
|
||||
reqwest = { version = "0.11.17", features = ["rustls", "rustls-tls"] }
|
||||
|
|
|
@ -29,9 +29,8 @@ where
|
|||
Box::pin(output)
|
||||
}
|
||||
|
||||
fn reset(self: std::pin::Pin<&mut Self>) {
|
||||
let wrapped_node = unsafe { self.map_unchecked_mut(|e| &mut e.node) };
|
||||
Node::reset(wrapped_node);
|
||||
fn reset(&self) {
|
||||
self.node.reset();
|
||||
}
|
||||
|
||||
fn serialize(&self) -> Option<std::sync::Arc<dyn core::any::Any>> {
|
||||
|
@ -67,9 +66,8 @@ where
|
|||
let output = async move { Box::new(result) as Any<'input> };
|
||||
Box::pin(output)
|
||||
}
|
||||
fn reset(self: std::pin::Pin<&mut Self>) {
|
||||
let wrapped_node = unsafe { self.map_unchecked_mut(|e| &mut e.node) };
|
||||
Node::reset(wrapped_node);
|
||||
fn reset(&self) {
|
||||
self.node.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,9 +112,8 @@ where
|
|||
fn eval(&'i self, input: T) -> Self::Output {
|
||||
Box::pin(async move { self.node.eval(input) })
|
||||
}
|
||||
fn reset(self: std::pin::Pin<&mut Self>) {
|
||||
let wrapped_node = unsafe { self.map_unchecked_mut(|e| &mut e.node) };
|
||||
Node::reset(wrapped_node);
|
||||
fn reset(&self) {
|
||||
self.node.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,7 +204,7 @@ impl<'n: 'input, 'input, O: 'input + StaticType, I: 'input + StaticType> Node<'i
|
|||
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}"));
|
||||
let out: Box<&_> = dyn_any::downcast::<&O>(self.node.eval(input).await).unwrap_or_else(|e| panic!("DowncastBothRefNode Input {e} in {node_name}"));
|
||||
*out
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
use glam::{DAffine2, DMat2, DVec2, Mat2, UVec3, Vec2};
|
||||
use glam::{DAffine2, DVec2, Mat2, Vec2};
|
||||
use gpu_executor::{Bindgroup, ComputePassDimensions, PipelineLayout, StorageBufferOptions};
|
||||
use gpu_executor::{GpuExecutor, ShaderIO, ShaderInput};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::*;
|
||||
use graph_craft::proto::*;
|
||||
use graphene_core::raster::bbox::{AxisAlignedBbox, Bbox};
|
||||
use graphene_core::raster::*;
|
||||
use graphene_core::*;
|
||||
use wgpu_executor::NewExecutor;
|
||||
|
||||
use bytemuck::Pod;
|
||||
use core::marker::PhantomData;
|
||||
use dyn_any::StaticTypeSized;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct GpuCompiler<TypingContext, ShaderIO> {
|
||||
|
|
|
@ -5,9 +5,6 @@ extern crate log;
|
|||
//pub mod value;
|
||||
//#![feature(const_type_name)]
|
||||
|
||||
#[cfg(feature = "memoization")]
|
||||
pub mod memo;
|
||||
|
||||
pub mod raster;
|
||||
|
||||
pub mod http;
|
||||
|
|
|
@ -1,148 +0,0 @@
|
|||
//#![feature(generic_associated_types)]
|
||||
// use borrow_stack::BorrowStack;
|
||||
// use dyn_any::{DynAny, StaticType};
|
||||
// use graphene_std::value::{AnyRefNode, AnyValueNode, StorageNode, ValueNode};
|
||||
// use graphene_std::*;
|
||||
|
||||
/*fn mul(#[dyn_any(default)] a: f32, b: f32) -> f32 {
|
||||
a * b
|
||||
}*/
|
||||
|
||||
/*
|
||||
mod mul {
|
||||
use dyn_any::downcast_ref;
|
||||
use graphene_std::{DynAnyNode, DynNode, DynamicInput, Node};
|
||||
pub struct MulNodeInput<'n> {
|
||||
pub a: &'n f32,
|
||||
pub b: &'n f32,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct MulNodeAnyProxy<'n> {
|
||||
pub a: Option<DynAnyNode<'n>>,
|
||||
pub b: Option<DynAnyNode<'n>>,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct MulNodeTypedProxy<'n> {
|
||||
pub a: Option<DynNode<'n, &'n f32>>,
|
||||
pub b: Option<DynNode<'n, &'n f32>>,
|
||||
}
|
||||
impl<'n> Node<'n> for MulNodeAnyProxy<'n> {
|
||||
type Output = MulNodeInput<'n>;
|
||||
fn eval(&'n self) -> <Self as graphene_std::Node<'n>>::Output {
|
||||
// let a = self.a.unwrap().eval();
|
||||
let a: &f32 = self.a.map(|v| downcast_ref(v.eval()).unwrap()).unwrap_or(&1.);
|
||||
/*let b: &f32 = self
|
||||
.b
|
||||
.map(|v| v.eval(&()).downcast_ref::<&'n f32, &'n f32>().unwrap())
|
||||
.unwrap_or(&&2.);
|
||||
a * b*/
|
||||
MulNodeInput { a, b: a }
|
||||
}
|
||||
}
|
||||
impl<'n> Node<'n> for MulNodeTypedProxy<'n> {
|
||||
type Output = MulNodeInput<'n>;
|
||||
fn eval(&'n self) -> <Self as graphene_std::Node<'n>>::Output {
|
||||
let a = self.a.unwrap().eval();
|
||||
let b = self.b.unwrap().eval();
|
||||
MulNodeInput { a, b }
|
||||
}
|
||||
}
|
||||
|
||||
/*macro_rules! new {
|
||||
() => {
|
||||
mul::MulNode { a: None, b: None }
|
||||
};
|
||||
}*/
|
||||
//pub(crate) use new;
|
||||
|
||||
impl<'n> DynamicInput<'n> for MulNodeAnyProxy<'n> {
|
||||
fn set_kwarg_by_name(&mut self, _name: &str, _value: DynAnyNode<'n>) {
|
||||
todo!()
|
||||
}
|
||||
fn set_arg_by_index(&mut self, index: usize, value: DynAnyNode<'n>) {
|
||||
match index {
|
||||
0 => {
|
||||
self.a = Some(value);
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// type SNode<'n> = dyn Node<'n, Output = &'n dyn DynAny<'n>>;
|
||||
*/
|
||||
// struct NodeStore<'n>(borrow_stack::FixedSizeStack<'n, Box<SNode<'n>>>);
|
||||
|
||||
// impl<'n> NodeStore<'n> {
|
||||
// fn len(&self) -> usize {
|
||||
// self.0.len()
|
||||
// }
|
||||
|
||||
// fn push(&'n mut self, f: fn(&'n [Box<SNode>]) -> Box<SNode<'n>>) {
|
||||
// unsafe { self.0.push(f(self.0.get())) };
|
||||
// }
|
||||
|
||||
// /*fn get_index(&'n self, index: usize) -> &'n SNode<'n> {
|
||||
// assert!(index < self.0.len());
|
||||
// &unsafe { self.0.get()[index] }
|
||||
// }*/
|
||||
// }
|
||||
|
||||
fn main() {
|
||||
// use syn::parse::Parse;
|
||||
/*let nodes = vec![
|
||||
NodeKind::Input,
|
||||
NodeKind::Value(syn::parse_quote!(1u32)),
|
||||
NodeKind::Node(syn::parse_quote!(graphene_core::ops::AddNode), vec![0, 0]),
|
||||
];
|
||||
|
||||
//println!("{}", node_graph(1));
|
||||
//
|
||||
|
||||
let _nodegraph = NodeGraph {
|
||||
nodes,
|
||||
input: syn::Type::Verbatim(quote! {u32}),
|
||||
output: syn::Type::Verbatim(quote! {u32}),
|
||||
};*/
|
||||
|
||||
//let pretty = pretty_token_stream::Pretty::new(nodegraph.serialize_gpu("add"));
|
||||
//pretty.print();
|
||||
/*
|
||||
use dyn_any::{downcast_ref, DynAny, StaticType};
|
||||
//let mut mul = mul::MulNode::new();
|
||||
let mut stack: borrow_stack::FixedSizeStack<Box<dyn Node<'_, Output = &dyn DynAny>>> =
|
||||
borrow_stack::FixedSizeStack::new(42);
|
||||
unsafe { stack.push(Box::new(AnyValueNode::new(1_f32))) };
|
||||
//let node = unsafe { stack.get(0) };
|
||||
//let boxed = Box::new(StorageNode::new(node));
|
||||
//unsafe { stack.push(boxed) };
|
||||
let result = unsafe { &stack.get()[0] }.eval();
|
||||
dbg!(downcast_ref::<f32>(result));
|
||||
/*unsafe {
|
||||
stack
|
||||
.push(Box::new(AnyRefNode::new(stack.get(0).as_ref()))
|
||||
as Box<dyn Node<(), Output = &dyn DynAny>>)
|
||||
};*/
|
||||
let f = (3.2_f32, 3.1_f32);
|
||||
let a = ValueNode::new(1.);
|
||||
let id = std::any::TypeId::of::<&f32>();
|
||||
let any_a = AnyRefNode::new(&a);
|
||||
/*let _mul2 = mul::MulNodeInput {
|
||||
a: None,
|
||||
b: Some(&any_a),
|
||||
};
|
||||
let mut mul2 = mul::new!();
|
||||
//let cached = memo::CacheNode::new(&mul1);
|
||||
//let foo = value::AnyRefNode::new(&cached);
|
||||
mul2.set_arg_by_index(0, &any_a);*/
|
||||
let int = value::IntNode::<32>;
|
||||
Node::eval(&int);
|
||||
println!("{}", Node::eval(&int));
|
||||
//let _add: u32 = ops::AddNode::<u32>::default().eval((int.exec(), int.exec()));
|
||||
//let fnode = generic::FnNode::new(|(a, b): &(i32, i32)| a - b);
|
||||
//let sub = fnode.any(&("a", 2));
|
||||
//let cache = memo::CacheNode::new(&fnode);
|
||||
//let cached_result = cache.eval(&(2, 3));
|
||||
*/
|
||||
//println!("{}", cached_result)
|
||||
}
|
|
@ -1,177 +0,0 @@
|
|||
use futures::Future;
|
||||
|
||||
use graphene_core::Node;
|
||||
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use xxhash_rust::xxh3::Xxh3;
|
||||
|
||||
/// Caches the output of a given Node and acts as a proxy
|
||||
#[derive(Default)]
|
||||
pub struct CacheNode<T, CachedNode> {
|
||||
// We have to use an append only data structure to make sure the references
|
||||
// to the cache entries are always valid
|
||||
cache: boxcar::Vec<(u64, T, AtomicBool)>,
|
||||
node: CachedNode,
|
||||
}
|
||||
impl<'i, T: 'i + Clone, I: 'i + Hash, CachedNode: 'i> Node<'i, I> for CacheNode<T, CachedNode>
|
||||
where
|
||||
CachedNode: for<'any_input> Node<'any_input, I>,
|
||||
for<'a> <CachedNode as Node<'a, I>>::Output: core::future::Future<Output = T> + 'a,
|
||||
{
|
||||
// TODO: This should return a reference to the cached cached_value
|
||||
// but that requires a lot of lifetime magic <- This was suggested by copilot but is pretty acurate xD
|
||||
type Output = Pin<Box<dyn Future<Output = T> + 'i>>;
|
||||
fn eval(&'i self, input: I) -> Self::Output {
|
||||
Box::pin(async move {
|
||||
let mut hasher = Xxh3::new();
|
||||
input.hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
|
||||
if let Some((_, cached_value, keep)) = self.cache.iter().find(|(h, _, _)| *h == hash) {
|
||||
keep.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
cached_value.clone()
|
||||
} else {
|
||||
trace!("Cache miss");
|
||||
let output = self.node.eval(input).await;
|
||||
let index = self.cache.push((hash, output, AtomicBool::new(true)));
|
||||
self.cache[index].1.clone()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn reset(mut self: Pin<&mut Self>) {
|
||||
let old_cache = std::mem::take(&mut self.cache);
|
||||
self.cache = old_cache.into_iter().filter(|(_, _, keep)| keep.swap(false, std::sync::atomic::Ordering::Relaxed)).collect();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, CachedNode> std::marker::Unpin for CacheNode<T, CachedNode> {}
|
||||
|
||||
impl<T, CachedNode> CacheNode<T, CachedNode> {
|
||||
pub fn new(node: CachedNode) -> CacheNode<T, CachedNode> {
|
||||
CacheNode { cache: boxcar::Vec::new(), node }
|
||||
}
|
||||
}
|
||||
|
||||
/// Caches the output of the last graph evaluation for introspection
|
||||
#[derive(Default)]
|
||||
pub struct MonitorNode<T> {
|
||||
output: Mutex<Option<Arc<T>>>,
|
||||
}
|
||||
impl<'i, T: 'static + Clone> Node<'i, T> for MonitorNode<T> {
|
||||
type Output = T;
|
||||
fn eval(&'i self, input: T) -> Self::Output {
|
||||
*self.output.lock().unwrap() = Some(Arc::new(input.clone()));
|
||||
input
|
||||
}
|
||||
|
||||
fn serialize(&self) -> Option<Arc<dyn core::any::Any>> {
|
||||
let output = self.output.lock().unwrap();
|
||||
(*output).as_ref().map(|output| output.clone() as Arc<dyn core::any::Any>)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> MonitorNode<T> {
|
||||
pub const fn new() -> MonitorNode<T> {
|
||||
MonitorNode { output: Mutex::new(None) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Caches the output of a given Node and acts as a proxy
|
||||
/// It provides two modes of operation, it can either be set
|
||||
/// when calling the node with a `Some<T>` variant or the last
|
||||
/// value that was added is returned when calling it with `None`
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct LetNode<T> {
|
||||
// We have to use an append only data structure to make sure the references
|
||||
// to the cache entries are always valid
|
||||
// TODO: We only ever access the last value so there is not really a reason for us
|
||||
// to store the previous entries. This should be reworked in the future
|
||||
cache: boxcar::Vec<(u64, T)>,
|
||||
}
|
||||
impl<'i, T: 'i + Hash> Node<'i, Option<T>> for LetNode<T> {
|
||||
type Output = &'i T;
|
||||
fn eval(&'i self, input: Option<T>) -> Self::Output {
|
||||
match input {
|
||||
Some(input) => {
|
||||
let mut hasher = Xxh3::new();
|
||||
input.hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
|
||||
if let Some((cached_hash, cached_value)) = self.cache.iter().last() {
|
||||
if hash == *cached_hash {
|
||||
return cached_value;
|
||||
}
|
||||
}
|
||||
trace!("Cache miss");
|
||||
let index = self.cache.push((hash, input));
|
||||
&self.cache[index].1
|
||||
}
|
||||
None => &self.cache.iter().last().expect("Let node was not initialized").1,
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(mut self: Pin<&mut Self>) {
|
||||
if let Some(last) = std::mem::take(&mut self.cache).into_iter().last() {
|
||||
self.cache = boxcar::vec![last];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::marker::Unpin for LetNode<T> {}
|
||||
|
||||
impl<T> LetNode<T> {
|
||||
pub fn new() -> LetNode<T> {
|
||||
LetNode { cache: boxcar::Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Caches the output of a given Node and acts as a proxy
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct EndLetNode<Input> {
|
||||
input: Input,
|
||||
}
|
||||
impl<'i, T: 'i, Input> Node<'i, &'i T> for EndLetNode<Input>
|
||||
where
|
||||
Input: Node<'i, ()>,
|
||||
{
|
||||
type Output = <Input>::Output;
|
||||
fn eval(&'i self, _: &'i T) -> Self::Output {
|
||||
let result = self.input.eval(());
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<Input> EndLetNode<Input> {
|
||||
pub const fn new(input: Input) -> EndLetNode<Input> {
|
||||
EndLetNode { input }
|
||||
}
|
||||
}
|
||||
|
||||
pub use graphene_core::ops::SomeNode as InitNode;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
pub struct RefNode<T, Let> {
|
||||
let_node: Let,
|
||||
_t: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'i, T: 'i, Let> Node<'i, ()> for RefNode<T, Let>
|
||||
where
|
||||
Let: for<'a> Node<'a, Option<T>>,
|
||||
{
|
||||
type Output = <Let as Node<'i, Option<T>>>::Output;
|
||||
fn eval(&'i self, _: ()) -> Self::Output {
|
||||
self.let_node.eval(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Let, T> RefNode<T, Let> {
|
||||
pub const fn new(let_node: Let) -> RefNode<T, Let> {
|
||||
RefNode { let_node, _t: PhantomData }
|
||||
}
|
||||
}
|
|
@ -13,18 +13,17 @@ quantization = ["graphene-std/quantization"]
|
|||
# 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-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", "glam"] }
|
||||
dyn-any = { path = "../../libraries/dyn-any", features = [
|
||||
"log-bad-types",
|
||||
"glam",
|
||||
] }
|
||||
num-traits = "0.2"
|
||||
borrow_stack = { path = "../borrow_stack" }
|
||||
dyn-clone = "1.0"
|
||||
log = "0.4"
|
||||
serde = { version = "1", features = ["derive"], optional = true }
|
||||
glam = { version = "0.22" }
|
||||
once_cell = "1.17.0"
|
||||
futures = "0.3.28"
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.12", features = ["rt", "macros"] }
|
||||
|
|
|
@ -3,12 +3,12 @@ use std::error::Error;
|
|||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use dyn_any::StaticType;
|
||||
use graph_craft::document::value::UpcastNode;
|
||||
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::{Any, TypeErasedPinned, TypeErasedPinnedRef};
|
||||
use graphene_std::any::{TypeErasedPinned, TypeErasedPinnedRef};
|
||||
|
||||
use crate::node_registry;
|
||||
|
||||
|
@ -73,9 +73,9 @@ impl DynamicExecutor {
|
|||
}
|
||||
}
|
||||
|
||||
impl Executor for DynamicExecutor {
|
||||
fn execute<'a>(&'a self, input: Any<'a>) -> LocalFuture<Result<Any<'a>, Box<dyn Error>>> {
|
||||
Box::pin(async move { self.tree.eval_any(self.output, input).await.ok_or_else(|| "Failed to execute".into()) })
|
||||
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()) })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,18 +167,17 @@ impl BorrowTree {
|
|||
self.nodes.get(&id).cloned()
|
||||
}
|
||||
|
||||
pub async fn eval<'i, I: StaticType + 'i + Send + Sync, O: StaticType + Send + Sync + 'i>(&'i self, id: NodeId, input: I) -> Option<O> {
|
||||
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_any<'i>(&'i self, id: NodeId, input: Any<'i>) -> Option<Any<'i>> {
|
||||
let node = self.nodes.get(&id)?;
|
||||
// TODO: Comments by @TrueDoctor before this was merged:
|
||||
// TODO: Oof I dislike the evaluation being an unsafe operation but I guess its fine because it only is a lifetime extension
|
||||
// TODO: We should ideally let miri run on a test that evaluates the nodegraph multiple times to check if this contains any subtle UB but this looks fine for now
|
||||
Some(unsafe { (*((&*node.read().unwrap()) as *const NodeContainer)).node.eval(input).await })
|
||||
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) {
|
||||
|
@ -226,12 +225,15 @@ mod test {
|
|||
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn push_node() {
|
||||
#[test]
|
||||
fn push_node_sync() {
|
||||
let mut tree = BorrowTree::default();
|
||||
let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32)), vec![]);
|
||||
tree.push_node(0, val_1_protonode, &TypingContext::default()).await.unwrap();
|
||||
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();
|
||||
assert_eq!(tree.eval(0, ()).await, Some(2u32));
|
||||
let result = futures::executor::block_on(tree.eval(0, ()));
|
||||
assert_eq!(result, Some(2u32));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,45 +7,14 @@ pub mod node_registry;
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use dyn_any::IntoDynAny;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graphene_core::*;
|
||||
use std::borrow::Cow;
|
||||
|
||||
/*
|
||||
use futures::executor::block_on;
|
||||
|
||||
#[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::pin(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);
|
||||
}*/
|
||||
|
||||
#[tokio::test]
|
||||
async fn execute_add() {
|
||||
fn execute_add() {
|
||||
use graph_craft::document::*;
|
||||
|
||||
use graph_craft::*;
|
||||
|
@ -109,15 +78,14 @@ mod tests {
|
|||
let compiler = Compiler {};
|
||||
let protograph = compiler.compile_single(network, true).expect("Graph should be generated");
|
||||
|
||||
let exec = DynamicExecutor::new(protograph).await.unwrap_or_else(|e| panic!("Failed to create executor: {}", e));
|
||||
let exec = block_on(DynamicExecutor::new(protograph)).unwrap_or_else(|e| panic!("Failed to create executor: {}", e));
|
||||
|
||||
let result = exec.execute(32_u32.into_dyn()).await.unwrap();
|
||||
let val = *dyn_any::downcast::<u32>(result).unwrap();
|
||||
assert_eq!(val, 33_u32);
|
||||
let result = block_on((&exec).execute(32_u32)).unwrap();
|
||||
assert_eq!(result, TaggedValue::U32(33));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn double_number() {
|
||||
#[test]
|
||||
fn double_number() {
|
||||
use graph_craft::document::*;
|
||||
|
||||
use graph_craft::*;
|
||||
|
@ -158,6 +126,6 @@ mod tests {
|
|||
let compiler = Compiler {};
|
||||
let protograph = compiler.compile_single(network, true).expect("Graph should be generated");
|
||||
|
||||
let _exec = DynamicExecutor::new(protograph).await.map(|e| panic!("The network should not type check: {:#?}", e)).unwrap_err();
|
||||
let _exec = block_on(DynamicExecutor::new(protograph)).map(|e| panic!("The network should not type check: {:#?}", e)).unwrap_err();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use graph_craft::document::DocumentNode;
|
||||
use graph_craft::proto::{NodeConstructor, TypeErasedPinned};
|
||||
use graphene_core::ops::IdNode;
|
||||
use graphene_core::quantization::QuantizationChannels;
|
||||
|
@ -10,13 +9,11 @@ use graphene_core::vector::brush_stroke::BrushStroke;
|
|||
use graphene_core::vector::VectorData;
|
||||
use graphene_core::wasm_application_io::WasmSurfaceHandle;
|
||||
use graphene_core::wasm_application_io::*;
|
||||
use graphene_core::{concrete, generic, value_fn};
|
||||
use graphene_core::{concrete, generic};
|
||||
use graphene_core::{fn_type, raster::*};
|
||||
use graphene_core::{Cow, NodeIdentifier, Type, TypeDescriptor};
|
||||
use graphene_core::{Node, NodeIO, NodeIOTypes};
|
||||
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyInRefNode, DynAnyNode, FutureWrapperNode, IntoTypeErasedNode, TypeErasedPinnedRef};
|
||||
use graphene_std::brush::*;
|
||||
use graphene_std::memo::{CacheNode, LetNode};
|
||||
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyNode, FutureWrapperNode, IntoTypeErasedNode};
|
||||
use graphene_std::raster::BlendImageTupleNode;
|
||||
use graphene_std::raster::*;
|
||||
|
||||
|
@ -27,8 +24,8 @@ use std::collections::HashMap;
|
|||
use std::sync::Arc;
|
||||
|
||||
macro_rules! construct_node {
|
||||
($args: ident, $path:ty, [$($type:tt),*]) => { async move {
|
||||
let mut args: Vec<TypeErasedPinnedRef<'static>> = $args.clone();
|
||||
($args: ident, $path:ty, [$($type:ty),*]) => { async move {
|
||||
let mut args = $args.clone();
|
||||
args.reverse();
|
||||
let node = <$path>::new($(
|
||||
{
|
||||
|
@ -60,7 +57,7 @@ macro_rules! register_node {
|
|||
let node = <$path>::new($(
|
||||
graphene_std::any::PanicNode::<(), $type>::new()
|
||||
),*);
|
||||
let params = vec![$(value_fn!($type)),*];
|
||||
let params = vec![$(fn_type!((), $type)),*];
|
||||
let mut node_io = <$path as NodeIO<'_, $input>>::to_node_io(&node, params);
|
||||
node_io.input = concrete!(<$input as StaticType>::Static);
|
||||
node_io
|
||||
|
@ -69,6 +66,38 @@ macro_rules! register_node {
|
|||
]
|
||||
};
|
||||
}
|
||||
macro_rules! async_node {
|
||||
// TODO: we currently need to annotate the type here because the compiler would otherwise (correctly)
|
||||
// assign a Pin<Box<dyn Fututure<Output=T>>> type to the node, which is not what we want for now.
|
||||
($path:ty, input: $input:ty, output: $output:ty, params: [ $($type:ty),*]) => {
|
||||
vec![
|
||||
(
|
||||
NodeIdentifier::new(stringify!($path)),
|
||||
|mut args| {
|
||||
Box::pin(async move {
|
||||
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
|
||||
})
|
||||
},
|
||||
{
|
||||
let node = <$path>::new($(
|
||||
graphene_std::any::PanicNode::<(), core::pin::Pin<Box<dyn core::future::Future<Output = $type>>>>::new()
|
||||
),*);
|
||||
// TODO: Propagate the future type through the node graph
|
||||
//let params = vec![$(Type::Fn(Box::new(concrete!(())), Box::new(Type::Future(Box::new(concrete!($type)))))),*];
|
||||
let params = vec![$(Type::Fn(Box::new(concrete!(())), Box::new(concrete!($type)))),*];
|
||||
let mut node_io = NodeIO::<'_, $input>::to_node_io(&node, params);
|
||||
node_io.input = concrete!(<$input as StaticType>::Static);
|
||||
node_io.input = concrete!(<$input as StaticType>::Static);
|
||||
node_io.output = concrete!(<$output as StaticType>::Static);
|
||||
node_io
|
||||
},
|
||||
)
|
||||
]
|
||||
};
|
||||
}
|
||||
macro_rules! raster_node {
|
||||
($path:ty, params: [$($type:ty),*]) => {{
|
||||
// this function could also be inlined but serves as a workaround for
|
||||
|
@ -92,7 +121,7 @@ macro_rules! raster_node {
|
|||
})
|
||||
},
|
||||
{
|
||||
let params = vec![$(value_fn!($type)),*];
|
||||
let params = vec![$(fn_type!($type)),*];
|
||||
NodeIOTypes::new(concrete!(Color), concrete!(Color), params)
|
||||
},
|
||||
),
|
||||
|
@ -108,7 +137,7 @@ macro_rules! raster_node {
|
|||
})
|
||||
},
|
||||
{
|
||||
let params = vec![$(value_fn!($type)),*];
|
||||
let params = vec![$(fn_type!($type)),*];
|
||||
NodeIOTypes::new(concrete!(Image<Color>), concrete!(Image<Color>), params)
|
||||
},
|
||||
),
|
||||
|
@ -124,7 +153,7 @@ macro_rules! raster_node {
|
|||
})
|
||||
},
|
||||
{
|
||||
let params = vec![$(value_fn!($type)),*];
|
||||
let params = vec![$(fn_type!($type)),*];
|
||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), params)
|
||||
},
|
||||
)
|
||||
|
@ -208,38 +237,32 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
NodeIOTypes::new(
|
||||
concrete!(()),
|
||||
concrete!(ImageFrame<Color>),
|
||||
vec![value_fn!(ImageFrame<Color>), value_fn!(ImageFrame<Color>), value_fn!(ImageFrame<Color>), value_fn!(ImageFrame<Color>)],
|
||||
vec![fn_type!(ImageFrame<Color>), fn_type!(ImageFrame<Color>), fn_type!(ImageFrame<Color>), fn_type!(ImageFrame<Color>)],
|
||||
),
|
||||
)],
|
||||
register_node!(graphene_std::raster::EmptyImageNode<_, _>, input: DAffine2, params: [Color]),
|
||||
register_node!(graphene_std::memo::MonitorNode<_>, input: ImageFrame<Color>, params: []),
|
||||
register_node!(graphene_std::memo::MonitorNode<_>, input: graphene_core::GraphicGroup, params: []),
|
||||
register_node!(graphene_core::wasm_application_io::CreateSurfaceNode, input: &graphene_core::EditorApi, params: []),
|
||||
vec![(
|
||||
NodeIdentifier::new("graphene_core::wasm_application_io::DrawImageFrameNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let surface: DowncastBothNode<(), Arc<WasmSurfaceHandle>> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_core::wasm_application_io::DrawImageFrameNode::new(surface);
|
||||
let any: DynAnyNode<ImageFrame<SRGBA8>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(ImageFrame<SRGBA8>), concrete!(WasmSurfaceHandleFrame), vec![value_fn!(Arc<WasmSurfaceHandle>)]),
|
||||
)],
|
||||
register_node!(graphene_core::memo::MonitorNode<_>, input: ImageFrame<Color>, params: []),
|
||||
register_node!(graphene_core::memo::MonitorNode<_>, input: graphene_core::GraphicGroup, params: []),
|
||||
register_node!(graphene_core::wasm_application_io::CreateSurfaceNode, input: graphene_core::EditorApi, params: []),
|
||||
async_node!(
|
||||
graphene_core::wasm_application_io::DrawImageFrameNode<_>,
|
||||
input: ImageFrame<SRGBA8>,
|
||||
output: WasmSurfaceHandleFrame,
|
||||
params: [Arc<WasmSurfaceHandle>]
|
||||
),
|
||||
#[cfg(feature = "gpu")]
|
||||
vec![(
|
||||
NodeIdentifier::new("graphene_std::executor::MapGpuSingleImageNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let document_node: DowncastBothNode<(), DocumentNode> = DowncastBothNode::new(args[0]);
|
||||
let document_node: DowncastBothNode<(), graph_craft::document::DocumentNode> = DowncastBothNode::new(args[0]);
|
||||
//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
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(DocumentNode)]),
|
||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![fn_type!(graph_craft::document::DocumentNode)]),
|
||||
)],
|
||||
#[cfg(feature = "gpu")]
|
||||
vec![(
|
||||
|
@ -258,7 +281,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
NodeIOTypes::new(
|
||||
concrete!(ImageFrame<Color>),
|
||||
concrete!(ImageFrame<Color>),
|
||||
vec![value_fn!(ImageFrame<Color>), value_fn!(BlendMode), value_fn!(f32)],
|
||||
vec![fn_type!(ImageFrame<Color>), fn_type!(BlendMode), fn_type!(f32)],
|
||||
),
|
||||
)],
|
||||
vec![(
|
||||
|
@ -327,28 +350,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
NodeIOTypes::new(
|
||||
concrete!(()),
|
||||
concrete!(ImageFrame<Color>),
|
||||
vec![value_fn!(ImageFrame<Color>), value_fn!(ImageFrame<Color>), value_fn!(Vec<BrushStroke>)],
|
||||
),
|
||||
)],
|
||||
vec![(
|
||||
NodeIdentifier::new("graphene_std::brush::ReduceNode<_, _>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let acc: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let image = acc.eval(()).await;
|
||||
let blend_node = graphene_core::raster::BlendNode::new(ClonedNode::new(BlendMode::Normal), ClonedNode::new(1.0));
|
||||
let _ = &blend_node as &dyn for<'i> Node<'i, (Color, Color), Output = Color>;
|
||||
let node = ReduceNode::new(ClonedNode::new(image), ValueNode::new(BlendImageTupleNode::new(ValueNode::new(blend_node))));
|
||||
//let _ = &node as &dyn for<'i> Node<'i, core::slice::Iter<ImageFrame<Color>>, Output = ImageFrame<Color>>;
|
||||
let node = FutureWrapperNode::new(node);
|
||||
let any: DynAnyNode<Box<dyn Iterator<Item = ImageFrame<Color>> + Sync + Send>, _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(node));
|
||||
any.into_type_erased()
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(
|
||||
concrete!(Box<dyn Iterator<Item = &ImageFrame<Color>> + Sync + Send>),
|
||||
concrete!(ImageFrame<Color>),
|
||||
vec![value_fn!(ImageFrame<Color>)],
|
||||
vec![fn_type!(ImageFrame<Color>), fn_type!(ImageFrame<Color>), fn_type!(Vec<BrushStroke>)],
|
||||
),
|
||||
)],
|
||||
// Filters
|
||||
|
@ -374,7 +376,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
NodeIOTypes::new(
|
||||
concrete!(ImageFrame<Color>),
|
||||
concrete!(ImageFrame<Color>),
|
||||
vec![value_fn!(ImageFrame<Color>), value_fn!(BlendMode), value_fn!(f64)],
|
||||
vec![fn_type!(ImageFrame<Color>), fn_type!(BlendMode), fn_type!(f64)],
|
||||
),
|
||||
)],
|
||||
raster_node!(graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>, params: [Color, f64, f64, f64, f64, f64, f64]),
|
||||
|
@ -417,265 +419,59 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
}
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(f64), value_fn!(f64), value_fn!(bool)]),
|
||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![fn_type!(f64), fn_type!(f64), fn_type!(bool)]),
|
||||
)],
|
||||
raster_node!(graphene_core::raster::OpacityNode<_>, params: [f64]),
|
||||
raster_node!(graphene_core::raster::PosterizeNode<_>, params: [f64]),
|
||||
raster_node!(graphene_core::raster::ExposureNode<_, _, _>, params: [f64, f64, f64]),
|
||||
vec![
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::LetNode<_>"),
|
||||
|_| {
|
||||
Box::pin(async move {
|
||||
let node: LetNode<ImageFrame<Color>> = graphene_std::memo::LetNode::new();
|
||||
let any = graphene_std::any::DynAnyRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(Option<ImageFrame<Color>>), concrete!(&ImageFrame<Color>), vec![]),
|
||||
register_node!(graphene_core::memo::LetNode<_>, input: Option<ImageFrame<Color>>, params: []),
|
||||
register_node!(graphene_core::memo::LetNode<_>, input: Option<graphene_core::EditorApi>, params: []),
|
||||
async_node!(
|
||||
graphene_core::memo::EndLetNode<_>,
|
||||
input: graphene_core::EditorApi,
|
||||
output: ImageFrame<Color>,
|
||||
params: [ImageFrame<Color>]
|
||||
),
|
||||
async_node!(graphene_core::memo::EndLetNode<_>, input: graphene_core::EditorApi, output: VectorData, params: [VectorData]),
|
||||
async_node!(
|
||||
graphene_core::memo::EndLetNode<_>,
|
||||
input: graphene_core::EditorApi,
|
||||
output: graphene_core::GraphicGroup,
|
||||
params: [graphene_core::GraphicGroup]
|
||||
),
|
||||
async_node!(
|
||||
graphene_core::memo::EndLetNode<_>,
|
||||
input: graphene_core::EditorApi,
|
||||
output: graphene_core::Artboard,
|
||||
params: [graphene_core::Artboard]
|
||||
),
|
||||
async_node!(
|
||||
graphene_core::memo::EndLetNode<_>,
|
||||
input: graphene_core::EditorApi,
|
||||
output: WasmSurfaceHandleFrame,
|
||||
params: [WasmSurfaceHandleFrame]
|
||||
),
|
||||
vec![(
|
||||
NodeIdentifier::new("graphene_core::memo::RefNode<_, _>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
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
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(
|
||||
concrete!(()),
|
||||
concrete!(graphene_core::EditorApi),
|
||||
vec![fn_type!(Option<graphene_core::EditorApi>, graphene_core::EditorApi)],
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::LetNode<_>"),
|
||||
|_| {
|
||||
Box::pin(async move {
|
||||
let node: LetNode<graphene_core::EditorApi> = graphene_std::memo::LetNode::new();
|
||||
let any = graphene_std::any::DynAnyRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(Option<graphene_core::EditorApi>), concrete!(&graphene_core::EditorApi), vec![]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||
Box::pin(any) as TypeErasedPinned<'_>
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(generic!(T), concrete!(ImageFrame<Color>), vec![value_fn!(ImageFrame<Color>)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), VectorData> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(generic!(T), concrete!(VectorData), vec![value_fn!(VectorData)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), graphene_core::GraphicGroup> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(generic!(T), concrete!(graphene_core::GraphicGroup), vec![value_fn!(graphene_core::GraphicGroup)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), graphene_core::Artboard> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(generic!(T), concrete!(graphene_core::Artboard), vec![value_fn!(graphene_core::Artboard)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), WasmSurfaceHandleFrame> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(generic!(T), concrete!(WasmSurfaceHandleFrame), vec![value_fn!(WasmSurfaceHandleFrame)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::RefNode<_, _>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let map_fn: DowncastBothNode<Option<graphene_core::EditorApi>, &graphene_core::EditorApi> = DowncastBothNode::new(args[0]);
|
||||
//let map_fn = map_fn.then(EvalSyncNode::new());
|
||||
let node = graphene_std::memo::RefNode::new(map_fn);
|
||||
let any = graphene_std::any::DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(
|
||||
concrete!(()),
|
||||
concrete!(&graphene_core::EditorApi),
|
||||
vec![fn_type!(Option<graphene_core::EditorApi>, &graphene_core::EditorApi)],
|
||||
),
|
||||
),
|
||||
/*
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::raster::ImaginateNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let cached = graphene_std::any::input_node::<Option<std::sync::Arc<Image<Color>>>>(args[15]);
|
||||
let cached = cached.then(EvalSyncNode::new());
|
||||
let node = graphene_std::raster::ImaginateNode::new(cached);
|
||||
let node = FutureWrapperNode::new(node);
|
||||
let any = DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(
|
||||
concrete!(ImageFrame<Color>),
|
||||
concrete!(ImageFrame<Color>),
|
||||
vec![
|
||||
value_fn!(f64),
|
||||
value_fn!(Option<DVec2>),
|
||||
value_fn!(f64),
|
||||
value_fn!(ImaginateSamplingMethod),
|
||||
value_fn!(f64),
|
||||
value_fn!(String),
|
||||
value_fn!(String),
|
||||
value_fn!(bool),
|
||||
value_fn!(f64),
|
||||
value_fn!(Option<Vec<u64>>),
|
||||
value_fn!(bool),
|
||||
value_fn!(f64),
|
||||
value_fn!(ImaginateMaskStartingFill),
|
||||
value_fn!(bool),
|
||||
value_fn!(bool),
|
||||
value_fn!(Option<std::sync::Arc<Image<Color>>>),
|
||||
value_fn!(f64),
|
||||
value_fn!(ImaginateStatus),
|
||||
],
|
||||
),
|
||||
),
|
||||
*/
|
||||
/*
|
||||
(
|
||||
NodeIdentifier::new("graphene_core::raster::BlurNode"),
|
||||
|args| {
|
||||
let radius = DowncastBothNode::<(), u32>::new(args[0]);
|
||||
let sigma = DowncastBothNode::<(), f64>::new(args[1]);
|
||||
let image = DowncastBothRefNode::<Image<Color>, Image<Color>>::new(args[2]);
|
||||
let image = image.then(EvalSyncNode::new());
|
||||
let empty_image: ValueNode<Image<Color>> = ValueNode::new(Image::empty());
|
||||
let empty: TypeNode<_, (), Image<Color>> = TypeNode::new(empty_image.then(CloneNode::new()));
|
||||
use graphene_core::Node;
|
||||
let radius = ClonedNode::new(radius.eval(()));
|
||||
let sigma = ClonedNode::new(sigma.eval(()));
|
||||
|
||||
//let image = &image as &dyn for<'a> Node<'a, (), Output = &'a Image>;
|
||||
// dirty hack: we abuse that the cache node will ignore the input if it is evaluated a second time
|
||||
let image = empty.then(image).then(ImageRefNode::new());
|
||||
|
||||
let window = WindowNode::new(radius, image.clone());
|
||||
let map_gaussian = MapSndNode::new(ValueNode::new(DistanceNode.then(GaussianNode::new(sigma))));
|
||||
let map_distances = MapNode::new(ValueNode::new(map_gaussian));
|
||||
let gaussian_iter = window.then(map_distances);
|
||||
let avg = gaussian_iter.then(WeightedAvgNode::new());
|
||||
let avg: TypeNode<_, u32, Color> = TypeNode::new(avg);
|
||||
let blur_iter = MapNode::new(ValueNode::new(avg));
|
||||
let pixel_iter = image.clone().then(ImageIndexIterNode::new());
|
||||
let blur = pixel_iter.then(blur_iter);
|
||||
let collect = CollectNode {};
|
||||
let vec = blur.then(collect);
|
||||
let new_image = MapImageSliceNode::new(vec);
|
||||
let dimensions = image.then(ImageDimensionsNode::new());
|
||||
let dimensions: TypeNode<_, (), (u32, u32)> = TypeNode::new(dimensions);
|
||||
let new_image = dimensions.then(new_image);
|
||||
let new_image = ForgetNode::new().then(new_image);
|
||||
let new_image = FutureWrapperNode::new(new_image);
|
||||
let node: DynAnyNode<&Image<Color>, _, _> = DynAnyNode::new(ValueNode::new(new_image));
|
||||
Box::pin(node)
|
||||
},
|
||||
NodeIOTypes::new(concrete!(Image<Color>), concrete!(Image<Color>), vec![value_fn!(u32), value_fn!(f64)]),
|
||||
),
|
||||
//register_node!(graphene_std::memo::CacheNode<_>, input: Image<Color>, params: []),
|
||||
*/
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), Image<Color>> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<Image<Color>, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(()), concrete!(Image<Color>), vec![value_fn!(Image<Color>)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<ImageFrame<Color>, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(()), concrete!(ImageFrame<Color>), vec![value_fn!(ImageFrame<Color>)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<ImageFrame<Color>, ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<ImageFrame<Color>, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![fn_type!(ImageFrame<Color>, ImageFrame<Color>)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), QuantizationChannels> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<QuantizationChannels, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(()), concrete!(QuantizationChannels), vec![value_fn!(QuantizationChannels)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), Vec<DVec2>> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<Vec<DVec2>, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(()), concrete!(Vec<DVec2>), vec![value_fn!(Vec<DVec2>)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), Arc<WasmSurfaceHandle>> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<Arc<WasmSurfaceHandle>, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(()), concrete!(Arc<WasmSurfaceHandle>), vec![value_fn!(Arc<WasmSurfaceHandle>)]),
|
||||
),
|
||||
],
|
||||
)],
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: Image<Color>, params: [Image<Color>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: ImageFrame<Color>, params: [ImageFrame<Color>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: QuantizationChannels, params: [QuantizationChannels]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: Vec<DVec2>, params: [Vec<DVec2>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: Arc<WasmSurfaceHandle>, params: [Arc<WasmSurfaceHandle>]),
|
||||
register_node!(graphene_core::structural::ConsNode<_, _>, input: Image<Color>, params: [&str]),
|
||||
register_node!(graphene_std::raster::ImageFrameNode<_, _>, input: Image<Color>, params: [DAffine2]),
|
||||
#[cfg(feature = "quantization")]
|
||||
|
@ -698,9 +494,9 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
input: Vec<graphene_core::vector::bezier_rs::Subpath<graphene_core::uuid::ManipulatorGroupId>>,
|
||||
params: [Vec<graphene_core::uuid::ManipulatorGroupId>]
|
||||
),
|
||||
register_node!(graphene_core::text::TextGenerator<_, _, _>, input: &graphene_core::EditorApi, params: [String, graphene_core::text::Font, f64]),
|
||||
register_node!(graphene_core::text::TextGenerator<_, _, _>, input: graphene_core::EditorApi, params: [String, graphene_core::text::Font, f64]),
|
||||
register_node!(graphene_std::brush::VectorPointsNode, input: VectorData, params: []),
|
||||
register_node!(graphene_core::ExtractImageFrame, input: &graphene_core::EditorApi, params: []),
|
||||
register_node!(graphene_core::ExtractImageFrame, input: graphene_core::EditorApi, params: []),
|
||||
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::vector::VectorData, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
|
||||
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: ImageFrame<Color>, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
|
||||
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::GraphicGroup, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
|
||||
|
|
|
@ -86,16 +86,14 @@ fn args(node: &syn::PathSegment) -> Vec<Type> {
|
|||
fn node_impl_proxy(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let fn_item = item.clone();
|
||||
let function = parse_macro_input!(fn_item as ItemFn);
|
||||
let sync_input = if function.sig.asyncness.is_some() {
|
||||
if function.sig.asyncness.is_some() {
|
||||
node_impl_impl(attr, item, Asyncness::AllAsync)
|
||||
} else {
|
||||
node_impl_impl(attr, item, Asyncness::Sync)
|
||||
};
|
||||
sync_input
|
||||
}
|
||||
}
|
||||
enum Asyncness {
|
||||
Sync,
|
||||
AsyncOut,
|
||||
AllAsync,
|
||||
}
|
||||
|
||||
|
@ -111,7 +109,7 @@ fn node_impl_impl(attr: TokenStream, item: TokenStream, asyncness: Asyncness) ->
|
|||
|
||||
let async_out = match asyncness {
|
||||
Asyncness::Sync => false,
|
||||
Asyncness::AsyncOut | Asyncness::AllAsync => true,
|
||||
Asyncness::AllAsync => true,
|
||||
};
|
||||
let async_in = matches!(asyncness, Asyncness::AllAsync);
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use std::error::Error;
|
||||
|
||||
use super::context::Context;
|
||||
|
||||
use graph_craft::executor::{Any, Executor};
|
||||
use graph_craft::executor::Executor;
|
||||
|
||||
use graph_craft::proto::LocalFuture;
|
||||
use graphene_core::gpu::PushConstants;
|
||||
|
@ -38,9 +40,8 @@ impl<I: StaticTypeSized, O> GpuExecutor<I, O> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync + Pod> Executor for GpuExecutor<I, O> {
|
||||
fn execute<'i>(&'i self, input: Any<'i>) -> LocalFuture<Result<Any<'i>, Box<dyn std::error::Error>>> {
|
||||
let input = dyn_any::downcast::<Vec<I>>(input).expect("Wrong input type");
|
||||
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>>> {
|
||||
let context = &self.context;
|
||||
let result: Vec<O> = execute_shader(
|
||||
context.device.clone(),
|
||||
|
@ -48,9 +49,9 @@ impl<I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync +
|
|||
self.shader.entry_point(&self.entry_point).expect("Entry point not found in shader"),
|
||||
&context.allocator,
|
||||
&context.command_buffer_allocator,
|
||||
*input,
|
||||
input,
|
||||
);
|
||||
Box::pin(async move { Ok(Box::new(result) as Any) })
|
||||
Box::pin(async move { Ok(result) })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
use std::borrow::Cow;
|
||||
use std::sync::Arc;
|
||||
use std::{borrow::Cow, error::Error};
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
use super::context::Context;
|
||||
use bytemuck::Pod;
|
||||
use dyn_any::StaticTypeSized;
|
||||
use graph_craft::{
|
||||
executor::{Any, Executor},
|
||||
proto::LocalFuture,
|
||||
};
|
||||
use graph_craft::{executor::Executor, proto::LocalFuture};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GpuExecutor<'a, I: StaticTypeSized, O> {
|
||||
|
@ -29,16 +26,15 @@ impl<'a, I: StaticTypeSized, O> GpuExecutor<'a, I, O> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, I: StaticTypeSized + Sync + Pod + Send, O: StaticTypeSized + Send + Sync + Pod> Executor for GpuExecutor<'a, I, O> {
|
||||
fn execute<'i>(&'i self, input: Any<'i>) -> LocalFuture<Result<Any<'i>, Box<dyn std::error::Error>>> {
|
||||
let input = dyn_any::downcast::<Vec<I>>(input).expect("Wrong input type");
|
||||
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>>> {
|
||||
let context = &self.context;
|
||||
let future = execute_shader(context.device.clone(), context.queue.clone(), self.shader.to_vec(), *input, self.entry_point.clone());
|
||||
let future = execute_shader(context.device.clone(), context.queue.clone(), self.shader.to_vec(), input, self.entry_point.clone());
|
||||
Box::pin(async move {
|
||||
let result = future.await;
|
||||
|
||||
let result: Vec<O> = result.ok_or_else(|| String::from("Failed to execute shader"))?;
|
||||
Ok(Box::new(result) as Any)
|
||||
Ok(result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue