Add comments to help explain Graphene concepts
This commit is contained in:
parent
ee08938bb0
commit
bafde43145
|
|
@ -93,6 +93,7 @@ impl NodeImplementation {
|
|||
}
|
||||
}
|
||||
|
||||
/// Acts as a description for a [DocumentNode] before it gets instantiated as one.
|
||||
#[derive(Clone)]
|
||||
pub struct DocumentNodeType {
|
||||
pub name: &'static str,
|
||||
|
|
@ -125,6 +126,8 @@ impl Default for DocumentNodeType {
|
|||
static DOCUMENT_NODE_TYPES: once_cell::sync::Lazy<Vec<DocumentNodeType>> = once_cell::sync::Lazy::new(static_nodes);
|
||||
|
||||
// TODO: Dynamic node library
|
||||
/// Defines the "signature" or "header file"-like metadata for the document nodes, but not the implementation (which is defined in the node registry).
|
||||
/// The document node is the instance while these are the "class" (or "blueprint").
|
||||
fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
vec![
|
||||
DocumentNodeType {
|
||||
|
|
@ -498,7 +501,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
name: "Frame",
|
||||
data_type: FrontendGraphDataType::Raster,
|
||||
}],
|
||||
properties: |_document_node, _node_id, _context| node_properties::string_properties("The graph's output is drawn in the layer"),
|
||||
properties: |_document_node, _node_id, _context| node_properties::string_properties("Consumes the scope opened by the Begin Scope node and evaluates the contained node network"),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeType {
|
||||
|
|
@ -798,8 +801,11 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
category: "Image Adjustments",
|
||||
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
||||
inputs: vec![0],
|
||||
outputs: vec![NodeOutput::new(4, 0), NodeOutput::new(1, 0), NodeOutput::new(2, 0), NodeOutput::new(3, 0), NodeOutput::new(4, 0)],
|
||||
outputs: vec![NodeOutput::new(1, 0), NodeOutput::new(2, 0), NodeOutput::new(3, 0), NodeOutput::new(4, 0)],
|
||||
nodes: [
|
||||
// The input image feeds into the identity, then we take its passed-through value when the other channels are reading from it instead of the original input.
|
||||
// We do this for technical restrictions imposed by Graphene which doesn't allow an input to feed into multiple interior nodes in the subgraph.
|
||||
// Diagram: <https://files.keavon.com/-/AchingSecondHypsilophodon/capture.png>
|
||||
DocumentNode {
|
||||
name: "Identity".to_string(),
|
||||
inputs: vec![NodeInput::Network(concrete!(ImageFrame<Color>))],
|
||||
|
|
|
|||
|
|
@ -2,6 +2,25 @@ use core::marker::PhantomData;
|
|||
|
||||
use crate::{Node, NodeMut};
|
||||
|
||||
// This is how we can generically define composition of two nodes.
|
||||
// This is done generically as shown: <https://files.keavon.com/-/SurprisedGaseousAnhinga/capture.png>
|
||||
// A concrete example: <https://files.keavon.com/-/ExcitableGoldRay/capture.png>
|
||||
// And showing the direction of data flow: <https://files.keavon.com/-/SoreShimmeringElephantseal/capture.png>
|
||||
/// ┌────────────────┐
|
||||
/// T │ │ U
|
||||
/// ───────────►│ Compose Node ├───────────►
|
||||
/// │ │
|
||||
/// └────┬───────────┤
|
||||
/// ┌──────────┐ │ │
|
||||
/// │ │ T -> V │ │
|
||||
/// │ First ├─────────────►│ │
|
||||
/// │ │ │ │
|
||||
/// └──────────┘ │ │
|
||||
/// ┌──────────┐ │ │
|
||||
/// │ │ V -> U │ │
|
||||
/// │ Second ├─────────────►│ │
|
||||
/// │ │ └───────────┘
|
||||
/// └──────────┘
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ComposeNode<First, Second, I> {
|
||||
first: First,
|
||||
|
|
|
|||
|
|
@ -102,12 +102,18 @@ impl PartialEq for TypeDescriptor {
|
|||
}
|
||||
}
|
||||
|
||||
/// Graph runtime type information used for type inference.
|
||||
#[derive(Clone, PartialEq, Eq, Hash, specta::Type)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Type {
|
||||
/// A wrapper for some type variable used within the inference system. Resolved at inference time and replaced with a concrete type.
|
||||
Generic(Cow<'static, str>),
|
||||
/// A wrapper around the Rust type id for any concrete Rust type. Allows us to do equality comparisons, like checking if a String == a String.
|
||||
Concrete(TypeDescriptor),
|
||||
/// Runtime type information for a function. Given some input, gives some output.
|
||||
/// See the example and explanation in the `ComposeNode` implementation within the node registry for more info.
|
||||
Fn(Box<Type>, Box<Type>),
|
||||
/// Not used at the moment.
|
||||
Future(Box<Type>),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -141,18 +141,30 @@ impl DocumentNode {
|
|||
}
|
||||
|
||||
/// Represents the possible inputs to a node.
|
||||
#[derive(Debug, Clone, PartialEq, Hash, DynAny)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum NodeInput {
|
||||
/// A reference to another node in the same network from which this node can receive its input.
|
||||
Node { node_id: NodeId, output_index: usize, lambda: bool },
|
||||
|
||||
/// A hardcoded value that can't change after the graph is compiled. Gets converted into a value node during graph compilation.
|
||||
Value { tagged_value: TaggedValue, exposed: bool },
|
||||
|
||||
/// Input that is provided by the parent network to this document node, instead of from a hardcoded value or another node within the same network.
|
||||
Network(Type),
|
||||
|
||||
/// A short circuting input represents an input that is not resolved through function composition
|
||||
/// but rather by actually consuming the provided input instead of passing it to its predecessor.
|
||||
///
|
||||
/// # More about short circuting
|
||||
///
|
||||
/// In Graphite nodes are functions and by default, these are composed into a single function
|
||||
/// by inserting Compose nodes.
|
||||
/// In Graphite nodes are functions, and by default these are composed into a single function
|
||||
/// by automatic insertion of inserting Compose nodes.
|
||||
///
|
||||
/// ```text
|
||||
/// ┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐
|
||||
/// │ │◄──────────────┤ │◄───────────────┤ │
|
||||
/// ┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
||||
/// │ │◄───┤ │◄───┤ │
|
||||
/// │ A │ │ B │ │ C │
|
||||
/// │ ├──────────────►│ ├───────────────►│ │
|
||||
/// └─────────────────┘ └──────────────────┘ └──────────────────┘
|
||||
/// │ ├───►│ ├───►│ │
|
||||
/// └───────────────┘ └───────────────┘ └───────────────┘
|
||||
/// ```
|
||||
///
|
||||
/// This is equivalent to calling c(b(a(input))) when evaluating c with input ( `c.eval(input)`).
|
||||
|
|
@ -160,36 +172,24 @@ impl DocumentNode {
|
|||
/// This is why we allow nodes to opt out of the input forwarding by consuming the input directly.
|
||||
///
|
||||
/// ```text
|
||||
/// ┌─────────────────────┐ ┌─────────────┐
|
||||
/// │ │◄───────────────┤ │
|
||||
/// ┌───────────────┐ ┌───────────────┐
|
||||
/// │ │◄───┤ │
|
||||
/// │ Cache Node │ │ C │
|
||||
/// │ ├───────────────►│ │
|
||||
/// ┌──────────────────┐ ├─────────────────────┤ └─────────────┘
|
||||
/// │ │◄──────────────┤ │
|
||||
/// │ ├───►│ │
|
||||
/// ┌───────────────┐ ├───────────────┤ └───────────────┘
|
||||
/// │ │◄───┤ │
|
||||
/// │ A │ │ * Cached Node │
|
||||
/// │ ├──────────────►│ │
|
||||
/// └──────────────────┘ └─────────────────────┘
|
||||
/// │ ├───►│ │
|
||||
/// └───────────────┘ └───────────────┘
|
||||
/// ```
|
||||
///
|
||||
/// In this case the Cache node actually consumes its input and then manually forwards it to its parameter Node.
|
||||
/// This is necessary because the Cache Node needs to short-circut the actual node evaluation.
|
||||
#[derive(Debug, Clone, PartialEq, Hash, DynAny)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum NodeInput {
|
||||
Node {
|
||||
node_id: NodeId,
|
||||
output_index: usize,
|
||||
lambda: bool,
|
||||
},
|
||||
Value {
|
||||
tagged_value: TaggedValue,
|
||||
exposed: bool,
|
||||
},
|
||||
Network(Type),
|
||||
/// A short circuting input represents an input that is not resolved through function composition
|
||||
/// but actually consuming the provided input instead of passing it to its predecessor.
|
||||
/// See [NodeInput] docs for more explanation.
|
||||
// TODO: Update
|
||||
// ShortCircut(Type),
|
||||
|
||||
/// A Rust source code string. Allows us to insert literal Rust code. Only used for GPU compilation.
|
||||
/// We can use this whenever we spin up Rustc. Sort of like inline assembly, but because our language is Rust, it acts as inline Rust.
|
||||
Inline(InlineRust),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -423,6 +423,8 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
node.into_type_erased()
|
||||
})
|
||||
},
|
||||
// This is how we can generically define composition of two nodes.
|
||||
// See further details in the code definition for the `struct ComposeNode<First, Second, I> { ... }` struct.
|
||||
NodeIOTypes::new(
|
||||
generic!(T),
|
||||
generic!(U),
|
||||
|
|
|
|||
Loading…
Reference in New Issue