diff --git a/panda/src/cull/cullLevelState.h b/panda/src/cull/cullLevelState.h index a1804e0f11..3314e46db8 100644 --- a/panda/src/cull/cullLevelState.h +++ b/panda/src/cull/cullLevelState.h @@ -21,7 +21,7 @@ class EXPCL_PANDA CullLevelState { public: CullStateLookup *_lookup; - UpdateSeq _now; + UpdateSeq _as_of; }; #endif diff --git a/panda/src/cull/cullState.cxx b/panda/src/cull/cullState.cxx index 55a21d29c0..240607ea9b 100644 --- a/panda/src/cull/cullState.cxx +++ b/panda/src/cull/cullState.cxx @@ -20,21 +20,24 @@ //////////////////////////////////////////////////////////////////// bool CullState:: check_currency(Node *node, const AllTransitionsWrapper &, - UpdateSeq now) { + UpdateSeq as_of) { // First, check the verified time stamp. Verified::iterator vi; vi = _verified.find(node); - nassertr(vi != _verified.end(), false); + if (vi == _verified.end()) { + // We have never seen this node before. + return false; + } UpdateSeq verified_stamp = (*vi).second; if (cull_cat.is_spam()) { cull_cat.spam() << "Checking currency for " << *node << ", verified_stamp = " - << verified_stamp << " now = " << now << "\n"; + << verified_stamp << " as_of = " << as_of << "\n"; } - if (verified_stamp == now && !verified_stamp.is_fresh()) { + if (as_of <= verified_stamp && !verified_stamp.is_fresh()) { return true; } diff --git a/panda/src/cull/cullState.h b/panda/src/cull/cullState.h index 6343308530..d8b767f83e 100644 --- a/panda/src/cull/cullState.h +++ b/panda/src/cull/cullState.h @@ -47,7 +47,7 @@ public: bool check_currency(Node *node, const AllTransitionsWrapper &trans, - UpdateSeq now); + UpdateSeq as_of); INLINE void mark_verified(Node *node, UpdateSeq now); diff --git a/panda/src/cull/cullStateSubtree.I b/panda/src/cull/cullStateSubtree.I index 3ceb209667..0d31ec5e96 100644 --- a/panda/src/cull/cullStateSubtree.I +++ b/panda/src/cull/cullStateSubtree.I @@ -35,7 +35,7 @@ update(const AllTransitionsWrapper &trans, Node *top_subtree, UpdateSeq now) { // blow out the cache for all of our children. We do it for now // just to cut down on things that can go wrong, but this should // come out of here before long. - clear(); + // clear(); _trans = trans; _parent->compose_trans(_trans, _trans_from_root); diff --git a/panda/src/cull/cullStateSubtree.cxx b/panda/src/cull/cullStateSubtree.cxx index 46d70d4738..90db5e7541 100644 --- a/panda/src/cull/cullStateSubtree.cxx +++ b/panda/src/cull/cullStateSubtree.cxx @@ -25,11 +25,11 @@ CullStateSubtree:: //////////////////////////////////////////////////////////////////// bool CullStateSubtree:: check_currency(const AllTransitionsWrapper &, Node *top_subtree, - UpdateSeq now) { + UpdateSeq as_of) { if (cull_cat.is_spam()) { cull_cat.spam() << "Checking currency for subtree " << (void *)this - << ", _verified = " << _verified << " now = " << now << "\n"; + << ", _verified = " << _verified << " as_of = " << as_of << "\n"; } // Make sure we've still got the same top_subtree node. @@ -38,7 +38,7 @@ check_currency(const AllTransitionsWrapper &, Node *top_subtree, } // First, check the verified time stamp. - if (_verified == now && !_verified.is_fresh()) { + if (as_of <= _verified && !_verified.is_fresh()) { return true; } diff --git a/panda/src/cull/cullStateSubtree.h b/panda/src/cull/cullStateSubtree.h index b58f4f465e..a5be628460 100644 --- a/panda/src/cull/cullStateSubtree.h +++ b/panda/src/cull/cullStateSubtree.h @@ -32,7 +32,7 @@ public: bool check_currency(const AllTransitionsWrapper &trans, Node *top_subtree, - UpdateSeq now); + UpdateSeq as_of); INLINE void update(const AllTransitionsWrapper &trans, Node *top_subtree, UpdateSeq now); diff --git a/panda/src/cull/cullTraverser.I b/panda/src/cull/cullTraverser.I index eec82da8df..f64f376b71 100644 --- a/panda/src/cull/cullTraverser.I +++ b/panda/src/cull/cullTraverser.I @@ -107,7 +107,7 @@ INLINE CullStateLookup *CullTraverser:: add_instance(NodeRelation *arc, const AllTransitionsWrapper &trans, Node *top_subtree, const CullLevelState &level_state) { return level_state._lookup->get_subtree - (arc, trans, top_subtree, level_state._now); + (arc, trans, top_subtree, level_state._as_of); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/cull/cullTraverser.cxx b/panda/src/cull/cullTraverser.cxx index a745d859b9..9ef2e015d3 100644 --- a/panda/src/cull/cullTraverser.cxx +++ b/panda/src/cull/cullTraverser.cxx @@ -91,11 +91,12 @@ traverse(Node *root, bool is_initial = (_nested_count == 0); if (is_initial) { if (cull_force_update) { - _now = UpdateSeq::fresh(); + _as_of = UpdateSeq::fresh(); } else { - _now = UpdateSeq::initial(); + _as_of = UpdateSeq::initial(); } } + _now = last_graph_update[_graph_type]; _nested_count++; if (is_initial) { @@ -109,7 +110,7 @@ traverse(Node *root, CullLevelState level_state; level_state._lookup = &_lookup; - level_state._now = _now; + level_state._as_of = _as_of; // Determine the relative transform matrix from the camera to our // starting node. This is important for proper view-frustum @@ -304,7 +305,7 @@ add_geom_node(GeomNode *node, const AllTransitionsWrapper &trans, complete_trans.clear_transition(DirectRenderTransition::get_class_type()); CullState *cs = level_state._lookup->find_node - (node, complete_trans, level_state._now); + (node, complete_trans, level_state._as_of); if (cs == (CullState *)NULL) { if (cull_cat.is_spam()) { cull_cat.spam() @@ -316,7 +317,7 @@ add_geom_node(GeomNode *node, const AllTransitionsWrapper &trans, cs = find_bin_state(complete_trans); nassertv(cs != (CullState *)NULL); - level_state._lookup->record_node(node, cs, level_state._now); + level_state._lookup->record_node(node, cs, level_state._as_of); } cs->record_current_geom_node(arc_chain); @@ -347,14 +348,14 @@ add_direct_node(Node *node, const AllTransitionsWrapper &trans, complete_trans.clear_transition(DirectRenderTransition::get_class_type()); CullState *cs = level_state._lookup->find_node - (node, complete_trans, level_state._now); + (node, complete_trans, level_state._as_of); if (cs == (CullState *)NULL) { // The node didn't have a previously-associated CullState that we // could use, so determine a new one for it. cs = find_bin_state(complete_trans); nassertv(cs != (CullState *)NULL); - level_state._lookup->record_node(node, cs, level_state._now); + level_state._lookup->record_node(node, cs, level_state._as_of); } cs->record_current_direct_node(arc_chain); @@ -385,8 +386,8 @@ forward_arc(NodeRelation *arc, NullTransitionWrapper &, AllTransitionsWrapper trans; UpdateSeq last_update = arc->get_last_update(); - if (level_state._now < last_update) { - level_state._now = last_update; + if (level_state._as_of < last_update) { + level_state._as_of = last_update; } bool is_instanced = (node->get_num_parents(_graph_type) > 1); @@ -435,16 +436,17 @@ forward_arc(NodeRelation *arc, NullTransitionWrapper &, #endif if (arc_has_sub_render) { - level_state._now = UpdateSeq::fresh(); + level_state._as_of = UpdateSeq::fresh(); } - _now = level_state._now; + _as_of = level_state._as_of; mark_forward_arc(arc); if (cull_cat.is_spam()) { cull_cat.spam() << "Reached " << *node << ":\n" - << " now = " << level_state._now + << " as_of = " << level_state._as_of + << " now = " << _now << " is_instanced = " << is_instanced << " is_geom = " << is_geom << " node_has_sub_render = " << node_has_sub_render @@ -458,6 +460,7 @@ forward_arc(NodeRelation *arc, NullTransitionWrapper &, // In any of these cases, we'll need to determine the net // transition to this node. wrt_subtree(arc, level_state._lookup->get_top_subtree(), + level_state._as_of, _now, trans, _graph_type); } diff --git a/panda/src/cull/cullTraverser.h b/panda/src/cull/cullTraverser.h index c3fdf5ca5c..15b04277a6 100644 --- a/panda/src/cull/cullTraverser.h +++ b/panda/src/cull/cullTraverser.h @@ -103,6 +103,7 @@ private: CullStateLookup _lookup; int _nested_count; + UpdateSeq _as_of; UpdateSeq _now; public: diff --git a/panda/src/graph/allTransitionsWrapper.I b/panda/src/graph/allTransitionsWrapper.I index 97a953b29a..c6019fd655 100644 --- a/panda/src/graph/allTransitionsWrapper.I +++ b/panda/src/graph/allTransitionsWrapper.I @@ -21,7 +21,8 @@ AllTransitionsWrapper() { //////////////////////////////////////////////////////////////////// INLINE AllTransitionsWrapper:: AllTransitionsWrapper(const AllTransitionsWrapper ©) : - _cache(copy._cache) + _cache(copy._cache), + _all_verified(copy._all_verified) { } @@ -33,6 +34,7 @@ AllTransitionsWrapper(const AllTransitionsWrapper ©) : INLINE void AllTransitionsWrapper:: operator = (const AllTransitionsWrapper ©) { _cache = copy._cache; + _all_verified = copy._all_verified; } //////////////////////////////////////////////////////////////////// @@ -102,11 +104,12 @@ set_transition(TypeHandle handle, NodeTransition *trans) { if (_cache == (NodeTransitionCache *)NULL) { _cache = new NodeTransitionCache; } + _all_verified.clear(); return _cache->set_transition(handle, trans); } //////////////////////////////////////////////////////////////////// -// Function: AllTransitionsWrapperset_transition +// Function: AllTransitionsWrapper::set_transition // Access: Public // Description: This flavor of set_transition() accepts a pointer to // a NodeTransition only. It infers the type of the @@ -137,6 +140,7 @@ clear_transition(TypeHandle handle) { if (_cache == (NodeTransitionCache *)NULL) { return NULL; } + _all_verified.clear(); return _cache->clear_transition(handle); } @@ -245,6 +249,7 @@ extract_from(const NodeRelation *arc) { } else { _cache = new NodeTransitionCache(arc->_transitions); } + _all_verified.clear(); } //////////////////////////////////////////////////////////////////// @@ -267,6 +272,7 @@ store_to(NodeRelation *arc) const { INLINE void AllTransitionsWrapper:: compose_in_place(const AllTransitionsWrapper &other) { _cache = NodeTransitionCache::compose(_cache, other._cache); + _all_verified.clear(); } //////////////////////////////////////////////////////////////////// @@ -277,6 +283,7 @@ compose_in_place(const AllTransitionsWrapper &other) { INLINE void AllTransitionsWrapper:: invert_in_place() { _cache = NodeTransitionCache::invert(_cache); + _all_verified.clear(); } //////////////////////////////////////////////////////////////////// @@ -288,6 +295,7 @@ invert_in_place() { INLINE void AllTransitionsWrapper:: invert_compose_in_place(const AllTransitionsWrapper &other) { _cache = NodeTransitionCache::invert_compose(_cache, other._cache); + _all_verified.clear(); } //////////////////////////////////////////////////////////////////// @@ -300,19 +308,63 @@ invert_compose_in_place(const AllTransitionsWrapper &other) { INLINE Node *AllTransitionsWrapper:: extract_from_cache(const NodeRelation *arc) { _cache = arc->_net_transitions; + _all_verified = arc->_all_verified; +#ifndef NDEBUG + if (wrt_cat.is_spam()) { + wrt_cat.spam() + << "AllTransitionsWrapper::extract_from_cache(" << *arc + << "), _all_verified = " << _all_verified << "\n"; + } +#endif return arc->_top_subtree; } //////////////////////////////////////////////////////////////////// // Function: AllTransitionsWrapper::store_to_cache // Access: Public -// Description: +// Description: Completely replaces the cached state on the arc with +// what is represented here. This makes sense if we +// have computed the complete set of net transitions to +// the arc. //////////////////////////////////////////////////////////////////// INLINE void AllTransitionsWrapper:: store_to_cache(NodeRelation *arc, Node *top_subtree) { + arc->_top_subtree = top_subtree; + arc->_net_transitions = _cache; + arc->_all_verified = _all_verified; + +#ifndef NDEBUG + if (wrt_cat.is_spam()) { + wrt_cat.spam() + << "AllTransitionsWrapper::store_to_cache(" << *arc + << "), _all_verified = " << _all_verified << "\n"; + } +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: AllTransitionsWrapper::store_to_cache_partial +// Access: Public +// Description: Updates the cached state on the arc with what is +// represented here, but does not remove transitions on +// the arc's cache that are not mentioned here. This +// makes sense if this cache represents only some of the +// net transitions to the arc, but not necessarily all +// of them. +//////////////////////////////////////////////////////////////////// +INLINE void AllTransitionsWrapper:: +store_to_cache_partial(NodeRelation *arc, Node *top_subtree) { arc->_top_subtree = top_subtree; arc->_net_transitions = NodeTransitionCache::c_union(arc->_net_transitions, _cache); + +#ifndef NDEBUG + if (wrt_cat.is_spam()) { + wrt_cat.spam() + << "AllTransitionsWrapper::store_to_cache_partial(" << *arc + << "), _all_verified = " << _all_verified << "\n"; + } +#endif } //////////////////////////////////////////////////////////////////// @@ -321,10 +373,16 @@ store_to_cache(NodeRelation *arc, Node *top_subtree) { // Description: //////////////////////////////////////////////////////////////////// INLINE bool AllTransitionsWrapper:: -is_cache_verified(UpdateSeq) const { - // We can't ever know if all elements in the set are verified, - // because the set might not be complete. - return false; +is_cache_verified(UpdateSeq as_of) const { +#ifndef NDEBUG + if (wrt_cat.is_spam()) { + wrt_cat.spam() + << "AllTransitionsWrapper::is_cache_verified(" << as_of + << "), _all_verified = " << _all_verified << ", result = " + << (as_of <= _all_verified) << "\n"; + } +#endif + return as_of <= _all_verified; } //////////////////////////////////////////////////////////////////// @@ -335,6 +393,14 @@ is_cache_verified(UpdateSeq) const { INLINE void AllTransitionsWrapper:: set_computed_verified(UpdateSeq now) { _cache = NodeTransitionCache::set_computed_verified(_cache, now); + _all_verified = now; + +#ifndef NDEBUG + if (wrt_cat.is_spam()) { + wrt_cat.spam() + << "AllTransitionsWrapper::set_computed_verified(" << now << ")\n"; + } +#endif } //////////////////////////////////////////////////////////////////// @@ -350,6 +416,7 @@ cached_compose(const AllTransitionsWrapper &cache, UpdateSeq now) { _cache = NodeTransitionCache::cached_compose(_cache, cache._cache, value._cache, now); + _all_verified = now; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/graph/allTransitionsWrapper.h b/panda/src/graph/allTransitionsWrapper.h index 07e24cab38..acb36af168 100644 --- a/panda/src/graph/allTransitionsWrapper.h +++ b/panda/src/graph/allTransitionsWrapper.h @@ -23,6 +23,7 @@ #include "nodeTransition.h" #include "nodeTransitionCache.h" +#include "config_graph.h" #include @@ -76,7 +77,8 @@ public: INLINE Node *extract_from_cache(const NodeRelation *arc); INLINE void store_to_cache(NodeRelation *arc, Node *top_subtree); - INLINE bool is_cache_verified(UpdateSeq now) const; + INLINE void store_to_cache_partial(NodeRelation *arc, Node *top_subtree); + INLINE bool is_cache_verified(UpdateSeq as_of) const; INLINE void set_computed_verified(UpdateSeq now); INLINE void cached_compose(const AllTransitionsWrapper &cache, @@ -104,6 +106,7 @@ public: private: PT(NodeTransitionCache) _cache; + UpdateSeq _all_verified; // This is a special cache object which is always around and always // empty. It's used just so we can have a sensible return value diff --git a/panda/src/graph/nodeRelation.cxx b/panda/src/graph/nodeRelation.cxx index e275c75553..701e84b57c 100644 --- a/panda/src/graph/nodeRelation.cxx +++ b/panda/src/graph/nodeRelation.cxx @@ -442,15 +442,33 @@ attach() { nassertv(!_attached); _attached = true; + + DownRelationPointers &parent_list = _parent->_children[_type]; + UpRelationPointers &child_list = _child->_parents[_type]; - bool inserted_one = internal_insert_arc(_parent->_children[_type], this); - bool inserted_two = internal_insert_arc(_child->_parents[_type], this); + bool inserted_one = internal_insert_arc(parent_list, this); + bool inserted_two = internal_insert_arc(child_list, this); nassertv(inserted_one && inserted_two); // Blow out the cache and increment the current update sequence. _net_transitions.clear(); _last_update = ++last_graph_update[_type]; + /* + // If we have just added a new parent arc to a node that previously + // had exactly one parent, we also need to increment the update + // counter for all the children of that node. + if (child_list.size() == 2) { + cerr << "Attaching " << *this << " at " << _last_update << "\n"; + DownRelationPointers &child_children = _child->_children[_type]; + DownRelationPointers::iterator drpi; + for (drpi = child_children.begin(); drpi != child_children.end(); ++drpi) { + cerr << "Forcing update for " << *(*drpi) << "\n"; + (*drpi)->_last_update = _last_update; + } + } + */ + _parent->force_bound_stale(); mark_bound_stale(); } @@ -481,8 +499,11 @@ detach() { force_bound_stale(); - bool removed_one = internal_remove_arc(_parent->_children[_type], this); - bool removed_two = internal_remove_arc(_child->_parents[_type], this); + DownRelationPointers &parent_list = _parent->_children[_type]; + UpRelationPointers &child_list = _child->_parents[_type]; + + bool removed_one = internal_remove_arc(parent_list, this); + bool removed_two = internal_remove_arc(child_list, this); nassertr(removed_one, result); nassertr(removed_two, result); @@ -493,6 +514,19 @@ detach() { _net_transitions.clear(); _last_update = ++last_graph_update[_type]; + /* + // If we have just removed a parent arc from a node, leaving exactly + // one parent, we also need to increment the update counter for all + // the children of that node. + if (child_list.size() == 1) { + DownRelationPointers &child_children = _child->_children[_type]; + DownRelationPointers::iterator drpi; + for (drpi = child_children.begin(); drpi != child_children.end(); ++drpi) { + (*drpi)->_last_update = _last_update; + } + } + */ + return result; } diff --git a/panda/src/graph/nodeRelation.h b/panda/src/graph/nodeRelation.h index 43ea9dfafb..ca7950d277 100644 --- a/panda/src/graph/nodeRelation.h +++ b/panda/src/graph/nodeRelation.h @@ -156,6 +156,11 @@ private: PT(NodeTransitionCache) _net_transitions; Node *_top_subtree; + // This is updated with the current update sequence whenever we + // verify that *all* the transitions to this arc are accurately + // reflected in the above set. + UpdateSeq _all_verified; + // This is updated with the current update sequence each time the // arc is changed (for instance, to change its state or to reparent // it or something). It exists to support caching in the cull diff --git a/panda/src/graph/nodeTransitionCache.cxx b/panda/src/graph/nodeTransitionCache.cxx index 6f7c9a0a65..e31837b8d4 100644 --- a/panda/src/graph/nodeTransitionCache.cxx +++ b/panda/src/graph/nodeTransitionCache.cxx @@ -390,7 +390,11 @@ invert_compose(const NodeTransitionCache *a, const NodeTransitionCache *b) { //////////////////////////////////////////////////////////////////// // Function: NodeTransitionCache::cached_compose // Access: Public, Static -// Description: +// Description: Returns a cache pointer (which might be a pointer to +// the same cache object, or to a newly allocated +// object) that represents the result of compose(a, b), +// as computed using the cache value as a hint. Mark +// the result as computed at time 'now'. //////////////////////////////////////////////////////////////////// NodeTransitionCache *NodeTransitionCache:: cached_compose(const NodeTransitionCache *a, @@ -440,7 +444,8 @@ cached_compose(const NodeTransitionCache *a, // Description: Returns a new pointer that represents the adjustment // of the given cache to set each computed and verified // value to the current now value. This may modify the -// source cache only if there is only one pointer to it. +// source cache only if there are no other pointers to +// it. //////////////////////////////////////////////////////////////////// NodeTransitionCache *NodeTransitionCache:: set_computed_verified(const NodeTransitionCache *a, UpdateSeq now) { diff --git a/panda/src/graph/nodeTransitionCacheEntry.I b/panda/src/graph/nodeTransitionCacheEntry.I index 90d1e803d8..45d256d710 100644 --- a/panda/src/graph/nodeTransitionCacheEntry.I +++ b/panda/src/graph/nodeTransitionCacheEntry.I @@ -142,8 +142,16 @@ get_trans() const { // Description: //////////////////////////////////////////////////////////////////// INLINE bool NodeTransitionCacheEntry:: -is_cache_verified(UpdateSeq now) const { - return _verified == now; +is_cache_verified(UpdateSeq as_of) const { +#ifndef NDEBUG + if (wrt_cat.is_spam()) { + wrt_cat.spam() + << "NodeTransitionCacheEntry::is_cache_verified(" << as_of + << "), _verified = " << _verified << ", result = " + << (as_of <= _verified) << "\n"; + } +#endif + return as_of <= _verified; } //////////////////////////////////////////////////////////////////// @@ -275,7 +283,8 @@ invert_compose(const NodeTransitionCacheEntry &a, // Function: NodeTransitionCacheEntry::cached_compose // Access: Public, Static // Description: Sets this cache entry to the result of compose(a, b), -// as computed using the cache value as a hint. +// as computed using the cache value as a hint. Mark +// the result as computed at time 'now'. //////////////////////////////////////////////////////////////////// INLINE NodeTransitionCacheEntry NodeTransitionCacheEntry:: cached_compose(const NodeTransitionCacheEntry &a, diff --git a/panda/src/graph/nodeTransitionCacheEntry.h b/panda/src/graph/nodeTransitionCacheEntry.h index 140a32a2a7..dea7b7a8fe 100644 --- a/panda/src/graph/nodeTransitionCacheEntry.h +++ b/panda/src/graph/nodeTransitionCacheEntry.h @@ -9,6 +9,7 @@ #include #include "nodeTransition.h" +#include "config_graph.h" #include #include @@ -35,7 +36,7 @@ public: INLINE bool has_trans() const; INLINE NodeTransition *get_trans() const; - INLINE bool is_cache_verified(UpdateSeq now) const; + INLINE bool is_cache_verified(UpdateSeq as_of) const; INLINE bool is_freshly_computed(UpdateSeq changed) const; INLINE void set_computed_verified(UpdateSeq now); diff --git a/panda/src/graph/nodeTransitionWrapper.I b/panda/src/graph/nodeTransitionWrapper.I index 46172308b5..f449cd42ac 100644 --- a/panda/src/graph/nodeTransitionWrapper.I +++ b/panda/src/graph/nodeTransitionWrapper.I @@ -214,8 +214,8 @@ store_to_cache(NodeRelation *arc, Node *top_subtree) { // Description: //////////////////////////////////////////////////////////////////// INLINE bool NodeTransitionWrapper:: -is_cache_verified(UpdateSeq now) const { - return _entry.is_cache_verified(now); +is_cache_verified(UpdateSeq as_of) const { + return _entry.is_cache_verified(as_of); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/graph/nodeTransitionWrapper.h b/panda/src/graph/nodeTransitionWrapper.h index 527000cb79..8f10da51c7 100644 --- a/panda/src/graph/nodeTransitionWrapper.h +++ b/panda/src/graph/nodeTransitionWrapper.h @@ -66,7 +66,7 @@ public: INLINE Node *extract_from_cache(const NodeRelation *arc); INLINE void store_to_cache(NodeRelation *arc, Node *top_subtree); - INLINE bool is_cache_verified(UpdateSeq now) const; + INLINE bool is_cache_verified(UpdateSeq as_of) const; INLINE void set_computed_verified(UpdateSeq now); INLINE void cached_compose(const NodeTransitionWrapper &cache, diff --git a/panda/src/graph/wrt.I b/panda/src/graph/wrt.I index 59738b46f8..a381372c93 100644 --- a/panda/src/graph/wrt.I +++ b/panda/src/graph/wrt.I @@ -21,15 +21,20 @@ // transitions returned by this function, the result is // always unambiguous; any wrt() ambiguity is resolved // later. +// +// as_of is the most recent update so far on this branch +// of the scene graph; now is the stamp to use to mark +// any computed cache values. //////////////////////////////////////////////////////////////////// template void -get_cached_net_transition(NodeRelation *arc, Node *&root, UpdateSeq now, +get_cached_net_transition(NodeRelation *arc, Node *&root, + UpdateSeq as_of, UpdateSeq now, TransitionWrapper &net, TypeHandle graph_type) { TransitionWrapper cur_cache = TransitionWrapper::init_from(net); Node *top_subtree = cur_cache.extract_from_cache(arc); - if (cur_cache.is_cache_verified(now)) { + if (cur_cache.is_cache_verified(as_of)) { // This arc's cached value has recently been verified, so we don't // even need to go anywhere--we trust it's still good. root = top_subtree; @@ -45,7 +50,11 @@ get_cached_net_transition(NodeRelation *arc, Node *&root, UpdateSeq now, wrt_cat.debug(false) << *root; } wrt_cat.debug(false) - << ") is current as of " << now << "\n"; + << ") is current as of " << as_of << " (now is " + << now << ")\n"; + if (wrt_cat.is_spam()) { + wrt_cat.spam() << "result of " << *arc << " is " << net << "\n"; + } } #endif @@ -83,7 +92,7 @@ get_cached_net_transition(NodeRelation *arc, Node *&root, UpdateSeq now, // The node has exactly one parent. Carry on. NodeRelation *parent = *(*uri).second.begin(); - get_cached_net_transition(parent, root, now, net, graph_type); + get_cached_net_transition(parent, root, as_of, now, net, graph_type); // Now recompute our own cache. TransitionWrapper cur_value = TransitionWrapper::init_from(net); @@ -103,7 +112,11 @@ get_cached_net_transition(NodeRelation *arc, Node *&root, UpdateSeq now, wrt_cat.debug(false) << *root; } wrt_cat.debug(false) - << ") is recomputed as of " << now << "\n"; + << ") is recomputed as of " << as_of << " (now is " + << now << ")\n"; + if (wrt_cat.is_spam()) { + wrt_cat.spam() << "result of " << *arc << " is " << net << "\n"; + } } #endif } @@ -120,13 +133,17 @@ get_cached_net_transition(NodeRelation *arc, Node *&root, UpdateSeq now, // contains a list of NodeRelation pointers to resolve // ambiguities when a node with multiple parents is // encountered. +// +// as_of is the most recent update so far on this branch +// of the scene graph; now is the stamp to use to mark +// any computed cache values. //////////////////////////////////////////////////////////////////// template void get_cached_net_transition(const Node *node, InputIterator arc_list_begin, InputIterator arc_list_end, - UpdateSeq now, + UpdateSeq as_of, UpdateSeq now, TransitionWrapper &result, TypeHandle graph_type) { if (node == NULL) { @@ -219,15 +236,15 @@ get_cached_net_transition(const Node *node, // Get the net transition leading into this node. Node *root; - get_cached_net_transition((NodeRelation *)parent_arc, root, now, result, - graph_type); + get_cached_net_transition((NodeRelation *)parent_arc, root, + as_of, now, result, graph_type); if (root != NULL) { // There's more to get. The above function call was forced to // stop at a node with multiple parents. TransitionWrapper more = TransitionWrapper::init_from(result); get_cached_net_transition(root, arc_list_begin, arc_list_end, - now, more, graph_type); + as_of, now, more, graph_type); more.compose_in_place(result); result = more; } @@ -396,14 +413,15 @@ cached_wrt_base(const Node *from, wrt_cat.debug(false) << *to; } wrt_cat.debug(false) - << "), as of " << now << "\n"; + << "), as of " << now << " (now is " + << now << ")\n"; } #endif - get_cached_net_transition(from, from_arcs_begin, from_arcs_end, now, - net_from_trans, graph_type); - get_cached_net_transition(to, to_arcs_begin, to_arcs_end, now, - result, graph_type); + get_cached_net_transition(from, from_arcs_begin, from_arcs_end, + now, now, net_from_trans, graph_type); + get_cached_net_transition(to, to_arcs_begin, to_arcs_end, + now, now, result, graph_type); #ifndef NDEBUG if (paranoid_wrt) { @@ -686,8 +704,8 @@ get_uncached_wrt_subtree(Node *node, Node *to, TransitionWrapper &result, template INLINE Node * -uncached_wrt_subtree(NodeRelation *arc, Node *to, TransitionWrapper &result, - TypeHandle graph_type) { +uncached_wrt_subtree(NodeRelation *arc, Node *to, + TransitionWrapper &result, TypeHandle graph_type) { Node *stop = get_uncached_wrt_subtree(arc->get_parent(), to, result, graph_type); @@ -717,14 +735,12 @@ uncached_wrt_subtree(NodeRelation *arc, Node *to, TransitionWrapper &result, template Node * -cached_wrt_subtree(NodeRelation *arc, Node *to, TransitionWrapper &result, - TypeHandle graph_type) { - UpdateSeq now = last_graph_update[graph_type]; - +cached_wrt_subtree(NodeRelation *arc, Node *to, UpdateSeq as_of, UpdateSeq now, + TransitionWrapper &result, TypeHandle graph_type) { // First, determine the net transition up to the top of the current // subtree. Node *top_subtree; - get_cached_net_transition(arc, top_subtree, now, result, graph_type); + get_cached_net_transition(arc, top_subtree, as_of, now, result, graph_type); if (top_subtree == to || to == (Node *)NULL) { // If the top of the subtree is the node we asked to wrt to, @@ -749,12 +765,6 @@ cached_wrt_subtree(NodeRelation *arc, Node *to, TransitionWrapper &result, // Otherwise, it must be the case that the node we want to wrt to is // some descendent of the top_subtree node. It also therefore // follows that this node has exactly one parent. - - nassertr(to->get_num_parents(graph_type) == 1, NULL); - NodeRelation *to_arc = to->get_parent(graph_type, 0); - - // Save the result from the first pass. - TransitionWrapper net_from_trans = result; #ifndef NDEBUG if (wrt_cat.is_spam()) { @@ -765,15 +775,22 @@ cached_wrt_subtree(NodeRelation *arc, Node *to, TransitionWrapper &result, } else { wrt_cat.spam(false) << *top_subtree; } - wrt_cat.spam() << ", first result is:\n"; + wrt_cat.spam(false) << ", first result is:\n"; result.write(wrt_cat.spam(false), 2); } #endif + nassertr(to->get_num_parents(graph_type) == 1, NULL); + NodeRelation *to_arc = to->get_parent(graph_type, 0); + + // Save the result from the first pass. + TransitionWrapper net_from_trans = result; + // Now determine the net transition to the top of the subtree from // this arc. It had better be the same subtree! Node *top_subtree_2; - get_cached_net_transition(to_arc, top_subtree_2, now, result, graph_type); + get_cached_net_transition(to_arc, top_subtree_2, as_of, now, + result, graph_type); nassertr(top_subtree == top_subtree_2, NULL); // And now compute the actual wrt. @@ -855,15 +872,15 @@ cached_wrt_subtree(NodeRelation *arc, Node *to, TransitionWrapper &result, template INLINE Node * -wrt_subtree(NodeRelation *arc, Node *to, TransitionWrapper &result, - TypeHandle graph_type) { +wrt_subtree(NodeRelation *arc, Node *to, UpdateSeq as_of, UpdateSeq now, + TransitionWrapper &result, TypeHandle graph_type) { #ifndef NDEBUG if (!cache_wrt) { - // If we aren't caching wrt, do this the hard way. + // If we aren't caching wrt, compute it explicitly. return uncached_wrt_subtree(arc, to, result, graph_type); } #endif - return cached_wrt_subtree(arc, to, result, graph_type); + return cached_wrt_subtree(arc, to, as_of, now, result, graph_type); } diff --git a/panda/src/graph/wrt.h b/panda/src/graph/wrt.h index abee0f1507..bd65b04104 100644 --- a/panda/src/graph/wrt.h +++ b/panda/src/graph/wrt.h @@ -118,10 +118,14 @@ uncached_wrt(const Node *from, // general utility; it is of primary interest to code (like the // CullTraverser) that needs to cache a wrt-type value for many nodes // across the entire tree. + +// as_of is the most recent update between 'arc' and 'to'; now is the +// current most recent update sequence anywhere, used to use to mark +// any computed cache values. template INLINE Node * -wrt_subtree(NodeRelation *arc, Node *to, TransitionWrapper &result, - TypeHandle graph_type); +wrt_subtree(NodeRelation *arc, Node *to, UpdateSeq as_of, UpdateSeq now, + TransitionWrapper &result, TypeHandle graph_type); #include "wrt.I"