Optimize rendering by caching intermediate render results when panning/zooming (#3147)

* Add svg render node

WIP

Fix error in context nullificaton node insertion

Correctly translate metadata

Fix warning

* Cleanup

* Remove color / gradient check and fix svg defs

* Implement viewport filling transform modification for vello

* Cleanup and comments

* Code review
This commit is contained in:
Dennis Kobert
2025-09-11 10:56:59 +02:00
parent 09ece9424d
commit ad5d8fcd37
12 changed files with 338 additions and 262 deletions

View File

@@ -21,12 +21,14 @@ use graphene_std::application_io::{ImageTexture, SurfaceFrame};
use graphene_std::brush::brush_cache::BrushCache;
use graphene_std::brush::brush_stroke::BrushStroke;
use graphene_std::gradient::GradientStops;
use graphene_std::render_node::RenderIntermediate;
use graphene_std::table::Table;
use graphene_std::transform::Footprint;
use graphene_std::uuid::NodeId;
use graphene_std::vector::Vector;
use graphene_std::wasm_application_io::WasmEditorApi;
#[cfg(feature = "gpu")]
use graphene_std::wasm_application_io::{WasmEditorApi, WasmSurfaceHandle};
use graphene_std::wasm_application_io::WasmSurfaceHandle;
use node_registry_macros::{async_node, convert_node, into_node};
use once_cell::sync::Lazy;
use std::collections::HashMap;
@@ -130,6 +132,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => &WasmEditorApi, Context => graphene_std::ContextFeatures]),
#[cfg(feature = "gpu")]
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => Arc<WasmSurfaceHandle>, Context => graphene_std::ContextFeatures]),
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => RenderIntermediate, Context => graphene_std::ContextFeatures]),
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => WgpuSurface, Context => graphene_std::ContextFeatures]),
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => Option<WgpuSurface>, Context => graphene_std::ContextFeatures]),
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => WindowHandle, Context => graphene_std::ContextFeatures]),
@@ -164,7 +167,6 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => DAffine2]),
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Footprint]),
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => RenderOutput]),
#[cfg(feature = "gpu")]
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => &WasmEditorApi]),
#[cfg(feature = "gpu")]
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => WgpuSurface]),
@@ -215,6 +217,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::CentroidType]),
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_path_bool::BooleanOperation]),
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_core::text::TextAlign]),
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => RenderIntermediate]),
// =================
// IMPURE MEMO NODES
// =================

View File

@@ -28,7 +28,7 @@ pub fn wrap_network_in_scope(mut network: NodeNetwork, editor_api: Arc<WasmEdito
let render_node = DocumentNode {
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::node(NodeId(2), 0)],
implementation: DocumentNodeImplementation::Network(NodeNetwork {
exports: vec![NodeInput::node(NodeId(2), 0)],
exports: vec![NodeInput::node(NodeId(4), 0)],
nodes: [
DocumentNode {
inputs: vec![NodeInput::scope("editor-api")],
@@ -41,18 +41,36 @@ pub fn wrap_network_in_scope(mut network: NodeNetwork, editor_api: Arc<WasmEdito
implementation: DocumentNodeImplementation::ProtoNode(graphene_core::memo::memo::IDENTIFIER),
..Default::default()
},
// TODO: Add conversion step
DocumentNode {
call_argument: concrete!(Context),
inputs: vec![
NodeInput::import(graphene_core::Type::Fn(Box::new(concrete!(Context)), Box::new(generic!(T))), 0),
NodeInput::scope("editor-api"),
],
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_node::render_intermediate::IDENTIFIER),
context_features: graphene_std::ContextDependencies {
extract: ContextFeatures::VARARGS,
inject: ContextFeatures::empty(),
},
..Default::default()
},
DocumentNode {
call_argument: concrete!(Context),
inputs: vec![NodeInput::scope("editor-api"), NodeInput::node(NodeId(2), 0), NodeInput::node(NodeId(1), 0)],
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_node::render::IDENTIFIER),
context_features: graphene_std::ContextDependencies {
extract: ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
inject: ContextFeatures::empty(),
},
..Default::default()
},
DocumentNode {
call_argument: concrete!(graphene_std::application_io::RenderConfig),
inputs: vec![
NodeInput::scope("editor-api"),
NodeInput::import(graphene_core::Type::Fn(Box::new(concrete!(Context)), Box::new(generic!(T))), 0),
NodeInput::node(NodeId(1), 0),
],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::RenderNode")),
inputs: vec![NodeInput::node(NodeId(3), 0)],
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_node::create_context::IDENTIFIER),
context_features: graphene_std::ContextDependencies {
extract: ContextFeatures::FOOTPRINT,
inject: ContextFeatures::FOOTPRINT | ContextFeatures::REAL_TIME | ContextFeatures::ANIMATION_TIME,
extract: ContextFeatures::empty(),
inject: ContextFeatures::REAL_TIME | ContextFeatures::ANIMATION_TIME | ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
},
..Default::default()
},