diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index efc7e0dd5c..12ad6bdb1a 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -33,6 +33,8 @@ #include "cullFaceAttrib.h" #include "string_utils.h" #include "geomCacheManager.h" +#include "thread.h" +#include "pipeline.h" #include "throw_event.h" #if defined(WIN32) @@ -1413,6 +1415,9 @@ get_window_renderer(const string &name) { } PT(RenderThread) thread = new RenderThread(name, this); + thread->set_pipeline_stage(1); + Pipeline::get_render_pipeline()->set_num_stages(2); + thread->start(TP_normal, true, true); _threads[name] = thread; diff --git a/panda/src/express/config_express.cxx b/panda/src/express/config_express.cxx index 6d1af12969..ddd073f060 100644 --- a/panda/src/express/config_express.cxx +++ b/panda/src/express/config_express.cxx @@ -20,6 +20,7 @@ #include "config_express.h" #include "datagram.h" #include "mainThread.h" +#include "externalThread.h" #include "referenceCount.h" #include "textEncoder.h" #include "thread.h" @@ -169,6 +170,7 @@ init_libexpress() { Datagram::init_type(); MainThread::init_type(); + ExternalThread::init_type(); ReferenceCount::init_type(); TextEncoder::init_type(); Thread::init_type(); diff --git a/panda/src/express/externalThread.cxx b/panda/src/express/externalThread.cxx index a8a2cf89c1..bf8b8e5a53 100644 --- a/panda/src/express/externalThread.cxx +++ b/panda/src/express/externalThread.cxx @@ -23,12 +23,29 @@ TypeHandle ExternalThread::_type_handle; //////////////////////////////////////////////////////////////////// // Function: ExternalThread::Constructor // Access: Private -// Description: +// Description: This constructor is used to create the one global +// ExternalThread object that is shared by all +// externally-created threads that are not specifically +// bound to a particular Thread object. //////////////////////////////////////////////////////////////////// ExternalThread:: ExternalThread() : Thread("External", "External") { _started = true; } + +//////////////////////////////////////////////////////////////////// +// Function: ExternalThread::Constructor +// Access: Private +// Description: This constructor is used to create the particular +// Thread object for each external thread that is bound +// via Thread::bind_thread(). +//////////////////////////////////////////////////////////////////// +ExternalThread:: +ExternalThread(const string &name, const string &sync_name) : + Thread(name, sync_name) +{ + _started = true; +} //////////////////////////////////////////////////////////////////// // Function: ExternalThread::thread_main diff --git a/panda/src/express/externalThread.h b/panda/src/express/externalThread.h index 67811ac143..312a9002c8 100644 --- a/panda/src/express/externalThread.h +++ b/panda/src/express/externalThread.h @@ -31,12 +31,14 @@ class EXPCL_PANDAEXPRESS ExternalThread : public Thread { private: ExternalThread(); + ExternalThread(const string &name, const string &sync_name); virtual void thread_main(); -public: +PUBLISHED: static TypeHandle get_class_type() { return _type_handle; } +public: static void init_type() { Thread::init_type(); register_type(_type_handle, "ExternalThread", diff --git a/panda/src/express/mainThread.h b/panda/src/express/mainThread.h index 3a30554e18..d830921a0f 100644 --- a/panda/src/express/mainThread.h +++ b/panda/src/express/mainThread.h @@ -33,10 +33,11 @@ private: MainThread(); virtual void thread_main(); -public: +PUBLISHED: static TypeHandle get_class_type() { return _type_handle; } +public: static void init_type() { Thread::init_type(); register_type(_type_handle, "MainThread", diff --git a/panda/src/express/thread.I b/panda/src/express/thread.I index f4370efc4c..6d5601db91 100644 --- a/panda/src/express/thread.I +++ b/panda/src/express/thread.I @@ -19,7 +19,7 @@ //////////////////////////////////////////////////////////////////// // Function: Thread::Constructor -// Access: Public +// Access: Protected // Description: Creates a new Thread object, but does not // immediately start executing it. This gives the // caller a chance to store it in a PT(Thread) object, @@ -43,6 +43,7 @@ Thread(const string &name, const string &sync_name) : { _started = false; _pstats_index = -1; + _pipeline_stage = 0; } //////////////////////////////////////////////////////////////////// @@ -67,7 +68,7 @@ operator = (const Thread ©) { //////////////////////////////////////////////////////////////////// // Function: Thread::get_name -// Access: Public +// Access: Published // Description: Returns the name of the thread. Each thread should // probably have a unique name, but this is not enforced // (and not strictly required). @@ -79,7 +80,7 @@ get_name() const { //////////////////////////////////////////////////////////////////// // Function: Thread::get_sync_name -// Access: Public +// Access: Published // Description: Returns the sync name of the thread. This name // collects threads into "sync groups", which are // expected to run synchronously. This is mainly used @@ -94,7 +95,7 @@ get_sync_name() const { //////////////////////////////////////////////////////////////////// // Function: Thread::get_pstats_index -// Access: Public +// Access: Published // Description: Returns the PStats index associated with this thread, // or -1 if no index has yet been associated with this // thread. This is used internally by the PStatClient; @@ -107,7 +108,7 @@ get_pstats_index() const { //////////////////////////////////////////////////////////////////// // Function: Thread::set_pstats_index -// Access: Public +// Access: Published // Description: Stores a PStats index to be associated with this // thread. This is used internally by the PStatClient; // you should not need to call this directly. @@ -117,6 +118,120 @@ set_pstats_index(int pstats_index) { _pstats_index = pstats_index; } +//////////////////////////////////////////////////////////////////// +// Function: Thread::get_pipeline_stage +// Access: Published +// Description: Returns the Pipeline stage number associated with +// this thread. The default stage is 0 if no stage is +// specified otherwise. See set_pipeline_stage(). +//////////////////////////////////////////////////////////////////// +INLINE int Thread:: +get_pipeline_stage() const { + return _pipeline_stage; +} + +//////////////////////////////////////////////////////////////////// +// Function: Thread::set_pipeline_stage +// Access: Published +// Description: Specifies the Pipeline stage number associated with +// this thread. The default stage is 0 if no stage is +// specified otherwise. +// +// This must be a value in the range [0 +// .. pipeline->get_num_stages() - 1]. It specifies the +// values that this thread observes for all pipelined +// data. Typically, an application thread will leave +// this at 0, but a render thread may set it to 1 or 2 +// (to operate on the previous frame's data, or the +// second previous frame's data). +//////////////////////////////////////////////////////////////////// +INLINE void Thread:: +set_pipeline_stage(int pipeline_stage) { + _pipeline_stage = pipeline_stage; +} + +//////////////////////////////////////////////////////////////////// +// Function: Thread::get_main_thread +// Access: Published, Static +// Description: Returns a pointer to the "main" Thread object--this +// is the Thread that started the whole process. +//////////////////////////////////////////////////////////////////// +INLINE Thread *Thread:: +get_main_thread() { + if (_main_thread == (Thread *)NULL) { + init_main_thread(); + } + return _main_thread; +} + +//////////////////////////////////////////////////////////////////// +// Function: Thread::get_external_thread +// Access: Published, Static +// Description: Returns a pointer to the "external" Thread +// object--this is a special Thread object that +// corresponds to any thread spawned outside of Panda's +// threading interface. Note that multiple different +// threads may share this same pointer. +//////////////////////////////////////////////////////////////////// +INLINE Thread *Thread:: +get_external_thread() { + if (_external_thread == (Thread *)NULL) { + init_external_thread(); + } + return _external_thread; +} + +//////////////////////////////////////////////////////////////////// +// Function: Thread::get_current_thread +// Access: Published, Static +// Description: Returns a pointer to the currently-executing Thread +// object. If this is called from the main thread, this +// will return the same value as get_main_thread(). +// +// This will always return some valid Thread pointer. +// It will never return NULL, even if the current thread +// was spawned outside of Panda's threading system, +// although all non-Panda threads will return the exact +// same Thread pointer. +//////////////////////////////////////////////////////////////////// +INLINE Thread *Thread:: +get_current_thread() { +#ifndef HAVE_THREADS + return get_main_thread(); +#else // HAVE_THREADS + Thread *thread = ThreadImpl::get_current_thread(); + if (thread == (Thread *)NULL) { + return Thread::get_external_thread(); + } + return thread; +#endif // HAVE_THREADS +} + +//////////////////////////////////////////////////////////////////// +// Function: Thread::is_threading_supported +// Access: Published, Static +// Description: Returns true if a real threading library is available +// that supports threads, or false if no threading +// library is available (and Thread::start() will always +// fail). +//////////////////////////////////////////////////////////////////// +INLINE bool Thread:: +is_threading_supported() { + return ThreadImpl::is_threading_supported(); +} + +//////////////////////////////////////////////////////////////////// +// Function: Thread::sleep +// Access: Published, Static +// Description: Suspends the current thread for at least the +// indicated amount of time. It might be suspended for +// longer. +//////////////////////////////////////////////////////////////////// +INLINE void Thread:: +sleep(double seconds) { + ThreadImpl::sleep(seconds); +} + //////////////////////////////////////////////////////////////////// // Function: Thread::start // Access: Public @@ -187,88 +302,6 @@ prepare_for_exit() { ThreadImpl::prepare_for_exit(); } -//////////////////////////////////////////////////////////////////// -// Function: Thread::get_main_thread -// Access: Public, Static -// Description: Returns a pointer to the "main" Thread object--this -// is the Thread that started the whole process. -//////////////////////////////////////////////////////////////////// -INLINE Thread *Thread:: -get_main_thread() { - if (_main_thread == (Thread *)NULL) { - init_main_thread(); - } - return _main_thread; -} - -//////////////////////////////////////////////////////////////////// -// Function: Thread::get_external_thread -// Access: Public, Static -// Description: Returns a pointer to the "external" Thread -// object--this is a special Thread object that -// corresponds to any thread spawned outside of Panda's -// threading interface. Note that multiple different -// threads may share this same pointer. -//////////////////////////////////////////////////////////////////// -INLINE Thread *Thread:: -get_external_thread() { - if (_external_thread == (Thread *)NULL) { - init_external_thread(); - } - return _external_thread; -} - -//////////////////////////////////////////////////////////////////// -// Function: Thread::get_current_thread -// Access: Public, Static -// Description: Returns a pointer to the currently-executing Thread -// object. If this is called from the main thread, this -// will return the same value as get_main_thread(). -// -// This will always return some valid Thread pointer. -// It will never return NULL, even if the current thread -// was spawned outside of Panda's threading system, -// although all non-Panda threads will return the exact -// same Thread pointer. -//////////////////////////////////////////////////////////////////// -INLINE Thread *Thread:: -get_current_thread() { -#ifndef HAVE_THREADS - return get_main_thread(); -#else // HAVE_THREADS - Thread *thread = ThreadImpl::get_current_thread(); - if (thread == (Thread *)NULL) { - return Thread::get_external_thread(); - } - return thread; -#endif // HAVE_THREADS -} - -//////////////////////////////////////////////////////////////////// -// Function: Thread::is_threading_supported -// Access: Public, Static -// Description: Returns true if a real threading library is available -// that supports threads, or false if no threading -// library is available (and Thread::start() will always -// fail). -//////////////////////////////////////////////////////////////////// -INLINE bool Thread:: -is_threading_supported() { - return ThreadImpl::is_threading_supported(); -} - -//////////////////////////////////////////////////////////////////// -// Function: Thread::sleep -// Access: Public, Static -// Description: Suspends the current thread for at least the -// indicated amount of time. It might be suspended for -// longer. -//////////////////////////////////////////////////////////////////// -INLINE void Thread:: -sleep(double seconds) { - ThreadImpl::sleep(seconds); -} - INLINE ostream & operator << (ostream &out, const Thread &thread) { thread.output(out); diff --git a/panda/src/express/thread.cxx b/panda/src/express/thread.cxx index da134d7e94..b513964ec2 100644 --- a/panda/src/express/thread.cxx +++ b/panda/src/express/thread.cxx @@ -26,16 +26,57 @@ TypeHandle Thread::_type_handle; //////////////////////////////////////////////////////////////////// // Function: Thread::Destructor -// Access: Public, Virtual +// Access: Published, Virtual // Description: //////////////////////////////////////////////////////////////////// Thread:: ~Thread() { } +//////////////////////////////////////////////////////////////////// +// Function: Thread::bind_thread +// Access: Published, Static +// Description: Returns a new Panda Thread object associated with the +// current thread (which has been created externally). +// This can be used to bind a unique Panda Thread object +// with an external thread, such as a new Python thread. +// +// It is particularly useful to bind a Panda Thread +// object to an external thread for the purposes of +// PStats monitoring. Without this call, each external +// thread will be assigned the same global +// ExternalThread object, which means they will all +// appear in the same PStats graph. +// +// It is the caller's responsibility to save the +// returned Thread pointer for the lifetime of the +// external thread. It is an error for the Thread +// pointer to destruct while the external thread is +// still in the system. +// +// It is also an error to call this method from the main +// thread, or twice within a given thread, unless it is +// given the same name each time (in which case the same +// pointer will be returned each time). +//////////////////////////////////////////////////////////////////// +PT(Thread) Thread:: +bind_thread(const string &name, const string &sync_name) { + Thread *current_thread = get_current_thread(); + if (current_thread != get_external_thread()) { + // This thread already has an associated thread. + nassertr(current_thread->get_name() == name && + current_thread->get_sync_name() == sync_name, current_thread); + return current_thread; + } + + PT(Thread) thread = new ExternalThread(name, sync_name); + ThreadImpl::bind_thread(thread); + return thread; +} + //////////////////////////////////////////////////////////////////// // Function: Thread::output -// Access: Public, Virtual +// Access: Published, Virtual // Description: //////////////////////////////////////////////////////////////////// void Thread:: diff --git a/panda/src/express/thread.h b/panda/src/express/thread.h index 98ed3d84d7..416fd658da 100644 --- a/panda/src/express/thread.h +++ b/panda/src/express/thread.h @@ -21,6 +21,7 @@ #include "pandabase.h" #include "typedReferenceCount.h" +#include "pointerTo.h" #include "threadPriority.h" #include "threadImpl.h" #include "notify.h" @@ -38,8 +39,10 @@ // are referencing it. //////////////////////////////////////////////////////////////////// class EXPCL_PANDAEXPRESS Thread : public TypedReferenceCount { -public: +protected: INLINE Thread(const string &name, const string &sync_name); + +PUBLISHED: virtual ~Thread(); private: @@ -49,18 +52,17 @@ private: protected: virtual void thread_main()=0; -public: +PUBLISHED: + static PT(Thread) bind_thread(const string &name, const string &sync_name); + INLINE const string &get_name() const; INLINE const string &get_sync_name() const; INLINE int get_pstats_index() const; INLINE void set_pstats_index(int pstats_index); - INLINE bool start(ThreadPriority priority, bool global, bool joinable); - INLINE void interrupt(); - INLINE void join(); - - INLINE static void prepare_for_exit(); + INLINE int get_pipeline_stage() const; + INLINE void set_pipeline_stage(int pipeline_stage); INLINE static Thread *get_main_thread(); INLINE static Thread *get_external_thread(); @@ -70,6 +72,13 @@ public: virtual void output(ostream &out) const; +public: + INLINE bool start(ThreadPriority priority, bool global, bool joinable); + INLINE void interrupt(); + INLINE void join(); + + INLINE static void prepare_for_exit(); + private: static void init_main_thread(); static void init_external_thread(); @@ -80,6 +89,7 @@ protected: string _sync_name; ThreadImpl _impl; int _pstats_index; + int _pipeline_stage; private: static Thread *_main_thread; diff --git a/panda/src/express/threadDummyImpl.I b/panda/src/express/threadDummyImpl.I index d119871616..4c91cbcd13 100644 --- a/panda/src/express/threadDummyImpl.I +++ b/panda/src/express/threadDummyImpl.I @@ -72,6 +72,19 @@ INLINE void ThreadDummyImpl:: prepare_for_exit() { } +//////////////////////////////////////////////////////////////////// +// Function: ThreadDummyImpl::bind_thread +// Access: Public, Static +// Description: Associates the indicated Thread object with the +// currently-executing thread. You should not call this +// directly; use Thread::bind_thread() instead. +//////////////////////////////////////////////////////////////////// +INLINE void ThreadDummyImpl:: +bind_thread(Thread *thread) { + // This method shouldn't be called in the non-threaded case. + nassertv(false); +} + //////////////////////////////////////////////////////////////////// // Function: ThreadDummyImpl::is_threading_supported // Access: Public, Static diff --git a/panda/src/express/threadDummyImpl.h b/panda/src/express/threadDummyImpl.h index 6f93de83d9..51b7379852 100644 --- a/panda/src/express/threadDummyImpl.h +++ b/panda/src/express/threadDummyImpl.h @@ -53,6 +53,7 @@ public: INLINE static void prepare_for_exit(); static Thread *get_current_thread(); + INLINE static void bind_thread(Thread *thread); INLINE static bool is_threading_supported(); INLINE static void sleep(double seconds); diff --git a/panda/src/express/threadNsprImpl.I b/panda/src/express/threadNsprImpl.I index 1e5856dbb8..8c131021e9 100644 --- a/panda/src/express/threadNsprImpl.I +++ b/panda/src/express/threadNsprImpl.I @@ -41,7 +41,7 @@ prepare_for_exit() { } //////////////////////////////////////////////////////////////////// -// Function: ThreadNsprImpl::Constructor +// Function: ThreadNsprImpl::get_current_thread // Access: Public, Static // Description: //////////////////////////////////////////////////////////////////// @@ -53,6 +53,22 @@ get_current_thread() { return (Thread *)PR_GetThreadPrivate(_pt_ptr_index); } +//////////////////////////////////////////////////////////////////// +// Function: ThreadNsprImpl::bind_thread +// Access: Public, Static +// Description: Associates the indicated Thread object with the +// currently-executing thread. You should not call this +// directly; use Thread::bind_thread() instead. +//////////////////////////////////////////////////////////////////// +INLINE void ThreadNsprImpl:: +bind_thread(Thread *thread) { + if (!_got_pt_ptr_index) { + init_pt_ptr_index(); + } + PRStatus result = PR_SetThreadPrivate(_pt_ptr_index, thread); + nassertv(result == PR_SUCCESS); +} + //////////////////////////////////////////////////////////////////// // Function: ThreadNsprImpl::is_threading_supported // Access: Public, Static diff --git a/panda/src/express/threadNsprImpl.h b/panda/src/express/threadNsprImpl.h index 6ee3c8a417..b50f8e59e6 100644 --- a/panda/src/express/threadNsprImpl.h +++ b/panda/src/express/threadNsprImpl.h @@ -49,6 +49,7 @@ public: INLINE static void prepare_for_exit(); INLINE static Thread *get_current_thread(); + INLINE static void bind_thread(Thread *thread); INLINE static bool is_threading_supported(); INLINE static void sleep(double seconds); diff --git a/panda/src/gobj/geomVertexFormat.cxx b/panda/src/gobj/geomVertexFormat.cxx index b439f40140..434b80e716 100644 --- a/panda/src/gobj/geomVertexFormat.cxx +++ b/panda/src/gobj/geomVertexFormat.cxx @@ -799,7 +799,7 @@ Registry() { (InternalName::get_vertex(), 3, NT_float32, C_point, InternalName::get_normal(), 3, - NT_float32, C_point, + NT_float32, C_vector, InternalName::get_color(), 1, NT_packed_dabc, C_color)); @@ -815,7 +815,7 @@ Registry() { (InternalName::get_vertex(), 3, NT_float32, C_point, InternalName::get_normal(), 3, - NT_float32, C_point, + NT_float32, C_vector, InternalName::get_color(), 1, NT_packed_dabc, C_color, InternalName::get_texcoord(), 2, @@ -834,7 +834,7 @@ Registry() { (InternalName::get_vertex(), 3, NT_float32, C_point, InternalName::get_normal(), 3, - NT_float32, C_point, + NT_float32, C_vector, InternalName::get_color(), 4, NT_uint8, C_color)); @@ -850,7 +850,7 @@ Registry() { (InternalName::get_vertex(), 3, NT_float32, C_point, InternalName::get_normal(), 3, - NT_float32, C_point, + NT_float32, C_vector, InternalName::get_color(), 4, NT_uint8, C_color, InternalName::get_texcoord(), 2, diff --git a/panda/src/pgraph/pandaNode.I b/panda/src/pgraph/pandaNode.I index 9bd90ee4a3..b6fbf2d6c9 100644 --- a/panda/src/pgraph/pandaNode.I +++ b/panda/src/pgraph/pandaNode.I @@ -125,33 +125,6 @@ CData() { _fixed_internal_bound = false; } -//////////////////////////////////////////////////////////////////// -// Function: PandaNode::CData::Copy Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE PandaNode::CData:: -CData(const PandaNode::CData ©) : - _down(copy._down), - _stashed(copy._stashed), - _up(copy._up), - _paths(copy._paths), - _state(copy._state), - _effects(copy._effects), - _transform(copy._transform), - _prev_transform(copy._prev_transform), - _tag_data(copy._tag_data), - _draw_mask(copy._draw_mask), - _into_collide_mask(copy._into_collide_mask), - _fixed_internal_bound(copy._fixed_internal_bound) -{ - _net_collide_mask = CollideMask::all_off(); - - // Note that this copy constructor is not used by the PandaNode copy - // constructor! Any elements that must be copied between nodes - // should also be explicitly copied there. -} - //////////////////////////////////////////////////////////////////// // Function: PandaNode::Children::Constructor // Access: Public diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index 8b6ad1f2a0..acb8b34a3f 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -55,6 +55,53 @@ TypeHandle PandaNode::_type_handle; // +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::CData::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PandaNode::CData:: +CData(const PandaNode::CData ©) : + _down(copy._down), + _stashed(copy._stashed), + _up(copy._up), + _paths(copy._paths), + _state(copy._state), + _effects(copy._effects), + _transform(copy._transform), + _prev_transform(copy._prev_transform), + _tag_data(copy._tag_data), + _draw_mask(copy._draw_mask), + _into_collide_mask(copy._into_collide_mask), + _net_collide_mask(copy._net_collide_mask), + _off_clip_planes(copy._off_clip_planes), + _fixed_internal_bound(copy._fixed_internal_bound) +{ + // Note that this copy constructor is not used by the PandaNode copy + // constructor! Any elements that must be copied between nodes + // should also be explicitly copied there. + +#ifdef HAVE_PYTHON + // Copy and increment all of the Python objects held by the other + // node. + _python_tag_data = _python_tag_data; + inc_py_refs(); +#endif // HAVE_PYTHON +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::CData::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +PandaNode::CData:: +~CData() { +#ifdef HAVE_PYTHON + // Free all of the Python objects held by this node. + dec_py_refs(); +#endif // HAVE_PYTHON +} + //////////////////////////////////////////////////////////////////// // Function: PandaNode::CData::make_copy // Access: Public, Virtual @@ -160,9 +207,47 @@ fillin(DatagramIterator &scan, BamReader *manager) { } } +#ifdef HAVE_PYTHON +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::CData::inc_py_refs +// Access: Public +// Description: Increments the reference counts on all held Python +// objects. +//////////////////////////////////////////////////////////////////// +void PandaNode::CData:: +inc_py_refs() { + PythonTagData::const_iterator ti; + for (ti = _python_tag_data.begin(); + ti != _python_tag_data.end(); + ++ti) { + PyObject *value = (*ti).second; + Py_XINCREF(value); + } +} +#endif // HAVE_PYTHON + +#ifdef HAVE_PYTHON +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::CData::dec_py_refs +// Access: Public +// Description: Decrements the reference counts on all held Python +// objects. +//////////////////////////////////////////////////////////////////// +void PandaNode::CData:: +dec_py_refs() { + PythonTagData::const_iterator ti; + for (ti = _python_tag_data.begin(); + ti != _python_tag_data.end(); + ++ti) { + PyObject *value = (*ti).second; + Py_XDECREF(value); + } +} +#endif // HAVE_PYTHON + //////////////////////////////////////////////////////////////////// // Function: PandaNode::CData::write_up_list -// Access: Private +// Access: Public // Description: Writes the indicated list of parent node pointers to // the datagram. //////////////////////////////////////////////////////////////////// @@ -198,7 +283,7 @@ write_up_list(const PandaNode::Up &up_list, //////////////////////////////////////////////////////////////////// // Function: PandaNode::CData::write_down_list -// Access: Private +// Access: Public // Description: Writes the indicated list of child node pointers to // the datagram. //////////////////////////////////////////////////////////////////// @@ -222,7 +307,7 @@ write_down_list(const PandaNode::Down &down_list, //////////////////////////////////////////////////////////////////// // Function: PandaNode::CData::complete_up_list -// Access: Private +// Access: Public // Description: Calls complete_pointers() on the list of parent node // pointers. //////////////////////////////////////////////////////////////////// @@ -254,7 +339,7 @@ complete_up_list(PandaNode::Up &up_list, //////////////////////////////////////////////////////////////////// // Function: PandaNode::CData::complete_down_list -// Access: Private +// Access: Public // Description: Calls complete_pointers() on the list of child node // pointers. //////////////////////////////////////////////////////////////////// @@ -279,7 +364,7 @@ complete_down_list(PandaNode::Down &down_list, //////////////////////////////////////////////////////////////////// // Function: PandaNode::CData::fillin_up_list -// Access: Private +// Access: Public // Description: Reads the indicated list parent node pointers from // the datagram (or at least calls read_pointer() for // each one). @@ -298,7 +383,7 @@ fillin_up_list(PandaNode::Up &up_list, //////////////////////////////////////////////////////////////////// // Function: PandaNode::CData::fillin_down_list -// Access: Private +// Access: Public // Description: Reads the indicated list child node pointers from // the datagram (or at least calls read_pointer() for // each one). @@ -370,20 +455,6 @@ PandaNode:: #endif // NDEBUG remove_all_children(); - -#ifdef HAVE_PYTHON - { - // Free all of the Python objects held by this node. - CDReader cdata(_cycler); - PythonTagData::const_iterator ti; - for (ti = cdata->_python_tag_data.begin(); - ti != cdata->_python_tag_data.end(); - ++ti) { - PyObject *value = (*ti).second; - Py_XDECREF(value); - } - } -#endif // HAVE_PYTHON } //////////////////////////////////////////////////////////////////// @@ -418,21 +489,16 @@ PandaNode(const PandaNode ©) : cdata->_tag_data = copy_cdata->_tag_data; cdata->_draw_mask = copy_cdata->_draw_mask; cdata->_into_collide_mask = copy_cdata->_into_collide_mask; + cdata->_net_collide_mask = CollideMask::all_off(); + cdata->_off_clip_planes = NULL; cdata->_fixed_internal_bound = copy_cdata->_fixed_internal_bound; #ifdef HAVE_PYTHON // Copy and increment all of the Python objects held by the other // node. cdata->_python_tag_data = copy_cdata->_python_tag_data; - PythonTagData::const_iterator ti; - for (ti = cdata->_python_tag_data.begin(); - ti != cdata->_python_tag_data.end(); - ++ti) { - PyObject *value = (*ti).second; - Py_XINCREF(value); - } + cdata->inc_py_refs(); #endif // HAVE_PYTHON - } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index f358bb1265..13ca2e51a5 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -315,12 +315,19 @@ private: class EXPCL_PANDA CData : public CycleData { public: INLINE CData(); - INLINE CData(const CData ©); + CData(const CData ©); + virtual ~CData(); + virtual CycleData *make_copy() const; virtual void write_datagram(BamWriter *manager, Datagram &dg) const; virtual int complete_pointers(TypedWritable **plist, BamReader *manager); virtual void fillin(DatagramIterator &scan, BamReader *manager); +#ifdef HAVE_PYTHON + void inc_py_refs(); + void dec_py_refs(); +#endif + void write_up_list(const Up &up_list, BamWriter *manager, Datagram &dg) const; void write_down_list(const Down &down_list, diff --git a/panda/src/pstatclient/pStatThread.cxx b/panda/src/pstatclient/pStatThread.cxx index eef0b8de60..b305c43d93 100644 --- a/panda/src/pstatclient/pStatThread.cxx +++ b/panda/src/pstatclient/pStatThread.cxx @@ -25,7 +25,7 @@ // Description: Returns the Panda Thread object associated with this // particular PStatThread. //////////////////////////////////////////////////////////////////// -INLINE Thread *PStatThread:: +Thread *PStatThread:: get_thread() const { return _client->get_thread_object(_index); } diff --git a/panda/src/putil/Sources.pp b/panda/src/putil/Sources.pp index f9fb03ec37..88dc5f0e89 100644 --- a/panda/src/putil/Sources.pp +++ b/panda/src/putil/Sources.pp @@ -48,7 +48,10 @@ nodePointerTo.h nodePointerTo.I \ pipeline.h pipeline.I \ pipelineCycler.h pipelineCycler.I \ - pipelineCyclerBase.h pipelineCyclerBase.I \ + pipelineCyclerBase.h \ + pipelineCyclerDummyImpl.h pipelineCyclerDummyImpl.I \ + pipelineCyclerTrivialImpl.h pipelineCyclerTrivialImpl.I \ + pipelineCyclerTrueImpl.h pipelineCyclerTrueImpl.I \ pta_double.h \ pta_float.h pta_int.h \ string_utils.I string_utils.N string_utils.h \ @@ -88,7 +91,9 @@ nodePointerTo.cxx \ pipeline.cxx \ pipelineCycler.cxx \ - pipelineCyclerBase.cxx \ + pipelineCyclerDummyImpl.cxx \ + pipelineCyclerTrivialImpl.cxx \ + pipelineCyclerTrueImpl.cxx \ pta_double.cxx pta_float.cxx \ pta_int.cxx pta_ushort.cxx \ string_utils.cxx timedCycle.cxx typedWritable.cxx \ @@ -138,7 +143,10 @@ nodePointerTo.h nodePointerTo.I \ pipeline.h pipeline.I \ pipelineCycler.h pipelineCycler.I \ - pipelineCyclerBase.h pipelineCyclerBase.I \ + pipelineCyclerBase.h \ + pipelineCyclerDummyImpl.h pipelineCyclerDummyImpl.I \ + pipelineCyclerTrivialImpl.h pipelineCyclerTrivialImpl.I \ + pipelineCyclerTrueImpl.h pipelineCyclerTrueImpl.I \ pta_double.h \ pta_float.h pta_int.h pta_ushort.h \ string_utils.I \ diff --git a/panda/src/putil/bamReader.h b/panda/src/putil/bamReader.h index b3d5738fc2..06a2eb0508 100644 --- a/panda/src/putil/bamReader.h +++ b/panda/src/putil/bamReader.h @@ -32,11 +32,10 @@ #include "pset.h" #include "pmap.h" #include "dcast.h" +#include "pipelineCyclerBase.h" #include -struct PipelineCyclerBase; - // A handy macro for reading PointerToArrays. #define READ_PTA(Manager, source, Read_func, array) \ diff --git a/panda/src/putil/bamWriter.h b/panda/src/putil/bamWriter.h index 3b6e9dd0d5..8a494f298a 100644 --- a/panda/src/putil/bamWriter.h +++ b/panda/src/putil/bamWriter.h @@ -28,8 +28,8 @@ #include "pset.h" #include "pmap.h" #include "vector_int.h" +#include "pipelineCyclerBase.h" -struct PipelineCyclerBase; // A handy macro for writing PointerToArrays. #define WRITE_PTA(Manager, dest, Write_func, array) \ diff --git a/panda/src/putil/pipeline.cxx b/panda/src/putil/pipeline.cxx index 7bd6ea73fd..59866d67a9 100644 --- a/panda/src/putil/pipeline.cxx +++ b/panda/src/putil/pipeline.cxx @@ -17,6 +17,7 @@ //////////////////////////////////////////////////////////////////// #include "pipeline.h" +#include "pipelineCyclerTrueImpl.h" Pipeline *Pipeline::_render_pipeline = (Pipeline *)NULL; @@ -29,26 +30,100 @@ Pipeline:: Pipeline(const string &name) : Namable(name) { + _num_stages = 1; } //////////////////////////////////////////////////////////////////// // Function: Pipeline::Destructor -// Access: Public, Virtual +// Access: Public // Description: //////////////////////////////////////////////////////////////////// Pipeline:: ~Pipeline() { +#if defined(DO_PIPELINING) && defined(HAVE_THREADS) + nassertv(_cyclers.empty()); +#endif // DO_PIPELINING && HAVE_THREADS } //////////////////////////////////////////////////////////////////// // Function: Pipeline::cycle -// Access: Public, Virtual +// Access: Public // Description: Flows all the pipeline data down to the next stage. //////////////////////////////////////////////////////////////////// void Pipeline:: cycle() { +#if defined(DO_PIPELINING) && defined(HAVE_THREADS) + Cyclers::iterator ci; + for (ci = _cyclers.begin(); ci != _cyclers.end(); ++ci) { + (*ci)->cycle(); + } +#endif // DO_PIPELINING && HAVE_THREADS } +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::set_num_stages +// Access: Public +// Description: Specifies the number of stages required for the +// pipeline. +//////////////////////////////////////////////////////////////////// +void Pipeline:: +set_num_stages(int num_stages) { + nassertv(num_stages >= 1); + if (num_stages != _num_stages) { + _num_stages = num_stages; + +#if defined(DO_PIPELINING) && defined(HAVE_THREADS) + Cyclers::iterator ci; + for (ci = _cyclers.begin(); ci != _cyclers.end(); ++ci) { + (*ci)->set_num_stages(num_stages); + } +#endif // DO_PIPELINING && HAVE_THREADS + } +} + +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::get_num_stages +// Access: Public +// Description: Returns the number of stages required for the +// pipeline. +//////////////////////////////////////////////////////////////////// +int Pipeline:: +get_num_stages() const { + return _num_stages; +} + + +#if defined(DO_PIPELINING) && defined(HAVE_THREADS) +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::add_cycler +// Access: Public +// Description: Adds the indicated cycler to the list of cyclers +// associated with the pipeline. This method only +// exists when true pipelining is configured on. +//////////////////////////////////////////////////////////////////// +void Pipeline:: +add_cycler(PipelineCyclerTrueImpl *cycler) { + bool inserted = _cyclers.insert(cycler).second; + nassertv(inserted); +} +#endif // DO_PIPELINING && HAVE_THREADS + +#if defined(DO_PIPELINING) && defined(HAVE_THREADS) +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::remove_cycler +// Access: Public +// Description: Removes the indicated cycler from the list of cyclers +// associated with the pipeline. This method only +// exists when true pipelining is configured on. +//////////////////////////////////////////////////////////////////// +void Pipeline:: +remove_cycler(PipelineCyclerTrueImpl *cycler) { + Cyclers::iterator ci = _cyclers.find(cycler); + nassertv(ci != _cyclers.end()); + _cyclers.erase(ci); +} +#endif // DO_PIPELINING && HAVE_THREADS + //////////////////////////////////////////////////////////////////// // Function: Pipeline::make_render_pipeline // Access: Private, Static @@ -59,4 +134,3 @@ make_render_pipeline() { nassertv(_render_pipeline == (Pipeline *)NULL); _render_pipeline = new Pipeline("render"); } - diff --git a/panda/src/putil/pipeline.h b/panda/src/putil/pipeline.h index 888dc80812..b930b1145e 100644 --- a/panda/src/putil/pipeline.h +++ b/panda/src/putil/pipeline.h @@ -21,6 +21,9 @@ #include "pandabase.h" #include "namable.h" +#include "pset.h" + +class PipelineCyclerTrueImpl; //////////////////////////////////////////////////////////////////// // Class : Pipeline @@ -38,15 +41,30 @@ class EXPCL_PANDA Pipeline : public Namable { public: Pipeline(const string &name); - virtual ~Pipeline(); + ~Pipeline(); INLINE static Pipeline *get_render_pipeline(); - virtual void cycle(); + void cycle(); + + void set_num_stages(int num_stages); + int get_num_stages() const; + +#if defined(DO_PIPELINING) && defined(HAVE_THREADS) + void add_cycler(PipelineCyclerTrueImpl *cycler); + void remove_cycler(PipelineCyclerTrueImpl *cycler); +#endif // DO_PIPELINING && HAVE_THREADS private: + int _num_stages; + static void make_render_pipeline(); static Pipeline *_render_pipeline; + +#if defined(DO_PIPELINING) && defined(HAVE_THREADS) + typedef pset Cyclers; + Cyclers _cyclers; +#endif // DO_PIPELINING && HAVE_THREADS }; #include "pipeline.I" diff --git a/panda/src/putil/pipelineCycler.I b/panda/src/putil/pipelineCycler.I index a854bc0cd5..6b450c9613 100644 --- a/panda/src/putil/pipelineCycler.I +++ b/panda/src/putil/pipelineCycler.I @@ -18,11 +18,11 @@ #ifdef DO_PIPELINING -// The following implementations are to support compiled-in pipeline -// sanity checks. +// The following implementations are to support the +// PipelineCyclerDummyImpl or the PipelineCyclerTrueImpl. //////////////////////////////////////////////////////////////////// -// Function: PipelineCycler::Constructor (sanity-check) +// Function: PipelineCycler::Constructor (dummy or true) // Access: Public // Description: //////////////////////////////////////////////////////////////////// @@ -34,20 +34,19 @@ PipelineCycler(Pipeline *pipeline) : } //////////////////////////////////////////////////////////////////// -// Function: PipelineCycler::Copy Constructor (sanity-check) +// Function: PipelineCycler::Copy Constructor (dummy or true) // Access: Public // Description: //////////////////////////////////////////////////////////////////// template INLINE PipelineCycler:: PipelineCycler(const PipelineCycler ©) : - // In the DO_PIPELINING copy constructor, the pointer value is ignored. - PipelineCyclerBase(NULL, copy) + PipelineCyclerBase(copy) { } //////////////////////////////////////////////////////////////////// -// Function: PipelineCycler::Copy Assignment (sanity-check) +// Function: PipelineCycler::Copy Assignment (dummy or true) // Access: Public // Description: //////////////////////////////////////////////////////////////////// @@ -58,7 +57,7 @@ operator = (const PipelineCycler ©) { } //////////////////////////////////////////////////////////////////// -// Function: PipelineCycler::read (sanity-check) +// Function: PipelineCycler::read (dummy or true) // Access: Public // Description: See PipelineCyclerBase::read(). //////////////////////////////////////////////////////////////////// @@ -69,7 +68,7 @@ read() const { } //////////////////////////////////////////////////////////////////// -// Function: PipelineCycler::write (sanity-check) +// Function: PipelineCycler::write (dummy or true) // Access: Public // Description: See PipelineCyclerBase::write(). //////////////////////////////////////////////////////////////////// @@ -80,7 +79,7 @@ write() { } //////////////////////////////////////////////////////////////////// -// Function: PipelineCycler::elevate_read (sanity-check) +// Function: PipelineCycler::elevate_read (dummy or true) // Access: Public // Description: See PipelineCyclerBase::elevate_read(). //////////////////////////////////////////////////////////////////// @@ -91,7 +90,7 @@ elevate_read(const CycleDataType *pointer) { } //////////////////////////////////////////////////////////////////// -// Function: PipelineCycler::write_stage (sanity-check) +// Function: PipelineCycler::write_stage (dummy or true) // Access: Public // Description: See PipelineCyclerBase::write_stage(). //////////////////////////////////////////////////////////////////// @@ -102,7 +101,7 @@ write_stage(int n) { } //////////////////////////////////////////////////////////////////// -// Function: PipelineCycler::cheat (sanity-check) +// Function: PipelineCycler::cheat (dummy or true) // Access: Public // Description: Returns a pointer without counting it. This is only // intended for use as the return value for certain @@ -142,7 +141,7 @@ PipelineCycler(Pipeline *pipeline) : template INLINE PipelineCycler:: PipelineCycler(const PipelineCycler ©) : - PipelineCyclerBase(&_typed_data, copy), + PipelineCyclerBase(&_typed_data), _typed_data(copy._typed_data) { } @@ -155,7 +154,6 @@ PipelineCycler(const PipelineCycler ©) : template INLINE void PipelineCycler:: operator = (const PipelineCycler ©) { - PipelineCyclerBase::operator = (copy); _typed_data = copy._typed_data; } diff --git a/panda/src/putil/pipelineCyclerBase.I b/panda/src/putil/pipelineCyclerBase.I deleted file mode 100644 index 988e340fbe..0000000000 --- a/panda/src/putil/pipelineCyclerBase.I +++ /dev/null @@ -1,527 +0,0 @@ -// Filename: pipelineCyclerBase.I -// Created by: drose (21Feb02) -// -//////////////////////////////////////////////////////////////////// -// -// 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 -// The following implementations are to support compiled-in pipeline -// sanity checks. - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::Constructor (sanity-check) -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE PipelineCyclerBase:: -PipelineCyclerBase(CycleData *initial_data, Pipeline *pipeline) : - _data(initial_data), - _pipeline(pipeline), - _read_count(0), - _write_count(0) -{ - if (_pipeline == (Pipeline *)NULL) { - _pipeline = Pipeline::get_render_pipeline(); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::Copy Constructor (sanity-check) -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE PipelineCyclerBase:: -PipelineCyclerBase(CycleData *, const PipelineCyclerBase ©) : - _data(copy._data->make_copy()), - _pipeline(copy._pipeline), - _read_count(0), - _write_count(0) -{ -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::Copy Assignment (sanity-check) -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void PipelineCyclerBase:: -operator = (const PipelineCyclerBase ©) { - nassertv(_read_count == 0 && _write_count == 0); - _data = copy._data->make_copy(); - _pipeline = copy._pipeline; -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::Destructor (sanity-check) -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE PipelineCyclerBase:: -~PipelineCyclerBase() { - nassertv(_read_count == 0 && _write_count == 0); -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::read (sanity-check) -// Access: Public -// Description: Returns a const CycleData pointer, filled with the -// data for the current stage of the pipeline as seen by -// this thread. This pointer should eventually be -// released by calling release_read(). -// -// There should be no outstanding write pointers on the -// data when this function is called. -//////////////////////////////////////////////////////////////////// -INLINE const CycleData *PipelineCyclerBase:: -read() const { - // This function isn't truly const, but it doesn't change the data - // in any meaningful way, so we pretend it is. - ((PipelineCyclerBase *)this)->_read_count++; - - // It's not an error to grab a read pointer while someone else holds - // a read or a write pointer. - return _data; -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::increment_read (sanity-check) -// Access: Public -// Description: Increments the count on a pointer previously -// retrieved by read(); now the pointer will need to be -// released twice. -//////////////////////////////////////////////////////////////////// -INLINE void PipelineCyclerBase:: -increment_read(const CycleData *pointer) const { - // This function isn't truly const, but it doesn't change the data - // in any meaningful way, so we pretend it is. - nassertv(pointer == _data); - nassertv(_read_count > 0); - ((PipelineCyclerBase *)this)->_read_count++; -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::release_read (sanity-check) -// Access: Public -// Description: Releases a pointer previously obtained via a call to -// read(). -//////////////////////////////////////////////////////////////////// -INLINE void PipelineCyclerBase:: -release_read(const CycleData *pointer) const { - // This function isn't truly const, but it doesn't change the data - // in any meaningful way, so we pretend it is. - nassertv(pointer == _data); - nassertv(_read_count > 0); - ((PipelineCyclerBase *)this)->_read_count--; -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::write (sanity-check) -// Access: Public -// Description: Returns a non-const CycleData pointer, filled with a -// unique copy of the data for the current stage of the -// pipeline as seen by this thread. This pointer may -// now be used to write to the data, and that copy of -// the data will be propagate to all later stages of the -// pipeline. This pointer should eventually be released -// by calling release_write(). -// -// There may only be one outstanding write pointer on a -// given stage at a time, and if there is a write -// pointer there may be no read pointers on the same -// stage (but see elevate_read). -//////////////////////////////////////////////////////////////////// -INLINE CycleData *PipelineCyclerBase:: -write() { - _write_count++; - - // It's an error to grab a write pointer while someone else holds a - // read pointer, because doing so may invalidate the read pointer. - nassertr(_read_count == 0, _data); - - // It's not an error to do this while someone else holds a write - // pointer, however. - - return _data; -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::elevate_read (sanity-check) -// Access: Public -// Description: Elevates a currently-held read pointer into a write -// pointer. This may or may not change the value of the -// pointer. It is only valid to do this if this is the -// only currently-outstanding read pointer on the -// current stage. -//////////////////////////////////////////////////////////////////// -INLINE CycleData *PipelineCyclerBase:: -elevate_read(const CycleData *pointer) { - release_read(pointer); - return write(); -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::release_write (sanity-check) -// Access: Public -// Description: Releases a pointer previously obtained via a call to -// write(). -//////////////////////////////////////////////////////////////////// -INLINE void PipelineCyclerBase:: -release_write(CycleData *pointer) { - nassertv(pointer == _data); - nassertv(_write_count > 0); - _write_count--; -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::get_num_stages (sanity-check) -// Access: Public -// Description: Returns the number of stages in the pipeline. -//////////////////////////////////////////////////////////////////// -INLINE int PipelineCyclerBase:: -get_num_stages() { - return 1; -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::is_stage_unique (sanity-check) -// Access: Public -// Description: Returns true if the nth stage is a different pointer -// than the previous stage, or false if its pointer is -// shared with the previous one. -//////////////////////////////////////////////////////////////////// -INLINE bool PipelineCyclerBase:: -is_stage_unique(int n) const { - nassertr(n == 0, false); - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::write_stage (sanity-check) -// Access: Public -// Description: Returns a pointer suitable for writing to the nth -// stage of the pipeline. This is for special -// applications that need to update the entire pipeline -// at once (for instance, to remove an invalid pointer). -// This pointer should later be released with -// release_write_stage(). -//////////////////////////////////////////////////////////////////// -INLINE CycleData *PipelineCyclerBase:: -write_stage(int n) { - nassertr(n == 0, (CycleData *)NULL); - _write_count++; - return _data; -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::release_write_stage (sanity-check) -// Access: Public -// Description: Releases a pointer previously obtained via a call to -// write_stage(). -//////////////////////////////////////////////////////////////////// -INLINE void PipelineCyclerBase:: -release_write_stage(int n, CycleData *pointer) { - nassertv(n == 0 && pointer == _data); - nassertv(_write_count > 0); - _write_count--; -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::cheat (sanity-check) -// Access: Public -// Description: Returns a pointer without counting it. This is only -// intended for use as the return value for certain -// nassertr() functions, so the application can recover -// after a failure to manage the read and write pointers -// correctly. You should never call this function -// directly. -//////////////////////////////////////////////////////////////////// -INLINE CycleData *PipelineCyclerBase:: -cheat() const { - return _data; -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::get_read_count (sanity-check) -// Access: Public -// Description: Returns the number of handles currently outstanding -// to read the current stage of the data. This should -// only be used for debugging purposes. -//////////////////////////////////////////////////////////////////// -INLINE int PipelineCyclerBase:: -get_read_count() const { - return _read_count; -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::get_write_count (sanity-check) -// Access: Public -// Description: Returns the number of handles currently outstanding -// to read the current stage of the data. This will -// normally only be either 0 or 1. This should only be -// used for debugging purposes. -//////////////////////////////////////////////////////////////////// -INLINE int PipelineCyclerBase:: -get_write_count() const { - return _write_count; -} - -#else // !DO_PIPELINING -// The following implementations are provided for when pipelining is -// not compiled in. They are trivial functions that do as little as -// possible. - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::Constructor (trivial) -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE PipelineCyclerBase:: -PipelineCyclerBase(CycleData *initial_data, Pipeline *) { - // In the trivial implementation, a derived class (the - // PipelineCycler template class) stores the CycleData object - // directly within itself, and since we have no data members or - // virtual functions, we get away with assuming the pointer is the - // same as the 'this' pointer. - - // If this turns out not to be true on a particular platform, we - // will have to store the pointer in this class, for a little bit of - // extra overhead. -#ifdef SIMPLE_STRUCT_POINTERS - nassertv(initial_data == (CycleData *)this); -#else - _data = initial_data; -#endif // SIMPLE_STRUCT_POINTERS -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::Copy Constructor (trivial) -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE PipelineCyclerBase:: -PipelineCyclerBase(CycleData *initial_data, const PipelineCyclerBase &) { - // The copy constructor for the DO_PIPELINING case is -#ifdef SIMPLE_STRUCT_POINTERS - nassertv(initial_data == (CycleData *)this); -#else - _data = initial_data; -#endif // SIMPLE_STRUCT_POINTERS -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::Copy Assignment (trivial) -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void PipelineCyclerBase:: -operator = (const PipelineCyclerBase &) { - // We don't reassign the _data pointer here; we assume it was set - // correctly previously. -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::Destructor (trivial) -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE PipelineCyclerBase:: -~PipelineCyclerBase() { -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::read (trivial) -// Access: Public -// Description: Returns a const CycleData pointer, filled with the -// data for the current stage of the pipeline as seen by -// this thread. This pointer should eventually be -// released by calling release_read(). -//////////////////////////////////////////////////////////////////// -INLINE const CycleData *PipelineCyclerBase:: -read() const { -#ifdef SIMPLE_STRUCT_POINTERS - return (const CycleData *)this; -#else - return _data; -#endif // SIMPLE_STRUCT_POINTERS -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::increment_read (trivial) -// Access: Public -// Description: Increments the count on a pointer previously -// retrieved by read(); now the pointer will need to be -// released twice. -//////////////////////////////////////////////////////////////////// -INLINE void PipelineCyclerBase:: -increment_read(const CycleData *) const { -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::release_read (trivial) -// Access: Public -// Description: Releases a pointer previously obtained via a call to -// read(). -//////////////////////////////////////////////////////////////////// -INLINE void PipelineCyclerBase:: -release_read(const CycleData *) const { -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::write (trivial) -// Access: Public -// Description: Returns a non-const CycleData pointer, filled with a -// unique copy of the data for the current stage of the -// pipeline as seen by this thread. This pointer may -// now be used to write to the data, and that copy of -// the data will be propagate to all later stages of the -// pipeline. This pointer should eventually be released -// by calling release_write(). -// -// There may only be one outstanding write pointer on a -// given stage at a time, and if there is a write -// pointer there may be no read pointers on the same -// stage (but see elevate_read). -//////////////////////////////////////////////////////////////////// -INLINE CycleData *PipelineCyclerBase:: -write() { -#ifdef SIMPLE_STRUCT_POINTERS - return (CycleData *)this; -#else - return _data; -#endif // SIMPLE_STRUCT_POINTERS -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::elevate_read (trivial) -// Access: Public -// Description: Elevates a currently-held read pointer into a write -// pointer. This may or may not change the value of the -// pointer. It is only valid to do this if this is the -// only currently-outstanding read pointer on the -// current stage. -//////////////////////////////////////////////////////////////////// -INLINE CycleData *PipelineCyclerBase:: -elevate_read(const CycleData *) { -#ifdef SIMPLE_STRUCT_POINTERS - return (CycleData *)this; -#else - return _data; -#endif // SIMPLE_STRUCT_POINTERS -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::release_write (trivial) -// Access: Public -// Description: Releases a pointer previously obtained via a call to -// write(). -//////////////////////////////////////////////////////////////////// -INLINE void PipelineCyclerBase:: -release_write(CycleData *) { -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::get_num_stages (trivial) -// Access: Public -// Description: Returns the number of stages in the pipeline. -//////////////////////////////////////////////////////////////////// -INLINE int PipelineCyclerBase:: -get_num_stages() { - return 1; -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::is_stage_unique (trivial) -// Access: Public -// Description: Returns true if the nth stage is a different pointer -// than the previous stage, or false if its pointer is -// shared with the previous one. -//////////////////////////////////////////////////////////////////// -INLINE bool PipelineCyclerBase:: -is_stage_unique(int n) const { - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::write_stage (trivial) -// Access: Public -// Description: Returns a pointer suitable for writing to the nth -// stage of the pipeline. This is for special -// applications that need to update the entire pipeline -// at once (for instance, to remove an invalid pointer). -// This pointer should later be released with -// release_write_stage(). -//////////////////////////////////////////////////////////////////// -INLINE CycleData *PipelineCyclerBase:: -write_stage(int) { - return (CycleData *)this; -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::release_write_stage (trivial) -// Access: Public -// Description: Releases a pointer previously obtained via a call to -// write_stage(). -//////////////////////////////////////////////////////////////////// -INLINE void PipelineCyclerBase:: -release_write_stage(int, CycleData *) { -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::cheat (trivial) -// Access: Public -// Description: Returns a pointer without counting it. This is only -// intended for use as the return value for certain -// nassertr() functions, so the application can recover -// after a failure to manage the read and write pointers -// correctly. You should never call this function -// directly. -//////////////////////////////////////////////////////////////////// -INLINE CycleData *PipelineCyclerBase:: -cheat() const { -#ifdef SIMPLE_STRUCT_POINTERS - return (CycleData *)this; -#else - return _data; -#endif // SIMPLE_STRUCT_POINTERS -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::get_read_count (trivial) -// Access: Public -// Description: Returns the number of handles currently outstanding -// to read the current stage of the data. This should -// only be used for debugging purposes. -//////////////////////////////////////////////////////////////////// -INLINE int PipelineCyclerBase:: -get_read_count() const { - return 0; -} - -//////////////////////////////////////////////////////////////////// -// Function: PipelineCyclerBase::get_write_count (trivial) -// Access: Public -// Description: Returns the number of handles currently outstanding -// to read the current stage of the data. This will -// normally only be either 0 or 1. This should only be -// used for debugging purposes. -//////////////////////////////////////////////////////////////////// -INLINE int PipelineCyclerBase:: -get_write_count() const { - return 0; -} - - -#endif // DO_PIPELINING diff --git a/panda/src/putil/pipelineCyclerBase.h b/panda/src/putil/pipelineCyclerBase.h index fb97b31677..4dcded70f7 100644 --- a/panda/src/putil/pipelineCyclerBase.h +++ b/panda/src/putil/pipelineCyclerBase.h @@ -21,68 +21,32 @@ #include "pandabase.h" -#include "cycleData.h" -#include "pipeline.h" -#include "pointerTo.h" - -//////////////////////////////////////////////////////////////////// -// Class : PipelineCyclerBase -// Description : This is the non-template part of the implementation -// of PipelineCycler. See PipelineCycler. -// -// We define this as a struct instead of a class to -// guarantee byte placement within the object, so that -// (particularly for the trivial implementation) the -// inherited struct's data is likely to be placed by the -// compiler at the "this" pointer. -//////////////////////////////////////////////////////////////////// -struct EXPCL_PANDA PipelineCyclerBase { -public: - INLINE PipelineCyclerBase(CycleData *initial_data, Pipeline *pipeline = NULL); - INLINE PipelineCyclerBase(CycleData *initial_data, const PipelineCyclerBase ©); - INLINE void operator = (const PipelineCyclerBase ©); - INLINE ~PipelineCyclerBase(); - - INLINE const CycleData *read() const; - INLINE void increment_read(const CycleData *pointer) const; - INLINE void release_read(const CycleData *pointer) const; - - INLINE CycleData *write(); - INLINE CycleData *elevate_read(const CycleData *pointer); - INLINE void release_write(CycleData *pointer); - - INLINE int get_num_stages(); - INLINE bool is_stage_unique(int n) const; - INLINE CycleData *write_stage(int n); - INLINE void release_write_stage(int n, CycleData *pointer); - - INLINE CycleData *cheat() const; - INLINE int get_read_count() const; - INLINE int get_write_count() const; - #ifdef DO_PIPELINING - // This private data is only stored here if we have pipelining - // compiled in. Actually, this particular data is only used for - // sanity checking the pipelining code; it doesn't do anything - // useful. -private: - PT(CycleData) _data; - Pipeline *_pipeline; - short _read_count, _write_count; -#else // !DO_PIPELINING - // In a trivial implementation, we only need to store the CycleData - // pointer. Actually, we don't even need to do that, if we're lucky - // and the compiler doesn't do anything funny with the struct - // layout. - #ifndef SIMPLE_STRUCT_POINTERS - CycleData *_data; - #endif // SIMPLE_STRUCT_POINTERS +#ifdef HAVE_THREADS + +// With DO_PIPELINING and threads available, we want the true cycler +// implementation. +#include "pipelineCyclerTrueImpl.h" +typedef PipelineCyclerTrueImpl PipelineCyclerBase; + +#else // HAVE_THREADS + +// With DO_PIPELINING but no threads available, we want the dummy, +// self-validating cycler implementation. +#include "pipelineCyclerDummyImpl.h" +typedef PipelineCyclerDummyImpl PipelineCyclerBase; + +#endif // HAVE_THREADS + +#else // DO_PIPELINING + +// Without DO_PIPELINING, we only want the trivial, do-nothing +// implementation. +#include "pipelineCyclerTrivialImpl.h" +typedef PipelineCyclerTrivialImpl PipelineCyclerBase; #endif // DO_PIPELINING -}; - -#include "pipelineCyclerBase.I" #endif diff --git a/panda/src/putil/pipelineCyclerDummyImpl.I b/panda/src/putil/pipelineCyclerDummyImpl.I new file mode 100644 index 0000000000..cefb631b2e --- /dev/null +++ b/panda/src/putil/pipelineCyclerDummyImpl.I @@ -0,0 +1,275 @@ +// Filename: pipelineCyclerDummyImpl.I +// Created by: drose (31Jan06) +// +//////////////////////////////////////////////////////////////////// +// +// 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: PipelineCyclerDummyImpl::Constructor (sanity-check) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PipelineCyclerDummyImpl:: +PipelineCyclerDummyImpl(CycleData *initial_data, Pipeline *pipeline) : + _data(initial_data), + _pipeline(pipeline), + _read_count(0), + _write_count(0) +{ + if (_pipeline == (Pipeline *)NULL) { + _pipeline = Pipeline::get_render_pipeline(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::Copy Constructor (sanity-check) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PipelineCyclerDummyImpl:: +PipelineCyclerDummyImpl(const PipelineCyclerDummyImpl ©) : + _data(copy._data->make_copy()), + _pipeline(copy._pipeline), + _read_count(0), + _write_count(0) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::Copy Assignment (sanity-check) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerDummyImpl:: +operator = (const PipelineCyclerDummyImpl ©) { + nassertv(_read_count == 0 && _write_count == 0); + _data = copy._data->make_copy(); + _pipeline = copy._pipeline; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::Destructor (sanity-check) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PipelineCyclerDummyImpl:: +~PipelineCyclerDummyImpl() { + nassertv(_read_count == 0 && _write_count == 0); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::read (sanity-check) +// Access: Public +// Description: Returns a const CycleData pointer, filled with the +// data for the current stage of the pipeline as seen by +// this thread. This pointer should eventually be +// released by calling release_read(). +// +// There should be no outstanding write pointers on the +// data when this function is called. +//////////////////////////////////////////////////////////////////// +INLINE const CycleData *PipelineCyclerDummyImpl:: +read() const { + // This function isn't truly const, but it doesn't change the data + // in any meaningful way, so we pretend it is. + ((PipelineCyclerDummyImpl *)this)->_read_count++; + + // It's not an error to grab a read pointer while someone else holds + // a read or a write pointer. + return _data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::increment_read (sanity-check) +// Access: Public +// Description: Increments the count on a pointer previously +// retrieved by read(); now the pointer will need to be +// released twice. +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerDummyImpl:: +increment_read(const CycleData *pointer) const { + // This function isn't truly const, but it doesn't change the data + // in any meaningful way, so we pretend it is. + nassertv(pointer == _data); + nassertv(_read_count > 0); + ((PipelineCyclerDummyImpl *)this)->_read_count++; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::release_read (sanity-check) +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// read(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerDummyImpl:: +release_read(const CycleData *pointer) const { + // This function isn't truly const, but it doesn't change the data + // in any meaningful way, so we pretend it is. + nassertv(pointer == _data); + nassertv(_read_count > 0); + ((PipelineCyclerDummyImpl *)this)->_read_count--; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::write (sanity-check) +// Access: Public +// Description: Returns a non-const CycleData pointer, filled with a +// unique copy of the data for the current stage of the +// pipeline as seen by this thread. This pointer may +// now be used to write to the data, and that copy of +// the data will be propagated to all later stages of the +// pipeline. This pointer should eventually be released +// by calling release_write(). +// +// There may only be one outstanding write pointer on a +// given stage at a time, and if there is a write +// pointer there may be no read pointers on the same +// stage (but see elevate_read). +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerDummyImpl:: +write() { + _write_count++; + + // It's an error to grab a write pointer while someone else holds a + // read pointer, because doing so may invalidate the read pointer. + nassertr(_read_count == 0, _data); + + // It's not an error to do this while someone else holds a write + // pointer, however. + + return _data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::elevate_read (sanity-check) +// Access: Public +// Description: Elevates a currently-held read pointer into a write +// pointer. This may or may not change the value of the +// pointer. It is only valid to do this if this is the +// only currently-outstanding read pointer on the +// current stage. +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerDummyImpl:: +elevate_read(const CycleData *pointer) { + release_read(pointer); + return write(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::release_write (sanity-check) +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// write(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerDummyImpl:: +release_write(CycleData *pointer) { + nassertv(pointer == _data); + nassertv(_write_count > 0); + _write_count--; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::get_num_stages (sanity-check) +// Access: Public +// Description: Returns the number of stages in the pipeline. +//////////////////////////////////////////////////////////////////// +INLINE int PipelineCyclerDummyImpl:: +get_num_stages() { + return 1; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::is_stage_unique (sanity-check) +// Access: Public +// Description: Returns true if the nth stage is a different pointer +// than the previous stage, or false if its pointer is +// shared with the previous one. +//////////////////////////////////////////////////////////////////// +INLINE bool PipelineCyclerDummyImpl:: +is_stage_unique(int n) const { + nassertr(n == 0, false); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::write_stage (sanity-check) +// Access: Public +// Description: Returns a pointer suitable for writing to the nth +// stage of the pipeline. This is for special +// applications that need to update the entire pipeline +// at once (for instance, to remove an invalid pointer). +// This pointer should later be released with +// release_write_stage(). +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerDummyImpl:: +write_stage(int n) { + nassertr(n == 0, (CycleData *)NULL); + _write_count++; + return _data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::release_write_stage (sanity-check) +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// write_stage(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerDummyImpl:: +release_write_stage(int n, CycleData *pointer) { + nassertv(n == 0 && pointer == _data); + nassertv(_write_count > 0); + _write_count--; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::cheat (sanity-check) +// Access: Public +// Description: Returns a pointer without counting it. This is only +// intended for use as the return value for certain +// nassertr() functions, so the application can recover +// after a failure to manage the read and write pointers +// correctly. You should never call this function +// directly. +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerDummyImpl:: +cheat() const { + return _data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::get_read_count (sanity-check) +// Access: Public +// Description: Returns the number of handles currently outstanding +// to read the current stage of the data. This should +// only be used for debugging purposes. +//////////////////////////////////////////////////////////////////// +INLINE int PipelineCyclerDummyImpl:: +get_read_count() const { + return _read_count; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::get_write_count (sanity-check) +// Access: Public +// Description: Returns the number of handles currently outstanding +// to read the current stage of the data. This will +// normally only be either 0 or 1. This should only be +// used for debugging purposes. +//////////////////////////////////////////////////////////////////// +INLINE int PipelineCyclerDummyImpl:: +get_write_count() const { + return _write_count; +} diff --git a/panda/src/putil/pipelineCyclerBase.cxx b/panda/src/putil/pipelineCyclerDummyImpl.cxx similarity index 60% rename from panda/src/putil/pipelineCyclerBase.cxx rename to panda/src/putil/pipelineCyclerDummyImpl.cxx index 1265cd42d4..e66d164b89 100644 --- a/panda/src/putil/pipelineCyclerBase.cxx +++ b/panda/src/putil/pipelineCyclerDummyImpl.cxx @@ -1,5 +1,5 @@ -// Filename: pipelineCyclerBase.cxx -// Created by: drose (21Feb02) +// Filename: pipelineCyclerDummyImpl.cxx +// Created by: drose (31Jan06) // //////////////////////////////////////////////////////////////////// // @@ -16,17 +16,4 @@ // //////////////////////////////////////////////////////////////////// -#include "pipelineCyclerBase.h" - - -#ifdef DO_PIPELINING -// The following implementations are to support compiled-in pipeline -// sanity checks. - - -#else // !DO_PIPELINING -// The following implementations are provided for when pipelining is -// not compiled in. They are trivial functions that do as little as -// possible. - -#endif +#include "pipelineCyclerDummyImpl.h" diff --git a/panda/src/putil/pipelineCyclerDummyImpl.h b/panda/src/putil/pipelineCyclerDummyImpl.h new file mode 100644 index 0000000000..0255447633 --- /dev/null +++ b/panda/src/putil/pipelineCyclerDummyImpl.h @@ -0,0 +1,83 @@ +// Filename: pipelineCyclerDummyImpl.h +// Created by: drose (31Jan06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 PIPELINECYCLERDUMMYIMPL_H +#define PIPELINECYCLERDUMMYIMPL_H + +#include "pandabase.h" + +#if defined(DO_PIPELINING) && !defined(HAVE_THREADS) + +#include "cycleData.h" +#include "pipeline.h" +#include "pointerTo.h" + +//////////////////////////////////////////////////////////////////// +// Class : PipelineCyclerDummyImpl +// Description : This is a simple, single-threaded-only implementation +// of PipelineCyclerBase. It is only compiled when +// DO_PIPELINING is defined, but threading is not +// available, which is usually the case only in +// development mode. +// +// This implmentation is similar in principle to +// PipelineCyclerTrivialImpl, except it does basic +// sanity checking to ensure that you use the interface +// in a reasonable way consistent with its design (e.g., +// read() is balanced with release_read(), etc.). +// +// This is defined as a struct instead of a class, +// mainly to be consistent with +// PipelineCyclerTrivialImpl. +//////////////////////////////////////////////////////////////////// +struct EXPCL_PANDA PipelineCyclerDummyImpl { +public: + INLINE PipelineCyclerDummyImpl(CycleData *initial_data, Pipeline *pipeline = NULL); + INLINE PipelineCyclerDummyImpl(const PipelineCyclerDummyImpl ©); + INLINE void operator = (const PipelineCyclerDummyImpl ©); + INLINE ~PipelineCyclerDummyImpl(); + + INLINE const CycleData *read() const; + INLINE void increment_read(const CycleData *pointer) const; + INLINE void release_read(const CycleData *pointer) const; + + INLINE CycleData *write(); + INLINE CycleData *elevate_read(const CycleData *pointer); + INLINE void release_write(CycleData *pointer); + + INLINE int get_num_stages(); + INLINE bool is_stage_unique(int n) const; + INLINE CycleData *write_stage(int n); + INLINE void release_write_stage(int n, CycleData *pointer); + + INLINE CycleData *cheat() const; + INLINE int get_read_count() const; + INLINE int get_write_count() const; + +private: + PT(CycleData) _data; + Pipeline *_pipeline; + short _read_count, _write_count; +}; + +#include "pipelineCyclerDummyImpl.I" + +#endif // DO_PIPELINING && !HAVE_THREADS + +#endif + diff --git a/panda/src/putil/pipelineCyclerTrivialImpl.I b/panda/src/putil/pipelineCyclerTrivialImpl.I new file mode 100644 index 0000000000..80a8187a16 --- /dev/null +++ b/panda/src/putil/pipelineCyclerTrivialImpl.I @@ -0,0 +1,261 @@ +// Filename: pipelineCyclerTrivialImpl.I +// Created by: drose (31Jan06) +// +//////////////////////////////////////////////////////////////////// +// +// 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: PipelineCyclerTrivialImpl::Constructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PipelineCyclerTrivialImpl:: +PipelineCyclerTrivialImpl(CycleData *initial_data, Pipeline *) { + // In the trivial implementation, a derived class (the + // PipelineCycler template class) stores the CycleData object + // directly within itself, and since we have no data members or + // virtual functions, we get away with assuming the pointer is the + // same as the 'this' pointer. + + // If this turns out not to be true on a particular platform, we + // will have to store the pointer in this class, for a little bit of + // extra overhead. +#ifdef SIMPLE_STRUCT_POINTERS + nassertv(initial_data == (CycleData *)this); +#else + _data = initial_data; +#endif // SIMPLE_STRUCT_POINTERS +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::Copy Constructor (trivial) +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PipelineCyclerTrivialImpl:: +PipelineCyclerTrivialImpl(const PipelineCyclerTrivialImpl &) { + // The copy constructor for the PipelineCyclerTrivialImpl case + // doesn't work. Don't try to use it. The PipelineCycler template + // class is #ifdeffed appropriately to call the normal constructor + // instead. + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::Copy Assignment (trivial) +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrivialImpl:: +operator = (const PipelineCyclerTrivialImpl &) { + // The copy assignment operator for the PipelineCyclerTrivialImpl + // case doesn't work. Don't try to use it. The PipelineCycler + // template class is #ifdeffed appropriately not to call this + // method. + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::Destructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PipelineCyclerTrivialImpl:: +~PipelineCyclerTrivialImpl() { +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::read (trivial) +// Access: Public +// Description: Returns a const CycleData pointer, filled with the +// data for the current stage of the pipeline as seen by +// this thread. This pointer should eventually be +// released by calling release_read(). +//////////////////////////////////////////////////////////////////// +INLINE const CycleData *PipelineCyclerTrivialImpl:: +read() const { +#ifdef SIMPLE_STRUCT_POINTERS + return (const CycleData *)this; +#else + return _data; +#endif // SIMPLE_STRUCT_POINTERS +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::increment_read (trivial) +// Access: Public +// Description: Increments the count on a pointer previously +// retrieved by read(); now the pointer will need to be +// released twice. +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrivialImpl:: +increment_read(const CycleData *) const { +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::release_read (trivial) +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// read(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrivialImpl:: +release_read(const CycleData *) const { +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::write (trivial) +// Access: Public +// Description: Returns a non-const CycleData pointer, filled with a +// unique copy of the data for the current stage of the +// pipeline as seen by this thread. This pointer may +// now be used to write to the data, and that copy of +// the data will be propagated to all later stages of the +// pipeline. This pointer should eventually be released +// by calling release_write(). +// +// There may only be one outstanding write pointer on a +// given stage at a time, and if there is a write +// pointer there may be no read pointers on the same +// stage (but see elevate_read). +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerTrivialImpl:: +write() { +#ifdef SIMPLE_STRUCT_POINTERS + return (CycleData *)this; +#else + return _data; +#endif // SIMPLE_STRUCT_POINTERS +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::elevate_read (trivial) +// Access: Public +// Description: Elevates a currently-held read pointer into a write +// pointer. This may or may not change the value of the +// pointer. It is only valid to do this if this is the +// only currently-outstanding read pointer on the +// current stage. +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerTrivialImpl:: +elevate_read(const CycleData *) { +#ifdef SIMPLE_STRUCT_POINTERS + return (CycleData *)this; +#else + return _data; +#endif // SIMPLE_STRUCT_POINTERS +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::release_write (trivial) +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// write(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrivialImpl:: +release_write(CycleData *) { +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::get_num_stages (trivial) +// Access: Public +// Description: Returns the number of stages in the pipeline. +//////////////////////////////////////////////////////////////////// +INLINE int PipelineCyclerTrivialImpl:: +get_num_stages() { + return 1; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::is_stage_unique (trivial) +// Access: Public +// Description: Returns true if the nth stage is a different pointer +// than the previous stage, or false if its pointer is +// shared with the previous one. +//////////////////////////////////////////////////////////////////// +INLINE bool PipelineCyclerTrivialImpl:: +is_stage_unique(int n) const { + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::write_stage (trivial) +// Access: Public +// Description: Returns a pointer suitable for writing to the nth +// stage of the pipeline. This is for special +// applications that need to update the entire pipeline +// at once (for instance, to remove an invalid pointer). +// This pointer should later be released with +// release_write_stage(). +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerTrivialImpl:: +write_stage(int) { + return (CycleData *)this; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::release_write_stage (trivial) +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// write_stage(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrivialImpl:: +release_write_stage(int, CycleData *) { +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::cheat (trivial) +// Access: Public +// Description: Returns a pointer without counting it. This is only +// intended for use as the return value for certain +// nassertr() functions, so the application can recover +// after a failure to manage the read and write pointers +// correctly. You should never call this function +// directly. +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerTrivialImpl:: +cheat() const { +#ifdef SIMPLE_STRUCT_POINTERS + return (CycleData *)this; +#else + return _data; +#endif // SIMPLE_STRUCT_POINTERS +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::get_read_count (trivial) +// Access: Public +// Description: Returns the number of handles currently outstanding +// to read the current stage of the data. This should +// only be used for debugging purposes. +//////////////////////////////////////////////////////////////////// +INLINE int PipelineCyclerTrivialImpl:: +get_read_count() const { + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::get_write_count (trivial) +// Access: Public +// Description: Returns the number of handles currently outstanding +// to read the current stage of the data. This will +// normally only be either 0 or 1. This should only be +// used for debugging purposes. +//////////////////////////////////////////////////////////////////// +INLINE int PipelineCyclerTrivialImpl:: +get_write_count() const { + return 0; +} + diff --git a/panda/src/putil/pipelineCyclerTrivialImpl.cxx b/panda/src/putil/pipelineCyclerTrivialImpl.cxx new file mode 100644 index 0000000000..cbbe4187b0 --- /dev/null +++ b/panda/src/putil/pipelineCyclerTrivialImpl.cxx @@ -0,0 +1,19 @@ +// Filename: pipelineCyclerTrivialImpl.cxx +// Created by: drose (31Jan06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "pipelineCyclerTrivialImpl.h" diff --git a/panda/src/putil/pipelineCyclerTrivialImpl.h b/panda/src/putil/pipelineCyclerTrivialImpl.h new file mode 100644 index 0000000000..e4104ae2cb --- /dev/null +++ b/panda/src/putil/pipelineCyclerTrivialImpl.h @@ -0,0 +1,89 @@ +// Filename: pipelineCyclerTrivialImpl.h +// Created by: drose (31Jan06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 PIPELINECYCLERTRIVIALIMPL_H +#define PIPELINECYCLERTRIVIALIMPL_H + +#include "pandabase.h" + +#ifndef DO_PIPELINING + +class CycleData; +class Pipeline; + +//////////////////////////////////////////////////////////////////// +// Class : PipelineCyclerTrivialImpl +// Description : This is the trivial, non-threaded implementation of +// PipelineCyclerBase. It is only compiled when +// DO_PIPELINING is not defined (which usually implies +// that threading is not available). +// +// This implementation is designed to do as little as +// possible, and to compile to nothing, or almost +// nothing. It doesn't actually support pipelining in +// any way. It doesn't even perform any sanity checks +// to speak of. It's designed for a strictly +// single-threaded application, and its purpose is to be +// as low-overhead as possible. +// +// We define this as a struct instead of a class to +// emphasize the importance of byte placement within the +// object, so that the inherited struct's data is likely +// to be placed by the compiler at the "this" pointer. +//////////////////////////////////////////////////////////////////// +struct EXPCL_PANDA PipelineCyclerTrivialImpl { +public: + INLINE PipelineCyclerTrivialImpl(CycleData *initial_data, Pipeline *pipeline = NULL); +private: + INLINE PipelineCyclerTrivialImpl(const PipelineCyclerTrivialImpl ©); + INLINE void operator = (const PipelineCyclerTrivialImpl ©); +public: + INLINE ~PipelineCyclerTrivialImpl(); + + INLINE const CycleData *read() const; + INLINE void increment_read(const CycleData *pointer) const; + INLINE void release_read(const CycleData *pointer) const; + + INLINE CycleData *write(); + INLINE CycleData *elevate_read(const CycleData *pointer); + INLINE void release_write(CycleData *pointer); + + INLINE int get_num_stages(); + INLINE bool is_stage_unique(int n) const; + INLINE CycleData *write_stage(int n); + INLINE void release_write_stage(int n, CycleData *pointer); + + INLINE CycleData *cheat() const; + INLINE int get_read_count() const; + INLINE int get_write_count() const; + + // In a trivial implementation, we only need to store the CycleData + // pointer. Actually, we don't even need to do that, if we're lucky + // and the compiler doesn't do anything funny with the struct + // layout. + #ifndef SIMPLE_STRUCT_POINTERS + CycleData *_data; + #endif // SIMPLE_STRUCT_POINTERS +}; + +#include "pipelineCyclerTrivialImpl.I" + +#endif // !DO_PIPELINING + +#endif + diff --git a/panda/src/putil/pipelineCyclerTrueImpl.I b/panda/src/putil/pipelineCyclerTrueImpl.I new file mode 100644 index 0000000000..d91bca6227 --- /dev/null +++ b/panda/src/putil/pipelineCyclerTrueImpl.I @@ -0,0 +1,196 @@ +// Filename: pipelineCyclerTrueImpl.I +// Created by: drose (31Jan06) +// +//////////////////////////////////////////////////////////////////// +// +// 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: PipelineCyclerTrueImpl::read +// Access: Public +// Description: Returns a const CycleData pointer, filled with the +// data for the current stage of the pipeline as seen by +// this thread. This pointer should eventually be +// released by calling release_read(). +// +// There should be no outstanding write pointers on the +// data when this function is called. +//////////////////////////////////////////////////////////////////// +INLINE const CycleData *PipelineCyclerTrueImpl:: +read() const { + int pipeline_stage = Thread::get_current_thread()->get_pipeline_stage(); + nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); + return _data[pipeline_stage]._cycle_data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::increment_read +// Access: Public +// Description: Increments the count on a pointer previously +// retrieved by read(); now the pointer will need to be +// released twice. +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrueImpl:: +increment_read(const CycleData *pointer) const { +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::release_read +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// read(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrueImpl:: +release_read(const CycleData *pointer) const { +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::write +// Access: Public +// Description: Returns a non-const CycleData pointer, filled with a +// unique copy of the data for the current stage of the +// pipeline as seen by this thread. This pointer may +// now be used to write to the data, and that copy of +// the data will be propagated to all later stages of the +// pipeline. This pointer should eventually be released +// by calling release_write(). +// +// There may only be one outstanding write pointer on a +// given stage at a time, and if there is a write +// pointer there may be no read pointers on the same +// stage (but see elevate_read). +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerTrueImpl:: +write() { + int pipeline_stage = Thread::get_current_thread()->get_pipeline_stage(); + nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); + return _data[pipeline_stage]._cycle_data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::elevate_read +// Access: Public +// Description: Elevates a currently-held read pointer into a write +// pointer. This may or may not change the value of the +// pointer. It is only valid to do this if this is the +// only currently-outstanding read pointer on the +// current stage. +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerTrueImpl:: +elevate_read(const CycleData *pointer) { + return (CycleData *)pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::release_write +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// write(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrueImpl:: +release_write(CycleData *pointer) { +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::get_num_stages +// Access: Public +// Description: Returns the number of stages in the pipeline. +//////////////////////////////////////////////////////////////////// +INLINE int PipelineCyclerTrueImpl:: +get_num_stages() { + return _num_stages; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::is_stage_unique +// Access: Public +// Description: Returns true if the nth stage is a different pointer +// than the previous stage, or false if its pointer is +// shared with the previous one. +//////////////////////////////////////////////////////////////////// +INLINE bool PipelineCyclerTrueImpl:: +is_stage_unique(int n) const { + nassertr(n >= 0 && n < _num_stages, false); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::write_stage +// Access: Public +// Description: Returns a pointer suitable for writing to the nth +// stage of the pipeline. This is for special +// applications that need to update the entire pipeline +// at once (for instance, to remove an invalid pointer). +// This pointer should later be released with +// release_write_stage(). +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerTrueImpl:: +write_stage(int n) { + nassertr(n >= 0 && n < _num_stages, (CycleData *)NULL); + return _data[n]._cycle_data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::release_write_stage +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// write_stage(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrueImpl:: +release_write_stage(int n, CycleData *pointer) { + nassertv(n >= 0 && n < _num_stages); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::cheat +// Access: Public +// Description: Returns a pointer without counting it. This is only +// intended for use as the return value for certain +// nassertr() functions, so the application can recover +// after a failure to manage the read and write pointers +// correctly. You should never call this function +// directly. +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerTrueImpl:: +cheat() const { + int pipeline_stage = Thread::get_current_thread()->get_pipeline_stage(); + nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); + return _data[pipeline_stage]._cycle_data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::get_read_count +// Access: Public +// Description: Returns the number of handles currently outstanding +// to read the current stage of the data. This should +// only be used for debugging purposes. +//////////////////////////////////////////////////////////////////// +INLINE int PipelineCyclerTrueImpl:: +get_read_count() const { + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::get_write_count +// Access: Public +// Description: Returns the number of handles currently outstanding +// to read the current stage of the data. This will +// normally only be either 0 or 1. This should only be +// used for debugging purposes. +//////////////////////////////////////////////////////////////////// +INLINE int PipelineCyclerTrueImpl:: +get_write_count() const { + return 0; +} diff --git a/panda/src/putil/pipelineCyclerTrueImpl.cxx b/panda/src/putil/pipelineCyclerTrueImpl.cxx new file mode 100644 index 0000000000..514dfb01d7 --- /dev/null +++ b/panda/src/putil/pipelineCyclerTrueImpl.cxx @@ -0,0 +1,140 @@ +// Filename: pipelineCyclerTrueImpl.cxx +// Created by: drose (31Jan06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "pipelineCyclerTrueImpl.h" + +#if defined(DO_PIPELINING) && defined(HAVE_THREADS) + +#include "pipeline.h" + + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PipelineCyclerTrueImpl:: +PipelineCyclerTrueImpl(CycleData *initial_data, Pipeline *pipeline) : + _pipeline(pipeline) +{ + if (_pipeline == (Pipeline *)NULL) { + _pipeline = Pipeline::get_render_pipeline(); + } + _pipeline->add_cycler(this); + + _num_stages = _pipeline->get_num_stages(); + _data = new StageData[_num_stages]; + for (int i = 0; i < _num_stages; ++i) { + _data[i]._cycle_data = initial_data->make_copy(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PipelineCyclerTrueImpl:: +PipelineCyclerTrueImpl(const PipelineCyclerTrueImpl ©) : + _pipeline(copy._pipeline) +{ + _pipeline->add_cycler(this); + + _num_stages = _pipeline->get_num_stages(); + nassertv(_num_stages == copy._num_stages); + _data = new StageData[_num_stages]; + for (int i = 0; i < _num_stages; ++i) { + _data[i]._cycle_data = copy._data[i]._cycle_data->make_copy(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::Copy Assignment +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void PipelineCyclerTrueImpl:: +operator = (const PipelineCyclerTrueImpl ©) { + nassertv(_num_stages == copy._num_stages); + for (int i = 0; i < _num_stages; ++i) { + _data[i]._cycle_data = copy._data[i]._cycle_data->make_copy(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PipelineCyclerTrueImpl:: +~PipelineCyclerTrueImpl() { + _pipeline->remove_cycler(this); + + delete[] _data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::cycle +// Access: Private +// Description: Cycles the data between frames. This is only called +// from Pipeline::cycle(). +//////////////////////////////////////////////////////////////////// +void PipelineCyclerTrueImpl:: +cycle() { + for (int i = _num_stages - 1; i > 0; --i) { + _data[i] = _data[i - 1]; + } + _data[0]._cycle_data = _data[0]._cycle_data->make_copy(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::set_num_stages +// Access: Private +// Description: Changes the number of stages in the cycler. This is +// only called from Pipeline::set_num_stages(); +//////////////////////////////////////////////////////////////////// +void PipelineCyclerTrueImpl:: +set_num_stages(int num_stages) { + if (num_stages <= _num_stages) { + // Don't bother to reallocate the array. + for (int i = _num_stages; i < num_stages; ++i) { + _data[i]._cycle_data.clear(); + } + + _num_stages = num_stages; + + + } else { + // Increase the array. + StageData *new_data = new StageData[num_stages]; + int i; + for (i = 0; i < _num_stages; ++i) { + new_data[i] = _data[i]; + } + for (i = _num_stages; i < num_stages; ++i) { + new_data[i]._cycle_data = _data[_num_stages - 1]._cycle_data->make_copy(); + } + delete[] _data; + + _num_stages = num_stages; + _data = new_data; + } +} + +#endif // DO_PIPELINING && HAVE_THREADS + diff --git a/panda/src/putil/pipelineCyclerTrueImpl.h b/panda/src/putil/pipelineCyclerTrueImpl.h new file mode 100644 index 0000000000..24c1111986 --- /dev/null +++ b/panda/src/putil/pipelineCyclerTrueImpl.h @@ -0,0 +1,94 @@ +// Filename: pipelineCyclerTrueImpl.h +// Created by: drose (31Jan06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 PIPELINECYCLERTRUEIMPL_H +#define PIPELINECYCLERTRUEIMPL_H + +#include "pandabase.h" + +#if defined(DO_PIPELINING) && defined(HAVE_THREADS) + +#include "cycleData.h" +#include "pointerTo.h" +#include "thread.h" + +class Pipeline; + +//////////////////////////////////////////////////////////////////// +// Class : PipelineCyclerTrueImpl +// Description : This is the true, threaded implementation of +// PipelineCyclerBase. It is only compiled when +// threading is available and DO_PIPELINING is defined. +// +// This implementation is designed to do the actual work +// of cycling the data through a pipeline, and returning +// the actual CycleData appropriate to the current +// thread's pipeline stage. +// +// This is defined as a struct instead of a class, +// mainly to be consistent with +// PipelineCyclerTrivialImpl. +//////////////////////////////////////////////////////////////////// +struct EXPCL_PANDA PipelineCyclerTrueImpl { +public: + PipelineCyclerTrueImpl(CycleData *initial_data, Pipeline *pipeline = NULL); + PipelineCyclerTrueImpl(const PipelineCyclerTrueImpl ©); + void operator = (const PipelineCyclerTrueImpl ©); + ~PipelineCyclerTrueImpl(); + + INLINE const CycleData *read() const; + INLINE void increment_read(const CycleData *pointer) const; + INLINE void release_read(const CycleData *pointer) const; + + INLINE CycleData *write(); + INLINE CycleData *elevate_read(const CycleData *pointer); + INLINE void release_write(CycleData *pointer); + + INLINE int get_num_stages(); + INLINE bool is_stage_unique(int n) const; + INLINE CycleData *write_stage(int n); + INLINE void release_write_stage(int n, CycleData *pointer); + + INLINE CycleData *cheat() const; + INLINE int get_read_count() const; + INLINE int get_write_count() const; + +private: + void cycle(); + void set_num_stages(int num_stages); + +private: + Pipeline *_pipeline; + + class StageData { + public: + PT(CycleData) _cycle_data; + }; + + StageData *_data; + int _num_stages; + + friend class Pipeline; +}; + +#include "pipelineCyclerTrueImpl.I" + +#endif // DO_PIPELINING && HAVE_THREADS + +#endif + diff --git a/panda/src/putil/putil_composite2.cxx b/panda/src/putil/putil_composite2.cxx index 853aa4eefa..ae35a40f52 100644 --- a/panda/src/putil/putil_composite2.cxx +++ b/panda/src/putil/putil_composite2.cxx @@ -6,7 +6,9 @@ #include "nodePointerTo.cxx" #include "pipeline.cxx" #include "pipelineCycler.cxx" -#include "pipelineCyclerBase.cxx" +#include "pipelineCyclerDummyImpl.cxx" +#include "pipelineCyclerTrivialImpl.cxx" +#include "pipelineCyclerTrueImpl.cxx" #include "pta_double.cxx" #include "pta_float.cxx" #include "pta_int.cxx"