mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-19 19:08:05 +08:00
WIP: Thumbnails
This commit is contained in:
@@ -6,7 +6,9 @@ fn compile_to_proto(c: &mut Criterion) {
|
||||
|
||||
for name in DEMO_ART {
|
||||
let network = load_from_name(name);
|
||||
c.bench_function(name, |b: &mut criterion::Bencher<'_>| b.iter_batched(|| network.clone(), |mut network| black_box(network.flatten()), criterion::BatchSize::SmallInput));
|
||||
c.bench_function(name, |b: &mut criterion::Bencher<'_>| {
|
||||
b.iter_batched(|| network.clone(), |mut network| black_box(network.compile()), criterion::BatchSize::SmallInput)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ use iai_callgrind::{black_box, library_benchmark, library_benchmark_group, main}
|
||||
#[library_benchmark]
|
||||
#[benches::with_setup(args = ["isometric-fountain", "painted-dreams", "procedural-string-lights", "parametric-dunescape", "red-dress", "valley-of-spires"], setup = load_from_name)]
|
||||
pub fn compile_to_proto(mut input: NodeNetwork) {
|
||||
let _ = black_box(input.flatten());
|
||||
let _ = black_box(input.compile());
|
||||
}
|
||||
|
||||
library_benchmark_group!(name = compile_group; benchmarks = compile_to_proto);
|
||||
|
||||
@@ -40,6 +40,9 @@ pub struct DocumentNode {
|
||||
/// Represents the eye icon for hiding/showing the node in the graph UI. When hidden, a node gets replaced with an identity node during the graph flattening step.
|
||||
#[serde(default = "return_true")]
|
||||
pub visible: bool,
|
||||
// Represents whether the output of the node should be cached. This is set to true whenever a node feeds into another node with more context dependencies
|
||||
#[serde(default)]
|
||||
pub cache_output: bool,
|
||||
pub manual_composition: Option<Type>,
|
||||
#[serde(default)]
|
||||
pub skip_deduplication: bool,
|
||||
@@ -50,6 +53,7 @@ impl Hash for DocumentNode {
|
||||
self.inputs.hash(state);
|
||||
self.implementation.hash(state);
|
||||
self.visible.hash(state);
|
||||
self.cache_output.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +63,7 @@ impl Default for DocumentNode {
|
||||
inputs: Default::default(),
|
||||
implementation: Default::default(),
|
||||
visible: true,
|
||||
cache_output: false,
|
||||
manual_composition: Some(generic!(T)),
|
||||
skip_deduplication: false,
|
||||
}
|
||||
@@ -518,7 +523,7 @@ impl NodeNetwork {
|
||||
/// Functions for compiling the network
|
||||
impl NodeNetwork {
|
||||
// Returns a topologically sorted vec of protonodes, as well as metadata extracted during compilation
|
||||
pub fn flatten(&mut self) -> Result<(ProtoNetwork, Vec<(OriginalLocation, SNI)>), String> {
|
||||
pub fn compile(&mut self) -> Result<(ProtoNetwork, Vec<(OriginalLocation, SNI)>), String> {
|
||||
// These three arrays are stored in parallel
|
||||
let mut protonetwork = Vec::new();
|
||||
|
||||
@@ -544,8 +549,8 @@ impl NodeNetwork {
|
||||
let Some(upstream_metadata) = upstream_metadata else {
|
||||
panic!("All inputs should be when the upstream SNI was generated");
|
||||
};
|
||||
if upstream_metadata.is_value {
|
||||
context_dependencies.add_dependencies(&upstream_metadata.context_dependencies);
|
||||
if !upstream_metadata.is_value {
|
||||
context_dependencies.add_dependencies(&upstream_metadata.nullify);
|
||||
}
|
||||
}
|
||||
// The context_dependencies are now the union of all inputs and the dependencies of the protonode. Set the dependencies of each input to the difference, which represents the data to nullify
|
||||
@@ -554,9 +559,9 @@ impl NodeNetwork {
|
||||
panic!("All inputs should be when the upstream SNI was generated");
|
||||
};
|
||||
match upstream_metadata.is_value {
|
||||
true => upstream_metadata.context_dependencies.difference(&context_dependencies),
|
||||
false => upstream_metadata.nullify.difference(&context_dependencies),
|
||||
// If the upstream node is a Value node, do not nullify the context
|
||||
false => upstream_metadata.context_dependencies = ContextDependencies::none(),
|
||||
true => upstream_metadata.nullify = ContextDependencies::none(),
|
||||
}
|
||||
}
|
||||
(context_dependencies.clone(), false)
|
||||
@@ -575,10 +580,7 @@ impl NodeNetwork {
|
||||
};
|
||||
(deduplicated_protonode.callers, deduplicated_protonode.original_location)
|
||||
} else {
|
||||
(
|
||||
std::mem::take(&mut protonode.callers),
|
||||
std::mem::replace(&mut protonode.original_location, OriginalLocation::Node(Vec::new())),
|
||||
)
|
||||
(std::mem::take(&mut protonode.callers), protonode.original_location.clone())
|
||||
};
|
||||
|
||||
// Map the callers inputs to the generated stable node id
|
||||
@@ -592,7 +594,7 @@ impl NodeNetwork {
|
||||
assert!(caller_index > current_protonode_index, "Caller index must be higher than current index");
|
||||
nodes.inputs[input_index] = Some(UpstreamInputMetadata {
|
||||
input_sni: stable_node_id,
|
||||
context_dependencies: protonode_context_dependencies.clone(),
|
||||
nullify: protonode_context_dependencies.clone(),
|
||||
is_value: upstream_is_value,
|
||||
})
|
||||
}
|
||||
@@ -726,7 +728,7 @@ impl NodeNetwork {
|
||||
log::error!("The node which was supposed to be flattened does not exist in the network, id {upstream_node_id}");
|
||||
return;
|
||||
};
|
||||
|
||||
let cache_output = upstream_document_node.cache_output;
|
||||
match &upstream_document_node.implementation {
|
||||
DocumentNodeImplementation::Network(_node_network) => {
|
||||
let traversal_input = AbsoluteInputConnector {
|
||||
@@ -766,6 +768,7 @@ impl NodeNetwork {
|
||||
identifier,
|
||||
inputs: vec![None; number_of_inputs],
|
||||
context_dependencies,
|
||||
cache_output,
|
||||
});
|
||||
let protonode = ProtoNode {
|
||||
construction_args,
|
||||
|
||||
@@ -13,6 +13,7 @@ use graphene_core::uuid::NodeId;
|
||||
use graphene_core::vector::style::Fill;
|
||||
use graphene_core::{Color, MemoHash, Node, Type};
|
||||
use graphene_svg_renderer::{GraphicElementRendered, RenderMetadata};
|
||||
use std::cell::Cell;
|
||||
use std::fmt::Display;
|
||||
use std::hash::Hash;
|
||||
use std::marker::PhantomData;
|
||||
@@ -396,6 +397,7 @@ impl Display for TaggedValue {
|
||||
|
||||
pub struct UpcastNode {
|
||||
value: MemoHash<TaggedValue>,
|
||||
inspected: Cell<bool>,
|
||||
}
|
||||
impl<'input> Node<'input, DAny<'input>> for UpcastNode {
|
||||
type Output = FutureAny<'input>;
|
||||
@@ -403,10 +405,15 @@ impl<'input> Node<'input, DAny<'input>> for UpcastNode {
|
||||
fn eval(&'input self, _: DAny<'input>) -> Self::Output {
|
||||
Box::pin(async move { self.value.clone().into_inner().to_dynany() })
|
||||
}
|
||||
|
||||
fn introspect(&self) -> graphene_core::memo::MonitorIntrospectResult {
|
||||
let inspected = self.inspected.replace(true);
|
||||
graphene_core::memo::MonitorIntrospectResult::Evaluated((Arc::new(self.value.clone().into_inner()) as Arc<dyn std::any::Any + Send + Sync>, !inspected))
|
||||
}
|
||||
}
|
||||
impl UpcastNode {
|
||||
pub fn new(value: MemoHash<TaggedValue>) -> Self {
|
||||
Self { value }
|
||||
Self { value, inspected: Cell::new(false) }
|
||||
}
|
||||
}
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
@@ -426,8 +433,6 @@ impl<T: AsRef<U> + Sync + Send, U: Sync + Send> UpcastAsRefNode<T, U> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, dyn_any::DynAny, serde::Serialize, serde::Deserialize)]
|
||||
pub struct RenderOutput {
|
||||
pub data: RenderOutputType,
|
||||
@@ -540,25 +545,13 @@ mod fake_hash {
|
||||
|
||||
macro_rules! thumbnail_render {
|
||||
( $( $ty:ty ),* $(,)? ) => {
|
||||
pub fn render_thumbnail_if_change(new_value: &Arc<dyn std::any::Any + Send + Sync>, old_value: Option<&Arc<dyn std::any::Any + Send + Sync>>) -> ThumbnailRenderResult {
|
||||
pub fn render_thumbnail(new_value: &Arc<dyn std::any::Any + Send + Sync>) -> Option<String> {
|
||||
$(
|
||||
if let Some(new_value) = new_value.downcast_ref::<$ty>() {
|
||||
match old_value {
|
||||
None => return ThumbnailRenderResult::UpdateThumbnail(new_value.render_thumbnail()),
|
||||
Some(old_value) => {
|
||||
if let Some(old_value) = old_value.downcast_ref::<$ty>() {
|
||||
match new_value == old_value {
|
||||
true => return ThumbnailRenderResult::NoChange,
|
||||
false => return ThumbnailRenderResult::UpdateThumbnail(new_value.render_thumbnail())
|
||||
}
|
||||
} else {
|
||||
return ThumbnailRenderResult::UpdateThumbnail(new_value.render_thumbnail())
|
||||
}
|
||||
},
|
||||
}
|
||||
return Some(new_value.render_thumbnail());
|
||||
}
|
||||
)*
|
||||
return ThumbnailRenderResult::ClearThumbnail;
|
||||
return None;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ impl ProtoNetwork {
|
||||
pub struct UpstreamInputMetadata {
|
||||
pub input_sni: SNI,
|
||||
// Context dependencies are accumulated during compilation, then replaced with the difference between the node's dependencies and the inputs dependencies
|
||||
pub context_dependencies: ContextDependencies,
|
||||
pub nullify: ContextDependencies,
|
||||
// If the upstream node is a value node, then do not nullify since the value nodes do not have a cache inserted after them
|
||||
pub is_value: bool,
|
||||
}
|
||||
@@ -112,6 +112,7 @@ pub struct NodeConstructionArgs {
|
||||
pub inputs: Vec<Option<UpstreamInputMetadata>>,
|
||||
// The union of all input context dependencies and the nodes context dependency. Used to generate the context nullification for the editor entry point
|
||||
pub context_dependencies: ContextDependencies,
|
||||
pub cache_output: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -258,7 +259,7 @@ impl Debug for GraphErrorType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct GraphError {
|
||||
pub original_location: OriginalLocation,
|
||||
pub identifier: Cow<'static, str>,
|
||||
@@ -279,11 +280,7 @@ impl GraphError {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Debug for GraphError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("NodeGraphError").field("identifier", &self.identifier.to_string()).field("error", &self.error).finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub type GraphErrors = Vec<GraphError>;
|
||||
|
||||
/// The `TypingContext` is used to store the types of the nodes indexed by their stable node id.
|
||||
|
||||
Reference in New Issue
Block a user