Skip to content

Commit ae6c22e

Browse files
committed
starting refactoring graph states and cache
1 parent d51cc12 commit ae6c22e

9 files changed

Lines changed: 668 additions & 120 deletions

File tree

crates/bevy_animation_graph/src/core/animation_graph/core.rs

Lines changed: 21 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use super::pin;
22
use crate::{
33
core::{
44
animation_node::AnimationNode,
5-
context::{CacheReadFilter, CacheWriteFilter},
65
duration_data::DurationData,
76
edge_data::AnimationEvent,
87
errors::{GraphError, GraphValidationError},
@@ -669,15 +668,10 @@ impl AnimationGraph {
669668
};
670669

671670
let source_value = match source_pin {
672-
SourcePin::NodeData(node_id, _) => {
673-
if ctx
674-
.caches()
675-
.get(
676-
|c| c.is_updated(node_id).then_some(()),
677-
CacheReadFilter::for_temp(ctx.temp_cache),
678-
)
679-
.is_none()
680-
{
671+
SourcePin::NodeData(node_id, node_pin) => {
672+
let key = ctx.state_key;
673+
674+
if !ctx.node_caches().is_updated(node_id.to_owned(), key) {
681675
let node = &self.nodes[node_id];
682676
let should_debug = node.should_debug;
683677

@@ -687,22 +681,11 @@ impl AnimationGraph {
687681
node.update(ctx.with_node(node_id, self).with_debugging(should_debug))?;
688682
}
689683

690-
let is_temp = ctx.temp_cache;
691-
692-
ctx.caches_mut().set(
693-
|c| c.set_updated(node_id.clone()),
694-
CacheWriteFilter::for_temp(is_temp),
695-
);
684+
ctx.node_caches_mut().mark_updated(node_id.to_owned(), key);
696685
}
697686

698-
let Some(value) = ctx.caches().get(
699-
|c| c.get_data(source_pin).cloned(),
700-
CacheReadFilter::for_temp(ctx.temp_cache),
701-
) else {
702-
return Err(GraphError::OutputMissing(source_pin.clone()));
703-
};
704-
705-
value
687+
ctx.node_caches()
688+
.get_output_data(node_id.clone(), key, node_pin.clone())?
706689
}
707690
SourcePin::InputData(pin_id) => ctx
708691
.parent_data_back(pin_id)
@@ -740,23 +723,15 @@ impl AnimationGraph {
740723
panic!("Incompatible pins connected: {source_pin:?} --> {target_pin:?}")
741724
}
742725
SourcePin::NodeTime(node_id) => {
743-
if let Some(dur) = ctx.caches().get(
744-
|c| c.get_duration(source_pin),
745-
CacheReadFilter::for_temp(ctx.temp_cache),
746-
) {
726+
let key = ctx.state_key;
727+
728+
if let Ok(dur) = ctx.node_caches().get_duration(node_id.clone(), key) {
747729
dur
748730
} else {
749731
let node = &self.nodes[node_id];
750732
let should_debug = node.should_debug;
751733
node.duration(ctx.with_node(node_id, self).with_debugging(should_debug))?;
752-
let Some(dur) = ctx.caches().get(
753-
|c| c.get_duration(source_pin),
754-
CacheReadFilter::for_temp(ctx.temp_cache),
755-
) else {
756-
// TODO: Make a graph error for duration missing
757-
return Err(GraphError::OutputMissing(source_pin.clone()));
758-
};
759-
dur
734+
ctx.node_caches().get_duration(node_id.clone(), key)?
760735
}
761736
}
762737
SourcePin::InputTime(pin_id) => {
@@ -780,37 +755,22 @@ impl AnimationGraph {
780755
return Err(GraphError::MissingEdgeToSource(source_pin));
781756
};
782757

758+
let key = ctx.state_key;
759+
783760
match target_pin {
784761
TargetPin::NodeData(_, _) => {
785762
panic!("Incompatible pins connected: {source_pin:?} --> {target_pin:?}")
786763
}
787764
TargetPin::OutputData(_) => {
788765
panic!("Incompatible pins connected: {source_pin:?} --> {target_pin:?}")
789766
}
790-
TargetPin::NodeTime(_, _) => {
791-
let Some(time_update) = ctx.caches().get(
792-
|c| c.get_time_update_back(target_pin).cloned(),
793-
CacheReadFilter::for_temp(ctx.temp_cache),
794-
) else {
795-
return Err(GraphError::TimeUpdateMissing(target_pin.clone()));
796-
};
797-
798-
Ok(time_update)
799-
}
800-
TargetPin::OutputTime => {
801-
let Some(time_update) = ctx
802-
.caches()
803-
.get(
804-
|c| c.get_time_update_back(target_pin).cloned(),
805-
CacheReadFilter::for_temp(ctx.temp_cache),
806-
)
807-
.or_else(|| ctx.parent_time_update_fwd().ok())
808-
else {
809-
return Err(GraphError::TimeUpdateMissing(target_pin.clone()));
810-
};
811-
812-
Ok(time_update)
813-
}
767+
TargetPin::NodeTime(target_node, target_pin) => ctx
768+
.node_caches()
769+
.get_input_time_update(target_node.clone(), key, target_pin.clone()),
770+
TargetPin::OutputTime => match ctx.context().query_output_time.clone() {
771+
Some(update) => Ok(update),
772+
None => ctx.parent_time_update_fwd(),
773+
},
814774
}
815775
}
816776

@@ -855,10 +815,7 @@ impl AnimationGraph {
855815
entity_map,
856816
deferred_gizmos,
857817
);
858-
ctx.caches_mut().set(
859-
|c| c.set_time_update_back(TargetPin::OutputTime, time_update),
860-
CacheWriteFilter::Primary,
861-
);
818+
ctx.context_mut().query_output_time = Some(time_update);
862819
let mut outputs = HashMap::new();
863820
for k in self.output_parameters.keys() {
864821
let out = self.get_data(TargetPin::OutputData(k.clone()), ctx.clone())?;

crates/bevy_animation_graph/src/core/animation_node.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
use bevy::{
1111
platform::collections::HashMap,
1212
prelude::{Deref, DerefMut},
13-
reflect::{FromType, prelude::*},
13+
reflect::{prelude::*, FromType},
1414
};
1515
use std::{any::TypeId, fmt::Debug};
1616

@@ -267,15 +267,15 @@ const _: () = {
267267
*/
268268
{
269269
#[inline]
270-
fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn ::core::any::Any> {
270+
fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn::core::any::Any> {
271271
self
272272
}
273273
#[inline]
274-
fn as_any(&self) -> &dyn ::core::any::Any {
274+
fn as_any(&self) -> &dyn::core::any::Any {
275275
self
276276
}
277277
#[inline]
278-
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any {
278+
fn as_any_mut(&mut self) -> &mut dyn::core::any::Any {
279279
self
280280
}
281281
#[inline]

crates/bevy_animation_graph/src/core/context/graph_context.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{
55
prelude::AnimationGraph,
66
state_machine::low_level::FSMState,
77
},
8-
prelude::DataValue,
8+
prelude::{DataValue, node_caches::NodeCaches, node_states::NodeStates},
99
};
1010
use bevy::{
1111
asset::AssetId,
@@ -204,20 +204,25 @@ impl GraphStateStack {
204204

205205
#[derive(Debug, Reflect)]
206206
pub struct GraphContext {
207-
pub caches: GraphStateStack,
207+
pub node_states: NodeStates,
208+
pub node_caches: NodeCaches,
209+
pub query_output_time: Option<TimeUpdate>,
208210
graph_id: AssetId<AnimationGraph>,
209211
}
210212

211213
impl GraphContext {
212214
pub fn new(graph_id: AssetId<AnimationGraph>) -> Self {
213215
Self {
214-
caches: GraphStateStack::default(),
215216
graph_id,
217+
node_states: NodeStates::default(),
218+
node_caches: NodeCaches::default(),
219+
query_output_time: None,
216220
}
217221
}
218222

219223
pub fn next_frame(&mut self) {
220-
self.caches.next_frame();
224+
self.node_states.next_frame();
225+
self.node_caches.next_frame();
221226
}
222227

223228
pub fn get_graph_id(&self) -> AssetId<AnimationGraph> {

crates/bevy_animation_graph/src/core/context/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
mod deferred_gizmos;
22
mod graph_context;
33
mod graph_context_arena;
4+
pub mod node_caches;
5+
pub mod node_state_box;
6+
pub mod node_states;
47
mod pass_context;
58
mod pose_fallback;
69
mod spec_context;
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
use bevy::{
2+
platform::collections::{HashMap, HashSet},
3+
reflect::Reflect,
4+
};
5+
6+
use crate::{
7+
core::{
8+
animation_graph::{NodeId, PinId, SourcePin, TargetPin, TimeUpdate},
9+
duration_data::DurationData,
10+
errors::GraphError,
11+
},
12+
prelude::{DataValue, node_states::StateKey},
13+
};
14+
15+
#[derive(Reflect, Default, Debug)]
16+
pub struct NodeCache {
17+
pub output_data: HashMap<(StateKey, PinId), DataValue>,
18+
/// Time update coming from the "output time" pin. Perhaps should be called "input time
19+
/// update".
20+
pub output_time_update: HashMap<StateKey, TimeUpdate>,
21+
/// Time updates sent back to nodes via "input time" pins
22+
pub input_time_updates: HashMap<(StateKey, PinId), TimeUpdate>,
23+
pub duration: HashMap<StateKey, DurationData>,
24+
pub updated: HashSet<StateKey>,
25+
}
26+
27+
#[derive(Reflect, Default, Debug)]
28+
pub struct NodeCaches {
29+
caches: HashMap<NodeId, NodeCache>,
30+
}
31+
32+
impl NodeCaches {
33+
pub fn next_frame(&mut self) {
34+
self.caches.clear();
35+
}
36+
37+
pub fn get_duration(&self, node_id: NodeId, key: StateKey) -> Result<DurationData, GraphError> {
38+
let error = || GraphError::DurationMissing(SourcePin::NodeTime(node_id.clone()));
39+
40+
self.caches
41+
.get(&node_id)
42+
.ok_or_else(&error)
43+
.and_then(|c| c.duration.get(&key).ok_or_else(&error))
44+
.cloned()
45+
}
46+
47+
pub fn set_duration(&mut self, node_id: NodeId, key: StateKey, duration: DurationData) {
48+
self.cache_mut(node_id).duration.insert(key, duration);
49+
}
50+
51+
pub fn get_output_data(
52+
&self,
53+
node_id: NodeId,
54+
key: StateKey,
55+
pin: PinId,
56+
) -> Result<DataValue, GraphError> {
57+
let error = || GraphError::OutputMissing(SourcePin::NodeData(node_id.clone(), pin.clone()));
58+
59+
self.caches
60+
.get(&node_id)
61+
.ok_or_else(&error)
62+
.and_then(|c| c.output_data.get(&(key, pin.clone())).ok_or_else(&error))
63+
.cloned()
64+
}
65+
66+
pub fn set_output_data(&mut self, node_id: NodeId, key: StateKey, pin: PinId, data: DataValue) {
67+
self.cache_mut(node_id).output_data.insert((key, pin), data);
68+
}
69+
70+
pub fn get_output_time_update(
71+
&self,
72+
node_id: NodeId,
73+
key: StateKey,
74+
) -> Result<TimeUpdate, GraphError> {
75+
let error = || GraphError::TimeUpdateMissingFwd(SourcePin::NodeTime(node_id.clone()));
76+
77+
self.caches
78+
.get(&node_id)
79+
.ok_or_else(&error)
80+
.and_then(|c| c.output_time_update.get(&key).ok_or_else(&error))
81+
.cloned()
82+
}
83+
84+
pub fn set_output_time_update(&mut self, node_id: NodeId, key: StateKey, update: TimeUpdate) {
85+
self.cache_mut(node_id)
86+
.output_time_update
87+
.insert(key, update);
88+
}
89+
90+
pub fn get_input_time_update(
91+
&self,
92+
node_id: NodeId,
93+
key: StateKey,
94+
pin: PinId,
95+
) -> Result<TimeUpdate, GraphError> {
96+
let error =
97+
|| GraphError::TimeUpdateMissingBack(TargetPin::NodeTime(node_id.clone(), pin.clone()));
98+
99+
self.caches
100+
.get(&node_id)
101+
.ok_or_else(&error)
102+
.and_then(|c| {
103+
c.input_time_updates
104+
.get(&(key, pin.clone()))
105+
.ok_or_else(&error)
106+
})
107+
.cloned()
108+
}
109+
110+
pub fn set_input_time_update(
111+
&mut self,
112+
node_id: NodeId,
113+
key: StateKey,
114+
pin: PinId,
115+
update: TimeUpdate,
116+
) {
117+
self.cache_mut(node_id)
118+
.input_time_updates
119+
.insert((key, pin), update);
120+
}
121+
122+
pub fn is_updated(&self, node_id: NodeId, key: StateKey) -> bool {
123+
self.caches
124+
.get(&node_id)
125+
.is_some_and(|c| c.updated.contains(&key))
126+
}
127+
128+
pub fn mark_updated(&mut self, node_id: NodeId, key: StateKey) {
129+
self.cache_mut(node_id).updated.insert(key);
130+
}
131+
132+
fn cache_mut(&mut self, node_id: NodeId) -> &mut NodeCache {
133+
self.caches.entry(node_id).or_default()
134+
}
135+
}

0 commit comments

Comments
 (0)