diff --git a/panda/src/chan/partBundle.cxx b/panda/src/chan/partBundle.cxx index 741d0f3826..25d3665893 100644 --- a/panda/src/chan/partBundle.cxx +++ b/panda/src/chan/partBundle.cxx @@ -94,7 +94,7 @@ void PartBundle:: set_blend_type(BlendType bt) { nassertv(Thread::get_current_pipeline_stage() == 0); - CDReader cdata(_cycler); + CDLockedReader cdata(_cycler); if (cdata->_blend_type != bt) { CDWriter cdataw(_cycler, cdata); cdataw->_blend_type = bt; @@ -131,7 +131,7 @@ void PartBundle:: clear_control_effects() { nassertv(Thread::get_current_pipeline_stage() == 0); - CDReader cdata(_cycler); + CDLockedReader cdata(_cycler); if (!cdata->_blend.empty()) { CDWriter cdataw(_cycler, cdata); cdataw->_blend.clear(); @@ -299,7 +299,7 @@ control_activated(AnimControl *control) { nassertv(Thread::get_current_pipeline_stage() == 0); nassertv(control->get_part() == this); - CDReader cdata(_cycler); + CDLockedReader cdata(_cycler); // If (and only if) our blend type is BT_single, which means no // blending, then starting an animation implicitly enables it. if (cdata->_blend_type == BT_single) { diff --git a/panda/src/chan/partBundle.h b/panda/src/chan/partBundle.h index bc07abb10b..6fdafdb857 100644 --- a/panda/src/chan/partBundle.h +++ b/panda/src/chan/partBundle.h @@ -26,6 +26,10 @@ #include "partSubset.h" #include "pointerTo.h" #include "thread.h" +#include "cycleData.h" +#include "cycleDataLockedReader.h" +#include "cycleDataReader.h" +#include "cycleDataWriter.h" class AnimBundle; class PartBundleNode; @@ -150,6 +154,7 @@ private: }; PipelineCycler _cycler; + typedef CycleDataLockedReader CDLockedReader; typedef CycleDataReader CDReader; typedef CycleDataWriter CDWriter; diff --git a/panda/src/display/displayRegion.cxx b/panda/src/display/displayRegion.cxx index 8e6aaf1f93..d67b59f62a 100644 --- a/panda/src/display/displayRegion.cxx +++ b/panda/src/display/displayRegion.cxx @@ -202,7 +202,7 @@ void DisplayRegion:: set_active(bool active) { int pipeline_stage = Thread::get_current_pipeline_stage(); nassertv(pipeline_stage == 0); - CDReader cdata(_cycler); + CDLockedReader cdata(_cycler); if (active != cdata->_active) { CDWriter cdataw(_cycler, cdata); @@ -222,7 +222,7 @@ set_active(bool active) { void DisplayRegion:: set_sort(int sort) { nassertv(Thread::get_current_pipeline_stage() == 0); - CDReader cdata(_cycler); + CDLockedReader cdata(_cycler); if (sort != cdata->_sort) { CDWriter cdataw(_cycler, cdata); diff --git a/panda/src/display/displayRegion.h b/panda/src/display/displayRegion.h index b99fcfa25f..018aa5a372 100644 --- a/panda/src/display/displayRegion.h +++ b/panda/src/display/displayRegion.h @@ -28,6 +28,7 @@ #include "sceneSetup.h" #include "pointerTo.h" #include "cycleData.h" +#include "cycleDataLockedReader.h" #include "cycleDataReader.h" #include "cycleDataWriter.h" #include "cycleDataStageWriter.h" @@ -176,6 +177,7 @@ private: }; PipelineCycler _cycler; + typedef CycleDataLockedReader CDLockedReader; typedef CycleDataReader CDReader; typedef CycleDataWriter CDWriter; typedef CycleDataStageWriter CDStageWriter; diff --git a/panda/src/express/Sources.pp b/panda/src/express/Sources.pp index e6028b8642..da7283489e 100644 --- a/panda/src/express/Sources.pp +++ b/panda/src/express/Sources.pp @@ -30,6 +30,9 @@ multifile.I multifile.h \ namable.I \ namable.h nativeNumericData.I nativeNumericData.h \ + nodePointerToBase.h nodePointerToBase.I \ + nodePointerTo.h nodePointerTo.I \ + nodeReferenceCount.h nodeReferenceCount.I \ objectDeletor.h objectDeletor.I \ ordered_vector.h ordered_vector.I ordered_vector.T \ password_hash.h \ @@ -80,6 +83,9 @@ memoryUsagePointers.cxx multifile.cxx \ namable.cxx \ nativeNumericData.cxx \ + nodePointerToBase.cxx \ + nodePointerTo.cxx \ + nodeReferenceCount.cxx \ objectDeletor.cxx \ ordered_vector.cxx \ password_hash.cxx \ @@ -136,6 +142,9 @@ multifile.I multifile.h \ namable.I \ namable.h nativeNumericData.I nativeNumericData.h \ + nodePointerToBase.h nodePointerToBase.I \ + nodePointerTo.h nodePointerTo.I \ + nodeReferenceCount.h nodeReferenceCount.I \ objectDeletor.h objectDeletor.I \ ordered_vector.h ordered_vector.I ordered_vector.T \ password_hash.h \ diff --git a/panda/src/express/config_express.cxx b/panda/src/express/config_express.cxx index a46e0001b2..b5c51cb6e7 100644 --- a/panda/src/express/config_express.cxx +++ b/panda/src/express/config_express.cxx @@ -18,6 +18,7 @@ #include "config_express.h" #include "datagram.h" +#include "nodeReferenceCount.h" #include "referenceCount.h" #include "textEncoder.h" #include "typedObject.h" @@ -147,6 +148,7 @@ init_libexpress() { initialized = true; Datagram::init_type(); + NodeReferenceCount::init_type(); ReferenceCount::init_type(); TextEncoder::init_type(); TypedObject::init_type(); diff --git a/panda/src/express/express_composite1.cxx b/panda/src/express/express_composite1.cxx index 2813e50d29..97eaead869 100644 --- a/panda/src/express/express_composite1.cxx +++ b/panda/src/express/express_composite1.cxx @@ -18,6 +18,9 @@ #include "multifile.cxx" #include "namable.cxx" #include "nativeNumericData.cxx" +#include "nodePointerToBase.cxx" +#include "nodePointerTo.cxx" +#include "nodeReferenceCount.cxx" #include "objectDeletor.cxx" #include "ordered_vector.cxx" #include "patchfile.cxx" @@ -27,4 +30,3 @@ #include "pointerToBase.cxx" #include "pointerToVoid.cxx" #include "profileTimer.cxx" -#include "pta_uchar.cxx" diff --git a/panda/src/express/express_composite2.cxx b/panda/src/express/express_composite2.cxx index 3ab809ac13..a7a7ae531e 100644 --- a/panda/src/express/express_composite2.cxx +++ b/panda/src/express/express_composite2.cxx @@ -1,3 +1,4 @@ +#include "pta_uchar.cxx" #include "ramfile.cxx" #include "referenceCount.cxx" #include "reversedNumericData.cxx" diff --git a/panda/src/express/nodePointerTo.I b/panda/src/express/nodePointerTo.I new file mode 100644 index 0000000000..da103e59f2 --- /dev/null +++ b/panda/src/express/nodePointerTo.I @@ -0,0 +1,259 @@ +// Filename: nodePointerTo.I +// Created by: drose (07May05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: NodePointerTo::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodePointerTo:: +NodePointerTo(To *ptr) : NodePointerToBase(ptr) { +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePointerTo::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodePointerTo:: +NodePointerTo(const NodePointerTo ©) : + NodePointerToBase((const NodePointerToBase &)copy) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePointerTo::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodePointerTo:: +~NodePointerTo() { +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePointerTo::Dereference operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE TYPENAME NodePointerTo::To &NodePointerTo:: +operator *() const { + return *((To *)(this->_void_ptr)); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePointerTo::Member access operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE TYPENAME NodePointerTo::To *NodePointerTo:: +operator -> () const { + return (To *)(this->_void_ptr); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePointerTo::Typecast operator +// Access: Public +// Description: We also have the typecast operator to automatically +// convert NodePointerTo's to the required kind of actual +// pointer. This introduces ambiguities which the +// compiler will resolve one way or the other, but we +// don't care which way it goes because either will be +// correct. +//////////////////////////////////////////////////////////////////// +template +INLINE NodePointerTo:: +operator TYPENAME NodePointerToBase::To *() const { + return (To *)(this->_void_ptr); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePointerTo::p +// Access: Public +// Description: Returns an ordinary pointer instead of a NodePointerTo. +// Useful to work around compiler problems, particularly +// for implicit upcasts. +//////////////////////////////////////////////////////////////////// +template +INLINE TYPENAME NodePointerTo::To *NodePointerTo:: +p() const { + return (To *)(this->_void_ptr); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePointerTo::Assignment operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodePointerTo &NodePointerTo:: +operator = (To *ptr) { + reassign(ptr); + return *this; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePointerTo::Assignment operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodePointerTo &NodePointerTo:: +operator = (const NodePointerTo ©) { + reassign((const NodePointerToBase &)copy); + return *this; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeConstPointerTo::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodeConstPointerTo:: +NodeConstPointerTo(const TYPENAME NodeConstPointerTo::To *ptr) : + NodePointerToBase((TYPENAME NodeConstPointerTo::To *)ptr) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeConstPointerTo::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodeConstPointerTo:: +NodeConstPointerTo(const NodePointerTo ©) : + NodePointerToBase((const NodePointerToBase &)copy) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeConstPointerTo::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodeConstPointerTo:: +NodeConstPointerTo(const NodeConstPointerTo ©) : + NodePointerToBase((const NodePointerToBase &)copy) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeConstPointerTo::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodeConstPointerTo:: +~NodeConstPointerTo() { +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeConstPointerTo::Dereference operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE const TYPENAME NodeConstPointerTo::To &NodeConstPointerTo:: +operator *() const { + return *((To *)(this->_void_ptr)); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeConstPointerTo::Member access operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE const TYPENAME NodeConstPointerTo::To *NodeConstPointerTo:: +operator -> () const { + return (To *)(this->_void_ptr); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeConstPointerTo::Typecast operator +// Access: Public +// Description: We also have the typecast operator to automatically +// convert NodeConstPointerTo's to the required kind of actual +// pointer. This introduces ambiguities which the +// compiler will resolve one way or the other, but we +// don't care which way it goes because either will be +// correct. +//////////////////////////////////////////////////////////////////// + +template +INLINE NodeConstPointerTo:: +operator const TYPENAME NodePointerToBase::To *() const { + return (To *)(this->_void_ptr); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeConstPointerTo::p +// Access: Public +// Description: Returns an ordinary pointer instead of a NodeConstPointerTo. +// Useful to work around compiler problems, particularly +// for implicit upcasts. +//////////////////////////////////////////////////////////////////// +template +INLINE const TYPENAME NodeConstPointerTo::To *NodeConstPointerTo:: +p() const { + return (To *)(this->_void_ptr); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeConstPointerTo::Assignment operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodeConstPointerTo &NodeConstPointerTo:: +operator = (const To *ptr) { + reassign((To *)ptr); + return *this; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeConstPointerTo::Assignment operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodeConstPointerTo &NodeConstPointerTo:: +operator = (const NodePointerTo ©) { + reassign((const NodePointerToBase &)copy); + return *this; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeConstPointerTo::Assignment operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodeConstPointerTo &NodeConstPointerTo:: +operator = (const NodeConstPointerTo ©) { + reassign((const NodePointerToBase &)copy); + return *this; +} diff --git a/panda/src/express/nodePointerTo.cxx b/panda/src/express/nodePointerTo.cxx new file mode 100644 index 0000000000..541a45cb96 --- /dev/null +++ b/panda/src/express/nodePointerTo.cxx @@ -0,0 +1,19 @@ +// Filename: nodePointerTo.cxx +// Created by: drose (07May05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "nodePointerTo.h" diff --git a/panda/src/express/nodePointerTo.h b/panda/src/express/nodePointerTo.h new file mode 100644 index 0000000000..aa1e7fb4d3 --- /dev/null +++ b/panda/src/express/nodePointerTo.h @@ -0,0 +1,81 @@ +// Filename: nodePointerTo.h +// Created by: drose (07May05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef NODEPOINTERTO_H +#define NODEPOINTERTO_H + +#include "pandabase.h" +#include "nodePointerToBase.h" + +//////////////////////////////////////////////////////////////////// +// Class : NodePointerTo +// Description : This implements the special NodePointerTo template +// class, which works just like PointerTo except it +// manages the objects node_ref_count instead of the +// normal ref_count. +//////////////////////////////////////////////////////////////////// +template +class NodePointerTo : public NodePointerToBase { +public: + typedef TYPENAME NodePointerToBase::To To; + INLINE NodePointerTo(To *ptr = (To *)NULL); + INLINE NodePointerTo(const NodePointerTo ©); + INLINE ~NodePointerTo(); + + INLINE To &operator *() const; + INLINE To *operator -> () const; + INLINE operator TYPENAME NodePointerToBase::To *() const; + + INLINE To *p() const; + + INLINE NodePointerTo &operator = (To *ptr); + INLINE NodePointerTo &operator = (const NodePointerTo ©); +}; + + +//////////////////////////////////////////////////////////////////// +// Class : NodeConstPointerTo +// Description : A NodeConstPointerTo is similar to a NodePointerTo, +// except it keeps a const pointer to the thing. +//////////////////////////////////////////////////////////////////// +template +class NodeConstPointerTo : public NodePointerToBase { +public: + typedef TYPENAME NodePointerToBase::To To; + INLINE NodeConstPointerTo(const To *ptr = (const To *)NULL); + INLINE NodeConstPointerTo(const NodePointerTo ©); + INLINE NodeConstPointerTo(const NodeConstPointerTo ©); + INLINE ~NodeConstPointerTo(); + + INLINE const To &operator *() const; + INLINE const To *operator -> () const; + INLINE operator const TYPENAME NodePointerToBase::To *() const; + + INLINE const To *p() const; + + INLINE NodeConstPointerTo &operator = (const To *ptr); + INLINE NodeConstPointerTo &operator = (const NodePointerTo ©); + INLINE NodeConstPointerTo &operator = (const NodeConstPointerTo ©); +}; + +#define NPT(type) NodePointerTo< type > +#define NCPT(type) NodeConstPointerTo< type > + +#include "nodePointerTo.I" + +#endif diff --git a/panda/src/express/nodePointerToBase.I b/panda/src/express/nodePointerToBase.I new file mode 100644 index 0000000000..8c7dd89147 --- /dev/null +++ b/panda/src/express/nodePointerToBase.I @@ -0,0 +1,135 @@ +// Filename: nodePointerToBase.I +// Created by: drose (07May05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: NodePointerToBase::Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodePointerToBase:: +NodePointerToBase(To *ptr) { + reassign(ptr); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePointerToBase::Copy Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodePointerToBase:: +NodePointerToBase(const NodePointerToBase ©) { + reassign(copy); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePointerToBase::Destructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodePointerToBase:: +~NodePointerToBase() { + reassign((To *)NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePointerToBase::reassign +// Access: Protected +// Description: This is the main work of the NodePointerTo family. When +// the pointer is reassigned, decrement the old +// reference count and increment the new one. +//////////////////////////////////////////////////////////////////// +template +void NodePointerToBase:: +reassign(To *ptr) { + if (ptr != (To *)_void_ptr) { + // First save the old pointer; we won't delete it until we have + // assigned the new one. We do this just in case there are + // cascading effects from deleting this pointer that might + // inadvertently delete the new one. (Don't laugh--it's + // happened!) + To *old_ptr = (To *)_void_ptr; + + _void_ptr = (void *)ptr; + if (ptr != (To *)NULL) { + ptr->node_ref(); +#ifdef DO_MEMORY_USAGE + if (MemoryUsage::get_track_memory_usage()) { + // Make sure the MemoryUsage record knows what the TypeHandle + // is, if we know it ourselves. + TypeHandle type = get_type_handle(To); + if (type == TypeHandle::none()) { + do_init_type(To); + type = get_type_handle(To); + } + if (type != TypeHandle::none()) { + MemoryUsage::update_type(ptr, type); + } + } +#endif + } + + // Now delete the old pointer. + if (old_ptr != (To *)NULL) { + node_unref_delete(old_ptr); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePointerToBase::reassign +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE void NodePointerToBase:: +reassign(const NodePointerToBase ©) { + reassign((To *)copy._void_ptr); +} + + +//////////////////////////////////////////////////////////////////// +// Function: NodePointerToBase::clear +// Access: Published +// Description: A convenient way to set the NodePointerTo object to NULL. +// (Assignment to a NULL pointer also works, of course.) +//////////////////////////////////////////////////////////////////// +template +INLINE void NodePointerToBase:: +clear() { + reassign((To *)NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePointerToBase::output +// Access: Published +// Description: A handy function to output NodePointerTo's as a hex +// pointer followed by a reference count. +//////////////////////////////////////////////////////////////////// +template +INLINE void NodePointerToBase:: +output(ostream &out) const { + out << _void_ptr; + if (_void_ptr != (void *)NULL) { + out << ":" << ((To *)_void_ptr)->get_node_ref_count() << "/" + << ((To *)_void_ptr)->get_ref_count(); + } +} diff --git a/panda/src/express/nodePointerToBase.cxx b/panda/src/express/nodePointerToBase.cxx new file mode 100644 index 0000000000..ea382868eb --- /dev/null +++ b/panda/src/express/nodePointerToBase.cxx @@ -0,0 +1,19 @@ +// Filename: nodePointerToBase.cxx +// Created by: drose (07May05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "nodePointerToBase.h" diff --git a/panda/src/express/nodePointerToBase.h b/panda/src/express/nodePointerToBase.h new file mode 100644 index 0000000000..c881205143 --- /dev/null +++ b/panda/src/express/nodePointerToBase.h @@ -0,0 +1,70 @@ +// Filename: nodePointerToBase.h +// Created by: drose (07May05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef NODEPOINTERTOBASE_H +#define NODEPOINTERTOBASE_H + +#include "pandabase.h" +#include "pointerToVoid.h" +#include "memoryUsage.h" +#include "config_express.h" + +//////////////////////////////////////////////////////////////////// +// Class : NodePointerToBase +// Description : This is similar to PointerToBase, but it manages +// objects of type NodeReferenceCount or +// NodeCachedReferenceCount, and it updates the +// node_ref_count instead of the regular ref_count. It +// is intended for use only in PandaNode, to hold a +// pointer to RenderState and TransformState, although +// it could be used by any object that wanted to +// maintain a separate reference count for reporting +// purposes. +//////////////////////////////////////////////////////////////////// +template +class NodePointerToBase : public PointerToVoid { +public: + typedef T To; + +protected: + INLINE NodePointerToBase(To *ptr); + INLINE NodePointerToBase(const NodePointerToBase ©); + INLINE ~NodePointerToBase(); + + void reassign(To *ptr); + INLINE void reassign(const NodePointerToBase ©); + + // No assignment or retrieval functions are declared in + // NodePointerToBase, because we will have to specialize on const + // vs. non-const later. + +PUBLISHED: + INLINE void clear(); + + void output(ostream &out) const; +}; + +template +INLINE ostream &operator <<(ostream &out, const NodePointerToBase &pointer) { + pointer.output(out); + return out; +} + +#include "nodePointerToBase.I" + +#endif diff --git a/panda/src/express/nodeReferenceCount.I b/panda/src/express/nodeReferenceCount.I new file mode 100644 index 0000000000..631e60f5d5 --- /dev/null +++ b/panda/src/express/nodeReferenceCount.I @@ -0,0 +1,295 @@ +// Filename: nodeReferenceCount.I +// Created by: drose (01May06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +template +TypeHandle NodeRefCountObj::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: NodeReferenceCount::Constructor +// Access: Protected +// Description: The ReferenceCount constructor is protected because +// you almost never want to create just a ReferenceCount +// object by itself, and it's probably a mistake if you +// try. +// +// ReferenceCount doesn't store any useful information +// in its own right; its only purpose is to add +// reference-counting to some other class via +// inheritance. +//////////////////////////////////////////////////////////////////// +INLINE NodeReferenceCount:: +NodeReferenceCount() { + _node_ref_count = 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeReferenceCount::Copy Constructor +// Access: Protected +// Description: The copies of reference-counted objects do not +// themselves inherit the reference count! +// +// This copy constructor is protected because you almost +// never want to create just a ReferenceCount object by +// itself, and it's probably a mistake if you try. +//////////////////////////////////////////////////////////////////// +INLINE NodeReferenceCount:: +NodeReferenceCount(const NodeReferenceCount ©) : ReferenceCount(copy) { + _node_ref_count = 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeReferenceCount::Copy Assignment Operator +// Access: Protected +// Description: The copies of reference-counted objects do not +// themselves inherit the reference count! +// +// This copy assignment operator is protected because +// you almost never want to copy just a ReferenceCount +// object by itself, and it's probably a mistake if you +// try. Instead, this should only be called from a +// derived class that implements this operator and then +// calls up the inheritance chain. +//////////////////////////////////////////////////////////////////// +INLINE void NodeReferenceCount:: +operator = (const NodeReferenceCount ©) { + nassertv(this != NULL); + + // If this assertion fails, our own pointer was recently deleted. + // Possibly you used a real pointer instead of a PointerTo at some + // point, and the object was deleted when the PointerTo went out of + // scope. Maybe you tried to create an automatic (local variable) + // instance of a class that derives from ReferenceCount. Or maybe + // your headers are out of sync, and you need to make clean in + // direct or some higher tree. + nassertv(_node_ref_count != -100); + + ReferenceCount::operator = (copy); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeReferenceCount::Destructor +// Access: Protected +// Description: The ReferenceCount destructor is protected to +// discourage users from accidentally trying to delete a +// ReferenceCount pointer directly. This is almost +// always a bad idea, since the destructor is not +// virtual, and you've almost certainly got some pointer +// to something that inherits from ReferenceCount, not +// just a plain old ReferenceCount object. +//////////////////////////////////////////////////////////////////// +INLINE NodeReferenceCount:: +~NodeReferenceCount() { + nassertv(this != NULL); + + // If this assertion fails, we're trying to delete an object that + // was just deleted. Possibly you used a real pointer instead of a + // PointerTo at some point, and the object was deleted when the + // PointerTo went out of scope. Maybe you tried to create an + // automatic (local variable) instance of a class that derives from + // ReferenceCount. Or maybe your headers are out of sync, and you + // need to make clean in direct or some higher tree. + nassertv(_node_ref_count != -100); + + // If this assertion fails, the reference counts are all screwed + // up altogether. Maybe some errant code stomped all over memory + // somewhere. + nassertv(_node_ref_count >= 0); + + // If this assertion fails, someone tried to delete this object + // while its reference count was still positive. Maybe you tried + // to point a PointerTo at a static object (a local variable, + // instead of one allocated via new)? The test below against 0x7f + // is supposed to check for that, but it's a pretty hokey test. + + // Another possibility is you inadvertently omitted a copy + // constructor for a ReferenceCount object, and then bitwise + // copied a dynamically allocated value--reference count and + // all--onto a locally allocated one. + nassertv(_node_ref_count == 0); + +#ifndef NDEBUG + // Ok, all clear to delete. Now set the reference count to -100, + // so we'll have a better chance of noticing if we happen to have + // a stray pointer to it still out there. + _node_ref_count = -100; +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeReferenceCount::get_node_ref_count +// Access: Published +// Description: Returns the current reference count. +//////////////////////////////////////////////////////////////////// +INLINE int NodeReferenceCount:: +get_node_ref_count() const { +#ifdef _DEBUG + test_ref_count_integrity(); +#endif + return AtomicAdjust::get(_node_ref_count); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeReferenceCount::node_ref +// Access: Published +// Description: Explicitly increments the reference count. +// +// This function is const, even though it changes the +// object, because generally fiddling with an object's +// reference count isn't considered part of fiddling +// with the object. An object might be const in other +// ways, but we still need to accurately count the +// number of references to it. +//////////////////////////////////////////////////////////////////// +INLINE void NodeReferenceCount:: +node_ref() const { +#ifdef _DEBUG + nassertv(test_ref_count_integrity()); +#endif + + ref(); + AtomicAdjust::inc(((NodeReferenceCount *)this)->_node_ref_count); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeReferenceCount::node_unref +// Access: Published +// Description: Explicitly decrements the reference count. Note that +// the object will not be implicitly deleted by unref() +// simply because the reference count drops to zero. +// (Having a member function delete itself is +// problematic; plus, we don't have a virtual destructor +// anyway.) However, see the helper function +// unref_delete(). +// +// User code should avoid using ref() and unref() +// directly, which can result in missed reference +// counts. Instead, let a PointerTo object manage the +// reference counting automatically. +// +// This function is const, even though it changes the +// object, because generally fiddling with an object's +// reference count isn't considered part of fiddling +// with the object. An object might be const in other +// ways, but we still need to accurately count the +// number of references to it. +// +// The return value is true if the new reference count +// is nonzero, false if it is zero. +//////////////////////////////////////////////////////////////////// +INLINE bool NodeReferenceCount:: +node_unref() const { +#ifdef _DEBUG + nassertr(test_ref_count_integrity(), 0); +#endif + + // If this assertion fails, you tried to unref an object with a + // zero reference count. Are you using ref() and unref() + // directly? Are you sure you can't use PointerTo's? + nassertr(_node_ref_count > 0, 0); + + unref(); + return AtomicAdjust::dec(((NodeReferenceCount *)this)->_node_ref_count); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeReferenceCount::test_ref_count_integrity +// Access: Published +// Description: Does some easy checks to make sure that the reference +// count isn't completely bogus. +//////////////////////////////////////////////////////////////////// +INLINE bool NodeReferenceCount:: +test_ref_count_integrity() const { +#ifndef NDEBUG + return do_test_ref_count_integrity(); +#else + return true; +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: node_unref_delete +// Description: This global helper function will unref the given +// ReferenceCount object, and if the reference count +// reaches zero, automatically delete it. It can't be a +// member function because it's usually a bad idea to +// delete an object from within its own member function. +// It's a template function so the destructor doesn't +// have to be virtual. +//////////////////////////////////////////////////////////////////// +template +INLINE void +node_unref_delete(RefCountType *ptr) { + ptr->node_unref(); + if (ptr->get_ref_count() == 0) { + ObjectDeletor *deletor = ObjectDeletor::get_global_ptr(); + if (deletor != (ObjectDeletor *)NULL) { + ptr->ref(); + deletor->delete_object(RefCountDeleteWrapper::do_delete, (void *)ptr); + return; + } + + delete ptr; + } +} + + + +//////////////////////////////////////////////////////////////////// +// Function: NodeRefCountObj::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodeRefCountObj:: +NodeRefCountObj() { +} + +//////////////////////////////////////////////////////////////////// +// Function: NodeRefCountObj::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE NodeRefCountObj:: +NodeRefCountObj(const Base ©) : Base(copy) { +} + + +//////////////////////////////////////////////////////////////////// +// Function: NodeRefCountObj::init_type +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +void NodeRefCountObj:: +init_type() { +#if defined(HAVE_RTTI) && !defined(__EDG__) + // If we have RTTI, we can determine the name of the base type. + string base_name = typeid(Base).name(); +#else + string base_name = "unknown"; +#endif + + TypeHandle base_type = register_dynamic_type(base_name); + + ReferenceCount::init_type(); + _type_handle = + register_dynamic_type("NodeRefCountObj<" + base_name + ">", + base_type, ReferenceCount::get_class_type()); +} diff --git a/panda/src/express/nodeReferenceCount.cxx b/panda/src/express/nodeReferenceCount.cxx new file mode 100644 index 0000000000..44dc2305f3 --- /dev/null +++ b/panda/src/express/nodeReferenceCount.cxx @@ -0,0 +1,48 @@ +// Filename: nodeReferenceCount.cxx +// Created by: drose (01May06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "nodeReferenceCount.h" + +TypeHandle NodeReferenceCount::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: NodeReferenceCount::do_test_ref_count_integrity +// Access: Protected +// Description: Does some easy checks to make sure that the reference +// count isn't completely bogus. +//////////////////////////////////////////////////////////////////// +bool NodeReferenceCount:: +do_test_ref_count_integrity() const { + nassertr(this != NULL, false); + + // If this assertion fails, we're trying to delete an object that + // was just deleted. Possibly you used a real pointer instead of a + // PointerTo at some point, and the object was deleted when the + // PointerTo went out of scope. Maybe you tried to create an + // automatic (local variable) instance of a class that derives from + // ReferenceCount. Or maybe your headers are out of sync, and you + // need to make clean in direct or some higher tree. + nassertr(_node_ref_count != -100, false); + + // If this assertion fails, the reference counts are all screwed + // up altogether. Maybe some errant code stomped all over memory + // somewhere. + nassertr(_node_ref_count >= 0, false); + + return ReferenceCount::do_test_ref_count_integrity(); +} diff --git a/panda/src/express/nodeReferenceCount.h b/panda/src/express/nodeReferenceCount.h new file mode 100644 index 0000000000..10a1dedb15 --- /dev/null +++ b/panda/src/express/nodeReferenceCount.h @@ -0,0 +1,107 @@ +// Filename: nodeReferenceCount.h +// Created by: drose (01May06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef NODEREFERENCECOUNT_H +#define NODEREFERENCECOUNT_H + +#include "pandabase.h" + +#include "referenceCount.h" +#include "objectDeletor.h" + +//////////////////////////////////////////////////////////////////// +// Class : NodeReferenceCount +// Description : This class specializes ReferenceCount to add an +// additional counter, called node_ref_count, for the +// purposes of counting the number of times the object +// is referenced by a "node", whatever that may mean in +// context. +// +// The new methods node_ref() and node_unref() +// automatically increment and decrement the primary +// reference count as well. There also exists a +// NodePointerTo<> class to maintain the node_ref +// counters automatically. +// +// See also CachedTypedWritableReferenceCount, which is +// similar in principle, as well as +// NodeCachedReferenceCount, which combines both of +// these. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDAEXPRESS NodeReferenceCount : public ReferenceCount { +protected: + INLINE NodeReferenceCount(); + INLINE NodeReferenceCount(const NodeReferenceCount ©); + INLINE void operator = (const NodeReferenceCount ©); + INLINE ~NodeReferenceCount(); + +PUBLISHED: + INLINE int get_node_ref_count() const; + INLINE void node_ref() const; + INLINE bool node_unref() const; + INLINE bool test_ref_count_integrity() const; + +protected: + bool do_test_ref_count_integrity() const; + +private: + PN_int32 _node_ref_count; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + + static void init_type() { + ReferenceCount::init_type(); + register_type(_type_handle, "NodeReferenceCount", + ReferenceCount::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +template +INLINE void node_unref_delete(RefCountType *ptr); + +//////////////////////////////////////////////////////////////////// +// Class : NodeRefCountObj +// Description : This works like RefCountObj, but it inherits from +// NodeReferenceCount instead of ReferenceCount. +//////////////////////////////////////////////////////////////////// +template +class NodeRefCountObj : public NodeReferenceCount, public Base { +public: + INLINE NodeRefCountObj(); + INLINE NodeRefCountObj(const Base ©); + ALLOC_DELETED_CHAIN(NodeRefCountObj); + + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type(); + +private: + static TypeHandle _type_handle; +}; + +#include "nodeReferenceCount.I" + +#endif + diff --git a/panda/src/express/pointerToArray.I b/panda/src/express/pointerToArray.I index e16c27dc32..93460a67ce 100644 --- a/panda/src/express/pointerToArray.I +++ b/panda/src/express/pointerToArray.I @@ -30,7 +30,7 @@ pvector ConstPointerToArray::_empty_array; template INLINE PointerToArray:: PointerToArray() : - PointerToBase > >((RefCountObj > *)NULL) + PointerToBase > >((NodeRefCountObj > *)NULL) { } @@ -52,7 +52,7 @@ PointerToArray::empty_array(size_type n) { template INLINE PointerToArray:: PointerToArray(size_type n, const Element &value) : - PointerToBase > >(new RefCountObj >) { + PointerToBase > >(new NodeRefCountObj >) { ((To *)(this->_void_ptr))->reserve(n); insert(begin(), n, value); } @@ -65,7 +65,7 @@ PointerToArray(size_type n, const Element &value) : template INLINE PointerToArray:: PointerToArray(const PointerToArray ©) : - PointerToBase > >(copy) + PointerToBase > >(copy) { } @@ -145,7 +145,7 @@ template INLINE TYPENAME PointerToArray::size_type PointerToArray:: max_size() const { nassertd((this->_void_ptr) != NULL) { - ((PointerToArray *)this)->reassign(new RefCountObj >); + ((PointerToArray *)this)->reassign(new NodeRefCountObj >); } return ((To *)(this->_void_ptr))->max_size(); } @@ -170,7 +170,7 @@ template INLINE void PointerToArray:: reserve(TYPENAME PointerToArray::size_type n) { if ((this->_void_ptr) == NULL) { - reassign(new RefCountObj >); + reassign(new NodeRefCountObj >); } ((To *)(this->_void_ptr))->reserve(n); } @@ -196,7 +196,7 @@ template INLINE TYPENAME PointerToArray::reference PointerToArray:: front() const { nassertd((this->_void_ptr) != NULL) { - ((PointerToArray *)this)->reassign(new RefCountObj >); + ((PointerToArray *)this)->reassign(new NodeRefCountObj >); } nassertd(!((To *)(this->_void_ptr))->empty()) { ((To *)(this->_void_ptr))->push_back(Element()); @@ -213,7 +213,7 @@ template INLINE TYPENAME PointerToArray::reference PointerToArray:: back() const { nassertd((this->_void_ptr) != NULL) { - ((PointerToArray *)this)->reassign(new RefCountObj >); + ((PointerToArray *)this)->reassign(new NodeRefCountObj >); } nassertd(!((To *)(this->_void_ptr))->empty()) { ((To *)(this->_void_ptr))->push_back(Element()); @@ -230,7 +230,7 @@ template INLINE TYPENAME PointerToArray::iterator PointerToArray:: insert(iterator position, const Element &x) { if ((this->_void_ptr) == NULL) { - reassign(new RefCountObj >); + reassign(new NodeRefCountObj >); position = end(); } nassertr(position >= ((To *)(this->_void_ptr))->begin() && @@ -247,7 +247,7 @@ template INLINE void PointerToArray:: insert(iterator position, size_type n, const Element &x) { if ((this->_void_ptr) == NULL) { - reassign(new RefCountObj >); + reassign(new NodeRefCountObj >); position = end(); } nassertv(position >= ((To *)(this->_void_ptr))->begin() && @@ -293,7 +293,7 @@ template INLINE TYPENAME PointerToArray::reference PointerToArray:: operator [](size_type n) const { nassertd((this->_void_ptr) != NULL) { - ((PointerToArray *)this)->reassign(new RefCountObj >); + ((PointerToArray *)this)->reassign(new NodeRefCountObj >); } nassertd(!((To *)(this->_void_ptr))->empty()) { ((To *)(this->_void_ptr))->push_back(Element()); @@ -354,7 +354,7 @@ template INLINE void PointerToArray:: push_back(const Element &x) { if ((this->_void_ptr) == NULL) { - reassign(new RefCountObj >); + reassign(new NodeRefCountObj >); } ((To *)(this->_void_ptr))->push_back(x); } @@ -368,7 +368,7 @@ template INLINE void PointerToArray:: pop_back() { nassertd((this->_void_ptr) != NULL) { - ((PointerToArray *)this)->reassign(new RefCountObj >); + ((PointerToArray *)this)->reassign(new NodeRefCountObj >); } nassertv(!((To *)(this->_void_ptr))->empty()); ((To *)(this->_void_ptr))->pop_back(); @@ -385,7 +385,7 @@ template INLINE void PointerToArray:: make_empty() { nassertd((this->_void_ptr) != NULL) { - ((PointerToArray *)this)->reassign(new RefCountObj >); + ((PointerToArray *)this)->reassign(new NodeRefCountObj >); } nassertv(!((To *)(this->_void_ptr))->empty()); ((To *)(this->_void_ptr))->clear(); @@ -429,7 +429,7 @@ template INLINE pvector &PointerToArray:: v() const { if ((this->_void_ptr) == NULL) { - ((PointerToArray *)this)->reassign(new RefCountObj >); + ((PointerToArray *)this)->reassign(new NodeRefCountObj >); } return *((To *)(this->_void_ptr)); } @@ -468,6 +468,43 @@ get_ref_count() const { return ((this->_void_ptr) == NULL) ? 0 : ((To *)(this->_void_ptr))->get_ref_count(); } +//////////////////////////////////////////////////////////////////// +// Function: PointerToArray::get_node_ref_count +// Access: Public +// Description: Returns the node_ref of the underlying vector. +//////////////////////////////////////////////////////////////////// +template +INLINE int PointerToArray:: +get_node_ref_count() const { + return ((this->_void_ptr) == NULL) ? 0 : ((To *)(this->_void_ptr))->get_node_ref_count(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PointerToArray::node_ref +// Access: Public +// Description: Increments the node_ref of the underlying vector. +//////////////////////////////////////////////////////////////////// +template +INLINE void PointerToArray:: +node_ref() const { + if ((this->_void_ptr) == NULL) { + ((PointerToArray *)this)->reassign(new NodeRefCountObj >); + } + ((To *)(this->_void_ptr))->node_ref(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PointerToArray::node_unref +// Access: Public +// Description: Decrements the node_ref of the underlying vector. +//////////////////////////////////////////////////////////////////// +template +INLINE bool PointerToArray:: +node_unref() const { + nassertr((this->_void_ptr) != NULL, true); + return ((To *)(this->_void_ptr))->node_unref(); +} + //////////////////////////////////////////////////////////////////// // Function: PointerToArray::Assignment operator // Access: Public @@ -475,7 +512,7 @@ get_ref_count() const { //////////////////////////////////////////////////////////////////// template INLINE PointerToArray &PointerToArray:: -operator = (RefCountObj > *ptr) { +operator = (NodeRefCountObj > *ptr) { reassign(ptr); return *this; } @@ -502,7 +539,7 @@ operator = (const PointerToArray ©) { template INLINE void PointerToArray:: clear() { - reassign((RefCountObj > *)NULL); + reassign((NodeRefCountObj > *)NULL); } @@ -515,7 +552,7 @@ clear() { template INLINE ConstPointerToArray:: ConstPointerToArray() : - PointerToBase > >((RefCountObj > *)NULL) + PointerToBase > >((NodeRefCountObj > *)NULL) { } @@ -527,7 +564,7 @@ ConstPointerToArray() : template INLINE ConstPointerToArray:: ConstPointerToArray(const PointerToArray ©) : - PointerToBase > >(copy) + PointerToBase > >(copy) { } @@ -539,7 +576,7 @@ ConstPointerToArray(const PointerToArray ©) : template INLINE ConstPointerToArray:: ConstPointerToArray(const ConstPointerToArray ©) : - PointerToBase > >(copy) + PointerToBase > >(copy) { } @@ -619,7 +656,7 @@ template INLINE TYPENAME ConstPointerToArray::size_type ConstPointerToArray:: max_size() const { nassertd((this->_void_ptr) != NULL) { - ((ConstPointerToArray *)this)->reassign(new RefCountObj >); + ((ConstPointerToArray *)this)->reassign(new NodeRefCountObj >); } return ((To *)(this->_void_ptr))->max_size(); } @@ -644,7 +681,7 @@ template INLINE TYPENAME ConstPointerToArray::size_type ConstPointerToArray:: capacity() const { nassertd((this->_void_ptr) != NULL) { - ((ConstPointerToArray *)this)->reassign(new RefCountObj >); + ((ConstPointerToArray *)this)->reassign(new NodeRefCountObj >); } return ((To *)(this->_void_ptr))->capacity(); } @@ -658,7 +695,7 @@ template INLINE TYPENAME ConstPointerToArray::reference ConstPointerToArray:: front() const { nassertd((this->_void_ptr) != NULL) { - ((ConstPointerToArray *)this)->reassign(new RefCountObj >); + ((ConstPointerToArray *)this)->reassign(new NodeRefCountObj >); } nassertd(!((To *)(this->_void_ptr))->empty()) { ((To *)(this->_void_ptr))->push_back(Element()); @@ -675,7 +712,7 @@ template INLINE TYPENAME ConstPointerToArray::reference ConstPointerToArray:: back() const { nassertd((this->_void_ptr) != NULL) { - ((ConstPointerToArray *)this)->reassign(new RefCountObj >); + ((ConstPointerToArray *)this)->reassign(new NodeRefCountObj >); } nassertd(!((To *)(this->_void_ptr))->empty()) { ((To *)(this->_void_ptr))->push_back(Element()); @@ -693,7 +730,7 @@ template INLINE TYPENAME ConstPointerToArray::reference ConstPointerToArray:: operator [](size_type n) const { nassertd((this->_void_ptr) != NULL) { - ((ConstPointerToArray *)this)->reassign(new RefCountObj >); + ((ConstPointerToArray *)this)->reassign(new NodeRefCountObj >); } nassertd(!((To *)(this->_void_ptr))->empty()) { ((To *)(this->_void_ptr))->push_back(Element()); @@ -767,7 +804,7 @@ template INLINE const pvector &ConstPointerToArray:: v() const { nassertd((this->_void_ptr) != NULL) { - ((ConstPointerToArray *)this)->reassign(new RefCountObj >); + ((ConstPointerToArray *)this)->reassign(new NodeRefCountObj >); } return *(To *)(this->_void_ptr); } @@ -783,6 +820,43 @@ get_ref_count() const { return ((this->_void_ptr) == NULL) ? 0 : ((To *)(this->_void_ptr))->get_ref_count(); } +//////////////////////////////////////////////////////////////////// +// Function: ConstPointerToArray::get_node_ref_count +// Access: Public +// Description: Returns the node_ref of the underlying vector. +//////////////////////////////////////////////////////////////////// +template +INLINE int ConstPointerToArray:: +get_node_ref_count() const { + return ((this->_void_ptr) == NULL) ? 0 : ((To *)(this->_void_ptr))->get_node_ref_count(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConstPointerToArray::node_ref +// Access: Public +// Description: Increments the node_ref of the underlying vector. +//////////////////////////////////////////////////////////////////// +template +INLINE void ConstPointerToArray:: +node_ref() const { + if ((this->_void_ptr) == NULL) { + ((PointerToArray *)this)->reassign(new NodeRefCountObj >); + } + ((To *)(this->_void_ptr))->node_ref(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ConstPointerToArray::node_unref +// Access: Public +// Description: Decrements the node_ref of the underlying vector. +//////////////////////////////////////////////////////////////////// +template +INLINE bool ConstPointerToArray:: +node_unref() const { + nassertr((this->_void_ptr) != NULL, true); + return ((To *)(this->_void_ptr))->node_unref(); +} + //////////////////////////////////////////////////////////////////// // Function: ConstPointerToArray::Assignment operator // Access: Public @@ -790,7 +864,7 @@ get_ref_count() const { //////////////////////////////////////////////////////////////////// template INLINE ConstPointerToArray &ConstPointerToArray:: -operator = (RefCountObj > *ptr) { +operator = (NodeRefCountObj > *ptr) { reassign(ptr); return *this; } @@ -829,6 +903,6 @@ operator = (const ConstPointerToArray ©) { template INLINE void ConstPointerToArray:: clear() { - reassign((RefCountObj > *)NULL); + reassign((NodeRefCountObj > *)NULL); } diff --git a/panda/src/express/pointerToArray.h b/panda/src/express/pointerToArray.h index 929a79f60a..46e434bd7a 100644 --- a/panda/src/express/pointerToArray.h +++ b/panda/src/express/pointerToArray.h @@ -70,7 +70,7 @@ #include "pandabase.h" -#include "referenceCount.h" +#include "nodeReferenceCount.h" #include "pointerTo.h" #include "pvector.h" @@ -87,11 +87,21 @@ // element. This is actually implemented as an STL // vector, using the RefCountObj class to wrap it up // with a reference count. +// +// We actually inherit from NodeRefCountObj these days, +// which adds node_ref() and node_unref() to the +// standard ref() and unref(). This is particularly +// useful for GeomVertexArrayData; other classes may or +// may not find this additional counter useful, but +// since it adds relatively little overhead (compared +// with what is presumably a largish array), we go ahead +// and add it here, even though it is inherited by many +// different parts of the system that may not use it. //////////////////////////////////////////////////////////////////// template -class PointerToArray : public PointerToBase > > { +class PointerToArray : public PointerToBase > > { public: - typedef TYPENAME PointerToBase > >::To To; + typedef TYPENAME PointerToBase > >::To To; typedef TYPENAME pvector::value_type value_type; typedef TYPENAME pvector::reference reference; typedef TYPENAME pvector::const_reference const_reference; @@ -176,9 +186,13 @@ public: INLINE int get_ref_count() const; + INLINE int get_node_ref_count() const; + INLINE void node_ref() const; + INLINE bool node_unref() const; + // Reassignment is by pointer, not memberwise as with a vector. INLINE PointerToArray & - operator = (RefCountObj > *ptr); + operator = (NodeRefCountObj > *ptr); INLINE PointerToArray & operator = (const PointerToArray ©); INLINE void clear(); @@ -198,9 +212,9 @@ private: // may not be modified. //////////////////////////////////////////////////////////////////// template -class ConstPointerToArray : public PointerToBase > > { +class ConstPointerToArray : public PointerToBase > > { public: - typedef TYPENAME PointerToBase > >::To To; + typedef TYPENAME PointerToBase > >::To To; typedef TYPENAME pvector::value_type value_type; typedef TYPENAME pvector::const_reference reference; typedef TYPENAME pvector::const_reference const_reference; @@ -258,9 +272,13 @@ public: INLINE int get_ref_count() const; + INLINE int get_node_ref_count() const; + INLINE void node_ref() const; + INLINE bool node_unref() const; + // Reassignment is by pointer, not memberwise as with a vector. INLINE ConstPointerToArray & - operator = (RefCountObj > *ptr); + operator = (NodeRefCountObj > *ptr); INLINE ConstPointerToArray & operator = (const PointerToArray ©); INLINE ConstPointerToArray & diff --git a/panda/src/gobj/geom.I b/panda/src/gobj/geom.I index d2e6246553..5ea248f52c 100644 --- a/panda/src/gobj/geom.I +++ b/panda/src/gobj/geom.I @@ -69,7 +69,7 @@ get_geom_rendering() const { //////////////////////////////////////////////////////////////////// INLINE Geom::UsageHint Geom:: get_usage_hint() const { - CDReader cdata(_cycler); + CDLockedReader cdata(_cycler); if (!cdata->_got_usage_hint) { CDWriter cdataw(((Geom *)this)->_cycler, cdata, false); ((Geom *)this)->reset_usage_hint(cdataw); @@ -463,7 +463,7 @@ INLINE GeomPipelineReader:: GeomPipelineReader(const Geom *object, Thread *current_thread) : _object(object), _current_thread(current_thread), - _cdata(object->_cycler.read(current_thread)) + _cdata(object->_cycler.read_unlocked(current_thread)) { #ifdef _DEBUG nassertv(_object->test_ref_count_nonzero()); @@ -506,7 +506,7 @@ INLINE GeomPipelineReader:: nassertv(_cdata->test_ref_count_nonzero()); #endif // DO_PIPELINING #endif // _DEBUG - _object->_cycler.release_read(_cdata); + // _object->_cycler.release_read(_cdata); #ifdef _DEBUG _object = NULL; @@ -534,19 +534,6 @@ get_current_thread() const { return _current_thread; } -//////////////////////////////////////////////////////////////////// -// Function: GeomPipelineReader::check_usage_hint -// Access: Public -// Description: Ensures that the Geom's usage_hint cache has been -// computed. -//////////////////////////////////////////////////////////////////// -INLINE void GeomPipelineReader:: -check_usage_hint() const { - if (!_cdata->_got_usage_hint) { - ((Geom *)_object)->reset_usage_hint((Geom::CData *)_cdata); - } -} - //////////////////////////////////////////////////////////////////// // Function: GeomPipelineReader::get_primitive_type // Access: Public diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index da35bfb0e8..19756b4465 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -729,7 +729,7 @@ check_valid(const GeomVertexData *vertex_data) const { //////////////////////////////////////////////////////////////////// CPT(BoundingVolume) Geom:: get_bounds(Thread *current_thread) const { - CDReader cdata(_cycler, current_thread); + CDLockedReader cdata(_cycler, current_thread); if (cdata->_internal_bounds_stale) { CDWriter cdataw(((Geom *)this)->_cycler, cdata, false); if (cdataw->_user_bounds != (BoundingVolume *)NULL) { @@ -1346,6 +1346,35 @@ fillin(DatagramIterator &scan, BamReader *manager) { _modified = Geom::get_next_modified(); } +//////////////////////////////////////////////////////////////////// +// Function: GeomPipelineReader::check_usage_hint +// Access: Public +// Description: Ensures that the Geom's usage_hint cache has been +// computed. +//////////////////////////////////////////////////////////////////// +void GeomPipelineReader:: +check_usage_hint() const { + if (!_cdata->_got_usage_hint) { + // We'll need to get a fresh pointer, since another thread might + // already have modified the pointer on the object since we + // queried it. + { + Geom::CDWriter fresh_cdata(((Geom *)_object)->_cycler, _current_thread); + if (!fresh_cdata->_got_usage_hint) { + // The cache is still stale. We have to do the work of + // freshening it. + ((Geom *)_object)->reset_usage_hint(fresh_cdata); + nassertv(fresh_cdata->_got_usage_hint); + } + + // Save the new pointer, and then let the lock release itself. + ((GeomPipelineReader *)this)->_cdata = fresh_cdata; + } + } + + nassertv(_cdata->_got_usage_hint); +} + //////////////////////////////////////////////////////////////////// // Function: GeomPipelineReader::check_valid // Access: Public diff --git a/panda/src/gobj/geom.h b/panda/src/gobj/geom.h index 7575c52dea..65841c15e5 100644 --- a/panda/src/gobj/geom.h +++ b/panda/src/gobj/geom.h @@ -22,6 +22,7 @@ #include "pandabase.h" #include "typedWritableReferenceCount.h" #include "cycleData.h" +#include "cycleDataLockedReader.h" #include "cycleDataReader.h" #include "cycleDataWriter.h" #include "cycleDataStageReader.h" @@ -261,6 +262,7 @@ private: }; PipelineCycler _cycler; + typedef CycleDataLockedReader CDLockedReader; typedef CycleDataReader CDReader; typedef CycleDataWriter CDWriter; typedef CycleDataStageReader CDStageReader; @@ -330,7 +332,7 @@ public: INLINE const Geom *get_object() const; INLINE Thread *get_current_thread() const; - INLINE void check_usage_hint() const; + void check_usage_hint() const; INLINE PrimitiveType get_primitive_type() const; INLINE ShadeModel get_shade_model() const; @@ -350,7 +352,7 @@ public: private: const Geom *_object; Thread *_current_thread; - const Geom::CData *_cdata; + CPT(Geom::CData) _cdata; }; INLINE ostream &operator << (ostream &out, const Geom &obj); diff --git a/panda/src/gobj/geomCacheEntry.cxx b/panda/src/gobj/geomCacheEntry.cxx index 977329e88f..bceca25b2f 100644 --- a/panda/src/gobj/geomCacheEntry.cxx +++ b/panda/src/gobj/geomCacheEntry.cxx @@ -82,10 +82,9 @@ record(Thread *current_thread) { //////////////////////////////////////////////////////////////////// void GeomCacheEntry:: refresh(Thread *current_thread) { - nassertv(_next != (GeomCacheEntry *)NULL && _prev != (GeomCacheEntry *)NULL); - GeomCacheManager *cache_mgr = GeomCacheManager::get_global_ptr(); MutexHolder holder(cache_mgr->_lock); + nassertv(_next != (GeomCacheEntry *)NULL && _prev != (GeomCacheEntry *)NULL); remove_from_list(); insert_before(cache_mgr->_list); diff --git a/panda/src/gobj/geomPrimitive.I b/panda/src/gobj/geomPrimitive.I index 1355112673..a9f9842dd5 100644 --- a/panda/src/gobj/geomPrimitive.I +++ b/panda/src/gobj/geomPrimitive.I @@ -478,7 +478,7 @@ GeomPrimitivePipelineReader(const GeomPrimitive *object, Thread *current_thread) : _object(object), _current_thread(current_thread), - _cdata(object->_cycler.read(current_thread)), + _cdata(object->_cycler.read_unlocked(current_thread)), _vertices_reader(NULL) { nassertv(_object->test_ref_count_nonzero()); @@ -529,7 +529,7 @@ INLINE GeomPrimitivePipelineReader:: nassertv(_cdata->test_ref_count_nonzero()); #endif // DO_PIPELINING #endif // _DEBUG - _object->_cycler.release_read(_cdata); + // _object->_cycler.release_read(_cdata); #ifdef _DEBUG _vertices_reader = NULL; @@ -558,19 +558,6 @@ get_current_thread() const { return _current_thread; } -//////////////////////////////////////////////////////////////////// -// Function: GeomPrimitivePipelineReader::check_minmax -// Access: Public -// Description: Ensures that the primitive's minmax cache has been -// computed. -//////////////////////////////////////////////////////////////////// -INLINE void GeomPrimitivePipelineReader:: -check_minmax() const { - if (!_cdata->_got_minmax) { - ((GeomPrimitive *)_object)->recompute_minmax((GeomPrimitive::CData *)_cdata); - } -} - //////////////////////////////////////////////////////////////////// // Function: GeomPrimitivePipelineReader::get_shade_model // Access: Public diff --git a/panda/src/gobj/geomPrimitive.cxx b/panda/src/gobj/geomPrimitive.cxx index 6f6f725fbb..554aae3b64 100644 --- a/panda/src/gobj/geomPrimitive.cxx +++ b/panda/src/gobj/geomPrimitive.cxx @@ -1491,6 +1491,34 @@ fillin(DatagramIterator &scan, BamReader *manager) { _got_minmax = false; } +//////////////////////////////////////////////////////////////////// +// Function: GeomPrimitivePipelineReader::check_minmax +// Access: Public +// Description: Ensures that the primitive's minmax cache has been +// computed. +//////////////////////////////////////////////////////////////////// +void GeomPrimitivePipelineReader:: +check_minmax() const { + if (!_cdata->_got_minmax) { + // We'll need to get a fresh pointer, since another thread might + // already have modified the pointer on the object since we + // queried it. + { + GeomPrimitive::CDWriter fresh_cdata(((GeomPrimitive *)_object)->_cycler, _current_thread); + if (!fresh_cdata->_got_minmax) { + // The cache is still stale. We have to do the work of + // freshening it. + ((GeomPrimitive *)_object)->recompute_minmax(fresh_cdata); + nassertv(fresh_cdata->_got_minmax); + } + + // Save the new pointer, and then let the lock release itself. + ((GeomPrimitivePipelineReader *)this)->_cdata = fresh_cdata; + } + } + + nassertv(_cdata->_got_minmax); +} //////////////////////////////////////////////////////////////////// // Function: GeomPrimitivePipelineReader::get_first_vertex diff --git a/panda/src/gobj/geomPrimitive.h b/panda/src/gobj/geomPrimitive.h index 25df3b96d1..04449913ac 100644 --- a/panda/src/gobj/geomPrimitive.h +++ b/panda/src/gobj/geomPrimitive.h @@ -309,7 +309,7 @@ public: INLINE const GeomPrimitive *get_object() const; INLINE Thread *get_current_thread() const; - INLINE void check_minmax() const; + void check_minmax() const; INLINE ShadeModel get_shade_model() const; INLINE UsageHint get_usage_hint() const; @@ -334,7 +334,7 @@ public: private: const GeomPrimitive *_object; Thread *_current_thread; - const GeomPrimitive::CData *_cdata; + CPT(GeomPrimitive::CData) _cdata; GeomVertexArrayDataPipelineReader *_vertices_reader; }; diff --git a/panda/src/gobj/geomVertexArrayData.I b/panda/src/gobj/geomVertexArrayData.I index 8921c12e5e..33bd7c34f4 100644 --- a/panda/src/gobj/geomVertexArrayData.I +++ b/panda/src/gobj/geomVertexArrayData.I @@ -183,6 +183,7 @@ INLINE GeomVertexArrayData::CData:: CData() : _usage_hint(UH_unspecified) { + _data.node_ref(); } //////////////////////////////////////////////////////////////////// @@ -196,6 +197,7 @@ CData(const GeomVertexArrayData::CData ©) : _data(copy._data), _modified(copy._modified) { + _data.node_ref(); } //////////////////////////////////////////////////////////////////// @@ -293,7 +295,7 @@ GeomVertexArrayDataPipelineReader(const GeomVertexArrayData *object, Thread *current_thread) : GeomVertexArrayDataPipelineBase((GeomVertexArrayData *)object, current_thread, - (GeomVertexArrayData::CData *)object->_cycler.read(current_thread)) + (GeomVertexArrayData::CData *)object->_cycler.read_unlocked(current_thread)) { #ifdef _DEBUG nassertv(_object->test_ref_count_nonzero()); @@ -338,7 +340,7 @@ INLINE GeomVertexArrayDataPipelineReader:: nassertv(_cdata->test_ref_count_nonzero()); #endif // DO_PIPELINING #endif // _DEBUG - _object->_cycler.release_read(_cdata); + // _object->_cycler.release_read(_cdata); #ifdef _DEBUG _object = NULL; diff --git a/panda/src/gobj/geomVertexArrayData.cxx b/panda/src/gobj/geomVertexArrayData.cxx index 43e9e8e451..3ba9af9bf9 100644 --- a/panda/src/gobj/geomVertexArrayData.cxx +++ b/panda/src/gobj/geomVertexArrayData.cxx @@ -432,6 +432,9 @@ finalize(BamReader *manager) { // Now is the time to endian-reverse the data. cdata->_data = reverse_data_endianness(cdata->_data); } + + // Now is also the time to node_ref the data. + cdata->_data.node_ref(); } //////////////////////////////////////////////////////////////////// @@ -470,6 +473,16 @@ fillin(DatagramIterator &scan, BamReader *manager) { manager->read_cdata(scan, _cycler, this); } +//////////////////////////////////////////////////////////////////// +// Function: GeomVertexArrayData::CData::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +GeomVertexArrayData::CData:: +~CData() { + _data.node_unref(); +} + //////////////////////////////////////////////////////////////////// // Function: GeomVertexArrayData::CData::make_copy // Access: Public, Virtual @@ -520,7 +533,7 @@ set_num_rows(int n) { int delta = n - (_cdata->_data.size() / stride); if (delta != 0) { - if (_cdata->_data.get_ref_count() > 1) { + if (_cdata->_data.get_node_ref_count() > 1) { // Copy-on-write: the data is already reffed somewhere else, // so we're just going to make a copy. PTA_uchar new_data; @@ -528,7 +541,9 @@ set_num_rows(int n) { new_data.insert(new_data.end(), n * stride, 0); memcpy(new_data, _cdata->_data, min((size_t)(n * stride), _cdata->_data.size())); + _cdata->_data.node_unref(); _cdata->_data = new_data; + _cdata->_data.node_ref(); } else { // We've got the only reference to the data, so we can change @@ -557,13 +572,16 @@ set_num_rows(int n) { //////////////////////////////////////////////////////////////////// PTA_uchar GeomVertexArrayDataPipelineWriter:: modify_data() { - // Perform copy-on-write: if the reference count on the vertex data - // is greater than 1, assume some other GeomVertexData has the same - // pointer, so make a copy of it first. - if (_cdata->_data.get_ref_count() > 1) { + // Perform copy-on-write: if the *node* reference count on the + // vertex data is greater than 1, assume some other + // GeomVertexArrayData has the same pointer, so make a copy of it + // first. + if (_cdata->_data.get_node_ref_count() > 1) { PTA_uchar orig_data = _cdata->_data; + _cdata->_data.node_unref(); _cdata->_data = PTA_uchar(); _cdata->_data.v() = orig_data.v(); + _cdata->_data.node_ref(); } _cdata->_modified = Geom::get_next_modified(); @@ -577,6 +595,8 @@ modify_data() { //////////////////////////////////////////////////////////////////// void GeomVertexArrayDataPipelineWriter:: set_data(CPTA_uchar array) { + _cdata->_data.node_unref(); _cdata->_data = (PTA_uchar &)array; + _cdata->_data.node_ref(); _cdata->_modified = Geom::get_next_modified(); } diff --git a/panda/src/gobj/geomVertexArrayData.h b/panda/src/gobj/geomVertexArrayData.h index a6e32b1f94..b3bd856a59 100644 --- a/panda/src/gobj/geomVertexArrayData.h +++ b/panda/src/gobj/geomVertexArrayData.h @@ -120,6 +120,7 @@ private: public: INLINE CData(); INLINE CData(const CData ©); + virtual ~CData(); ALLOC_DELETED_CHAIN(CData); virtual CycleData *make_copy() const; virtual void write_datagram(BamWriter *manager, Datagram &dg, @@ -207,7 +208,7 @@ public: protected: GeomVertexArrayData *_object; Thread *_current_thread; - GeomVertexArrayData::CData *_cdata; + PT(GeomVertexArrayData::CData) _cdata; }; //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/geomVertexData.I b/panda/src/gobj/geomVertexData.I index d9f2ea1a04..5be66bf93c 100644 --- a/panda/src/gobj/geomVertexData.I +++ b/panda/src/gobj/geomVertexData.I @@ -590,7 +590,7 @@ INLINE GeomVertexDataPipelineReader:: GeomVertexDataPipelineReader(const GeomVertexData *object, Thread *current_thread) : GeomVertexDataPipelineBase((GeomVertexData *)object, current_thread, - (GeomVertexData::CData *)object->_cycler.read(current_thread)), + (GeomVertexData::CData *)object->_cycler.read_unlocked(current_thread)), _got_array_readers(false) { nassertv(_object->test_ref_count_nonzero()); @@ -637,7 +637,7 @@ INLINE GeomVertexDataPipelineReader:: nassertv(_cdata->test_ref_count_nonzero()); #endif // DO_PIPELINING #endif // _DEBUG - _object->_cycler.release_read(_cdata); + // _object->_cycler.release_read(_cdata); #ifdef _DEBUG _object = NULL; diff --git a/panda/src/gobj/geomVertexData.cxx b/panda/src/gobj/geomVertexData.cxx index 46b4cd637c..1c810812e2 100644 --- a/panda/src/gobj/geomVertexData.cxx +++ b/panda/src/gobj/geomVertexData.cxx @@ -243,7 +243,7 @@ set_format(const GeomVertexFormat *format) { Thread *current_thread = Thread::get_current_thread(); nassertv(format->is_registered()); - CDReader cdata(_cycler, current_thread); + CDLockedReader cdata(_cycler, current_thread); if (format == cdata->_format) { // Trivially no-op. @@ -902,7 +902,7 @@ set_color(const Colorf &color, int num_components, //////////////////////////////////////////////////////////////////// CPT(GeomVertexData) GeomVertexData:: animate_vertices(Thread *current_thread) const { - CDReader cdata(_cycler, current_thread); + CDLockedReader cdata(_cycler, current_thread); if (cdata->_format->get_animation().get_animation_type() != AT_panda) { return this; @@ -1812,13 +1812,14 @@ set_num_rows(int n) { if (color_array >= 0 && orig_color_rows < n) { // We have just added some rows, fill the "color" column with // (1, 1, 1, 1), for the programmer's convenience. - GeomVertexArrayData *array_data = _cdata->_arrays[color_array]; + GeomVertexArrayDataPipelineWriter *array_writer = _array_writers[color_array]; + const GeomVertexArrayFormat *array_format = array_writer->get_array_format(); const GeomVertexColumn *column = - array_data->get_array_format()->get_column(InternalName::get_color()); - int stride = array_data->get_array_format()->get_stride(); + array_format->get_column(InternalName::get_color()); + int stride = array_format->get_stride(); unsigned char *start = - array_data->modify_data() + column->get_start(); - unsigned char *stop = start + array_data->get_data_size_bytes(); + array_writer->modify_data() + column->get_start(); + unsigned char *stop = start + array_writer->get_data_size_bytes(); unsigned char *pointer = start + stride * orig_color_rows; int num_values = column->get_num_values(); diff --git a/panda/src/gobj/geomVertexData.h b/panda/src/gobj/geomVertexData.h index 279dcf03e5..35a9df47fb 100644 --- a/panda/src/gobj/geomVertexData.h +++ b/panda/src/gobj/geomVertexData.h @@ -31,6 +31,7 @@ #include "sliderTable.h" #include "internalName.h" #include "cycleData.h" +#include "cycleDataLockedReader.h" #include "cycleDataReader.h" #include "cycleDataWriter.h" #include "cycleDataStageReader.h" @@ -257,6 +258,7 @@ private: }; PipelineCycler _cycler; + typedef CycleDataLockedReader CDLockedReader; typedef CycleDataReader CDReader; typedef CycleDataWriter CDWriter; typedef CycleDataStageReader CDStageReader; @@ -341,7 +343,7 @@ public: protected: GeomVertexData *_object; Thread *_current_thread; - GeomVertexData::CData *_cdata; + PT(GeomVertexData::CData) _cdata; }; //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/geomVertexReader.I b/panda/src/gobj/geomVertexReader.I index 44a9fe9ae0..3d5b15b31a 100644 --- a/panda/src/gobj/geomVertexReader.I +++ b/panda/src/gobj/geomVertexReader.I @@ -147,6 +147,7 @@ GeomVertexReader(const GeomVertexReader ©) : _current_thread(copy._current_thread), _packer(copy._packer), _stride(copy._stride), + _data(copy._data), _pointer_begin(copy._pointer_begin), _pointer_end(copy._pointer_end), _pointer(copy._pointer), @@ -167,6 +168,7 @@ operator = (const GeomVertexReader ©) { _current_thread = copy._current_thread; _packer = copy._packer; _stride = copy._stride; + _data = copy._data; _pointer_begin = copy._pointer_begin; _pointer_end = copy._pointer_end; _pointer = copy._pointer; @@ -510,7 +512,8 @@ get_packer() const { //////////////////////////////////////////////////////////////////// INLINE void GeomVertexReader:: set_pointer(int row, const GeomVertexArrayDataPipelineReader *array_reader) { - _pointer_begin = array_reader->get_data(); + _data = array_reader->get_data(); + _pointer_begin = _data; _pointer_end = _pointer_begin + array_reader->get_data_size_bytes(); quick_set_pointer(row); } @@ -526,7 +529,12 @@ INLINE void GeomVertexReader:: quick_set_pointer(int row) { nassertv(has_column()); -#ifdef _DEBUG +#if defined(_DEBUG) && !defined(HAVE_THREADS) + // Make sure we still have the same pointer as stored the array. We + // only perform this test in debug mode, because it is expensive, + // and only in single-threaded mode, because in threaded mode + // another thread might have reallocated the other pointer outside + // of our control anyway. if (_vertex_data != (const GeomVertexData *)NULL) { const GeomVertexArrayData *array_data = _vertex_data->get_array(_array); nassertv(_pointer_begin == array_data->get_data()); diff --git a/panda/src/gobj/geomVertexReader.h b/panda/src/gobj/geomVertexReader.h index a948809f22..ee07f0e289 100644 --- a/panda/src/gobj/geomVertexReader.h +++ b/panda/src/gobj/geomVertexReader.h @@ -143,6 +143,7 @@ private: GeomVertexColumn::Packer *_packer; int _stride; + CPTA_uchar _data; const unsigned char *_pointer_begin; const unsigned char *_pointer_end; const unsigned char *_pointer; diff --git a/panda/src/gobj/geomVertexWriter.I b/panda/src/gobj/geomVertexWriter.I index b9db532486..38428cbcef 100644 --- a/panda/src/gobj/geomVertexWriter.I +++ b/panda/src/gobj/geomVertexWriter.I @@ -145,6 +145,7 @@ GeomVertexWriter(const GeomVertexWriter ©) : _current_thread(copy._current_thread), _packer(copy._packer), _stride(copy._stride), + _data(copy._data), _pointer_begin(copy._pointer_begin), _pointer_end(copy._pointer_end), _pointer(copy._pointer), @@ -165,6 +166,7 @@ operator = (const GeomVertexWriter ©) { _current_thread = copy._current_thread; _packer = copy._packer; _stride = copy._stride; + _data = copy._data; _pointer_begin = copy._pointer_begin; _pointer_end = copy._pointer_end; _pointer = copy._pointer; @@ -813,7 +815,8 @@ get_packer() const { //////////////////////////////////////////////////////////////////// INLINE void GeomVertexWriter:: set_pointer(int row, GeomVertexArrayDataPipelineWriter *array_writer) { - _pointer_begin = array_writer->modify_data(); + _data = array_writer->modify_data(); + _pointer_begin = _data; _pointer_end = _pointer_begin + array_writer->get_data_size_bytes(); quick_set_pointer(row); } @@ -829,7 +832,12 @@ INLINE void GeomVertexWriter:: quick_set_pointer(int row) { nassertv(has_column()); -#ifdef _DEBUG +#if defined(_DEBUG) && !defined(HAVE_THREADS) + // Make sure we still have the same pointer as stored the array. We + // only perform this test in debug mode, because it is expensive, + // and only in single-threaded mode, because in threaded mode + // another thread might have reallocated the other pointer outside + // of our control anyway. if (_vertex_data != (const GeomVertexData *)NULL) { const GeomVertexArrayData *array_data = _vertex_data->get_array(_array); nassertv(_pointer_begin == array_data->get_data()); diff --git a/panda/src/gobj/geomVertexWriter.h b/panda/src/gobj/geomVertexWriter.h index 1874290971..5e7c75a70e 100644 --- a/panda/src/gobj/geomVertexWriter.h +++ b/panda/src/gobj/geomVertexWriter.h @@ -181,6 +181,7 @@ private: GeomVertexColumn::Packer *_packer; int _stride; + PTA_uchar _data; unsigned char *_pointer_begin; unsigned char *_pointer_end; unsigned char *_pointer; diff --git a/panda/src/gobj/transformBlend.I b/panda/src/gobj/transformBlend.I index 82f8c67714..f09435f14f 100644 --- a/panda/src/gobj/transformBlend.I +++ b/panda/src/gobj/transformBlend.I @@ -211,7 +211,7 @@ set_weight(int n, float weight) { //////////////////////////////////////////////////////////////////// INLINE void TransformBlend:: update_blend(Thread *current_thread) const { - CDReader cdata(_cycler, current_thread); + CDLockedReader cdata(_cycler, current_thread); if (cdata->_global_modified != VertexTransform::get_global_modified(current_thread)) { CDWriter cdataw(((TransformBlend *)this)->_cycler, cdata, false); ((TransformBlend *)this)->recompute_result(cdataw, current_thread); @@ -290,7 +290,7 @@ transform_vector(LVector3f &vector, Thread *current_thread) const { //////////////////////////////////////////////////////////////////// INLINE UpdateSeq TransformBlend:: get_modified(Thread *current_thread) const { - CDReader cdata(_cycler, current_thread); + CDLockedReader cdata(_cycler, current_thread); if (cdata->_global_modified != VertexTransform::get_global_modified(current_thread)) { CDWriter cdataw(((TransformBlend *)this)->_cycler, cdata, false); ((TransformBlend *)this)->recompute_result(cdataw, current_thread); diff --git a/panda/src/gobj/transformBlend.h b/panda/src/gobj/transformBlend.h index 77fc15fbf5..cc8b049cb4 100644 --- a/panda/src/gobj/transformBlend.h +++ b/panda/src/gobj/transformBlend.h @@ -25,6 +25,7 @@ #include "pvector.h" #include "ordered_vector.h" #include "cycleData.h" +#include "cycleDataLockedReader.h" #include "cycleDataReader.h" #include "cycleDataWriter.h" #include "pipelineCycler.h" @@ -114,6 +115,7 @@ private: }; PipelineCycler _cycler; + typedef CycleDataLockedReader CDLockedReader; typedef CycleDataReader CDReader; typedef CycleDataWriter CDWriter; diff --git a/panda/src/gobj/transformBlendTable.I b/panda/src/gobj/transformBlendTable.I index b2d18120b2..208112b132 100644 --- a/panda/src/gobj/transformBlendTable.I +++ b/panda/src/gobj/transformBlendTable.I @@ -48,7 +48,7 @@ get_blend(int n) const { //////////////////////////////////////////////////////////////////// INLINE UpdateSeq TransformBlendTable:: get_modified(Thread *current_thread) const { - CDReader cdata(_cycler); + CDLockedReader cdata(_cycler); if (cdata->_global_modified != VertexTransform::get_global_modified(current_thread)) { CDWriter cdataw(((TransformBlendTable *)this)->_cycler, cdata, false); ((TransformBlendTable *)this)->recompute_modified(cdataw, current_thread); diff --git a/panda/src/gobj/transformBlendTable.h b/panda/src/gobj/transformBlendTable.h index b9272c4e59..fefb7a014a 100644 --- a/panda/src/gobj/transformBlendTable.h +++ b/panda/src/gobj/transformBlendTable.h @@ -28,6 +28,7 @@ #include "pmap.h" #include "indirectLess.h" #include "cycleData.h" +#include "cycleDataLockedReader.h" #include "cycleDataReader.h" #include "cycleDataWriter.h" #include "pipelineCycler.h" @@ -115,6 +116,7 @@ private: }; PipelineCycler _cycler; + typedef CycleDataLockedReader CDLockedReader; typedef CycleDataReader CDReader; typedef CycleDataWriter CDWriter; diff --git a/panda/src/pgraph/nodePathComponent.cxx b/panda/src/pgraph/nodePathComponent.cxx index b44b535b89..bf56ef9f5a 100644 --- a/panda/src/pgraph/nodePathComponent.cxx +++ b/panda/src/pgraph/nodePathComponent.cxx @@ -133,7 +133,7 @@ get_next(int pipeline_stage, Thread *current_thread) const { //////////////////////////////////////////////////////////////////// bool NodePathComponent:: fix_length(int pipeline_stage, Thread *current_thread) { - CDStageReader cdata(_cycler, pipeline_stage, current_thread); + CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); int length_should_be = 1; if (cdata->_next != (NodePathComponent *)NULL) { diff --git a/panda/src/pgraph/nodePathComponent.h b/panda/src/pgraph/nodePathComponent.h index 73a5a52706..3d58de66ec 100644 --- a/panda/src/pgraph/nodePathComponent.h +++ b/panda/src/pgraph/nodePathComponent.h @@ -27,6 +27,7 @@ #include "cycleData.h" #include "cycleDataReader.h" #include "cycleDataWriter.h" +#include "cycleDataLockedStageReader.h" #include "cycleDataStageReader.h" #include "cycleDataStageWriter.h" #include "pmutex.h" @@ -100,6 +101,7 @@ private: PipelineCycler _cycler; typedef CycleDataReader CDReader; typedef CycleDataWriter CDWriter; + typedef CycleDataLockedStageReader CDLockedStageReader; typedef CycleDataStageReader CDStageReader; typedef CycleDataStageWriter CDStageWriter; diff --git a/panda/src/pgraph/pandaNode.I b/panda/src/pgraph/pandaNode.I index d1dd3bda5d..27d4e5a6c3 100644 --- a/panda/src/pgraph/pandaNode.I +++ b/panda/src/pgraph/pandaNode.I @@ -1161,7 +1161,7 @@ INLINE PandaNodePipelineReader:: PandaNodePipelineReader(const PandaNode *object, Thread *current_thread) : _object(object), _current_thread(current_thread), - _cdata(object->_cycler.read(current_thread)) + _cdata(object->_cycler.read_unlocked(current_thread)) { #ifdef _DEBUG nassertv(_object->test_ref_count_nonzero()); @@ -1182,9 +1182,11 @@ PandaNodePipelineReader(const PandaNodePipelineReader ©) : _current_thread(copy._current_thread), _cdata(copy._cdata) { + /* if (_cdata != (PandaNode::CData *)NULL) { _object->_cycler.increment_read(_cdata); } + */ } //////////////////////////////////////////////////////////////////// @@ -1196,16 +1198,20 @@ INLINE void PandaNodePipelineReader:: operator = (const PandaNodePipelineReader ©) { nassertv(_current_thread == copy._current_thread); + /* if (_cdata != (PandaNode::CData *)NULL) { _object->_cycler.release_read(_cdata); } + */ _object = copy._object; _cdata = copy._cdata; + /* if (_cdata != (PandaNode::CData *)NULL) { _object->_cycler.increment_read(_cdata); } + */ } //////////////////////////////////////////////////////////////////// @@ -1215,9 +1221,11 @@ operator = (const PandaNodePipelineReader ©) { //////////////////////////////////////////////////////////////////// INLINE PandaNodePipelineReader:: ~PandaNodePipelineReader() { + /* if (_cdata != (PandaNode::CData *)NULL) { _object->_cycler.release_read(_cdata); } + */ #ifdef _DEBUG _object = NULL; @@ -1253,30 +1261,12 @@ get_current_thread() const { //////////////////////////////////////////////////////////////////// INLINE void PandaNodePipelineReader:: release() { + /* if (_cdata != (PandaNode::CData *)NULL) { _object->_cycler.release_read(_cdata); _cdata = NULL; } -} - -//////////////////////////////////////////////////////////////////// -// Function: PandaNodePipelineReader::check_bounds -// Access: Public -// Description: Ensures that the bounding volume is properly computed -// on this node. -//////////////////////////////////////////////////////////////////// -INLINE void PandaNodePipelineReader:: -check_bounds() const { - nassertv(_cdata != (PandaNode::CData *)NULL); - if (_cdata->_last_update != _cdata->_next_update) { - // The cache is stale; it needs to be rebuilt. - - // We should technically drop _cdata while we do this operation, - // but at the moment, it doesn't really matter. - int pipeline_stage = _current_thread->get_pipeline_stage(); - PandaNode::CDStageReader fresh_cdata(_object->_cycler, pipeline_stage, _current_thread); - ((PandaNode *)_object)->update_bounds(pipeline_stage, fresh_cdata); - } + */ } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index 38d16d0266..a82a893d5d 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -1404,8 +1404,7 @@ copy_tags(PandaNode *other) { Thread *current_thread = Thread::get_current_thread(); OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) { CDStageWriter cdataw(_cycler, pipeline_stage, current_thread); - CDStageReader cdatar(other->_cycler, pipeline_stage, - current_thread); + CDStageReader cdatar(other->_cycler, pipeline_stage, current_thread); TagData::const_iterator ti; for (ti = cdatar->_tag_data.begin(); @@ -1565,7 +1564,7 @@ DrawMask PandaNode:: get_net_draw_control_mask() const { Thread *current_thread = Thread::get_current_thread(); int pipeline_stage = current_thread->get_pipeline_stage(); - CDStageReader cdata(_cycler, pipeline_stage, current_thread); + CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); if (cdata->_last_update != cdata->_next_update) { // The cache is stale; it needs to be rebuilt. CDStageWriter cdataw = @@ -1595,7 +1594,7 @@ DrawMask PandaNode:: get_net_draw_show_mask() const { Thread *current_thread = Thread::get_current_thread(); int pipeline_stage = current_thread->get_pipeline_stage(); - CDStageReader cdata(_cycler, pipeline_stage, current_thread); + CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); if (cdata->_last_update != cdata->_next_update) { // The cache is stale; it needs to be rebuilt. CDStageWriter cdataw = @@ -1667,7 +1666,7 @@ get_legal_collide_mask() const { CollideMask PandaNode:: get_net_collide_mask(Thread *current_thread) const { int pipeline_stage = current_thread->get_pipeline_stage(); - CDStageReader cdata(_cycler, pipeline_stage, current_thread); + CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); if (cdata->_last_update != cdata->_next_update) { // The cache is stale; it needs to be rebuilt. CDStageWriter cdataw = @@ -1687,7 +1686,7 @@ get_net_collide_mask(Thread *current_thread) const { CPT(RenderAttrib) PandaNode:: get_off_clip_planes(Thread *current_thread) const { int pipeline_stage = current_thread->get_pipeline_stage(); - CDStageReader cdata(_cycler, pipeline_stage, current_thread); + CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); if (cdata->_last_update != cdata->_next_update) { // The cache is stale; it needs to be rebuilt. CDStageWriter cdataw = @@ -1808,7 +1807,7 @@ set_bound(const BoundingVolume *volume) { CPT(BoundingVolume) PandaNode:: get_bounds(Thread *current_thread) const { int pipeline_stage = current_thread->get_pipeline_stage(); - CDStageReader cdata(_cycler, pipeline_stage, current_thread); + CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); if (cdata->_last_update != cdata->_next_update) { // The cache is stale; it needs to be rebuilt. CPT(BoundingVolume) result; @@ -1900,7 +1899,7 @@ as_light() { //////////////////////////////////////////////////////////////////// CPT(BoundingVolume) PandaNode:: get_internal_bounds(int pipeline_stage, Thread *current_thread) const { - CDStageReader cdata(_cycler, pipeline_stage, current_thread); + CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread); if (cdata->_internal_bounds_stale) { CDStageWriter cdataw(((PandaNode *)this)->_cycler, pipeline_stage, cdata); if (cdataw->_user_bounds != (BoundingVolume *)NULL) { @@ -2868,7 +2867,7 @@ r_list_descendants(ostream &out, int indent_level) const { // released. The new value is returned. //////////////////////////////////////////////////////////////////// PandaNode::CDStageWriter PandaNode:: -update_bounds(int pipeline_stage, PandaNode::CDStageReader &cdata) { +update_bounds(int pipeline_stage, PandaNode::CDLockedStageReader &cdata) { // We might need to try this a couple of times, in case someone else // steps on our result. if (drawmask_cat.is_debug()) { @@ -2878,24 +2877,20 @@ update_bounds(int pipeline_stage, PandaNode::CDStageReader &cdata) { Thread *current_thread = cdata.get_current_thread(); do { - // Grab the last_update counter, then release the lock. + // Grab the last_update counter. UpdateSeq last_update = cdata->_last_update; UpdateSeq next_update = cdata->_next_update; nassertr(last_update != next_update, CDStageWriter(_cycler, pipeline_stage, cdata)); - _cycler.release_read_stage(pipeline_stage, cdata.take_pointer()); // Start with a clean slate, or at least with the contents of the // node itself. - CollideMask net_collide_mask; + CollideMask net_collide_mask = cdata->_into_collide_mask; DrawMask net_draw_control_mask, net_draw_show_mask; DrawMask draw_control_mask, draw_show_mask; + draw_control_mask = net_draw_control_mask = cdata->_draw_control_mask; + draw_show_mask = net_draw_show_mask = cdata->_draw_show_mask; bool renderable = is_renderable(); - { - CDStageReader cdata(_cycler, pipeline_stage, current_thread); - net_collide_mask = cdata->_into_collide_mask; - draw_control_mask = net_draw_control_mask = cdata->_draw_control_mask; - draw_show_mask = net_draw_show_mask = cdata->_draw_show_mask; - } + if (!renderable) { // This is not a "renderable" node. This means that this node // does not itself contribute any bits to net_draw_show_mask or @@ -2914,15 +2909,18 @@ update_bounds(int pipeline_stage, PandaNode::CDStageReader &cdata) { << "\ndraw_show_mask = " << draw_show_mask << "\n"; } - CPT(RenderAttrib) off_clip_planes; - { - CDStageReader cdata(_cycler, pipeline_stage, current_thread); - off_clip_planes = cdata->_state->get_clip_plane(); - } + CPT(RenderAttrib) off_clip_planes = cdata->_state->get_clip_plane(); if (off_clip_planes == (RenderAttrib *)NULL) { off_clip_planes = ClipPlaneAttrib::make(); } + // Also get the list of the node's children. + Children children(cdata); + + // Now that we've got all the data we need from the node, we can + // release the lock. + _cycler.release_read_stage(pipeline_stage, cdata.take_pointer()); + // We need to keep references to the bounding volumes, since in a // threaded environment the pointers might go away while we're // working (since we're not holding a lock on our set of children @@ -2937,7 +2935,6 @@ update_bounds(int pipeline_stage, PandaNode::CDStageReader &cdata) { child_volumes.push_back(internal_bounds); // Now expand those contents to include all of our children. - Children children = get_children(current_thread); int num_children = children.get_num_children(); for (int i = 0; i < num_children; ++i) { @@ -2945,7 +2942,7 @@ update_bounds(int pipeline_stage, PandaNode::CDStageReader &cdata) { const ClipPlaneAttrib *orig_cp = DCAST(ClipPlaneAttrib, off_clip_planes); - CDStageReader child_cdata(child->_cycler, pipeline_stage, current_thread); + CDLockedStageReader child_cdata(child->_cycler, pipeline_stage, current_thread); if (child_cdata->_last_update != child_cdata->_next_update) { // Child needs update. CDStageWriter child_cdataw = child->update_bounds(pipeline_stage, child_cdata); @@ -3089,7 +3086,7 @@ update_bounds(int pipeline_stage, PandaNode::CDStageReader &cdata) { // We need to go around again. Release the write lock, and grab // the read lock back. - cdata = CDStageReader(_cycler, pipeline_stage, current_thread); + cdata = CDLockedStageReader(_cycler, pipeline_stage, current_thread); if (cdata->_last_update == cdata->_next_update) { // Someone else has computed the cache for us while we were @@ -3633,3 +3630,41 @@ fillin_down_list(PandaNode::Down &down_list, down_list.push_back(DownConnection(NULL, sort)); } } + +//////////////////////////////////////////////////////////////////// +// Function: PandaNodePipelineReader::check_bounds +// Access: Public +// Description: Ensures that the bounding volume is properly computed +// on this node. +//////////////////////////////////////////////////////////////////// +void PandaNodePipelineReader:: +check_bounds() const { + if (_cdata->_last_update != _cdata->_next_update) { + // The cache is stale; it needs to be rebuilt. + + // We'll need to get a fresh read pointer, since another thread + // might already have modified the pointer on the object since we + // queried it. + { + int pipeline_stage = _current_thread->get_pipeline_stage(); + PandaNode::CDLockedStageReader fresh_cdata(_object->_cycler, pipeline_stage, _current_thread); + if (fresh_cdata->_last_update == fresh_cdata->_next_update) { + // What luck, some other thread has already freshened the + // cache for us. Save the new pointer, and let the lock + // release itself. + ((PandaNodePipelineReader *)this)->_cdata = fresh_cdata; + + } else { + // No, the cache is still stale. We have to do the work of + // freshening it. + PandaNode::CDStageWriter cdataw = ((PandaNode *)_object)->update_bounds(pipeline_stage, fresh_cdata); + nassertv(cdataw->_last_update == cdataw->_next_update); + // As above, we save the new pointer, and then let the lock + // release itself. + ((PandaNodePipelineReader *)this)->_cdata = cdataw; + } + } + } + + nassertv(_cdata->_last_update == _cdata->_next_update); +} diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index 444d6fda85..134bf1ad40 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -24,6 +24,7 @@ #include "cycleData.h" #include "cycleDataReader.h" #include "cycleDataWriter.h" +#include "cycleDataLockedStageReader.h" #include "cycleDataStageReader.h" #include "cycleDataStageWriter.h" #include "pipelineCycler.h" @@ -505,10 +506,11 @@ private: PipelineCycler _cycler; typedef CycleDataReader CDReader; typedef CycleDataWriter CDWriter; + typedef CycleDataLockedStageReader CDLockedStageReader; typedef CycleDataStageReader CDStageReader; typedef CycleDataStageWriter CDStageWriter; - CDStageWriter update_bounds(int pipeline_stage, CDStageReader &cdata); + CDStageWriter update_bounds(int pipeline_stage, CDLockedStageReader &cdata); static DrawMask _overall_bit; @@ -631,7 +633,7 @@ public: INLINE void release(); - INLINE void check_bounds() const; + void check_bounds() const; INLINE void compose_draw_mask(DrawMask &running_draw_mask) const; INLINE bool compare_draw_mask(DrawMask running_draw_mask, @@ -671,7 +673,7 @@ public: private: const PandaNode *_object; Thread *_current_thread; - const PandaNode::CData *_cdata; + CPT(PandaNode::CData) _cdata; }; INLINE ostream &operator << (ostream &out, const PandaNode &node) { diff --git a/panda/src/pgraph/planeNode.cxx b/panda/src/pgraph/planeNode.cxx index e5a81e5361..f2a6a01056 100644 --- a/panda/src/pgraph/planeNode.cxx +++ b/panda/src/pgraph/planeNode.cxx @@ -222,7 +222,7 @@ compute_internal_bounds(int pipeline_stage, Thread *current_thread) const { //////////////////////////////////////////////////////////////////// PT(Geom) PlaneNode:: get_viz(CullTraverser *trav, CullTraverserData &data) { - CDReader cdata(_cycler); + CDLockedReader cdata(_cycler); // Figure out whether we are looking at the front or the back of the // plane. diff --git a/panda/src/pgraph/planeNode.h b/panda/src/pgraph/planeNode.h index 0cdee825e1..4661c1fb6b 100644 --- a/panda/src/pgraph/planeNode.h +++ b/panda/src/pgraph/planeNode.h @@ -26,6 +26,7 @@ #include "updateSeq.h" #include "geom.h" #include "cycleData.h" +#include "cycleDataLockedReader.h" #include "cycleDataReader.h" #include "cycleDataWriter.h" #include "cycleDataStageReader.h" @@ -97,6 +98,7 @@ private: }; PipelineCycler _cycler; + typedef CycleDataLockedReader CDLockedReader; typedef CycleDataReader CDReader; typedef CycleDataWriter CDWriter; typedef CycleDataStageReader CDStageReader; diff --git a/panda/src/pipeline/Sources.pp b/panda/src/pipeline/Sources.pp index 477dd74092..3c55ff7786 100644 --- a/panda/src/pipeline/Sources.pp +++ b/panda/src/pipeline/Sources.pp @@ -22,6 +22,8 @@ conditionVarSpinlockImpl.h conditionVarSpinlockImpl.I \ config_pipeline.h \ cycleData.h cycleData.I \ + cycleDataLockedReader.h cycleDataLockedReader.I \ + cycleDataLockedStageReader.h cycleDataLockedStageReader.I \ cycleDataReader.h cycleDataReader.I \ cycleDataStageReader.h cycleDataStageReader.I \ cycleDataStageWriter.h cycleDataStageWriter.I \ @@ -62,6 +64,8 @@ conditionVarSpinlockImpl.cxx \ config_pipeline.cxx \ cycleData.cxx \ + cycleDataLockedReader.cxx \ + cycleDataLockedStageReader.cxx \ cycleDataReader.cxx \ cycleDataStageReader.cxx \ cycleDataStageWriter.cxx \ @@ -100,6 +104,8 @@ conditionVarSpinlockImpl.h conditionVarSpinlockImpl.I \ config_pipeline.h \ cycleData.h cycleData.I \ + cycleDataLockedReader.h cycleDataLockedReader.I \ + cycleDataLockedStageReader.h cycleDataLockedStageReader.I \ cycleDataReader.h cycleDataReader.I \ cycleDataStageReader.h cycleDataStageReader.I \ cycleDataStageWriter.h cycleDataStageWriter.I \ diff --git a/panda/src/pipeline/cycleData.h b/panda/src/pipeline/cycleData.h index 45d1cc814a..f009cf8b02 100644 --- a/panda/src/pipeline/cycleData.h +++ b/panda/src/pipeline/cycleData.h @@ -21,7 +21,7 @@ #include "pandabase.h" #include "typeHandle.h" -#include "referenceCount.h" +#include "nodeReferenceCount.h" class BamWriter; class BamReader; @@ -40,8 +40,11 @@ class DatagramIterator; // If we are compiling in pipelining support, we maintain a pointer to // a CycleData object in each containing class, instead of the object -// itself. Thus, it should be a ReferenceCount object. -class EXPCL_PANDA CycleData : public ReferenceCount +// itself. Thus, it should be a ReferenceCount object. Furthermore, +// since we want to make a distinction between references within the +// cycler, and references outside the cycler +// (e.g. GeomPipelineReader), we make it a NodeReferenceCount. +class EXPCL_PANDA CycleData : public NodeReferenceCount #else // !DO_PIPELINING diff --git a/panda/src/pipeline/cycleDataLockedReader.I b/panda/src/pipeline/cycleDataLockedReader.I new file mode 100644 index 0000000000..0b075060b0 --- /dev/null +++ b/panda/src/pipeline/cycleDataLockedReader.I @@ -0,0 +1,242 @@ +// Filename: cycleDataLockedReader.I +// Created by: drose (30Apr06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifdef DO_PIPELINING +// This is the implementation for full support of pipelining (as well +// as the sanity-check only implementation). + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedReader::Constructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataLockedReader:: +CycleDataLockedReader(const PipelineCycler &cycler, + Thread *current_thread) : + _cycler(&cycler), + _current_thread(current_thread) +{ + _pointer = _cycler->read(_current_thread); + nassertv(_pointer != (const CycleDataType *)NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedReader::Copy Constructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataLockedReader:: +CycleDataLockedReader(const CycleDataLockedReader ©) : + _cycler(copy._cycler), + _current_thread(copy._current_thread), + _pointer(copy._pointer) +{ + nassertv(_pointer != (const CycleDataType *)NULL); + _cycler->increment_read(_pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedReader::Copy Assignment (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE void CycleDataLockedReader:: +operator = (const CycleDataLockedReader ©) { + nassertv(_pointer == (CycleDataType *)NULL); + nassertv(_current_thread == copy._current_thread); + + _cycler = copy._cycler; + _pointer = copy._pointer; + + nassertv(_pointer != (const CycleDataType *)NULL); + _cycler->increment_read(_pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedReader::Destructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataLockedReader:: +~CycleDataLockedReader() { + if (_pointer != NULL) { + _cycler->release_read(_pointer); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedReader::operator -> (full) +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataLockedReader:: +operator -> () const { + nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat()); + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedReader::Typecast pointer (full) +// Access: Public +// Description: This allows the CycleDataLockedReader to be passed to any +// function that expects a const CycleDataType pointer. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataLockedReader:: +operator const CycleDataType * () const { + nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat()); + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedReader::take_pointer (full) +// Access: Public +// Description: This is intended to be called only from +// CycleDataWriter when it elevates the pointer from +// read to write status. This function returns the +// reader's pointer and relinquishes ownership of the +// pointer, rendering the reader invalid for future +// reads. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataLockedReader:: +take_pointer() { + const CycleDataType *pointer = _pointer; + _pointer = (CycleDataType *)NULL; + nassertr(pointer != (const CycleDataType *)NULL, _cycler->cheat()); + return pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedReader::get_current_thread (full) +// Access: Public +// Description: Returns the Thread pointer of the currently-executing +// thread, as passed to the constructor of this object. +//////////////////////////////////////////////////////////////////// +template +INLINE Thread *CycleDataLockedReader:: +get_current_thread() const { + return _current_thread; +} + +#else // !DO_PIPELINING +// This is the trivial, do-nothing implementation. + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedReader::Constructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataLockedReader:: +CycleDataLockedReader(const PipelineCycler &cycler, Thread *) { + _pointer = cycler.cheat(); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedReader::Copy Constructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataLockedReader:: +CycleDataLockedReader(const CycleDataLockedReader ©) : + _pointer(copy._pointer) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedReader::Copy Assignment (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE void CycleDataLockedReader:: +operator = (const CycleDataLockedReader ©) { + _pointer = copy._pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedReader::Destructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataLockedReader:: +~CycleDataLockedReader() { +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedReader::operator -> (trivial) +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataLockedReader:: +operator -> () const { + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedReader::Typecast pointer (trivial) +// Access: Public +// Description: This allows the CycleDataLockedReader to be passed to any +// function that expects a const CycleDataType pointer. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataLockedReader:: +operator const CycleDataType * () const { + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedReader::take_pointer (trivial) +// Access: Public +// Description: This is intended to be called only from +// CycleDataWriter when it elevates the pointer from +// read to write status. This function returns the +// reader's pointer and relinquishes ownership of the +// pointer, rendering the reader invalid for future +// reads. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataLockedReader:: +take_pointer() { + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedReader::get_current_thread (trivial) +// Access: Public +// Description: Returns the Thread pointer of the currently-executing +// thread, as passed to the constructor of this object. +//////////////////////////////////////////////////////////////////// +template +INLINE Thread *CycleDataLockedReader:: +get_current_thread() const { + return Thread::get_current_thread(); +} + +#endif // DO_PIPELINING diff --git a/panda/src/pipeline/cycleDataLockedReader.cxx b/panda/src/pipeline/cycleDataLockedReader.cxx new file mode 100644 index 0000000000..4e5dab0bf6 --- /dev/null +++ b/panda/src/pipeline/cycleDataLockedReader.cxx @@ -0,0 +1,19 @@ +// Filename: cycleDataLockedReader.cxx +// Created by: drose (30Apr06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "cycleDataLockedReader.h" diff --git a/panda/src/pipeline/cycleDataLockedReader.h b/panda/src/pipeline/cycleDataLockedReader.h new file mode 100644 index 0000000000..58dfdf6634 --- /dev/null +++ b/panda/src/pipeline/cycleDataLockedReader.h @@ -0,0 +1,81 @@ +// Filename: cycleDataLockedReader.h +// Created by: drose (30Apr06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CYCLEDATALOCKEDREADER_H +#define CYCLEDATALOCKEDREADER_H + +#include "pandabase.h" + +#include "cycleData.h" +#include "pipelineCycler.h" +#include "thread.h" + +//////////////////////////////////////////////////////////////////// +// Class : CycleDataLockedReader +// Description : This template class calls PipelineCycler::read() in +// the constructor and PipelineCycler::release_read() in +// the destructor. In the interim, it provides a +// transparent read-only access to the CycleData. +// +// Since a lock is held on the data while the instance +// of this class exists, no other thread may modify any +// stage of the pipeline during that time. Thus, this +// class is appropriate to use for cases in which you +// might want to read and then modify the data. It is +// possible to pass an instance of CycleDataLockedReader +// to the CycleDataWriter constructor, which +// automatically elevates the read lock into a write +// lock. +// +// It exists as a syntactic convenience to access the +// data in the CycleData. It also allows the whole +// system to compile down to nothing if +// SUPPORT_PIPELINING is not defined. +//////////////////////////////////////////////////////////////////// +template +class CycleDataLockedReader { +public: + INLINE CycleDataLockedReader(const PipelineCycler &cycler, + Thread *current_thread = Thread::get_current_thread()); + INLINE CycleDataLockedReader(const CycleDataLockedReader ©); + INLINE void operator = (const CycleDataLockedReader ©); + + INLINE ~CycleDataLockedReader(); + + INLINE const CycleDataType *operator -> () const; + INLINE operator const CycleDataType * () const; + + INLINE const CycleDataType *take_pointer(); + INLINE Thread *get_current_thread() const; + +private: +#ifdef DO_PIPELINING + // This is the data stored for a real pipelining implementation. + const PipelineCycler *_cycler; + Thread *_current_thread; + const CycleDataType *_pointer; + CycleDataType *_write_pointer; +#else // !DO_PIPELINING + // This is all we need for the trivial, do-nothing implementation. + const CycleDataType *_pointer; +#endif // DO_PIPELINING +}; + +#include "cycleDataLockedReader.I" + +#endif diff --git a/panda/src/pipeline/cycleDataLockedStageReader.I b/panda/src/pipeline/cycleDataLockedStageReader.I new file mode 100644 index 0000000000..9921636588 --- /dev/null +++ b/panda/src/pipeline/cycleDataLockedStageReader.I @@ -0,0 +1,247 @@ +// Filename: cycleDataLockedStageReader.I +// Created by: drose (30Apr06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +#ifdef DO_PIPELINING +// This is the implementation for full support of pipelining (as well +// as the sanity-check only implementation). + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedStageReader::Constructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataLockedStageReader:: +CycleDataLockedStageReader(const PipelineCycler &cycler, + int stage, Thread *current_thread) : + _cycler(&cycler), + _current_thread(current_thread), + _stage(stage) +{ + _pointer = _cycler->read_stage(_stage, _current_thread); + nassertv(_pointer != (const CycleDataType *)NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedStageReader::Copy Constructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataLockedStageReader:: +CycleDataLockedStageReader(const CycleDataLockedStageReader ©) : + _cycler(copy._cycler), + _current_thread(copy._current_thread), + _pointer(copy._pointer), + _stage(copy._stage) +{ + nassertv(_pointer != (const CycleDataType *)NULL); + _cycler->increment_read(_pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedStageReader::Copy Assignment (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE void CycleDataLockedStageReader:: +operator = (const CycleDataLockedStageReader ©) { + nassertv(_pointer == (CycleDataType *)NULL); + nassertv(_current_thread == copy._current_thread); + + _cycler = copy._cycler; + _pointer = copy._pointer; + _stage = copy._stage; + + nassertv(_pointer != (const CycleDataType *)NULL); + _cycler->increment_read(_pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedStageReader::Destructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataLockedStageReader:: +~CycleDataLockedStageReader() { + if (_pointer != NULL) { + _cycler->release_read_stage(_stage, _pointer); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedStageReader::operator -> (full) +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataLockedStageReader:: +operator -> () const { + nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat()); + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedStageReader::Typecast pointer (full) +// Access: Public +// Description: This allows the CycleDataLockedStageReader to be passed to any +// function that expects a const CycleDataType pointer. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataLockedStageReader:: +operator const CycleDataType * () const { + nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat()); + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedStageReader::take_pointer (full) +// Access: Public +// Description: This is intended to be called only from +// CycleDataStageWriter when it elevates the pointer from +// read to write status. This function returns the +// reader's pointer and relinquishes ownership of the +// pointer, rendering the reader invalid for future +// reads. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataLockedStageReader:: +take_pointer() { + const CycleDataType *pointer = _pointer; + _pointer = (CycleDataType *)NULL; + nassertr(pointer != (const CycleDataType *)NULL, _cycler->cheat()); + return pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedStageReader::get_current_thread (full) +// Access: Public +// Description: Returns the Thread pointer of the currently-executing +// thread, as passed to the constructor of this object. +//////////////////////////////////////////////////////////////////// +template +INLINE Thread *CycleDataLockedStageReader:: +get_current_thread() const { + return _current_thread; +} + +#else // !DO_PIPELINING +// This is the trivial, do-nothing implementation. + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedStageReader::Constructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataLockedStageReader:: +CycleDataLockedStageReader(const PipelineCycler &cycler, int, + Thread *) { + _pointer = cycler.cheat(); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedStageReader::Copy Constructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataLockedStageReader:: +CycleDataLockedStageReader(const CycleDataLockedStageReader ©) : + _pointer(copy._pointer) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedStageReader::Copy Assignment (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE void CycleDataLockedStageReader:: +operator = (const CycleDataLockedStageReader ©) { + _pointer = copy._pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedStageReader::Destructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataLockedStageReader:: +~CycleDataLockedStageReader() { +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedStageReader::operator -> (trivial) +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataLockedStageReader:: +operator -> () const { + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedStageReader::Typecast pointer (trivial) +// Access: Public +// Description: This allows the CycleDataLockedStageReader to be passed to any +// function that expects a const CycleDataType pointer. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataLockedStageReader:: +operator const CycleDataType * () const { + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedStageReader::take_pointer (trivial) +// Access: Public +// Description: This is intended to be called only from +// CycleDataStageWriter when it elevates the pointer from +// read to write status. This function returns the +// reader's pointer and relinquishes ownership of the +// pointer, rendering the reader invalid for future +// reads. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataLockedStageReader:: +take_pointer() { + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataLockedStageReader::get_current_thread (trivial) +// Access: Public +// Description: Returns the Thread pointer of the currently-executing +// thread, as passed to the constructor of this object. +//////////////////////////////////////////////////////////////////// +template +INLINE Thread *CycleDataLockedStageReader:: +get_current_thread() const { + return Thread::get_current_thread(); +} + +#endif // DO_PIPELINING diff --git a/panda/src/pipeline/cycleDataLockedStageReader.cxx b/panda/src/pipeline/cycleDataLockedStageReader.cxx new file mode 100644 index 0000000000..4fd56b71e6 --- /dev/null +++ b/panda/src/pipeline/cycleDataLockedStageReader.cxx @@ -0,0 +1,19 @@ +// Filename: cycleDataLockedStageReader.cxx +// Created by: drose (30Apr06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "cycleDataLockedStageReader.h" diff --git a/panda/src/pipeline/cycleDataLockedStageReader.h b/panda/src/pipeline/cycleDataLockedStageReader.h new file mode 100644 index 0000000000..cbed9e7e76 --- /dev/null +++ b/panda/src/pipeline/cycleDataLockedStageReader.h @@ -0,0 +1,64 @@ +// Filename: cycleDataLockedStageReader.h +// Created by: drose (30Apr06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CYCLEDATALOCKEDSTAGEREADER_H +#define CYCLEDATALOCKEDSTAGEREADER_H + +#include "pandabase.h" + +#include "cycleData.h" +#include "pipelineCycler.h" + +//////////////////////////////////////////////////////////////////// +// Class : CycleDataLockedStageReader +// Description : This class is similar to CycleDataLockedReader, +// except it allows reading from a particular stage of +// the pipeline. +//////////////////////////////////////////////////////////////////// +template +class CycleDataLockedStageReader { +public: + INLINE CycleDataLockedStageReader(const PipelineCycler &cycler, + int stage, Thread *current_thread = Thread::get_current_thread()); + INLINE CycleDataLockedStageReader(const CycleDataLockedStageReader ©); + INLINE void operator = (const CycleDataLockedStageReader ©); + + INLINE ~CycleDataLockedStageReader(); + + INLINE const CycleDataType *operator -> () const; + INLINE operator const CycleDataType * () const; + + INLINE const CycleDataType *take_pointer(); + INLINE Thread *get_current_thread() const; + +private: +#ifdef DO_PIPELINING + // This is the data stored for a real pipelining implementation. + const PipelineCycler *_cycler; + Thread *_current_thread; + const CycleDataType *_pointer; + int _stage; +#else // !DO_PIPELINING + // This is all we need for the trivial, do-nothing implementation. + const CycleDataType *_pointer; +#endif // DO_PIPELINING +}; + +#include "cycleDataLockedStageReader.I" + +#endif diff --git a/panda/src/pipeline/cycleDataReader.I b/panda/src/pipeline/cycleDataReader.I index f06b6fd769..e612e1a5cf 100644 --- a/panda/src/pipeline/cycleDataReader.I +++ b/panda/src/pipeline/cycleDataReader.I @@ -32,8 +32,7 @@ CycleDataReader(const PipelineCycler &cycler, _cycler(&cycler), _current_thread(current_thread) { - _pointer = _cycler->read(_current_thread); - nassertv(_pointer != (const CycleDataType *)NULL); + _pointer = _cycler->read_unlocked(_current_thread); } //////////////////////////////////////////////////////////////////// @@ -48,8 +47,6 @@ CycleDataReader(const CycleDataReader ©) : _current_thread(copy._current_thread), _pointer(copy._pointer) { - nassertv(_pointer != (const CycleDataType *)NULL); - _cycler->increment_read(_pointer); } //////////////////////////////////////////////////////////////////// @@ -60,14 +57,10 @@ CycleDataReader(const CycleDataReader ©) : template INLINE void CycleDataReader:: operator = (const CycleDataReader ©) { - nassertv(_pointer == (CycleDataType *)NULL); nassertv(_current_thread == copy._current_thread); _cycler = copy._cycler; _pointer = copy._pointer; - - nassertv(_pointer != (const CycleDataType *)NULL); - _cycler->increment_read(_pointer); } //////////////////////////////////////////////////////////////////// @@ -78,9 +71,6 @@ operator = (const CycleDataReader ©) { template INLINE CycleDataReader:: ~CycleDataReader() { - if (_pointer != NULL) { - _cycler->release_read(_pointer); - } } //////////////////////////////////////////////////////////////////// @@ -92,7 +82,6 @@ INLINE CycleDataReader:: template INLINE const CycleDataType *CycleDataReader:: operator -> () const { - nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat()); return _pointer; } @@ -105,29 +94,9 @@ operator -> () const { template INLINE CycleDataReader:: operator const CycleDataType * () const { - nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat()); return _pointer; } -//////////////////////////////////////////////////////////////////// -// Function: CycleDataReader::take_pointer (full) -// Access: Public -// Description: This is intended to be called only from -// CycleDataWriter when it elevates the pointer from -// read to write status. This function returns the -// reader's pointer and relinquishes ownership of the -// pointer, rendering the reader invalid for future -// reads. -//////////////////////////////////////////////////////////////////// -template -INLINE const CycleDataType *CycleDataReader:: -take_pointer() { - const CycleDataType *pointer = _pointer; - _pointer = (CycleDataType *)NULL; - nassertr(pointer != (const CycleDataType *)NULL, _cycler->cheat()); - return pointer; -} - //////////////////////////////////////////////////////////////////// // Function: CycleDataReader::get_current_thread (full) // Access: Public @@ -211,22 +180,6 @@ operator const CycleDataType * () const { return _pointer; } -//////////////////////////////////////////////////////////////////// -// Function: CycleDataReader::take_pointer (trivial) -// Access: Public -// Description: This is intended to be called only from -// CycleDataWriter when it elevates the pointer from -// read to write status. This function returns the -// reader's pointer and relinquishes ownership of the -// pointer, rendering the reader invalid for future -// reads. -//////////////////////////////////////////////////////////////////// -template -INLINE const CycleDataType *CycleDataReader:: -take_pointer() { - return _pointer; -} - //////////////////////////////////////////////////////////////////// // Function: CycleDataReader::get_current_thread (trivial) // Access: Public diff --git a/panda/src/pipeline/cycleDataReader.h b/panda/src/pipeline/cycleDataReader.h index f09df2bba4..1a3d85651d 100644 --- a/panda/src/pipeline/cycleDataReader.h +++ b/panda/src/pipeline/cycleDataReader.h @@ -27,10 +27,14 @@ //////////////////////////////////////////////////////////////////// // Class : CycleDataReader -// Description : This template class calls PipelineCycler::read() in -// the constructor and PipelineCycler::release_read() in -// the destructor. In the interim, it provides a -// transparent read-only access to the CycleData. +// Description : This template class calls +// PipelineCycler::read_unlocked(), and then provides a +// transparent read-only access to the CycleData. It is +// used to access the data quickly, without holding a +// lock, for a thread that does not intend to modify the +// data and write it back out. For cases where the data +// might be subsequently modified, you should use +// CycleDataLockedReader. // // It exists as a syntactic convenience to access the // data in the CycleData. It also allows the whole @@ -50,7 +54,6 @@ public: INLINE const CycleDataType *operator -> () const; INLINE operator const CycleDataType * () const; - INLINE const CycleDataType *take_pointer(); INLINE Thread *get_current_thread() const; private: diff --git a/panda/src/pipeline/cycleDataStageReader.I b/panda/src/pipeline/cycleDataStageReader.I index 8bee04547e..1d25d08e3b 100644 --- a/panda/src/pipeline/cycleDataStageReader.I +++ b/panda/src/pipeline/cycleDataStageReader.I @@ -34,8 +34,7 @@ CycleDataStageReader(const PipelineCycler &cycler, _current_thread(current_thread), _stage(stage) { - _pointer = _cycler->read_stage(_stage, _current_thread); - nassertv(_pointer != (const CycleDataType *)NULL); + _pointer = _cycler->read_stage_unlocked(_stage); } //////////////////////////////////////////////////////////////////// @@ -51,8 +50,6 @@ CycleDataStageReader(const CycleDataStageReader ©) : _pointer(copy._pointer), _stage(copy._stage) { - nassertv(_pointer != (const CycleDataType *)NULL); - _cycler->increment_read(_pointer); } //////////////////////////////////////////////////////////////////// @@ -63,15 +60,11 @@ CycleDataStageReader(const CycleDataStageReader ©) : template INLINE void CycleDataStageReader:: operator = (const CycleDataStageReader ©) { - nassertv(_pointer == (CycleDataType *)NULL); nassertv(_current_thread == copy._current_thread); _cycler = copy._cycler; _pointer = copy._pointer; _stage = copy._stage; - - nassertv(_pointer != (const CycleDataType *)NULL); - _cycler->increment_read(_pointer); } //////////////////////////////////////////////////////////////////// @@ -82,9 +75,6 @@ operator = (const CycleDataStageReader ©) { template INLINE CycleDataStageReader:: ~CycleDataStageReader() { - if (_pointer != NULL) { - _cycler->release_read_stage(_stage, _pointer); - } } //////////////////////////////////////////////////////////////////// @@ -96,7 +86,6 @@ INLINE CycleDataStageReader:: template INLINE const CycleDataType *CycleDataStageReader:: operator -> () const { - nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat()); return _pointer; } @@ -109,29 +98,9 @@ operator -> () const { template INLINE CycleDataStageReader:: operator const CycleDataType * () const { - nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat()); return _pointer; } -//////////////////////////////////////////////////////////////////// -// Function: CycleDataStageReader::take_pointer (full) -// Access: Public -// Description: This is intended to be called only from -// CycleDataStageWriter when it elevates the pointer from -// read to write status. This function returns the -// reader's pointer and relinquishes ownership of the -// pointer, rendering the reader invalid for future -// reads. -//////////////////////////////////////////////////////////////////// -template -INLINE const CycleDataType *CycleDataStageReader:: -take_pointer() { - const CycleDataType *pointer = _pointer; - _pointer = (CycleDataType *)NULL; - nassertr(pointer != (const CycleDataType *)NULL, _cycler->cheat()); - return pointer; -} - //////////////////////////////////////////////////////////////////// // Function: CycleDataStageReader::get_current_thread (full) // Access: Public @@ -216,22 +185,6 @@ operator const CycleDataType * () const { return _pointer; } -//////////////////////////////////////////////////////////////////// -// Function: CycleDataStageReader::take_pointer (trivial) -// Access: Public -// Description: This is intended to be called only from -// CycleDataStageWriter when it elevates the pointer from -// read to write status. This function returns the -// reader's pointer and relinquishes ownership of the -// pointer, rendering the reader invalid for future -// reads. -//////////////////////////////////////////////////////////////////// -template -INLINE const CycleDataType *CycleDataStageReader:: -take_pointer() { - return _pointer; -} - //////////////////////////////////////////////////////////////////// // Function: CycleDataStageReader::get_current_thread (trivial) // Access: Public diff --git a/panda/src/pipeline/cycleDataStageReader.h b/panda/src/pipeline/cycleDataStageReader.h index 0d86a3c43f..836055ac52 100644 --- a/panda/src/pipeline/cycleDataStageReader.h +++ b/panda/src/pipeline/cycleDataStageReader.h @@ -43,7 +43,6 @@ public: INLINE const CycleDataType *operator -> () const; INLINE operator const CycleDataType * () const; - INLINE const CycleDataType *take_pointer(); INLINE Thread *get_current_thread() const; private: diff --git a/panda/src/pipeline/cycleDataStageWriter.I b/panda/src/pipeline/cycleDataStageWriter.I index 11d20f9ff3..df82c96588 100644 --- a/panda/src/pipeline/cycleDataStageWriter.I +++ b/panda/src/pipeline/cycleDataStageWriter.I @@ -94,13 +94,13 @@ operator = (const CycleDataStageWriter ©) { // Function: CycleDataStageWriter::Constructor (full) // Access: Public // Description: This flavor of the constructor elevates the pointer -// from the CycleDataStageReader from a read to a write +// from the CycleDataLockedStageReader from a read to a write // pointer (and invalidates the reader). //////////////////////////////////////////////////////////////////// template INLINE CycleDataStageWriter:: CycleDataStageWriter(PipelineCycler &cycler, int stage, - CycleDataStageReader &take_from) : + CycleDataLockedStageReader &take_from) : _cycler(&cycler), _current_thread(take_from.get_current_thread()), _stage(stage) @@ -113,13 +113,13 @@ CycleDataStageWriter(PipelineCycler &cycler, int stage, // Function: CycleDataStageWriter::Constructor (full) // Access: Public // Description: This flavor of the constructor elevates the pointer -// from the CycleDataStageReader from a read to a write +// from the CycleDataLockedStageReader from a read to a write // pointer (and invalidates the reader). //////////////////////////////////////////////////////////////////// template INLINE CycleDataStageWriter:: CycleDataStageWriter(PipelineCycler &cycler, int stage, - CycleDataStageReader &take_from, + CycleDataLockedStageReader &take_from, bool force_to_0) : _cycler(&cycler), _current_thread(take_from.get_current_thread()), @@ -245,13 +245,13 @@ operator = (const CycleDataStageWriter ©) { // Function: CycleDataStageWriter::Constructor (trivial) // Access: Public // Description: This flavor of the constructor elevates the pointer -// from the CycleDataStageReader from a read to a write +// from the CycleDataLockedStageReader from a read to a write // pointer (and invalidates the reader). //////////////////////////////////////////////////////////////////// template INLINE CycleDataStageWriter:: CycleDataStageWriter(PipelineCycler &, int, - CycleDataStageReader &take_from) : + CycleDataLockedStageReader &take_from) : _pointer((CycleDataType *)take_from.take_pointer()) { } @@ -260,13 +260,13 @@ CycleDataStageWriter(PipelineCycler &, int, // Function: CycleDataStageWriter::Constructor (trivial) // Access: Public // Description: This flavor of the constructor elevates the pointer -// from the CycleDataStageReader from a read to a write +// from the CycleDataLockedStageReader from a read to a write // pointer (and invalidates the reader). //////////////////////////////////////////////////////////////////// template INLINE CycleDataStageWriter:: CycleDataStageWriter(PipelineCycler &, int, - CycleDataStageReader &take_from, + CycleDataLockedStageReader &take_from, bool) : _pointer((CycleDataType *)take_from.take_pointer()) { diff --git a/panda/src/pipeline/cycleDataStageWriter.h b/panda/src/pipeline/cycleDataStageWriter.h index b79ec04749..c2dce13fd5 100644 --- a/panda/src/pipeline/cycleDataStageWriter.h +++ b/panda/src/pipeline/cycleDataStageWriter.h @@ -23,7 +23,7 @@ #include "cycleData.h" #include "pipelineCycler.h" -#include "cycleDataStageReader.h" +#include "cycleDataLockedStageReader.h" //////////////////////////////////////////////////////////////////// // Class : CycleDataStageWriter @@ -46,9 +46,9 @@ public: INLINE void operator = (const CycleDataStageWriter ©); INLINE CycleDataStageWriter(PipelineCycler &cycler, int stage, - CycleDataStageReader &take_from); + CycleDataLockedStageReader &take_from); INLINE CycleDataStageWriter(PipelineCycler &cycler, int stage, - CycleDataStageReader &take_from, + CycleDataLockedStageReader &take_from, bool force_to_0); INLINE ~CycleDataStageWriter(); diff --git a/panda/src/pipeline/cycleDataWriter.I b/panda/src/pipeline/cycleDataWriter.I index a01dcf0463..fbd5d8464b 100644 --- a/panda/src/pipeline/cycleDataWriter.I +++ b/panda/src/pipeline/cycleDataWriter.I @@ -95,13 +95,13 @@ operator = (const CycleDataWriter ©) { // Function: CycleDataWriter::Constructor (full) // Access: Public // Description: This flavor of the constructor elevates the pointer -// from the CycleDataReader from a read to a write +// from the CycleDataLockedReader from a read to a write // pointer (and invalidates the reader). //////////////////////////////////////////////////////////////////// template INLINE CycleDataWriter:: CycleDataWriter(PipelineCycler &cycler, - CycleDataReader &take_from) : + CycleDataLockedReader &take_from) : _cycler(&cycler), _current_thread(take_from.get_current_thread()) { @@ -112,7 +112,7 @@ CycleDataWriter(PipelineCycler &cycler, // Function: CycleDataWriter::Constructor (full) // Access: Public // Description: This flavor of the constructor elevates the pointer -// from the CycleDataReader from a read to a write +// from the CycleDataLockedReader from a read to a write // pointer (and invalidates the reader). It also // propagates the pointer back upstream; see // PipelineCycler::write_upstream(). @@ -120,7 +120,7 @@ CycleDataWriter(PipelineCycler &cycler, template INLINE CycleDataWriter:: CycleDataWriter(PipelineCycler &cycler, - CycleDataReader &take_from, + CycleDataLockedReader &take_from, bool force_to_0) : _cycler(&cycler), _current_thread(take_from.get_current_thread()) @@ -245,13 +245,13 @@ operator = (const CycleDataWriter ©) { // Function: CycleDataWriter::Constructor (trivial) // Access: Public // Description: This flavor of the constructor elevates the pointer -// from the CycleDataReader from a read to a write +// from the CycleDataLockedReader from a read to a write // pointer (and invalidates the reader). //////////////////////////////////////////////////////////////////// template INLINE CycleDataWriter:: CycleDataWriter(PipelineCycler &, - CycleDataReader &take_from) : + CycleDataLockedReader &take_from) : _pointer((CycleDataType *)take_from.take_pointer()) { } @@ -260,7 +260,7 @@ CycleDataWriter(PipelineCycler &, // Function: CycleDataWriter::Constructor (trivial) // Access: Public // Description: This flavor of the constructor elevates the pointer -// from the CycleDataReader from a read to a write +// from the CycleDataLockedReader from a read to a write // pointer (and invalidates the reader). It also // propagates the pointer back upstream; see // PipelineCycler::write_upstream(). @@ -268,7 +268,7 @@ CycleDataWriter(PipelineCycler &, template INLINE CycleDataWriter:: CycleDataWriter(PipelineCycler &, - CycleDataReader &take_from, + CycleDataLockedReader &take_from, bool force_to_0) : _pointer((CycleDataType *)take_from.take_pointer()) { diff --git a/panda/src/pipeline/cycleDataWriter.h b/panda/src/pipeline/cycleDataWriter.h index 9f7c1bfa4e..b5129efcd2 100644 --- a/panda/src/pipeline/cycleDataWriter.h +++ b/panda/src/pipeline/cycleDataWriter.h @@ -23,7 +23,7 @@ #include "cycleData.h" #include "pipelineCycler.h" -#include "cycleDataReader.h" +#include "cycleDataLockedReader.h" #include "thread.h" //////////////////////////////////////////////////////////////////// @@ -48,8 +48,8 @@ public: INLINE CycleDataWriter(const CycleDataWriter ©); INLINE void operator = (const CycleDataWriter ©); - INLINE CycleDataWriter(PipelineCycler &cycler, CycleDataReader &take_from); - INLINE CycleDataWriter(PipelineCycler &cycler, CycleDataReader &take_from, bool force_to_0); + INLINE CycleDataWriter(PipelineCycler &cycler, CycleDataLockedReader &take_from); + INLINE CycleDataWriter(PipelineCycler &cycler, CycleDataLockedReader &take_from, bool force_to_0); INLINE ~CycleDataWriter(); diff --git a/panda/src/pipeline/pipelineCycler.I b/panda/src/pipeline/pipelineCycler.I index 4cbb0a7324..55da036062 100644 --- a/panda/src/pipeline/pipelineCycler.I +++ b/panda/src/pipeline/pipelineCycler.I @@ -56,6 +56,17 @@ operator = (const PipelineCycler ©) { PipelineCyclerBase::operator = (copy); } +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::read_unlocked (dummy or true) +// Access: Public +// Description: See PipelineCyclerBase::read_unlocked(). +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *PipelineCycler:: +read_unlocked(Thread *current_thread) const { + return (const CycleDataType *)PipelineCyclerBase::read_unlocked(current_thread); +} + //////////////////////////////////////////////////////////////////// // Function: PipelineCycler::read (dummy or true) // Access: Public @@ -113,7 +124,18 @@ elevate_read_upstream(const CycleDataType *pointer, bool force_to_0, } //////////////////////////////////////////////////////////////////// -// Function: PipelineCycler::read (dummy or true) +// Function: PipelineCycler::read_stage_unlocked (dummy or true) +// Access: Public +// Description: See PipelineCyclerBase::read_stage_unlocked(). +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *PipelineCycler:: +read_stage_unlocked(int pipeline_stage) const { + return (const CycleDataType *)PipelineCyclerBase::read_stage_unlocked(pipeline_stage); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::read_stage (dummy or true) // Access: Public // Description: See PipelineCyclerBase::read_stage(). //////////////////////////////////////////////////////////////////// @@ -227,6 +249,17 @@ operator = (const PipelineCycler ©) { _typed_data = copy._typed_data; } +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::read_unlocked (trivial) +// Access: Public +// Description: See PipelineCyclerBase::read_unlocked(). +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *PipelineCycler:: +read_unlocked(Thread *) const { + return &_typed_data; +} + //////////////////////////////////////////////////////////////////// // Function: PipelineCycler::read (trivial) // Access: Public @@ -282,6 +315,17 @@ elevate_read_upstream(const CycleDataType *, bool, Thread *) { return &_typed_data; } +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::read_stage_unlocked (trivial) +// Access: Public +// Description: See PipelineCyclerBase::read_stage_unlocked(). +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *PipelineCycler:: +read_stage_unlocked(int) const { + return &_typed_data; +} + //////////////////////////////////////////////////////////////////// // Function: PipelineCycler::read_stage (trivial) // Access: Public diff --git a/panda/src/pipeline/pipelineCycler.h b/panda/src/pipeline/pipelineCycler.h index bff182f9cc..168489e88d 100644 --- a/panda/src/pipeline/pipelineCycler.h +++ b/panda/src/pipeline/pipelineCycler.h @@ -63,12 +63,14 @@ public: INLINE PipelineCycler(const PipelineCycler ©); INLINE void operator = (const PipelineCycler ©); + INLINE const CycleDataType *read_unlocked(Thread *current_thread) const; INLINE const CycleDataType *read(Thread *current_thread) const; INLINE CycleDataType *write(Thread *current_thread); INLINE CycleDataType *write_upstream(bool force_to_0, Thread *current_thread); INLINE CycleDataType *elevate_read(const CycleDataType *pointer, Thread *current_thread); INLINE CycleDataType *elevate_read_upstream(const CycleDataType *pointer, bool force_to_0, Thread *current_thread); + INLINE const CycleDataType *read_stage_unlocked(int pipeline_stage) const; INLINE const CycleDataType *read_stage(int pipeline_stage, Thread *current_thread) const; INLINE CycleDataType *elevate_read_stage(int pipeline_stage, const CycleDataType *pointer, Thread *current_thread); INLINE CycleDataType *elevate_read_stage_upstream(int pipeline_stage, const CycleDataType *pointer, bool force_to_0, Thread *current_thread); diff --git a/panda/src/pipeline/pipelineCyclerDummyImpl.I b/panda/src/pipeline/pipelineCyclerDummyImpl.I index 8e3767a339..3019b7f687 100644 --- a/panda/src/pipeline/pipelineCyclerDummyImpl.I +++ b/panda/src/pipeline/pipelineCyclerDummyImpl.I @@ -99,6 +99,26 @@ release() { _locked = false; } +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::read_unlocked +// Access: Public +// Description: Returns a const CycleData pointer, filled with the +// data for the current stage of the pipeline as seen by +// this thread. No lock is made on the contents; there +// is no guarantee that some other thread won't modify +// this object's data while you are working on it. +// (However, the data within the returned CycleData +// object itself is safe from modification; if another +// thread modifies the data, it will perform a +// copy-on-write, and thereby change the pointer stored +// within the object.) +//////////////////////////////////////////////////////////////////// +INLINE const CycleData *PipelineCyclerDummyImpl:: +read_unlocked(Thread *current_thread) const { + TAU_PROFILE("const CycleData *PipelineCyclerDummyImpl::read_unlocked()", " ", TAU_USER); + return _data; +} + //////////////////////////////////////////////////////////////////// // Function: PipelineCyclerDummyImpl::read // Access: Public @@ -294,6 +314,21 @@ get_num_stages() { return 1; } +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::read_stage_unlocked +// Access: Public +// Description: Returns a const CycleData pointer, filled with the +// data for the indicated stage of the pipeline. As in +// read_unlocked(), no lock is held on the returned +// pointer. +//////////////////////////////////////////////////////////////////// +INLINE const CycleData *PipelineCyclerDummyImpl:: +read_stage_unlocked(int pipeline_stage) const { + TAU_PROFILE("const CycleData *PipelineCyclerDummyImpl::read_stage_unlocked(int)", " ", TAU_USER); + nassertr(pipeline_stage == 0, NULL); + return _data; +} + //////////////////////////////////////////////////////////////////// // Function: PipelineCyclerDummyImpl::read_stage // Access: Public @@ -307,7 +342,7 @@ get_num_stages() { //////////////////////////////////////////////////////////////////// INLINE const CycleData *PipelineCyclerDummyImpl:: read_stage(int pipeline_stage, Thread *) const { - TAU_PROFILE("const CycleData *PipelineCyclerDummyImpl::read_stage(int)", " ", TAU_USER); + TAU_PROFILE("const CycleData *PipelineCyclerDummyImpl::read_stage(int, Thread *)", " ", TAU_USER); // This function isn't truly const, but it doesn't change the data // in any meaningful way, so we pretend it is. nassertr(pipeline_stage == 0, NULL); diff --git a/panda/src/pipeline/pipelineCyclerDummyImpl.h b/panda/src/pipeline/pipelineCyclerDummyImpl.h index f46a927a5a..a1cf876447 100644 --- a/panda/src/pipeline/pipelineCyclerDummyImpl.h +++ b/panda/src/pipeline/pipelineCyclerDummyImpl.h @@ -55,6 +55,7 @@ public: INLINE void lock(Thread *current_thread = NULL); INLINE void release(); + INLINE const CycleData *read_unlocked(Thread *current_thread) const; INLINE const CycleData *read(Thread *current_thread) const; INLINE void increment_read(const CycleData *pointer) const; INLINE void release_read(const CycleData *pointer) const; @@ -67,6 +68,7 @@ public: INLINE void release_write(CycleData *pointer); INLINE int get_num_stages(); + INLINE const CycleData *read_stage_unlocked(int pipeline_stage) const; INLINE const CycleData *read_stage(int pipeline_stage, Thread *current_thread) const; INLINE void release_read_stage(int pipeline_stage, const CycleData *pointer) const; INLINE CycleData *write_stage(int pipeline_stage, Thread *current_thread); diff --git a/panda/src/pipeline/pipelineCyclerTrivialImpl.I b/panda/src/pipeline/pipelineCyclerTrivialImpl.I index 59b38789dc..c31c90a880 100644 --- a/panda/src/pipeline/pipelineCyclerTrivialImpl.I +++ b/panda/src/pipeline/pipelineCyclerTrivialImpl.I @@ -98,6 +98,29 @@ INLINE void PipelineCyclerTrivialImpl:: release() { } +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::read_unlocked +// Access: Public +// Description: Returns a const CycleData pointer, filled with the +// data for the current stage of the pipeline as seen by +// this thread. No lock is made on the contents; there +// is no guarantee that some other thread won't modify +// this object's data while you are working on it. +// (However, the data within the returned CycleData +// object itself is safe from modification; if another +// thread modifies the data, it will perform a +// copy-on-write, and thereby change the pointer stored +// within the object.) +//////////////////////////////////////////////////////////////////// +INLINE const CycleData *PipelineCyclerTrivialImpl:: +read_unlocked(Thread *) const { +#ifdef SIMPLE_STRUCT_POINTERS + return (const CycleData *)this; +#else + return _data; +#endif // SIMPLE_STRUCT_POINTERS +} + //////////////////////////////////////////////////////////////////// // Function: PipelineCyclerTrivialImpl::read // Access: Public @@ -265,6 +288,23 @@ get_num_stages() { return 1; } +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::read_stage_unlocked +// Access: Public +// Description: Returns a const CycleData pointer, filled with the +// data for the indicated stage of the pipeline. As in +// read_unlocked(), no lock is held on the returned +// pointer. +//////////////////////////////////////////////////////////////////// +INLINE const CycleData *PipelineCyclerTrivialImpl:: +read_stage_unlocked(int) const { +#ifdef SIMPLE_STRUCT_POINTERS + return (const CycleData *)this; +#else + return _data; +#endif // SIMPLE_STRUCT_POINTERS +} + //////////////////////////////////////////////////////////////////// // Function: PipelineCyclerTrivialImpl::read_stage // Access: Public diff --git a/panda/src/pipeline/pipelineCyclerTrivialImpl.h b/panda/src/pipeline/pipelineCyclerTrivialImpl.h index 6690428f9e..586a2bd38c 100644 --- a/panda/src/pipeline/pipelineCyclerTrivialImpl.h +++ b/panda/src/pipeline/pipelineCyclerTrivialImpl.h @@ -60,6 +60,7 @@ public: INLINE void lock(Thread *current_thread = NULL); INLINE void release(); + INLINE const CycleData *read_unlocked(Thread *current_thread) const; INLINE const CycleData *read(Thread *current_thread) const; INLINE void increment_read(const CycleData *pointer) const; INLINE void release_read(const CycleData *pointer) const; @@ -73,6 +74,7 @@ public: INLINE void release_write(CycleData *pointer); INLINE int get_num_stages(); + INLINE const CycleData *read_stage_unlocked(int pipeline_stage) const; INLINE const CycleData *read_stage(int pipeline_stage, Thread *current_thread) const; INLINE void release_read_stage(int pipeline_stage, const CycleData *pointer) const; INLINE CycleData *write_stage(int pipeline_stage, Thread *current_thread); diff --git a/panda/src/pipeline/pipelineCyclerTrueImpl.I b/panda/src/pipeline/pipelineCyclerTrueImpl.I index 4f34082ec6..b276814637 100644 --- a/panda/src/pipeline/pipelineCyclerTrueImpl.I +++ b/panda/src/pipeline/pipelineCyclerTrueImpl.I @@ -55,6 +55,30 @@ release() { _lock.release(); } +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::read_unlocked +// Access: Public +// Description: Returns a const CycleData pointer, filled with the +// data for the current stage of the pipeline as seen by +// this thread. No lock is made on the contents; there +// is no guarantee that some other thread won't modify +// this object's data while you are working on it. +// (However, the data within the returned CycleData +// object itself is safe from modification; if another +// thread modifies the data, it will perform a +// copy-on-write, and thereby change the pointer stored +// within the object.) +//////////////////////////////////////////////////////////////////// +INLINE const CycleData *PipelineCyclerTrueImpl:: +read_unlocked(Thread *current_thread) const { + TAU_PROFILE("const CycleData *PipelineCyclerTrueImpl::read_unlocked(Thread *)", " ", TAU_USER); + int pipeline_stage = current_thread->get_pipeline_stage(); +#ifdef _DEBUG + nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); +#endif + return _data[pipeline_stage]; +} + //////////////////////////////////////////////////////////////////// // Function: PipelineCyclerTrueImpl::read // Access: Public @@ -258,6 +282,23 @@ get_num_stages() { return _num_stages; } +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::read_stage_unlocked +// Access: Public +// Description: Returns a const CycleData pointer, filled with the +// data for the indicated stage of the pipeline. As in +// read_unlocked(), no lock is held on the returned +// pointer. +//////////////////////////////////////////////////////////////////// +INLINE const CycleData *PipelineCyclerTrueImpl:: +read_stage_unlocked(int pipeline_stage) const { + TAU_PROFILE("const CycleData *PipelineCyclerTrueImpl::read_stage_unlocked(int)", " ", TAU_USER); +#ifdef _DEBUG + nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); +#endif + return _data[pipeline_stage]; +} + //////////////////////////////////////////////////////////////////// // Function: PipelineCyclerTrueImpl::read_stage // Access: Public @@ -271,7 +312,7 @@ get_num_stages() { //////////////////////////////////////////////////////////////////// INLINE const CycleData *PipelineCyclerTrueImpl:: read_stage(int pipeline_stage, Thread *current_thread) const { - TAU_PROFILE("const CycleData *PipelineCyclerTrueImpl::read_stage(int)", " ", TAU_USER); + TAU_PROFILE("const CycleData *PipelineCyclerTrueImpl::read_stage(int, Thread *)", " ", TAU_USER); #ifdef _DEBUG nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); #endif @@ -421,7 +462,7 @@ get_write_count() const { INLINE PT(CycleData) PipelineCyclerTrueImpl:: cycle_2() { TAU_PROFILE("PT(CycleData) PipelineCyclerTrueImpl::cycle_2()", " ", TAU_USER); - PT(CycleData) last_val = _data[1]; + PT(CycleData) last_val = _data[1].p(); nassertr(_lock.debug_is_locked(), last_val); nassertr(_dirty, last_val); nassertr(_num_stages == 2, last_val); @@ -445,7 +486,7 @@ cycle_2() { INLINE PT(CycleData) PipelineCyclerTrueImpl:: cycle_3() { TAU_PROFILE("PT(CycleData) PipelineCyclerTrueImpl::cycle_3()", " ", TAU_USER); - PT(CycleData) last_val = _data[2]; + PT(CycleData) last_val = _data[2].p(); nassertr(_lock.debug_is_locked(), last_val); nassertr(_dirty, last_val); nassertr(_num_stages == 3, last_val); diff --git a/panda/src/pipeline/pipelineCyclerTrueImpl.cxx b/panda/src/pipeline/pipelineCyclerTrueImpl.cxx index 31a2c427ff..373adf3ec0 100644 --- a/panda/src/pipeline/pipelineCyclerTrueImpl.cxx +++ b/panda/src/pipeline/pipelineCyclerTrueImpl.cxx @@ -39,7 +39,7 @@ PipelineCyclerTrueImpl(CycleData *initial_data, Pipeline *pipeline) : } _num_stages = _pipeline->get_num_stages(); - _data = new PT(CycleData)[_num_stages]; + _data = new NPT(CycleData)[_num_stages]; for (int i = 0; i < _num_stages; ++i) { _data[i] = initial_data; } @@ -63,7 +63,7 @@ PipelineCyclerTrueImpl(const PipelineCyclerTrueImpl ©) : _num_stages = _pipeline->get_num_stages(); nassertv(_num_stages == copy._num_stages); - _data = new PT(CycleData)[_num_stages]; + _data = new NPT(CycleData)[_num_stages]; // It's no longer critically important that we preserve pointerwise // equivalence between different stages in the copy, but it doesn't @@ -77,7 +77,7 @@ PipelineCyclerTrueImpl(const PipelineCyclerTrueImpl ©) : if (new_pt == NULL) { new_pt = copy._data[i]->make_copy(); } - _data[i] = new_pt; + _data[i] = new_pt.p(); } _pipeline->add_cycler(this); @@ -105,7 +105,7 @@ operator = (const PipelineCyclerTrueImpl ©) { if (new_pt == NULL) { new_pt = copy._data[i]->make_copy(); } - _data[i] = new_pt; + _data[i] = new_pt.p(); } if (copy._dirty && !_dirty) { @@ -152,7 +152,11 @@ write_stage(int pipeline_stage, Thread *current_thread) { CycleData *old_data = _data[pipeline_stage]; - if (old_data->get_ref_count() != 1) { + // Only the node reference count is considered an important count + // for copy-on-write purposes. A standard reference of other than 1 + // just means that some code (other that the PipelineCycler) has a + // pointer, which is safe to modify. + if (old_data->get_node_ref_count() != 1) { // Copy-on-write. _data[pipeline_stage] = old_data->make_copy(); @@ -203,7 +207,7 @@ write_stage_upstream(int pipeline_stage, bool force_to_0, Thread *current_thread k = pipeline_stage - 1; while (k >= 0 && (_data[k] == old_data || force_to_0)) { - _data[k] = new_data; + _data[k] = new_data.p(); --k; } @@ -251,7 +255,7 @@ write_stage_upstream(int pipeline_stage, bool force_to_0, Thread *current_thread //////////////////////////////////////////////////////////////////// PT(CycleData) PipelineCyclerTrueImpl:: cycle() { - PT(CycleData) last_val = _data[_num_stages - 1]; + PT(CycleData) last_val = _data[_num_stages - 1].p(); nassertr(_lock.debug_is_locked(), last_val); nassertr(_dirty, last_val); @@ -294,7 +298,7 @@ set_num_stages(int num_stages) { } else { // To increase the array, we must reallocate it larger. - PT(CycleData) *new_data = new PT(CycleData)[num_stages]; + NPT(CycleData) *new_data = new NPT(CycleData)[num_stages]; int i; for (i = 0; i < _num_stages; ++i) { new_data[i] = _data[i]; diff --git a/panda/src/pipeline/pipelineCyclerTrueImpl.h b/panda/src/pipeline/pipelineCyclerTrueImpl.h index 764227d3a0..5a55fa8e0b 100644 --- a/panda/src/pipeline/pipelineCyclerTrueImpl.h +++ b/panda/src/pipeline/pipelineCyclerTrueImpl.h @@ -27,6 +27,7 @@ #include "pipelineCyclerLinks.h" #include "cycleData.h" #include "pointerTo.h" +#include "nodePointerTo.h" #include "thread.h" #include "reMutex.h" #include "reMutexHolder.h" @@ -61,6 +62,8 @@ public: INLINE void lock(Thread *current_thread); INLINE void release(); + INLINE const CycleData *read_unlocked(Thread *current_thread) const; + INLINE const CycleData *read(Thread *current_thread) const; INLINE void increment_read(const CycleData *pointer) const; INLINE void release_read(const CycleData *pointer) const; @@ -73,6 +76,7 @@ public: INLINE void release_write(CycleData *pointer); INLINE int get_num_stages(); + INLINE const CycleData *read_stage_unlocked(int pipeline_stage) const; INLINE const CycleData *read_stage(int pipeline_stage, Thread *current_thread) const; INLINE void release_read_stage(int pipeline_stage, const CycleData *pointer) const; CycleData *write_stage(int pipeline_stage, Thread *current_thread); @@ -113,8 +117,8 @@ private: private: Pipeline *_pipeline; - // An array of PT(CycleData) objects. - PT(CycleData) *_data; + // An array of NPT(CycleData) objects. + NPT(CycleData) *_data; int _num_stages; bool _dirty; diff --git a/panda/src/pipeline/pipeline_composite1.cxx b/panda/src/pipeline/pipeline_composite1.cxx index aafcb22f64..707c36d58d 100644 --- a/panda/src/pipeline/pipeline_composite1.cxx +++ b/panda/src/pipeline/pipeline_composite1.cxx @@ -9,6 +9,8 @@ #include "conditionVarSpinlockImpl.cxx" #include "config_pipeline.cxx" #include "cycleData.cxx" +#include "cycleDataLockedReader.cxx" +#include "cycleDataLockedStageReader.cxx" #include "cycleDataReader.cxx" #include "cycleDataStageReader.cxx" #include "cycleDataStageWriter.cxx" diff --git a/panda/src/putil/Sources.pp b/panda/src/putil/Sources.pp index 5cfd5b29a6..b42f3202bc 100644 --- a/panda/src/putil/Sources.pp +++ b/panda/src/putil/Sources.pp @@ -46,8 +46,6 @@ modifierButtons.I modifierButtons.h mouseButton.h \ mouseData.I mouseData.h nameUniquifier.I nameUniquifier.h \ nodeCachedReferenceCount.h nodeCachedReferenceCount.I \ - nodePointerToBase.h nodePointerToBase.I \ - nodePointerTo.h nodePointerTo.I \ nonDeletor.h \ pta_double.h \ pta_float.h pta_int.h \ @@ -86,8 +84,6 @@ modifierButtons.cxx mouseButton.cxx mouseData.cxx \ nameUniquifier.cxx \ nodeCachedReferenceCount.cxx \ - nodePointerToBase.cxx \ - nodePointerTo.cxx \ nonDeletor.cxx \ pta_double.cxx pta_float.cxx \ pta_int.cxx pta_ushort.cxx \ @@ -135,8 +131,6 @@ modifierButtons.h mouseButton.h mouseData.I mouseData.h \ nameUniquifier.I nameUniquifier.h \ nodeCachedReferenceCount.h nodeCachedReferenceCount.I \ - nodePointerToBase.h nodePointerToBase.I \ - nodePointerTo.h nodePointerTo.I \ nonDeletor.h \ pta_double.h \ pta_float.h pta_int.h pta_ushort.h \ diff --git a/panda/src/putil/nodeCachedReferenceCount.I b/panda/src/putil/nodeCachedReferenceCount.I index e16c8f50a4..682c933eb0 100644 --- a/panda/src/putil/nodeCachedReferenceCount.I +++ b/panda/src/putil/nodeCachedReferenceCount.I @@ -242,30 +242,3 @@ get_referenced_bits() const { return result; } - -//////////////////////////////////////////////////////////////////// -// Function: node_unref_delete -// Description: This global helper function will unref the given -// ReferenceCount object, and if the reference count -// reaches zero, automatically delete it. It can't be a -// member function because it's usually a bad idea to -// delete an object from within its own member function. -// It's a template function so the destructor doesn't -// have to be virtual. -//////////////////////////////////////////////////////////////////// -template -INLINE void -node_unref_delete(RefCountType *ptr) { - ptr->node_unref(); - if (ptr->get_ref_count() == 0) { - ObjectDeletor *deletor = ObjectDeletor::get_global_ptr(); - if (deletor != (ObjectDeletor *)NULL) { - ptr->ref(); - deletor->delete_object(RefCountDeleteWrapper::do_delete, (void *)ptr); - return; - } - - delete ptr; - } -} - diff --git a/panda/src/putil/nodeCachedReferenceCount.h b/panda/src/putil/nodeCachedReferenceCount.h index e7177af6d4..5f0614ffdc 100644 --- a/panda/src/putil/nodeCachedReferenceCount.h +++ b/panda/src/putil/nodeCachedReferenceCount.h @@ -22,6 +22,7 @@ #include "pandabase.h" #include "cachedTypedWritableReferenceCount.h" +#include "nodeReferenceCount.h" // for node_unref_delete() #include "objectDeletor.h" //////////////////////////////////////////////////////////////////// @@ -32,6 +33,19 @@ // number of times the object is referenced by a "node", // presumably a PandaNode. // +// This essentially combines the functionality of +// NodeReferenceCount and +// CachedTypedWritableReferenceCount, so that a +// derivative of this object actually has three +// counters: the standard reference count, the "cache" +// reference count, and the "node" reference count. +// Rather than multiply inheriting from the two +// reference count classes, we inherit only from +// CachedTypedWritableReferenceCount and simply +// duplicate the functionality of NodeReferenceCount, to +// avoid all of the problems associated with multiple +// inheritance. +// // The intended design is to use this as a base class // for RenderState and TransformState, both of which are // held by PandaNodes, and also have caches which are @@ -90,9 +104,6 @@ private: static TypeHandle _type_handle; }; -template -INLINE void node_unref_delete(RefCountType *ptr); - #include "nodeCachedReferenceCount.I" #endif diff --git a/panda/src/putil/putil_composite2.cxx b/panda/src/putil/putil_composite2.cxx index 604e113687..e1735ca24d 100644 --- a/panda/src/putil/putil_composite2.cxx +++ b/panda/src/putil/putil_composite2.cxx @@ -3,8 +3,6 @@ #include "mouseData.cxx" #include "nameUniquifier.cxx" #include "nodeCachedReferenceCount.cxx" -#include "nodePointerToBase.cxx" -#include "nodePointerTo.cxx" #include "nonDeletor.cxx" #include "pta_double.cxx" #include "pta_float.cxx"