Skip to content

Commit 8d8e2ed

Browse files
authored
Add 'Freeze Real Time' and 'Boundless Footprint' nodes as alternatives to using 'Memoize Impure' (#2509)
* WIP debugging * Only create parent ref if var args are used in context + Cleanup * Eval nodes with None instead of relying on MemoImpure * Remove unused imports * Show parent in debug output * Remove TODO comment
1 parent bc03941 commit 8d8e2ed

File tree

6 files changed

+93
-25
lines changed

6 files changed

+93
-25
lines changed

editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ mod test_transform_layer {
705705
use crate::messages::portfolio::document::graph_operation::transform_utils;
706706
use crate::test_utils::test_prelude::*;
707707
// Use ModifyInputsContext to locate the transform node
708-
use crate::messages::portfolio::document::graph_operation::utility_types::{ModifyInputsContext, TransformIn};
708+
use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext;
709709
use crate::messages::prelude::Message;
710710
use glam::DAffine2;
711711
use std::collections::VecDeque;

node-graph/gcore/src/context.rs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub trait ExtractFootprint {
1313
fn footprint(&self) -> &Footprint {
1414
self.try_footprint().unwrap_or_else(|| {
1515
log::error!("Context did not have a footprint, called from: {}", Location::caller());
16-
&const { Footprint::empty() }
16+
&Footprint::DEFAULT
1717
})
1818
}
1919
}
@@ -76,7 +76,7 @@ impl<T: ExtractFootprint + Sync> ExtractFootprint for Option<T> {
7676
fn footprint(&self) -> &Footprint {
7777
self.try_footprint().unwrap_or_else(|| {
7878
log::warn!("trying to extract footprint from context None {} ", Location::caller());
79-
&const { Footprint::empty() }
79+
&Footprint::DEFAULT
8080
})
8181
}
8282
}
@@ -193,7 +193,7 @@ impl ExtractFootprint for OwnedContextImpl {
193193
}
194194
impl ExtractTime for OwnedContextImpl {
195195
fn try_time(&self) -> Option<f64> {
196-
self.time
196+
self.real_time
197197
}
198198
}
199199
impl ExtractAnimationTime for OwnedContextImpl {
@@ -245,10 +245,23 @@ pub struct OwnedContextImpl {
245245
parent: Option<Arc<dyn ExtractVarArgs + Sync + Send>>,
246246
// This could be converted into a single enum to save extra bytes
247247
index: Option<usize>,
248-
time: Option<f64>,
248+
real_time: Option<f64>,
249249
animation_time: Option<f64>,
250250
}
251251

252+
impl core::fmt::Debug for OwnedContextImpl {
253+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
254+
f.debug_struct("OwnedContextImpl")
255+
.field("footprint", &self.footprint)
256+
.field("varargs", &self.varargs)
257+
.field("parent", &self.parent.as_ref().map(|_| "<Parent>"))
258+
.field("index", &self.index)
259+
.field("real_time", &self.real_time)
260+
.field("animation_time", &self.animation_time)
261+
.finish()
262+
}
263+
}
264+
252265
impl Default for OwnedContextImpl {
253266
#[track_caller]
254267
fn default() -> Self {
@@ -259,10 +272,11 @@ impl Default for OwnedContextImpl {
259272
impl core::hash::Hash for OwnedContextImpl {
260273
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
261274
self.footprint.hash(state);
262-
self.index.hash(state);
263-
self.time.map(|x| x.to_bits()).hash(state);
264-
self.parent.as_ref().map(|x| Arc::as_ptr(x).addr()).hash(state);
265275
self.varargs.as_ref().map(|x| Arc::as_ptr(x).addr()).hash(state);
276+
self.parent.as_ref().map(|x| Arc::as_ptr(x).addr()).hash(state);
277+
self.index.hash(state);
278+
self.real_time.map(|x| x.to_bits()).hash(state);
279+
self.animation_time.map(|x| x.to_bits()).hash(state);
266280
}
267281
}
268282

@@ -273,13 +287,16 @@ impl OwnedContextImpl {
273287
let index = value.try_index();
274288
let time = value.try_time();
275289
let frame_time = value.try_animation_time();
276-
let parent = value.arc_clone();
290+
let parent = match value.varargs_len() {
291+
Ok(x) if x > 0 => value.arc_clone(),
292+
_ => None,
293+
};
277294
OwnedContextImpl {
278295
footprint,
279296
varargs: None,
280297
parent,
281298
index,
282-
time,
299+
real_time: time,
283300
animation_time: frame_time,
284301
}
285302
}
@@ -289,7 +306,7 @@ impl OwnedContextImpl {
289306
varargs: None,
290307
parent: None,
291308
index: None,
292-
time: None,
309+
real_time: None,
293310
animation_time: None,
294311
}
295312
}
@@ -303,8 +320,8 @@ impl OwnedContextImpl {
303320
self.footprint = Some(footprint);
304321
self
305322
}
306-
pub fn with_time(mut self, time: f64) -> Self {
307-
self.time = Some(time);
323+
pub fn with_real_time(mut self, time: f64) -> Self {
324+
self.real_time = Some(time);
308325
self
309326
}
310327
pub fn with_animation_time(mut self, animation_time: f64) -> Self {
@@ -314,6 +331,10 @@ impl OwnedContextImpl {
314331
pub fn into_context(self) -> Option<Arc<Self>> {
315332
Some(Arc::new(self))
316333
}
334+
pub fn erase_parent(mut self) -> Self {
335+
self.parent = None;
336+
self
337+
}
317338
}
318339

319340
#[derive(Default, Clone, Copy, dyn_any::DynAny)]

node-graph/gcore/src/memo.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ where
2525
let mut hasher = DefaultHasher::new();
2626
input.hash(&mut hasher);
2727
let hash = hasher.finish();
28+
2829
if let Some(data) = self.cache.lock().as_ref().unwrap().as_ref().and_then(|data| (data.0 == hash).then_some(data.1.clone())) {
2930
Box::pin(async move { data })
3031
} else {

node-graph/gcore/src/transform.rs

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use crate::raster::bbox::AxisAlignedBbox;
44
use crate::raster::image::ImageFrameTable;
55
use crate::vector::VectorDataTable;
66
use crate::{Artboard, ArtboardGroupTable, CloneVarArgs, Color, Context, Ctx, ExtractAll, GraphicGroupTable, OwnedContextImpl};
7-
use glam::{DAffine2, DVec2};
7+
use core::f64;
8+
use glam::{DAffine2, DMat2, DVec2};
89

910
pub trait Transform {
1011
fn transform(&self) -> DAffine2;
@@ -94,18 +95,26 @@ pub struct Footprint {
9495

9596
impl Default for Footprint {
9697
fn default() -> Self {
97-
Self::empty()
98+
Self::DEFAULT
9899
}
99100
}
100101

101102
impl Footprint {
102-
pub const fn empty() -> Self {
103-
Self {
104-
transform: DAffine2::IDENTITY,
105-
resolution: glam::UVec2::new(1920, 1080),
106-
quality: RenderQuality::Full,
107-
}
108-
}
103+
pub const DEFAULT: Self = Self {
104+
transform: DAffine2::IDENTITY,
105+
resolution: glam::UVec2::new(1920, 1080),
106+
quality: RenderQuality::Full,
107+
};
108+
109+
pub const BOUNDLESS: Self = Self {
110+
transform: DAffine2 {
111+
matrix2: DMat2::from_diagonal(DVec2::splat(f64::INFINITY)),
112+
translation: DVec2::ZERO,
113+
},
114+
resolution: glam::UVec2::new(0, 0),
115+
quality: RenderQuality::Full,
116+
};
117+
109118
pub fn viewport_bounds_in_local_space(&self) -> AxisAlignedBbox {
110119
let inverse = self.transform.inverse();
111120
let start = inverse.transform_point2((0., 0.).into());
@@ -198,3 +207,38 @@ fn replace_transform<Data, TransformInput: Transform>(
198207
}
199208
data
200209
}
210+
211+
#[node_macro::node(category("Debug"))]
212+
async fn boundless_footprint<T: 'n + 'static>(
213+
ctx: impl Ctx + CloneVarArgs + ExtractAll,
214+
#[implementations(
215+
Context -> VectorDataTable,
216+
Context -> GraphicGroupTable,
217+
Context -> ImageFrameTable<Color>,
218+
Context -> TextureFrameTable,
219+
Context -> String,
220+
Context -> f64,
221+
)]
222+
transform_target: impl Node<Context<'static>, Output = T>,
223+
) -> T {
224+
let ctx = OwnedContextImpl::from(ctx).with_footprint(Footprint::BOUNDLESS);
225+
226+
transform_target.eval(ctx.into_context()).await
227+
}
228+
#[node_macro::node(category("Debug"))]
229+
async fn freeze_real_time<T: 'n + 'static>(
230+
ctx: impl Ctx + CloneVarArgs + ExtractAll,
231+
#[implementations(
232+
Context -> VectorDataTable,
233+
Context -> GraphicGroupTable,
234+
Context -> ImageFrameTable<Color>,
235+
Context -> TextureFrameTable,
236+
Context -> String,
237+
Context -> f64,
238+
)]
239+
transform_target: impl Node<Context<'static>, Output = T>,
240+
) -> T {
241+
let ctx = OwnedContextImpl::from(ctx).with_real_time(0.);
242+
243+
transform_target.eval(ctx.into_context()).await
244+
}

node-graph/gstd/src/wasm_application_io.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ async fn render<'a: 'n, T: 'n + GraphicElementRendered + WasmNotSend>(
237237
let footprint = render_config.viewport;
238238
let ctx = OwnedContextImpl::default()
239239
.with_footprint(footprint)
240-
.with_time(render_config.time.time)
240+
.with_real_time(render_config.time.time)
241241
.with_animation_time(render_config.time.animation_time.as_secs_f64())
242242
.into_context();
243243
ctx.footprint();
@@ -246,10 +246,10 @@ async fn render<'a: 'n, T: 'n + GraphicElementRendered + WasmNotSend>(
246246
let render_params = RenderParams::new(render_config.view_mode, None, false, hide_artboards, for_export);
247247

248248
let data = data.eval(ctx.clone()).await;
249-
let editor_api = editor_api.eval(ctx.clone()).await;
249+
let editor_api = editor_api.eval(None).await;
250250

251251
#[cfg(all(feature = "vello", target_arch = "wasm32"))]
252-
let surface_handle = _surface_handle.eval(ctx.clone()).await;
252+
let surface_handle = _surface_handle.eval(None).await;
253253

254254
let use_vello = editor_api.editor_preferences.use_vello();
255255
#[cfg(all(feature = "vello", target_arch = "wasm32"))]

node-graph/interpreted-executor/src/node_registry.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,8 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
307307
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => wgpu_executor::WindowHandle]),
308308
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => graphene_std::SurfaceFrame]),
309309
async_node!(graphene_core::memo::MemoNode<_, _>, input: UVec2, fn_params: [UVec2 => graphene_std::SurfaceFrame]),
310+
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => f64]),
311+
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => String]),
310312
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => RenderOutput]),
311313
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => GraphicElement]),
312314
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => GraphicGroupTable]),

0 commit comments

Comments
 (0)