From 160c848b686a55ff88ff54f28dced23ab7003203 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 25 Apr 2006 13:55:46 +0000 Subject: [PATCH] better PandaNode::get_children(), introduce PandaNode::reset_all_prev_transform() --- panda/src/collide/collisionTraverser.cxx | 29 +- panda/src/collide/collisionTraverser.h | 3 - panda/src/pgraph/Sources.pp | 3 + panda/src/pgraph/cullTraverser.cxx | 12 +- panda/src/pgraph/geomNode.cxx | 22 +- panda/src/pgraph/geomTransformer.cxx | 5 +- panda/src/pgraph/pandaNode.I | 426 ++++++++++++----------- panda/src/pgraph/pandaNode.cxx | 380 +++++++++++--------- panda/src/pgraph/pandaNode.h | 118 +++---- panda/src/pgraph/pgraph_composite3.cxx | 1 + panda/src/pgraph/sceneGraphReducer.cxx | 4 +- panda/src/pipeline/pipelineCycler.h | 18 +- 12 files changed, 517 insertions(+), 504 deletions(-) diff --git a/panda/src/collide/collisionTraverser.cxx b/panda/src/collide/collisionTraverser.cxx index 032edbaaba..4cad625001 100644 --- a/panda/src/collide/collisionTraverser.cxx +++ b/panda/src/collide/collisionTraverser.cxx @@ -41,7 +41,6 @@ #include "indent.h" PStatCollector CollisionTraverser::_collisions_pcollector("App:Collisions"); -PStatCollector CollisionTraverser::_reset_prev_pcollector("App:Collisions:Reset"); PStatCollector CollisionTraverser::_cnode_volume_pcollector("Collision Volumes:CollisionNode"); PStatCollector CollisionTraverser::_gnode_volume_pcollector("Collision Volumes:GeomNode"); @@ -313,16 +312,12 @@ traverse(const NodePath &root) { //////////////////////////////////////////////////////////////////// // Function: CollisionTraverser::reset_prev_transform // Access: Published -// Description: Once the collision traversal has finished, resets all -// of the velocity deltas in the scene graph by setting -// the "previous" transform to the current transform. -// This must be called at least once per frame for -// collisions to respect this velocity setting properly. +// Description: This method is deprecated. Just call +// PandaNode::reset_all_prev_transform() now. //////////////////////////////////////////////////////////////////// void CollisionTraverser:: -reset_prev_transform(const NodePath &root) { - PStatTimer timer(_reset_prev_pcollector); - r_reset_prev_transform(root.node()); +reset_prev_transform(const NodePath &) { + PandaNode::reset_all_prev_transform(); } #ifdef DO_COLLISION_RECORDING @@ -883,22 +878,6 @@ remove_handler(CollisionTraverser::Handlers::iterator hi) { return hi; } -//////////////////////////////////////////////////////////////////// -// Function: CollisionTraverser::r_reset_prev_transform -// Access: Private -// Description: -//////////////////////////////////////////////////////////////////// -void CollisionTraverser:: -r_reset_prev_transform(PandaNode *node) { - node->reset_prev_transform(); - - PandaNode::Children children = node->get_children(); - int num_children = children.get_num_children(); - for (int i = 0; i < num_children; ++i) { - r_reset_prev_transform(children.get_child(i)); - } -} - //////////////////////////////////////////////////////////////////// // Function: CollisionTraverser::get_pass_collector // Access: Private diff --git a/panda/src/collide/collisionTraverser.h b/panda/src/collide/collisionTraverser.h index 3f463bae47..40c75cdfd5 100644 --- a/panda/src/collide/collisionTraverser.h +++ b/panda/src/collide/collisionTraverser.h @@ -102,8 +102,6 @@ private: const GeometricBoundingVolume *from_node_gbv, const GeometricBoundingVolume *solid_gbv); - void r_reset_prev_transform(PandaNode *node); - PStatCollector &get_pass_collector(int pass); private: @@ -134,7 +132,6 @@ private: // Statistics static PStatCollector _collisions_pcollector; - static PStatCollector _reset_prev_pcollector; static PStatCollector _cnode_volume_pcollector; static PStatCollector _gnode_volume_pcollector; diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index 42b5b12ba7..00a8732bb7 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -73,6 +73,7 @@ nodePathComponent.I nodePathComponent.h \ nodePathLerps.h \ pandaNode.I pandaNode.h \ + pandaNodeChain.I pandaNodeChain.h \ planeNode.I planeNode.h \ pointLight.I pointLight.h \ polylightNode.I polylightNode.h \ @@ -174,6 +175,7 @@ nodePathComponent.cxx \ nodePathLerps.cxx \ pandaNode.cxx \ + pandaNodeChain.cxx \ planeNode.cxx \ pointLight.cxx \ polylightNode.cxx \ @@ -272,6 +274,7 @@ nodePathComponent.I nodePathComponent.h \ nodePathLerps.h \ pandaNode.I pandaNode.h \ + pandaNodeChain.I pandaNodeChain.h \ planeNode.I planeNode.h \ pointLight.I pointLight.h \ polylightNode.I polylightNode.h \ diff --git a/panda/src/pgraph/cullTraverser.cxx b/panda/src/pgraph/cullTraverser.cxx index 2479f72a9f..62897af494 100644 --- a/panda/src/pgraph/cullTraverser.cxx +++ b/panda/src/pgraph/cullTraverser.cxx @@ -248,22 +248,20 @@ traverse_below(CullTraverserData &data) { #endif } - // Now visit all the node's children. We cannot use the - // node->get_children() interface, because that will keep a read - // pointer open, and we might end up changing this node during the - // traversal. - int num_children = node->get_num_children(); + // Now visit all the node's children. + PandaNode::Children children = node->get_children(); + int num_children = children.get_num_children(); if (node->has_selective_visibility()) { int i = node->get_first_visible_child(); while (i < num_children) { - CullTraverserData next_data(data, node->get_child(i)); + CullTraverserData next_data(data, children.get_child(i)); traverse(next_data); i = node->get_next_visible_child(i); } } else { for (int i = 0; i < num_children; i++) { - CullTraverserData next_data(data, node->get_child(i)); + CullTraverserData next_data(data, children.get_child(i)); traverse(next_data); } } diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index f72b9dea4b..868cb72384 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -191,8 +191,9 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, } } - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler) { - CDStageWriter cdata(_cycler, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { + CDStageWriter cdata(_cycler, pipeline_stage, current_thread); Geoms::iterator gi; for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) { GeomEntry &entry = (*gi); @@ -409,8 +410,9 @@ add_geom(Geom *geom, const RenderState *state) { nassertv(geom->check_valid()); nassertv(state != (RenderState *)NULL); - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler) { - CDStageWriter cdata(_cycler, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { + CDStageWriter cdata(_cycler, pipeline_stage, current_thread); cdata->_geoms.push_back(GeomEntry(geom, state)); } @@ -427,9 +429,10 @@ add_geom(Geom *geom, const RenderState *state) { //////////////////////////////////////////////////////////////////// void GeomNode:: add_geoms_from(const GeomNode *other) { - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler) { - CDStageWriter cdata(_cycler, pipeline_stage); - CDStageReader cdata_other(other->_cycler, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { + CDStageWriter cdata(_cycler, pipeline_stage, current_thread); + CDStageReader cdata_other(other->_cycler, pipeline_stage, current_thread); Geoms::const_iterator gi; for (gi = cdata_other->_geoms.begin(); @@ -511,8 +514,9 @@ check_valid() const { //////////////////////////////////////////////////////////////////// void GeomNode:: unify() { - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler) { - CDStageWriter cdata(_cycler, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { + CDStageWriter cdata(_cycler, pipeline_stage, current_thread); Geoms new_geoms; diff --git a/panda/src/pgraph/geomTransformer.cxx b/panda/src/pgraph/geomTransformer.cxx index f5f0d5814e..9ff82797d1 100644 --- a/panda/src/pgraph/geomTransformer.cxx +++ b/panda/src/pgraph/geomTransformer.cxx @@ -128,8 +128,9 @@ bool GeomTransformer:: transform_vertices(GeomNode *node, const LMatrix4f &mat) { bool any_changed = false; - OPEN_ITERATE_CURRENT_AND_UPSTREAM(node->_cycler) { - GeomNode::CDStageWriter cdata(node->_cycler, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(node->_cycler, current_thread) { + GeomNode::CDStageWriter cdata(node->_cycler, pipeline_stage, current_thread); GeomNode::Geoms::iterator gi; for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) { GeomNode::GeomEntry &entry = (*gi); diff --git a/panda/src/pgraph/pandaNode.I b/panda/src/pgraph/pandaNode.I index e8e5b7ae87..f347daacd5 100644 --- a/panda/src/pgraph/pandaNode.I +++ b/panda/src/pgraph/pandaNode.I @@ -86,20 +86,23 @@ compare_draw_mask(DrawMask running_draw_mask, DrawMask camera_mask) const { INLINE int PandaNode:: get_num_parents() const { CDLinksReader cdata(_cycler_links); - return cdata->_up.size(); + return cdata->get_up()->size(); } //////////////////////////////////////////////////////////////////// // Function: PandaNode::get_parent // Access: Published // Description: Returns the nth parent node of this node. See -// get_num_parents(). +// get_num_parents(). Also see get_parents(), if your +// intention is to iterate through the complete list of +// parents; get_parents() is preferable in this case. //////////////////////////////////////////////////////////////////// INLINE PandaNode *PandaNode:: get_parent(int n) const { CDLinksReader cdata(_cycler_links); - nassertr(n >= 0 && n < (int)cdata->_up.size(), NULL); - return cdata->_up[n].get_parent(); + const Up &up = *cdata->get_up(); + nassertr(n >= 0 && n < (int)up.size(), NULL); + return up[n].get_parent(); } //////////////////////////////////////////////////////////////////// @@ -125,20 +128,23 @@ find_parent(PandaNode *node) const { INLINE int PandaNode:: get_num_children() const { CDLinksReader cdata(_cycler_links); - return cdata->_down.size(); + return cdata->get_down()->size(); } //////////////////////////////////////////////////////////////////// // Function: PandaNode::get_child // Access: Published // Description: Returns the nth child node of this node. See -// get_num_children(). +// get_num_children(). Also see get_children(), if your +// intention is to iterate through the complete list of +// children; get_children() is preferable in this case. //////////////////////////////////////////////////////////////////// INLINE PandaNode *PandaNode:: get_child(int n) const { CDLinksReader cdata(_cycler_links); - nassertr(n >= 0 && n < (int)cdata->_down.size(), NULL); - return cdata->_down[n].get_child(); + const Down &down = *cdata->get_down(); + nassertr(n >= 0 && n < (int)down.size(), NULL); + return down[n].get_child(); } //////////////////////////////////////////////////////////////////// @@ -151,8 +157,9 @@ get_child(int n) const { INLINE int PandaNode:: get_child_sort(int n) const { CDLinksReader cdata(_cycler_links); - nassertr(n >= 0 && n < (int)cdata->_down.size(), -1); - return cdata->_down[n].get_sort(); + const Down &down = *cdata->get_down(); + nassertr(n >= 0 && n < (int)down.size(), -1); + return down[n].get_sort(); } //////////////////////////////////////////////////////////////////// @@ -229,20 +236,24 @@ unstash_child(PandaNode *child_node) { INLINE int PandaNode:: get_num_stashed() const { CDLinksReader cdata(_cycler_links); - return cdata->_stashed.size(); + return cdata->get_stashed()->size(); } //////////////////////////////////////////////////////////////////// // Function: PandaNode::get_stashed // Access: Published -// Description: Returns the nth stashed node of this node. See -// get_num_stashed(). +// Description: Returns the nth stashed child of this node. See +// get_num_stashed(). Also see get_stashed(), if your +// intention is to iterate through the complete list of +// stashed children; get_stashed() is preferable in this +// case. //////////////////////////////////////////////////////////////////// INLINE PandaNode *PandaNode:: get_stashed(int n) const { CDLinksReader cdata(_cycler_links); - nassertr(n >= 0 && n < (int)cdata->_stashed.size(), NULL); - return cdata->_stashed[n].get_child(); + const Down &stashed = *cdata->get_stashed(); + nassertr(n >= 0 && n < (int)stashed.size(), NULL); + return stashed[n].get_child(); } //////////////////////////////////////////////////////////////////// @@ -255,8 +266,9 @@ get_stashed(int n) const { INLINE int PandaNode:: get_stashed_sort(int n) const { CDLinksReader cdata(_cycler_links); - nassertr(n >= 0 && n < (int)cdata->_stashed.size(), -1); - return cdata->_stashed[n].get_sort(); + const Down &stashed = *cdata->get_stashed(); + nassertr(n >= 0 && n < (int)stashed.size(), -1); + return stashed[n].get_sort(); } //////////////////////////////////////////////////////////////////// @@ -422,6 +434,20 @@ get_prev_transform() const { return cdata->_prev_transform; } +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::has_dirty_prev_transform +// Access: Published +// Description: Returns true if this node has the +// _dirty_prev_transform flag set, which indicates its +// _prev_transform is different from its _transform +// value (in pipeline stage 0). In this case, the node +// will be visited by reset_prev_transform(). +//////////////////////////////////////////////////////////////////// +INLINE bool PandaNode:: +has_dirty_prev_transform() const { + return _dirty_prev_transform; +} + //////////////////////////////////////////////////////////////////// // Function: PandaNode::get_tag // Access: Published @@ -690,22 +716,6 @@ mark_internal_bounds_stale(int pipeline_stage) { mark_bounds_stale(pipeline_stage); } -//////////////////////////////////////////////////////////////////// -// Function: PandaNode::get_children_copy -// Access: Public -// Description: Returns an object that can be used to walk through -// the list of children of the node. Unlike -// get_children(), this function actually returns an -// object that protects you from self-modifying loops, -// because it makes and returns a copy of the complete -// children list. -//////////////////////////////////////////////////////////////////// -INLINE PandaNode::ChildrenCopy PandaNode:: -get_children_copy() const { - CDLinksReader cdata(_cycler_links); - return ChildrenCopy(cdata); -} - //////////////////////////////////////////////////////////////////// // Function: PandaNode::get_children // Access: Public @@ -713,74 +723,56 @@ get_children_copy() const { // the list of children of the node. When you intend to // visit multiple children, using this is slightly // faster than calling get_child() directly on the -// PandaNode, since this object keeps the PipelineCycler -// open the whole time. +// PandaNode, since this object avoids reopening the +// PipelineCycler each time. // -// However, this object does not protect you from -// self-modifying loops (e.g. adding or removing -// children during traversal). Furthermore, if Panda is -// compiled with pipelining enabled, this method is -// compiled to behave exactly as get_children_copy(): it -// returns a copy. This is intended to reduce the risk -// of deadlocks. +// This object also protects you from self-modifying +// loops (e.g. adding or removing children during +// traversal), since a virtual copy of the children is +// made ahead of time. The virtual copy is fast--it is +// a form of copy-on-write, so the list is not actually +// copied unless it is modified during the traversal. //////////////////////////////////////////////////////////////////// INLINE PandaNode::Children PandaNode:: -get_children() const { - CDLinksReader cdata(_cycler_links); +get_children(Thread *current_thread) const { + CDLinksReader cdata(_cycler_links, current_thread); return Children(cdata); } -//////////////////////////////////////////////////////////////////// -// Function: PandaNode::get_stashed_copy -// Access: Public -// Description: Returns an object that can be used to walk through -// the list of stashed children of the node. Unlike -// get_stashed(), this function actually returns an -// object that protects you from self-modifying loops, -// because it makes and returns a copy of the complete -// stashed list. -//////////////////////////////////////////////////////////////////// -INLINE PandaNode::StashedCopy PandaNode:: -get_stashed_copy() const { - CDLinksReader cdata(_cycler_links); - return StashedCopy(cdata); -} - //////////////////////////////////////////////////////////////////// // Function: PandaNode::get_stashed // Access: Public // Description: Returns an object that can be used to walk through -// the list of stashed children of the node. When you -// intend to visit multiple children, using this is -// slightly faster than calling get_stashed() directly -// on the PandaNode, since this object keeps the -// PipelineCycler open the whole time. +// the list of children of the node. When you intend to +// visit multiple children, using this is slightly +// faster than calling get_stashed() directly on the +// PandaNode, since this object avoids reopening the +// PipelineCycler each time. // -// However, this object does not protect you from -// self-modifying loops (e.g. adding or removing -// stashed during traversal). Furthermore, if Panda is -// compiled with pipelining enabled, this method is -// compiled to behave exactly as get_stashed_copy(): it -// returns a copy. This is intended to reduce the risk -// of deadlocks. +// This object also protects you from self-modifying +// loops (e.g. adding or removing children during +// traversal), since a virtual copy of the children is +// made ahead of time. The virtual copy is fast--it is +// a form of copy-on-write, so the list is not actually +// copied unless it is modified during the traversal. //////////////////////////////////////////////////////////////////// INLINE PandaNode::Stashed PandaNode:: -get_stashed() const { - CDLinksReader cdata(_cycler_links); +get_stashed(Thread *current_thread) const { + CDLinksReader cdata(_cycler_links, current_thread); return Stashed(cdata); } //////////////////////////////////////////////////////////////////// -// Function: PandaNode::get_parents_copy +// Function: PandaNode::get_parents // Access: Public // Description: Returns an object that can be used to walk through // the list of parents of the node, similar to -// get_children_copy()/ +// get_children() and get_stashed(). //////////////////////////////////////////////////////////////////// -INLINE PandaNode::ParentsCopy PandaNode:: -get_parents_copy() const { - CDLinksReader cdata(_cycler_links); - return ParentsCopy(cdata); +INLINE PandaNode::Parents PandaNode:: +get_parents(Thread *current_thread) const { + CDLinksReader cdata(_cycler_links, current_thread); + return Parents(cdata); } //////////////////////////////////////////////////////////////////// @@ -790,11 +782,46 @@ get_parents_copy() const { //////////////////////////////////////////////////////////////////// INLINE int PandaNode:: do_find_parent(PandaNode *node, const CDataLinks *cdata) const { - Up::const_iterator ui = cdata->_up.find(UpConnection(node)); - if (ui == cdata->_up.end()) { + const Up &up = *cdata->get_up(); + Up::const_iterator ui = up.find(UpConnection(node)); + if (ui == up.end()) { return -1; } - return ui - cdata->_up.begin(); + return ui - up.begin(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::set_dirty_prev_transform +// Access: Private +// Description: Sets the dirty_prev_transform flag, and adds the node +// to the _dirty_prev_transforms chain. +//////////////////////////////////////////////////////////////////// +INLINE void PandaNode:: +set_dirty_prev_transform() { + if (!_dirty_prev_transform) { + MutexHolder holder(_dirty_prev_transforms._lock); + if (!_dirty_prev_transform) { + LinkedListNode::insert_before(&_dirty_prev_transforms); + _dirty_prev_transform = true; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::clear_dirty_prev_transform +// Access: Private +// Description: Clears the dirty_prev_transform flag, and removes the node +// from the _dirty_prev_transforms chain. +//////////////////////////////////////////////////////////////////// +INLINE void PandaNode:: +clear_dirty_prev_transform() { + if (_dirty_prev_transform) { + MutexHolder holder(_dirty_prev_transforms._lock); + if (_dirty_prev_transform) { + LinkedListNode::remove_from_list(); + _dirty_prev_transform = false; + } + } } //////////////////////////////////////////////////////////////////// @@ -936,10 +963,85 @@ CDataBounds() { // Description: //////////////////////////////////////////////////////////////////// INLINE PandaNode::CDataLinks:: -CDataLinks() { +CDataLinks() : + _down(new PandaNode::Down), + _stashed(new PandaNode::Down), + _up(new PandaNode::Up) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::CDataLinks::get_down +// Access: Public +// Description: Returns a read-only pointer to the _down list. +//////////////////////////////////////////////////////////////////// +INLINE const PandaNode::Down *PandaNode::CDataLinks:: +get_down() const { + return _down; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::CDataLinks::modify_down +// Access: Public +// Description: Returns a modifiable, unique pointer to the _down +// list. +//////////////////////////////////////////////////////////////////// +INLINE PandaNode::Down *PandaNode::CDataLinks:: +modify_down() { + if (_down->get_ref_count() > 1) { + _down = new Down(*_down); + } + return _down; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::CDataLinks::get_stashed +// Access: Public +// Description: Returns a read-only pointer to the _stashed list. +//////////////////////////////////////////////////////////////////// +INLINE const PandaNode::Down *PandaNode::CDataLinks:: +get_stashed() const { + return _stashed; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::CDataLinks::modify_stashed +// Access: Public +// Description: Returns a modifiable, unique pointer to the _stashed +// list. +//////////////////////////////////////////////////////////////////// +INLINE PandaNode::Down *PandaNode::CDataLinks:: +modify_stashed() { + if (_stashed->get_ref_count() > 1) { + _stashed = new Down(*_stashed); + } + return _stashed; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::CDataLinks::get_up +// Access: Public +// Description: Returns a read-only pointer to the _up list. +//////////////////////////////////////////////////////////////////// +INLINE const PandaNode::Up *PandaNode::CDataLinks:: +get_up() const { + return _up; +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::CDataLinks::modify_up +// Access: Public +// Description: Returns a modifiable, unique pointer to the _up +// list. +//////////////////////////////////////////////////////////////////// +INLINE PandaNode::Up *PandaNode::CDataLinks:: +modify_up() { + if (_up->get_ref_count() > 1) { + _up = new Up(*_up); + } + return _up; } -#ifndef DO_PIPELINING //////////////////////////////////////////////////////////////////// // Function: PandaNode::Children::Constructor // Access: Public @@ -947,12 +1049,10 @@ CDataLinks() { //////////////////////////////////////////////////////////////////// INLINE PandaNode::Children:: Children(const PandaNode::CDLinksReader &cdata) : - _cdata(cdata) + _down(cdata->get_down()) { } -#endif // DO_PIPELINING -#ifndef DO_PIPELINING //////////////////////////////////////////////////////////////////// // Function: PandaNode::Children::Copy Constructor // Access: Public @@ -960,12 +1060,10 @@ Children(const PandaNode::CDLinksReader &cdata) : //////////////////////////////////////////////////////////////////// INLINE PandaNode::Children:: Children(const PandaNode::Children ©) : - _cdata(copy._cdata) + _down(copy._down) { } -#endif // DO_PIPELINING -#ifndef DO_PIPELINING //////////////////////////////////////////////////////////////////// // Function: PandaNode::Children::Copy Assignment Operator // Access: Public @@ -973,11 +1071,9 @@ Children(const PandaNode::Children ©) : //////////////////////////////////////////////////////////////////// INLINE void PandaNode::Children:: operator = (const PandaNode::Children ©) { - _cdata = copy._cdata; + _down = copy._down; } -#endif // DO_PIPELINING -#ifndef DO_PIPELINING //////////////////////////////////////////////////////////////////// // Function: PandaNode::Children::get_num_children // Access: Public @@ -985,11 +1081,9 @@ operator = (const PandaNode::Children ©) { //////////////////////////////////////////////////////////////////// INLINE int PandaNode::Children:: get_num_children() const { - return _cdata->_down.size(); + return _down->size(); } -#endif // DO_PIPELINING -#ifndef DO_PIPELINING //////////////////////////////////////////////////////////////////// // Function: PandaNode::Children::get_child // Access: Public @@ -997,54 +1091,10 @@ get_num_children() const { //////////////////////////////////////////////////////////////////// INLINE PandaNode *PandaNode::Children:: get_child(int n) const { - nassertr(n >= 0 && n < (int)_cdata->_down.size(), NULL); - return _cdata->_down[n].get_child(); -} -#endif // DO_PIPELINING - -//////////////////////////////////////////////////////////////////// -// Function: PandaNode::ChildrenCopy::Copy Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE PandaNode::ChildrenCopy:: -ChildrenCopy(const PandaNode::ChildrenCopy ©) : - _list(copy._list) -{ + nassertr(n >= 0 && n < (int)_down->size(), NULL); + return (*_down)[n].get_child(); } -//////////////////////////////////////////////////////////////////// -// Function: PandaNode::ChildrenCopy::Copy Assignment Operator -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void PandaNode::ChildrenCopy:: -operator = (const PandaNode::ChildrenCopy ©) { - _list = copy._list; -} - -//////////////////////////////////////////////////////////////////// -// Function: PandaNode::ChildrenCopy::get_num_children -// Access: Public -// Description: Returns the number of children of the node. -//////////////////////////////////////////////////////////////////// -INLINE int PandaNode::ChildrenCopy:: -get_num_children() const { - return _list.size(); -} - -//////////////////////////////////////////////////////////////////// -// Function: PandaNode::ChildrenCopy::get_child -// Access: Public -// Description: Returns the nth child of the node. -//////////////////////////////////////////////////////////////////// -INLINE PandaNode *PandaNode::ChildrenCopy:: -get_child(int n) const { - nassertr(n >= 0 && n < (int)_list.size(), NULL); - return _list[n]; -} - -#ifndef DO_PIPELINING //////////////////////////////////////////////////////////////////// // Function: PandaNode::Stashed::Constructor // Access: Public @@ -1052,12 +1102,10 @@ get_child(int n) const { //////////////////////////////////////////////////////////////////// INLINE PandaNode::Stashed:: Stashed(const PandaNode::CDLinksReader &cdata) : - _cdata(cdata) + _stashed(cdata->get_stashed()) { } -#endif // DO_PIPELINING -#ifndef DO_PIPELINING //////////////////////////////////////////////////////////////////// // Function: PandaNode::Stashed::Copy Constructor // Access: Public @@ -1065,12 +1113,10 @@ Stashed(const PandaNode::CDLinksReader &cdata) : //////////////////////////////////////////////////////////////////// INLINE PandaNode::Stashed:: Stashed(const PandaNode::Stashed ©) : - _cdata(copy._cdata) + _stashed(copy._stashed) { } -#endif // DO_PIPELINING -#ifndef DO_PIPELINING //////////////////////////////////////////////////////////////////// // Function: PandaNode::Stashed::Copy Assignment Operator // Access: Public @@ -1078,11 +1124,9 @@ Stashed(const PandaNode::Stashed ©) : //////////////////////////////////////////////////////////////////// INLINE void PandaNode::Stashed:: operator = (const PandaNode::Stashed ©) { - _cdata = copy._cdata; + _stashed = copy._stashed; } -#endif // DO_PIPELINING -#ifndef DO_PIPELINING //////////////////////////////////////////////////////////////////// // Function: PandaNode::Stashed::get_num_stashed // Access: Public @@ -1090,11 +1134,9 @@ operator = (const PandaNode::Stashed ©) { //////////////////////////////////////////////////////////////////// INLINE int PandaNode::Stashed:: get_num_stashed() const { - return _cdata->_stashed.size(); + return _stashed->size(); } -#endif // DO_PIPELINING -#ifndef DO_PIPELINING //////////////////////////////////////////////////////////////////// // Function: PandaNode::Stashed::get_stashed // Access: Public @@ -1102,91 +1144,59 @@ get_num_stashed() const { //////////////////////////////////////////////////////////////////// INLINE PandaNode *PandaNode::Stashed:: get_stashed(int n) const { - nassertr(n >= 0 && n < (int)_cdata->_stashed.size(), NULL); - return _cdata->_stashed[n].get_child(); + nassertr(n >= 0 && n < (int)_stashed->size(), NULL); + return (*_stashed)[n].get_child(); } -#endif // DO_PIPELINING //////////////////////////////////////////////////////////////////// -// Function: PandaNode::StashedCopy::Copy Constructor +// Function: PandaNode::Parents::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE PandaNode::StashedCopy:: -StashedCopy(const PandaNode::StashedCopy ©) : - _list(copy._list) +INLINE PandaNode::Parents:: +Parents(const PandaNode::CDLinksReader &cdata) : + _up(cdata->get_up()) { } //////////////////////////////////////////////////////////////////// -// Function: PandaNode::StashedCopy::Copy Assignment Operator +// Function: PandaNode::Parents::Copy Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE void PandaNode::StashedCopy:: -operator = (const PandaNode::StashedCopy ©) { - _list = copy._list; -} - -//////////////////////////////////////////////////////////////////// -// Function: PandaNode::StashedCopy::get_num_stashed -// Access: Public -// Description: Returns the number of stashed children of the node. -//////////////////////////////////////////////////////////////////// -INLINE int PandaNode::StashedCopy:: -get_num_stashed() const { - return _list.size(); -} - -//////////////////////////////////////////////////////////////////// -// Function: PandaNode::StashedCopy::get_stashed -// Access: Public -// Description: Returns the nth stashed child of the node. -//////////////////////////////////////////////////////////////////// -INLINE PandaNode *PandaNode::StashedCopy:: -get_stashed(int n) const { - nassertr(n >= 0 && n < (int)_list.size(), NULL); - return _list[n]; -} - -//////////////////////////////////////////////////////////////////// -// Function: PandaNode::ParentsCopy::Copy Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE PandaNode::ParentsCopy:: -ParentsCopy(const PandaNode::ParentsCopy ©) : - _list(copy._list) +INLINE PandaNode::Parents:: +Parents(const PandaNode::Parents ©) : + _up(copy._up) { } //////////////////////////////////////////////////////////////////// -// Function: PandaNode::ParentsCopy::Copy Assignment Operator +// Function: PandaNode::Parents::Copy Assignment Operator // Access: Public // Description: //////////////////////////////////////////////////////////////////// -INLINE void PandaNode::ParentsCopy:: -operator = (const PandaNode::ParentsCopy ©) { - _list = copy._list; +INLINE void PandaNode::Parents:: +operator = (const PandaNode::Parents ©) { + _up = copy._up; } //////////////////////////////////////////////////////////////////// -// Function: PandaNode::ParentsCopy::get_num_parents +// Function: PandaNode::Parents::get_num_parents // Access: Public // Description: Returns the number of parents of the node. //////////////////////////////////////////////////////////////////// -INLINE int PandaNode::ParentsCopy:: +INLINE int PandaNode::Parents:: get_num_parents() const { - return _list.size(); + return _up->size(); } //////////////////////////////////////////////////////////////////// -// Function: PandaNode::ParentsCopy::get_parent +// Function: PandaNode::Parents::get_parent // Access: Public // Description: Returns the nth parent of the node. //////////////////////////////////////////////////////////////////// -INLINE PandaNode *PandaNode::ParentsCopy:: +INLINE PandaNode *PandaNode::Parents:: get_parent(int n) const { - nassertr(n >= 0 && n < (int)_list.size(), NULL); - return _list[n]; + nassertr(n >= 0 && n < (int)_up->size(), NULL); + return (*_up)[n].get_parent(); } diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index d5f099ef3d..6dec8eea26 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -27,12 +27,17 @@ #include "accumulatedAttribs.h" #include "clipPlaneAttrib.h" #include "boundingSphere.h" +#include "pStatTimer.h" // This category is just temporary for debugging convenience. NotifyCategoryDecl(drawmask, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDef(drawmask, ""); +PandaNodeChain PandaNode::_dirty_prev_transforms; DrawMask PandaNode::_overall_bit = DrawMask::bit(31); + +PStatCollector PandaNode::_reset_prev_pcollector("App:Collisions:Reset"); + TypeHandle PandaNode::_type_handle; // @@ -68,7 +73,8 @@ TypeHandle PandaNode::_type_handle; PandaNode:: PandaNode(const string &name) : Namable(name), - _paths_lock("PandaNode::_paths_lock") + _paths_lock("PandaNode::_paths_lock"), + _dirty_prev_transform(false) { if (pgraph_cat.is_debug()) { pgraph_cat.debug() @@ -90,13 +96,14 @@ PandaNode:: pgraph_cat.debug() << "Destructing " << (void *)this << ", " << get_name() << "\n"; } + clear_dirty_prev_transform(); // We shouldn't have any parents left by the time we destruct, or // there's a refcount fault somewhere. #ifndef NDEBUG { CDLinksReader cdata(_cycler_links); - nassertv(cdata->_up.empty()); + nassertv(cdata->get_up()->empty()); } #endif // NDEBUG @@ -115,7 +122,8 @@ PandaNode(const PandaNode ©) : ReferenceCount(copy), TypedWritable(copy), Namable(copy), - _paths_lock("PandaNode::_paths_lock") + _paths_lock("PandaNode::_paths_lock"), + _dirty_prev_transform(false) { if (pgraph_cat.is_debug()) { pgraph_cat.debug() @@ -129,14 +137,17 @@ PandaNode(const PandaNode ©) : // Copy the other node's state. { CDLightReader copy_cdata(copy._cycler_light); - CDLightWriter cdata(_cycler_light); + CDLightWriter cdata(_cycler_light, true); cdata->_state = copy_cdata->_state; cdata->_transform = copy_cdata->_transform; cdata->_prev_transform = copy_cdata->_prev_transform; + if (cdata->_transform != cdata->_prev_transform) { + set_dirty_prev_transform(); + } } { CDHeavyReader copy_cdata(copy._cycler_heavy); - CDHeavyWriter cdata(_cycler_heavy); + CDHeavyWriter cdata(_cycler_heavy, true); cdata->_effects = copy_cdata->_effects; cdata->_tag_data = copy_cdata->_tag_data; cdata->_draw_control_mask = copy_cdata->_draw_control_mask; @@ -565,16 +576,17 @@ add_child(PandaNode *child_node, int sort) { // Apply this operation to the current stage as well as to all // upstream stages. - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_links) { - CDLinksStageWriter cdata(_cycler_links, pipeline_stage); - CDLinksStageWriter cdata_child(child_node->_cycler_links, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_links, current_thread) { + CDLinksStageWriter cdata(_cycler_links, pipeline_stage, current_thread); + CDLinksStageWriter cdata_child(child_node->_cycler_links, pipeline_stage, current_thread); - cdata->_down.insert(DownConnection(child_node, sort)); - cdata_child->_up.insert(UpConnection(this)); + cdata->modify_down()->insert(DownConnection(child_node, sort)); + cdata_child->modify_up()->insert(UpConnection(this)); } CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler_links); - OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler_links) { + OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler_links, current_thread) { new_connection(this, child_node, pipeline_stage); } CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler_links); @@ -595,13 +607,15 @@ remove_child(int child_index) { nassertv(pipeline_stage == 0); CDLinksStageWriter cdata(_cycler_links, pipeline_stage); - nassertv(child_index >= 0 && child_index < (int)cdata->_down.size()); + Down &down = *cdata->modify_down(); + nassertv(child_index >= 0 && child_index < (int)down.size()); - PT(PandaNode) child_node = cdata->_down[child_index].get_child(); + PT(PandaNode) child_node = down[child_index].get_child(); CDLinksStageWriter cdata_child(child_node->_cycler_links, pipeline_stage); + Up &up = *cdata_child->modify_up(); - cdata->_down.erase(cdata->_down.begin() + child_index); - int num_erased = cdata_child->_up.erase(UpConnection(this)); + down.erase(down.begin() + child_index); + int num_erased = up.erase(UpConnection(this)); nassertv(num_erased == 1); sever_connection(this, child_node, pipeline_stage); @@ -630,7 +644,8 @@ remove_child(PandaNode *child_node) { // We have to do this for each upstream pipeline stage. bool any_removed = false; - OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler_links) { + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler_links, current_thread) { if (stage_remove_child(child_node, pipeline_stage)) { any_removed = true; @@ -674,7 +689,8 @@ replace_child(PandaNode *orig_child, PandaNode *new_child) { // We have to do this for each upstream pipeline stage. bool any_replaced = false; - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_links) { + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_links, current_thread) { if (stage_replace_child(orig_child, new_child, pipeline_stage)) { any_replaced = true; } @@ -723,8 +739,8 @@ stash_child(int child_index) { CDLinksStageWriter cdata(_cycler_links, pipeline_stage); CDLinksStageWriter cdata_child(child_node->_cycler_links, pipeline_stage); - cdata->_stashed.insert(DownConnection(child_node, sort)); - cdata_child->_up.insert(UpConnection(this)); + cdata->modify_stashed()->insert(DownConnection(child_node, sort)); + cdata_child->modify_up()->insert(UpConnection(this)); } new_connection(this, child_node, pipeline_stage); @@ -767,9 +783,9 @@ unstash_child(int stashed_index) { { CDLinksWriter cdata(_cycler_links); CDLinksWriter cdata_child(child_node->_cycler_links); - - cdata->_down.insert(DownConnection(child_node, sort)); - cdata_child->_up.insert(UpConnection(this)); + + cdata->modify_down()->insert(DownConnection(child_node, sort)); + cdata_child->modify_up()->insert(UpConnection(this)); } int pipeline_stage = Thread::get_current_pipeline_stage(); @@ -806,8 +822,8 @@ add_stashed(PandaNode *child_node, int sort) { CDLinksWriter cdata(_cycler_links); CDLinksWriter cdata_child(child_node->_cycler_links); - cdata->_stashed.insert(DownConnection(child_node, sort)); - cdata_child->_up.insert(UpConnection(this)); + cdata->modify_stashed()->insert(DownConnection(child_node, sort)); + cdata_child->modify_up()->insert(UpConnection(this)); } int pipeline_stage = Thread::get_current_pipeline_stage(); @@ -829,13 +845,14 @@ remove_stashed(int child_index) { nassertv(pipeline_stage == 0); CDLinksStageWriter cdata(_cycler_links, pipeline_stage); - nassertv(child_index >= 0 && child_index < (int)cdata->_stashed.size()); + Down &stashed = *cdata->modify_stashed(); + nassertv(child_index >= 0 && child_index < (int)stashed.size()); - PT(PandaNode) child_node = cdata->_stashed[child_index].get_child(); + PT(PandaNode) child_node = stashed[child_index].get_child(); CDLinksStageWriter cdata_child(child_node->_cycler_links, pipeline_stage); - cdata->_stashed.erase(cdata->_stashed.begin() + child_index); - int num_erased = cdata_child->_up.erase(UpConnection(this)); + stashed.erase(stashed.begin() + child_index); + int num_erased = cdata_child->modify_up()->erase(UpConnection(this)); nassertv(num_erased == 1); sever_connection(this, child_node, pipeline_stage); @@ -857,29 +874,33 @@ remove_stashed(int child_index) { void PandaNode:: remove_all_children() { // We have to do this for each upstream pipeline stage. - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_links) { - CDLinksStageWriter cdata(_cycler_links, pipeline_stage); - + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_links, current_thread) { + CDLinksStageWriter cdata(_cycler_links, pipeline_stage, current_thread); + Down &down = *cdata->modify_down(); Down::iterator di; - for (di = cdata->_down.begin(); di != cdata->_down.end(); ++di) { + for (di = down.begin(); di != down.end(); ++di) { PT(PandaNode) child_node = (*di).get_child(); - CDLinksStageWriter cdata_child(child_node->_cycler_links, pipeline_stage); - cdata_child->_up.erase(UpConnection(this)); + CDLinksStageWriter cdata_child(child_node->_cycler_links, pipeline_stage, + current_thread); + cdata_child->modify_up()->erase(UpConnection(this)); sever_connection(this, child_node, pipeline_stage); child_node->parents_changed(); } - cdata->_down.clear(); + down.clear(); - for (di = cdata->_stashed.begin(); di != cdata->_stashed.end(); ++di) { + Down &stashed = *cdata->modify_stashed(); + for (di = stashed.begin(); di != stashed.end(); ++di) { PT(PandaNode) child_node = (*di).get_child(); - CDLinksStageWriter cdata_child(child_node->_cycler_links, pipeline_stage); - cdata_child->_up.erase(UpConnection(this)); + CDLinksStageWriter cdata_child(child_node->_cycler_links, pipeline_stage, + current_thread); + cdata_child->modify_up()->erase(UpConnection(this)); sever_connection(this, child_node, pipeline_stage); child_node->parents_changed(); } - cdata->_stashed.clear(); + stashed.clear(); } CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler_links); @@ -965,8 +986,9 @@ set_attrib(const RenderAttrib *attrib, int override) { // Apply this operation to the current stage as well as to all // upstream stages. bool any_changed = false; - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_light) { - CDLightStageWriter cdata(_cycler_light, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_light, current_thread) { + CDLightStageWriter cdata(_cycler_light, pipeline_stage, current_thread); CPT(RenderState) new_state = cdata->_state->add_attrib(attrib, override); if (cdata->_state != new_state) { @@ -995,8 +1017,9 @@ void PandaNode:: clear_attrib(TypeHandle type) { bool any_changed = false; - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_light) { - CDLightStageWriter cdata(_cycler_light, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_light, current_thread) { + CDLightStageWriter cdata(_cycler_light, pipeline_stage, current_thread); CPT(RenderState) new_state = cdata->_state->remove_attrib(type); if (cdata->_state != new_state) { @@ -1025,8 +1048,9 @@ void PandaNode:: set_effect(const RenderEffect *effect) { // Apply this operation to the current stage as well as to all // upstream stages. - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy) { - CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy, current_thread) { + CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage, current_thread); cdata->_effects = cdata->_effects->add_effect(effect); } CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy); @@ -1040,8 +1064,9 @@ set_effect(const RenderEffect *effect) { //////////////////////////////////////////////////////////////////// void PandaNode:: clear_effect(TypeHandle type) { - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy) { - CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy, current_thread) { + CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage, current_thread); cdata->_effects = cdata->_effects->remove_effect(type); } CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy); @@ -1062,8 +1087,9 @@ set_state(const RenderState *state) { // Apply this operation to the current stage as well as to all // upstream stages. bool any_changed = false; - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_light) { - CDLightStageWriter cdata(_cycler_light, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_light, current_thread) { + CDLightStageWriter cdata(_cycler_light, pipeline_stage, current_thread); if (cdata->_state != state) { cdata->_state = state; any_changed = true; @@ -1090,8 +1116,9 @@ void PandaNode:: set_effects(const RenderEffects *effects) { // Apply this operation to the current stage as well as to all // upstream stages. - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy) { - CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy, current_thread) { + CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage, current_thread); cdata->_effects = effects; } CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy); @@ -1109,8 +1136,9 @@ set_transform(const TransformState *transform) { // Apply this operation to the current stage as well as to all // upstream stages. bool any_changed = false; - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_light) { - CDLightStageWriter cdata(_cycler_light, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_light, current_thread) { + CDLightStageWriter cdata(_cycler_light, pipeline_stage, current_thread); if (cdata->_transform != transform) { cdata->_transform = transform; any_changed = true; @@ -1136,9 +1164,17 @@ void PandaNode:: set_prev_transform(const TransformState *transform) { // Apply this operation to the current stage as well as to all // upstream stages. - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_light) { - CDLightStageWriter cdata(_cycler_light, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_light, current_thread) { + CDLightStageWriter cdata(_cycler_light, pipeline_stage, current_thread); cdata->_prev_transform = transform; + if (pipeline_stage == 0) { + if (cdata->_transform != cdata->_prev_transform) { + set_dirty_prev_transform(); + } else { + clear_dirty_prev_transform(); + } + } } CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler_light); } @@ -1146,24 +1182,63 @@ set_prev_transform(const TransformState *transform) { //////////////////////////////////////////////////////////////////// // Function: PandaNode::reset_prev_transform // Access: Published -// Description: Resets the "previous" transform on this node to be -// the same as the current transform. This is not the -// same as clearing it to identity. +// Description: Resets the transform that represents this node's +// "previous" position to the same as the current +// transform. This is not the same thing as clearing it +// to identity. //////////////////////////////////////////////////////////////////// void PandaNode:: reset_prev_transform() { // Apply this operation to the current stage as well as to all // upstream stages. - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_light) { - CDLightStageReader cdata(_cycler_light, pipeline_stage); - if (cdata->_prev_transform != cdata->_transform) { - CDLightStageWriter cdataw(_cycler_light, pipeline_stage, cdata); - cdataw->_prev_transform = cdataw->_transform; - } + Thread *current_thread = Thread::get_current_thread(); + + clear_dirty_prev_transform(); + + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_light, current_thread) { + CDLightStageWriter cdata(_cycler_light, pipeline_stage, current_thread); + cdata->_prev_transform = cdata->_transform; } CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler_light); } +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::reset_all_prev_transform +// Access: Published, Static +// Description: Visits all nodes in the world with the +// _dirty_prev_transform flag--that is, all nodes whose +// _prev_transform is different from the _transform in +// pipeline stage 0--and resets the _prev_transform to +// be the same as _transform. +//////////////////////////////////////////////////////////////////// +void PandaNode:: +reset_all_prev_transform() { + Thread *current_thread = Thread::get_current_thread(); + nassertv(current_thread->get_pipeline_stage() == 0); + + PStatTimer timer(_reset_prev_pcollector); + MutexHolder holder(_dirty_prev_transforms._lock); + + LinkedListNode *list_node = _dirty_prev_transforms._next; + while (list_node != &_dirty_prev_transforms) { + PandaNode *panda_node = (PandaNode *)list_node; + nassertv(panda_node->_dirty_prev_transform); + panda_node->_dirty_prev_transform = false; + + CDLightStageWriter cdata(panda_node->_cycler_light, 0, current_thread); + cdata->_prev_transform = cdata->_transform; + + list_node = panda_node->_next; +#ifndef NDEBUG + panda_node->_prev = NULL; + panda_node->_next = NULL; +#endif // NDEBUG + } + + _dirty_prev_transforms._prev = &_dirty_prev_transforms; + _dirty_prev_transforms._next = &_dirty_prev_transforms; +} + //////////////////////////////////////////////////////////////////// // Function: PandaNode::set_tag // Access: Published @@ -1181,8 +1256,9 @@ void PandaNode:: set_tag(const string &key, const string &value) { // Apply this operation to the current stage as well as to all // upstream stages. - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy) { - CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy, current_thread) { + CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage, current_thread); cdata->_tag_data[key] = value; } CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy); @@ -1197,8 +1273,9 @@ set_tag(const string &key, const string &value) { //////////////////////////////////////////////////////////////////// void PandaNode:: clear_tag(const string &key) { - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy) { - CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy, current_thread) { + CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage, current_thread); cdata->_tag_data.erase(key); } CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy); @@ -1322,9 +1399,11 @@ copy_tags(PandaNode *other) { // Apply this operation to the current stage as well as to all // upstream stages. - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy) { - CDHeavyStageWriter cdataw(_cycler_heavy, pipeline_stage); - CDHeavyStageReader cdatar(other->_cycler_heavy, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy, current_thread) { + CDHeavyStageWriter cdataw(_cycler_heavy, pipeline_stage, current_thread); + CDHeavyStageReader cdatar(other->_cycler_heavy, pipeline_stage, + current_thread); TagData::const_iterator ti; for (ti = cdatar->_tag_data.begin(); @@ -1444,8 +1523,9 @@ void PandaNode:: adjust_draw_mask(DrawMask show_mask, DrawMask hide_mask, DrawMask clear_mask) { bool any_changed = false; - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy) { - CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy, current_thread) { + CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage, current_thread); DrawMask draw_control_mask = (cdata->_draw_control_mask | show_mask | hide_mask) & ~clear_mask; DrawMask draw_show_mask = (cdata->_draw_show_mask | show_mask) & ~hide_mask; @@ -1543,8 +1623,9 @@ set_into_collide_mask(CollideMask mask) { mask &= get_legal_collide_mask(); bool any_changed = false; - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy) { - CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy, current_thread) { + CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage, current_thread); if (cdata->_into_collide_mask != mask) { cdata->_into_collide_mask = mask; any_changed = true; @@ -1686,8 +1767,9 @@ write(ostream &out, int indent_level) const { //////////////////////////////////////////////////////////////////// void PandaNode:: set_bounds(const BoundingVolume *volume) { - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy) { - CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy, current_thread) { + CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage, current_thread); if (volume == NULL) { cdata->_user_bounds = NULL; } else { @@ -1756,7 +1838,8 @@ get_bounds() const { //////////////////////////////////////////////////////////////////// void PandaNode:: mark_bounds_stale() const { - OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler_links) { + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler_links, current_thread) { mark_bounds_stale(pipeline_stage); } CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler_links); @@ -1839,8 +1922,9 @@ get_internal_bounds(int pipeline_stage) const { //////////////////////////////////////////////////////////////////// void PandaNode:: set_internal_bounds(const BoundingVolume *volume) { - OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy) { - CDHeavyStageWriter cdataw(_cycler_heavy, pipeline_stage); + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy, current_thread) { + CDHeavyStageWriter cdataw(_cycler_heavy, pipeline_stage, current_thread); cdataw->_internal_bounds = volume; cdataw->_internal_bounds_stale = false; } @@ -1861,7 +1945,8 @@ set_internal_bounds(const BoundingVolume *volume) { //////////////////////////////////////////////////////////////////// void PandaNode:: force_bounds_stale() { - OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler_links) { + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler_links, current_thread) { force_bounds_stale(pipeline_stage); } CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler_links); @@ -1888,7 +1973,7 @@ force_bounds_stale(int pipeline_stage) { // It is similarly important that we use get_parents() here to copy // the parents list, instead of keeping the lock open while we walk // through the parents list directly on the node. - ParentsCopy parents = get_parents_copy(); + Parents parents = get_parents(); int num_parents = parents.get_num_parents(); for (int i = 0; i < num_parents; ++i) { PandaNode *parent = parents.get_parent(i); @@ -1910,7 +1995,8 @@ force_bounds_stale(int pipeline_stage) { //////////////////////////////////////////////////////////////////// void PandaNode:: mark_internal_bounds_stale() { - OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler_links) { + Thread *current_thread = Thread::get_current_thread(); + OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler_links, current_thread) { mark_internal_bounds_stale(pipeline_stage); } CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler_links); @@ -2032,8 +2118,9 @@ r_copy_subgraph(PandaNode::InstanceMap &inst_map) const { void PandaNode:: r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map) { CDLinksReader from_cdata(from->_cycler_links); + const Down &from_down = *from_cdata->get_down(); Down::const_iterator di; - for (di = from_cdata->_down.begin(); di != from_cdata->_down.end(); ++di) { + for (di = from_down.begin(); di != from_down.end(); ++di) { int sort = (*di).get_sort(); PandaNode *source_child = (*di).get_child(); PT(PandaNode) dest_child; @@ -2066,10 +2153,11 @@ do_find_child(PandaNode *node, const CDataLinks *cdata) const { // We have to search for the child by brute force, since we don't // know what sort index it was added as. + const Down &down = *cdata->get_down(); Down::const_iterator di; - for (di = cdata->_down.begin(); di != cdata->_down.end(); ++di) { + for (di = down.begin(); di != down.end(); ++di) { if ((*di).get_child() == node) { - return di - cdata->_down.begin(); + return di - down.begin(); } } @@ -2087,10 +2175,11 @@ do_find_stashed(PandaNode *node, const CDataLinks *cdata) const { // We have to search for the child by brute force, since we don't // know what sort index it was added as. + const Down &stashed = *cdata->get_stashed(); Down::const_iterator di; - for (di = cdata->_stashed.begin(); di != cdata->_stashed.end(); ++di) { + for (di = stashed.begin(); di != stashed.end(); ++di) { if ((*di).get_child() == node) { - return di - cdata->_stashed.begin(); + return di - stashed.begin(); } } @@ -2120,8 +2209,9 @@ stage_remove_child(PandaNode *child_node, int pipeline_stage) { int child_index = do_find_child(child_node, cdata); if (child_index >= 0) { // The child exists; remove it. - cdata->_down.erase(cdata->_down.begin() + child_index); - int num_erased = cdata_child->_up.erase(UpConnection(this)); + Down &down = *cdata->modify_down(); + down.erase(down.begin() + child_index); + int num_erased = cdata_child->modify_up()->erase(UpConnection(this)); nassertr(num_erased == 1, false); return true; } @@ -2129,8 +2219,9 @@ stage_remove_child(PandaNode *child_node, int pipeline_stage) { int stashed_index = do_find_stashed(child_node, cdata); if (stashed_index >= 0) { // The child has been stashed; remove it. - cdata->_stashed.erase(cdata->_stashed.begin() + stashed_index); - int num_erased = cdata_child->_up.erase(UpConnection(this)); + Down &stashed = *cdata->modify_down(); + stashed.erase(stashed.begin() + stashed_index); + int num_erased = cdata_child->modify_up()->erase(UpConnection(this)); nassertr(num_erased == 1, false); return true; } @@ -2175,7 +2266,7 @@ stage_replace_child(PandaNode *orig_child, PandaNode *new_child, int child_index = do_find_child(orig_child, cdata); if (child_index >= 0) { // The child exists; replace it. - DownConnection &down = cdata->_down[child_index]; + DownConnection &down = (*cdata->modify_down())[child_index]; nassertr(down.get_child() == orig_child, false); down.set_child(new_child); @@ -2183,7 +2274,7 @@ stage_replace_child(PandaNode *orig_child, PandaNode *new_child, int stashed_index = do_find_stashed(orig_child, cdata); if (stashed_index >= 0) { // The child has been stashed; remove it. - DownConnection &down = cdata->_stashed[stashed_index]; + DownConnection &down = (*cdata->modify_stashed())[stashed_index]; nassertr(down.get_child() == orig_child, false); down.set_child(new_child); @@ -2197,8 +2288,8 @@ stage_replace_child(PandaNode *orig_child, PandaNode *new_child, } // Now adjust the bookkeeping on both children. - cdata_new_child->_up.insert(UpConnection(this)); - int num_erased = cdata_orig_child->_up.erase(UpConnection(this)); + cdata_new_child->modify_up()->insert(UpConnection(this)); + int num_erased = cdata_orig_child->modify_up()->erase(UpConnection(this)); nassertr(num_erased == 1, false); } @@ -2300,7 +2391,7 @@ detach_one_stage(NodePathComponent *child, int pipeline_stage) { // First, look for and remove the parent node from the child's up // list. - int num_erased = cdata_child->_up.erase(UpConnection(parent_node)); + int num_erased = cdata_child->modify_up()->erase(UpConnection(parent_node)); nassertv(num_erased == 1); // Now, look for and remove the child node from the parent's down @@ -2308,19 +2399,17 @@ detach_one_stage(NodePathComponent *child, int pipeline_stage) { // has been stashed. Down::iterator di; bool found = false; - for (di = cdata_parent->_down.begin(); - di != cdata_parent->_down.end() && !found; - ++di) { + Down &down = *cdata_parent->modify_down(); + for (di = down.begin(); di != down.end() && !found; ++di) { if ((*di).get_child() == child_node) { - cdata_parent->_down.erase(di); + down.erase(di); found = true; } } - for (di = cdata_parent->_stashed.begin(); - di != cdata_parent->_stashed.end() && !found; - ++di) { + Down &stashed = *cdata_parent->modify_stashed(); + for (di = stashed.begin(); di != stashed.end() && !found; ++di) { if ((*di).get_child() == child_node) { - cdata_parent->_stashed.erase(di); + stashed.erase(di); found = true; } } @@ -2417,11 +2506,11 @@ reparent_one_stage(NodePathComponent *new_parent, NodePathComponent *child, CDLinksStageWriter cdata_child(child_node->_cycler_links, pipeline_stage); if (as_stashed) { - cdata_parent->_stashed.insert(DownConnection(child_node, sort)); + cdata_parent->modify_stashed()->insert(DownConnection(child_node, sort)); } else { - cdata_parent->_down.insert(DownConnection(child_node, sort)); + cdata_parent->modify_down()->insert(DownConnection(child_node, sort)); } - cdata_child->_up.insert(UpConnection(parent_node)); + cdata_child->modify_up()->insert(UpConnection(parent_node)); #ifndef NDEBUG // The NodePathComponent should already be in the set. @@ -2569,7 +2658,7 @@ r_get_generic_component(bool accept_ambiguity, bool &ambiguity_detected, { CDLinksStageReader cdata(_cycler_links, pipeline_stage); - int num_parents = cdata->_up.size(); + int num_parents = cdata->get_up()->size(); if (num_parents == 0) { // No parents; no ambiguity. This is the root. return get_top_component(this, true, pipeline_stage); @@ -2590,7 +2679,8 @@ r_get_generic_component(bool accept_ambiguity, bool &ambiguity_detected, << " parents; choosing arbitrary path to root.\n"; } ambiguity_detected = true; - parent_node = cdata->_up[0].get_parent(); + const Up &up = *cdata->get_up(); + parent_node = up[0].get_parent(); } // Now that the lock is released, it's safe to recurse. @@ -3453,9 +3543,9 @@ make_copy() const { //////////////////////////////////////////////////////////////////// void PandaNode::CDataLinks:: write_datagram(BamWriter *manager, Datagram &dg) const { - write_up_list(_up, manager, dg); - write_down_list(_down, manager, dg); - write_down_list(_stashed, manager, dg); + write_up_list(*get_up(), manager, dg); + write_down_list(*get_down(), manager, dg); + write_down_list(*get_stashed(), manager, dg); } //////////////////////////////////////////////////////////////////// @@ -3470,9 +3560,9 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) { int pi = CycleData::complete_pointers(p_list, manager); // Get the parent and child pointers. - pi += complete_up_list(_up, p_list + pi, manager); - pi += complete_down_list(_down, p_list + pi, manager); - pi += complete_down_list(_stashed, p_list + pi, manager); + pi += complete_up_list(*modify_up(), p_list + pi, manager); + pi += complete_down_list(*modify_down(), p_list + pi, manager); + pi += complete_down_list(*modify_stashed(), p_list + pi, manager); return pi; } @@ -3486,9 +3576,9 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) { //////////////////////////////////////////////////////////////////// void PandaNode::CDataLinks:: fillin(DatagramIterator &scan, BamReader *manager) { - fillin_up_list(_up, scan, manager); - fillin_down_list(_down, scan, manager); - fillin_down_list(_stashed, scan, manager); + fillin_up_list(*modify_up(), scan, manager); + fillin_down_list(*modify_down(), scan, manager); + fillin_down_list(*modify_stashed(), scan, manager); } //////////////////////////////////////////////////////////////////// @@ -3620,10 +3710,10 @@ fillin_up_list(PandaNode::Up &up_list, DatagramIterator &scan, BamReader *manager) { int num_parents = scan.get_uint16(); // Read the list of parent nodes. Push back a NULL for each one. - _up.reserve(num_parents); + up_list.reserve(num_parents); for (int i = 0; i < num_parents; i++) { manager->read_pointer(scan); - _up.push_back(UpConnection(NULL)); + up_list.push_back(UpConnection(NULL)); } } @@ -3646,51 +3736,3 @@ fillin_down_list(PandaNode::Down &down_list, down_list.push_back(DownConnection(NULL, sort)); } } - -//////////////////////////////////////////////////////////////////// -// Function: PandaNode::ChildrenCopy::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -PandaNode::ChildrenCopy:: -ChildrenCopy(const PandaNode::CDLinksReader &cdata) { - _list.reserve(cdata->_down.size()); - - Down::const_iterator di; - for (di = cdata->_down.begin(); di != cdata->_down.end(); ++di) { - PandaNode *child = (*di).get_child(); - _list.push_back(child); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: PandaNode::StashedCopy::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -PandaNode::StashedCopy:: -StashedCopy(const PandaNode::CDLinksReader &cdata) { - _list.reserve(cdata->_down.size()); - - Down::const_iterator di; - for (di = cdata->_stashed.begin(); di != cdata->_stashed.end(); ++di) { - PandaNode *child = (*di).get_child(); - _list.push_back(child); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: PandaNode::ParentsCopy::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -PandaNode::ParentsCopy:: -ParentsCopy(const PandaNode::CDLinksReader &cdata) { - _list.reserve(cdata->_up.size()); - - Up::const_iterator ui; - for (ui = cdata->_up.begin(); ui != cdata->_up.end(); ++ui) { - PandaNode *parent = (*ui).get_parent(); - _list.push_back(parent); - } -} diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index 474f75e12e..57f6f4d2ba 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -43,6 +43,8 @@ #include "pnotify.h" #include "updateSeq.h" #include "deletedChain.h" +#include "pandaNodeChain.h" +#include "pStatCollector.h" #ifdef HAVE_PYTHON @@ -66,7 +68,8 @@ class GeomTransformer; // is the base class of all specialized nodes, and also // serves as a generic node with no special properties. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA PandaNode : public TypedWritable, public Namable, +class EXPCL_PANDA PandaNode : public TypedWritable, public Namable, + public LinkedListNode, virtual public ReferenceCount { PUBLISHED: PandaNode(const string &name); @@ -169,6 +172,8 @@ PUBLISHED: void set_prev_transform(const TransformState *transform); INLINE const TransformState *get_prev_transform() const; void reset_prev_transform(); + INLINE bool has_dirty_prev_transform() const; + static void reset_all_prev_transform(); void set_tag(const string &key, const string &value); INLINE string get_tag(const string &key) const; @@ -303,6 +308,9 @@ private: void fix_path_lengths(int pipeline_stage); void r_list_descendants(ostream &out, int indent_level) const; + INLINE void set_dirty_prev_transform(); + INLINE void clear_dirty_prev_transform(); + public: // This must be declared public so that VC6 will allow the nested // CData class to access it. @@ -323,7 +331,7 @@ public: }; private: - typedef ov_multiset Down; + typedef RefCountObj< ov_multiset > Down; class EXPCL_PANDA UpConnection { public: @@ -336,7 +344,7 @@ private: // children do not circularly reference each other. PandaNode *_parent; }; - typedef ov_set Up; + typedef RefCountObj< ov_set > Up; // We also maintain a set of NodePathComponents in the node. This // represents the set of instances of this node that we have @@ -352,6 +360,9 @@ private: Paths _paths; Mutex _paths_lock; + bool _dirty_prev_transform; + static PandaNodeChain _dirty_prev_transforms; + // This is used to maintain a table of keyed data on each node, for // the user's purposes. typedef phash_map TagData; @@ -368,7 +379,7 @@ private: // are grouped into a different one. // The CDataLight object stores the lightweight parts of the node - // that are likely to change fairly often: transform and stage. + // that are likely to change fairly often: transform and state. class EXPCL_PANDA CDataLight : public CycleData { public: INLINE CDataLight(); @@ -529,9 +540,19 @@ private: void fillin_down_list(Down &down_list, DatagramIterator &scan, BamReader *manager); - Down _down; - Down _stashed; - Up _up; + INLINE const Down *get_down() const; + INLINE Down *modify_down(); + INLINE const Down *get_stashed() const; + INLINE Down *modify_stashed(); + INLINE const Up *get_up() const; + INLINE Up *modify_up(); + + private: + // We store the child lists by reference, so we can copy them + // quickly. We perform copy-on-write when necessary. + PT(Down) _down; + PT(Down) _stashed; + PT(Up) _up; }; PipelineCycler _cycler_links; @@ -545,37 +566,16 @@ private: static DrawMask _overall_bit; + static PStatCollector _reset_prev_pcollector; + public: - // This class is returned from get_children_copy(). Use it to walk - // through the list of children, particularly with a self-modifying - // loop, since the list of children is copied first and is thus safe - // from self modification. - class EXPCL_PANDA ChildrenCopy { - public: - ChildrenCopy(const CDLinksReader &cdata); - INLINE ChildrenCopy(const ChildrenCopy ©); - INLINE void operator = (const ChildrenCopy ©); - - INLINE int get_num_children() const; - INLINE PandaNode *get_child(int n) const; - - private: - typedef PTA(PT(PandaNode)) List; - List _list; - }; - - // This class is returned from get_children(). Use this interface - // when you want to walk through the list of children with less - // overhead than get_children_copy(); in single-threaded Panda, a - // copy is not made first, so this interface is fast. However, this - // does not protect you from self-modifying loops. Also, since the - // lock is kept open the whole time, this is generally unsafe to use - // in threaded code (which would then hold the lock on the root node - // during an entire traversal), so when pipelining is enabled, - // get_children() returns the same thing as get_children_copy(). -#ifdef DO_PIPELINING - typedef ChildrenCopy Children; -#else + // This class is returned from get_children(). Use it to walk + // through the list of children. This is faster, and safer, than + // walking through the children one at a time via + // get_num_children()/get_child(), since the list of children is + // saved out ahead of time, rather than having to reacquire the lock + // with each iteration, or to keep the lock held for the entire + // pass. class EXPCL_PANDA Children { public: INLINE Children(const CDLinksReader &cdata); @@ -586,28 +586,10 @@ public: INLINE PandaNode *get_child(int n) const; private: - CDLinksReader _cdata; + CPT(Down) _down; }; -#endif // DO_PIPELINING // Similarly for stashed children. - class EXPCL_PANDA StashedCopy { - public: - StashedCopy(const CDLinksReader &cdata); - INLINE StashedCopy(const StashedCopy ©); - INLINE void operator = (const StashedCopy ©); - - INLINE int get_num_stashed() const; - INLINE PandaNode *get_stashed(int n) const; - - private: - typedef PTA(PT(PandaNode)) List; - List _list; - }; - -#ifdef DO_PIPELINING - typedef StashedCopy Stashed; -#else class EXPCL_PANDA Stashed { public: INLINE Stashed(const CDLinksReader &cdata); @@ -618,30 +600,26 @@ public: INLINE PandaNode *get_stashed(int n) const; private: - CDLinksReader _cdata; + CPT(Down) _stashed; }; -#endif // DO_PIPELINING - // This class is returned from get_parents_copy(). - class EXPCL_PANDA ParentsCopy { + // This class is returned from get_parents(). + class EXPCL_PANDA Parents { public: - ParentsCopy(const CDLinksReader &cdata); - INLINE ParentsCopy(const ParentsCopy ©); - INLINE void operator = (const ParentsCopy ©); + INLINE Parents(const CDLinksReader &cdata); + INLINE Parents(const Parents ©); + INLINE void operator = (const Parents ©); INLINE int get_num_parents() const; INLINE PandaNode *get_parent(int n) const; private: - typedef PTA(PT(PandaNode)) List; - List _list; + CPT(Up) _up; }; - INLINE ChildrenCopy get_children_copy() const; - INLINE Children get_children() const; - INLINE StashedCopy get_stashed_copy() const; - INLINE Stashed get_stashed() const; - INLINE ParentsCopy get_parents_copy() const; + INLINE Children get_children(Thread *current_thread = Thread::get_current_thread()) const; + INLINE Stashed get_stashed(Thread *current_thread = Thread::get_current_thread()) const; + INLINE Parents get_parents(Thread *current_thread = Thread::get_current_thread()) const; public: static void register_with_read_factory(); diff --git a/panda/src/pgraph/pgraph_composite3.cxx b/panda/src/pgraph/pgraph_composite3.cxx index 0ece1a3361..8f60b37e4f 100644 --- a/panda/src/pgraph/pgraph_composite3.cxx +++ b/panda/src/pgraph/pgraph_composite3.cxx @@ -19,6 +19,7 @@ #include "nodePathComponent.cxx" #include "nodePathLerps.cxx" #include "pandaNode.cxx" +#include "pandaNodeChain.cxx" #include "planeNode.cxx" #include "pointLight.cxx" #include "polylightNode.cxx" diff --git a/panda/src/pgraph/sceneGraphReducer.cxx b/panda/src/pgraph/sceneGraphReducer.cxx index b54407b213..4f6ce2002e 100644 --- a/panda/src/pgraph/sceneGraphReducer.cxx +++ b/panda/src/pgraph/sceneGraphReducer.cxx @@ -62,7 +62,7 @@ flatten(PandaNode *root, int combine_siblings_bits) { // Get a copy of the children list, so we don't have to worry // about self-modifications. - PandaNode::ChildrenCopy cr = root->get_children_copy(); + PandaNode::Children cr = root->get_children(); // Now visit each of the children in turn. int num_children = cr.get_num_children(); @@ -257,7 +257,7 @@ r_flatten(PandaNode *grandparent_node, PandaNode *parent_node, // First, recurse on each of the children. { - PandaNode::ChildrenCopy cr = parent_node->get_children_copy(); + PandaNode::Children cr = parent_node->get_children(); int num_children = cr.get_num_children(); for (int i = 0; i < num_children; i++) { PandaNode *child_node = cr.get_child(i); diff --git a/panda/src/pipeline/pipelineCycler.h b/panda/src/pipeline/pipelineCycler.h index f96f0ecaad..bff182f9cc 100644 --- a/panda/src/pipeline/pipelineCycler.h +++ b/panda/src/pipeline/pipelineCycler.h @@ -95,10 +95,10 @@ private: // Iterates through all of the pipeline stages upstream of the current // stage, but not including the current stage. -#define OPEN_ITERATE_UPSTREAM_ONLY(cycler) { \ +#define OPEN_ITERATE_UPSTREAM_ONLY(cycler, current_thread) { \ CyclerHolder cholder(cycler); \ int pipeline_stage; \ - for (pipeline_stage = Thread::get_current_pipeline_stage() - 1; \ + for (pipeline_stage = current_thread->get_pipeline_stage() - 1; \ pipeline_stage >= 0; \ --pipeline_stage) @@ -107,10 +107,10 @@ private: // Iterates through all of the pipeline stages upstream of the current // stage, and including the current stage. -#define OPEN_ITERATE_CURRENT_AND_UPSTREAM(cycler) { \ +#define OPEN_ITERATE_CURRENT_AND_UPSTREAM(cycler, current_thread) { \ CyclerHolder cholder(cycler); \ int pipeline_stage; \ - for (pipeline_stage = Thread::get_current_pipeline_stage(); \ + for (pipeline_stage = current_thread->get_pipeline_stage(); \ pipeline_stage >= 0; \ --pipeline_stage) @@ -118,9 +118,9 @@ private: } // As above, but without holding the cycler lock during the loop. -#define OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(cycler) { \ +#define OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(cycler, current_thread) { \ int pipeline_stage; \ - for (pipeline_stage = Thread::get_current_pipeline_stage(); \ + for (pipeline_stage = current_thread->get_pipeline_stage(); \ pipeline_stage >= 0; \ --pipeline_stage) @@ -142,20 +142,20 @@ private: // These are trivial implementations of the above macros, defined when // pipelining is not enabled, that simply operate on stage 0 without // bothering to create a for loop. -#define OPEN_ITERATE_UPSTREAM_ONLY(cycler) \ +#define OPEN_ITERATE_UPSTREAM_ONLY(cycler, current_thread) \ if (false) { \ const int pipeline_stage = -1; #define CLOSE_ITERATE_UPSTREAM_ONLY(cycler) \ } -#define OPEN_ITERATE_CURRENT_AND_UPSTREAM(cycler) { \ +#define OPEN_ITERATE_CURRENT_AND_UPSTREAM(cycler, current_thread) { \ const int pipeline_stage = 0; \ #define CLOSE_ITERATE_CURRENT_AND_UPSTREAM(cycler) \ } -#define OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(cycler) { \ +#define OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(cycler, current_thread) { \ const int pipeline_stage = 0; \ #define CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(cycler) \