From 851eb4cd8b0f51ef11b7d37103f14cb3317b3e3d Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 22 Feb 2006 02:12:08 +0000 Subject: [PATCH] move Pipeline* and Cycle* from putil, in order to pipeline the ClockObject class --- panda/src/express/Sources.pp | 43 +- panda/src/express/clockObject.I | 68 ++- panda/src/express/clockObject.cxx | 77 ++-- panda/src/express/clockObject.h | 40 +- panda/src/express/config_express.cxx | 2 + panda/src/express/config_express.h | 1 - panda/src/express/cycleData.I | 27 ++ panda/src/express/cycleData.cxx | 109 +++++ panda/src/express/cycleData.h | 81 ++++ panda/src/express/cycleDataReader.I | 214 +++++++++ panda/src/express/cycleDataReader.cxx | 19 + panda/src/express/cycleDataReader.h | 67 +++ panda/src/express/cycleDataStageReader.I | 219 +++++++++ panda/src/express/cycleDataStageReader.cxx | 19 + panda/src/express/cycleDataStageReader.h | 61 +++ panda/src/express/cycleDataStageWriter.I | 239 ++++++++++ panda/src/express/cycleDataStageWriter.cxx | 19 + panda/src/express/cycleDataStageWriter.h | 68 +++ panda/src/express/cycleDataWriter.I | 309 +++++++++++++ panda/src/express/cycleDataWriter.cxx | 19 + panda/src/express/cycleDataWriter.h | 71 +++ panda/src/express/cyclerHolder.I | 63 +++ panda/src/express/cyclerHolder.cxx | 19 + panda/src/express/cyclerHolder.h | 48 ++ panda/src/express/express_composite1.cxx | 8 + panda/src/express/express_composite2.cxx | 8 +- panda/src/express/pipeline.I | 84 ++++ panda/src/express/pipeline.cxx | 377 ++++++++++++++++ panda/src/express/pipeline.h | 101 +++++ panda/src/express/pipelineCycler.I | 287 ++++++++++++ panda/src/express/pipelineCycler.cxx | 19 + panda/src/express/pipelineCycler.h | 171 +++++++ panda/src/express/pipelineCyclerBase.h | 52 +++ panda/src/express/pipelineCyclerDummyImpl.I | 420 ++++++++++++++++++ panda/src/express/pipelineCyclerDummyImpl.cxx | 19 + panda/src/express/pipelineCyclerDummyImpl.h | 94 ++++ panda/src/express/pipelineCyclerLinks.I | 83 ++++ panda/src/express/pipelineCyclerLinks.h | 55 +++ panda/src/express/pipelineCyclerTrivialImpl.I | 396 +++++++++++++++++ .../src/express/pipelineCyclerTrivialImpl.cxx | 19 + panda/src/express/pipelineCyclerTrivialImpl.h | 100 +++++ panda/src/express/pipelineCyclerTrueImpl.I | 381 ++++++++++++++++ panda/src/express/pipelineCyclerTrueImpl.cxx | 350 +++++++++++++++ panda/src/express/pipelineCyclerTrueImpl.h | 124 ++++++ 44 files changed, 4998 insertions(+), 52 deletions(-) create mode 100644 panda/src/express/cycleData.I create mode 100644 panda/src/express/cycleData.cxx create mode 100644 panda/src/express/cycleData.h create mode 100644 panda/src/express/cycleDataReader.I create mode 100644 panda/src/express/cycleDataReader.cxx create mode 100644 panda/src/express/cycleDataReader.h create mode 100644 panda/src/express/cycleDataStageReader.I create mode 100644 panda/src/express/cycleDataStageReader.cxx create mode 100644 panda/src/express/cycleDataStageReader.h create mode 100644 panda/src/express/cycleDataStageWriter.I create mode 100644 panda/src/express/cycleDataStageWriter.cxx create mode 100644 panda/src/express/cycleDataStageWriter.h create mode 100644 panda/src/express/cycleDataWriter.I create mode 100644 panda/src/express/cycleDataWriter.cxx create mode 100644 panda/src/express/cycleDataWriter.h create mode 100644 panda/src/express/cyclerHolder.I create mode 100644 panda/src/express/cyclerHolder.cxx create mode 100644 panda/src/express/cyclerHolder.h create mode 100644 panda/src/express/pipeline.I create mode 100644 panda/src/express/pipeline.cxx create mode 100644 panda/src/express/pipeline.h create mode 100644 panda/src/express/pipelineCycler.I create mode 100644 panda/src/express/pipelineCycler.cxx create mode 100644 panda/src/express/pipelineCycler.h create mode 100644 panda/src/express/pipelineCyclerBase.h create mode 100644 panda/src/express/pipelineCyclerDummyImpl.I create mode 100644 panda/src/express/pipelineCyclerDummyImpl.cxx create mode 100644 panda/src/express/pipelineCyclerDummyImpl.h create mode 100644 panda/src/express/pipelineCyclerLinks.I create mode 100644 panda/src/express/pipelineCyclerLinks.h create mode 100644 panda/src/express/pipelineCyclerTrivialImpl.I create mode 100644 panda/src/express/pipelineCyclerTrivialImpl.cxx create mode 100644 panda/src/express/pipelineCyclerTrivialImpl.h create mode 100644 panda/src/express/pipelineCyclerTrueImpl.I create mode 100644 panda/src/express/pipelineCyclerTrueImpl.cxx create mode 100644 panda/src/express/pipelineCyclerTrueImpl.h diff --git a/panda/src/express/Sources.pp b/panda/src/express/Sources.pp index 1c6aaa5670..fcbdbf8ddf 100644 --- a/panda/src/express/Sources.pp +++ b/panda/src/express/Sources.pp @@ -26,6 +26,12 @@ conditionVarPosixImpl.h conditionVarPosixImpl.I \ conditionVarWin32Impl.h conditionVarWin32Impl.I \ config_express.h \ + cycleData.h cycleData.I \ + cycleDataReader.h cycleDataReader.I \ + cycleDataStageReader.h cycleDataStageReader.I \ + cycleDataStageWriter.h cycleDataStageWriter.I \ + cycleDataWriter.h cycleDataWriter.I \ + cyclerHolder.h cyclerHolder.I \ datagram.I datagram.h datagramGenerator.I \ datagramGenerator.h \ datagramIterator.I datagramIterator.h datagramSink.I datagramSink.h \ @@ -52,6 +58,13 @@ ordered_vector.h ordered_vector.I ordered_vector.T \ password_hash.h \ patchfile.I patchfile.h \ + pipeline.h pipeline.I \ + pipelineCycler.h pipelineCycler.I \ + pipelineCyclerLinks.h pipelineCyclerLinks.I \ + pipelineCyclerBase.h \ + pipelineCyclerDummyImpl.h pipelineCyclerDummyImpl.I \ + pipelineCyclerTrivialImpl.h pipelineCyclerTrivialImpl.I \ + pipelineCyclerTrueImpl.h pipelineCyclerTrueImpl.I \ pmutex.h pmutex.I \ pointerTo.I pointerTo.h \ pointerToArray.I pointerToArray.h \ @@ -105,7 +118,14 @@ conditionVarNsprImpl.cxx \ conditionVarPosixImpl.cxx \ conditionVarWin32Impl.cxx \ - config_express.cxx datagram.cxx datagramGenerator.cxx \ + config_express.cxx \ + cycleData.cxx \ + cycleDataReader.cxx \ + cycleDataStageReader.cxx \ + cycleDataStageWriter.cxx \ + cycleDataWriter.cxx \ + cyclerHolder.cxx \ + datagram.cxx datagramGenerator.cxx \ datagramIterator.cxx \ datagramSink.cxx dcast.cxx \ encryptStreamBuf.cxx encryptStream.cxx \ @@ -118,6 +138,11 @@ mutexDebug.cxx \ mutexDirect.cxx \ mutexHolder.cxx \ + pipeline.cxx \ + pipelineCycler.cxx \ + pipelineCyclerDummyImpl.cxx \ + pipelineCyclerTrivialImpl.cxx \ + pipelineCyclerTrueImpl.cxx \ pmutex.cxx \ namable.cxx \ nativeNumericData.cxx \ @@ -176,7 +201,14 @@ conditionVarNsprImpl.h conditionVarNsprImpl.I \ conditionVarPosixImpl.h conditionVarPosixImpl.I \ conditionVarWin32Impl.h conditionVarWin32Impl.I \ - config_express.h datagram.I datagram.h \ + config_express.h \ + cycleData.h cycleData.I \ + cycleDataReader.h cycleDataReader.I \ + cycleDataStageReader.h cycleDataStageReader.I \ + cycleDataStageWriter.h cycleDataStageWriter.I \ + cycleDataWriter.h cycleDataWriter.I \ + cyclerHolder.h cyclerHolder.I \ + datagram.I datagram.h \ datagramGenerator.I datagramGenerator.h \ datagramIterator.I datagramIterator.h \ datagramSink.I datagramSink.h dcast.T dcast.h \ @@ -200,6 +232,13 @@ ordered_vector.h ordered_vector.I ordered_vector.T \ password_hash.h \ patchfile.I patchfile.h \ + pipeline.h pipeline.I \ + pipelineCycler.h pipelineCycler.I \ + pipelineCyclerLinks.h pipelineCyclerLinks.I \ + pipelineCyclerBase.h \ + pipelineCyclerDummyImpl.h pipelineCyclerDummyImpl.I \ + pipelineCyclerTrivialImpl.h pipelineCyclerTrivialImpl.I \ + pipelineCyclerTrueImpl.h pipelineCyclerTrueImpl.I \ pmutex.h pmutex.I \ pointerTo.I pointerTo.h \ pointerToArray.I pointerToArray.h \ diff --git a/panda/src/express/clockObject.I b/panda/src/express/clockObject.I index 221fa96b69..0fdfe60e20 100644 --- a/panda/src/express/clockObject.I +++ b/panda/src/express/clockObject.I @@ -28,13 +28,35 @@ INLINE ClockObject:: //////////////////////////////////////////////////////////////////// // Function: ClockObject::set_mode // Access: Published -// Description: Changes the mode of the clock, e.g. from normal -// (real-time) to non-real-time. In non-real-time mode, -// tick() will add the value of dt to the value returned -// by get_frame_time(), regardless of how much time has -// actually passed. In normal, real-time mode, tick() -// will set the value returned by get_frame_time() to -// the current real time. +// Description: Changes the mode of the clock. Normally, the clock +// is in mode M_normal. In this mode, each call to +// tick() will set the value returned by +// get_frame_time() to the current real time; thus, the +// clock simply reports time advancing. +// +// Other possible modes: +// +// M_non_real_time - the clock ignores real time +// completely; at each call to tick(), it pretends that +// exactly dt seconds have elapsed since the last call +// to tick(). You may set the value of dt with +// set_dt(). +// +// M_forced - the clock forces the application to run at +// the rate specified by set_dt(). If the application +// would run faster than this rate, the clock will slow +// down the application; if the application would run +// slower than this rate, the clock slows down time so +// that the application believes it is running at the +// given rate. +// +// M_degrade - the clock runs at real time, but the +// application is slowed down by a set factor of its +// frame rate, specified by set_degrade_factor(). +// +// M_slave - the clock does not advance, but relies on +// the user to call set_frame_time() and/or +// set_frame_count() each frame. //////////////////////////////////////////////////////////////////// INLINE void ClockObject:: set_mode(ClockObject::Mode mode) { @@ -66,7 +88,8 @@ get_mode() const { //////////////////////////////////////////////////////////////////// INLINE double ClockObject:: get_frame_time() const { - return _reported_frame_time; + CDReader cdata(_cycler); + return cdata->_reported_frame_time; } //////////////////////////////////////////////////////////////////// @@ -130,7 +153,8 @@ reset() { //////////////////////////////////////////////////////////////////// INLINE int ClockObject:: get_frame_count() const { - return _frame_count; + CDReader cdata(_cycler); + return cdata->_frame_count; } //////////////////////////////////////////////////////////////////// @@ -156,10 +180,11 @@ get_net_frame_rate() const { //////////////////////////////////////////////////////////////////// INLINE double ClockObject:: get_dt() const { + CDReader cdata(_cycler); if (_max_dt > 0.0) { - return min(_max_dt, _dt); + return min(_max_dt, cdata->_dt); } - return _dt; + return cdata->_dt; } //////////////////////////////////////////////////////////////////// @@ -172,7 +197,9 @@ get_dt() const { //////////////////////////////////////////////////////////////////// INLINE void ClockObject:: set_dt(double dt) { - _dt = dt; + nassertv(Thread::get_current_pipeline_stage() == 0); + CDWriter cdata(_cycler); + cdata->_dt = dt; } //////////////////////////////////////////////////////////////////// @@ -282,10 +309,11 @@ get_average_frame_rate_interval() const { //////////////////////////////////////////////////////////////////// INLINE double ClockObject:: get_average_frame_rate() const { + CDStageReader cdata(_cycler, 0); if (_ticks.size() <= 1) { return 0.0; } else { - return _ticks.size() / (_reported_frame_time - _ticks.front()); + return _ticks.size() / (cdata->_reported_frame_time - _ticks.front()); } } @@ -301,6 +329,7 @@ get_average_frame_rate() const { //////////////////////////////////////////////////////////////////// INLINE bool ClockObject:: check_errors() { + CDReader cdata(_cycler); // Just to hold a mutex. int orig_error_count = _error_count; _error_count = _true_clock->get_error_count(); return (_error_count != orig_error_count); @@ -321,6 +350,19 @@ get_global_clock() { return _global_clock; } +//////////////////////////////////////////////////////////////////// +// Function: ClockObject::CData::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE ClockObject::CData:: +CData(const ClockObject::CData ©) : + _frame_count(copy._frame_count), + _reported_frame_time(copy._reported_frame_time), + _dt(copy._dt) +{ +} + //////////////////////////////////////////////////////////////////// // Function: TimeVal::contructor // Access: Published diff --git a/panda/src/express/clockObject.cxx b/panda/src/express/clockObject.cxx index 4f4fa60de4..502bb83678 100644 --- a/panda/src/express/clockObject.cxx +++ b/panda/src/express/clockObject.cxx @@ -20,16 +20,10 @@ #include "clockObject.h" #include "config_express.h" #include "configVariableEnum.h" - -#if defined(WIN32) - #define WINDOWS_LEAN_AND_MEAN - #include // For select() - #undef WINDOWS_LEAN_AND_MEAN -#else - #include // For select() -#endif +#include "thread.h" ClockObject *ClockObject::_global_clock = (ClockObject *)NULL; +TypeHandle ClockObject::_type_handle; //////////////////////////////////////////////////////////////////// // Function: ClockObject::Constructor @@ -47,10 +41,7 @@ ClockObject() { _start_short_time = _true_clock->get_short_time(); _start_long_time = _true_clock->get_long_time(); - _frame_count = 0; _actual_frame_time = 0.0; - _reported_frame_time = 0.0; - _dt = 1.0 / clock_frame_rate; _max_dt = max_dt; _degrade_factor = clock_degrade_factor; _average_frame_rate_interval = average_frame_rate_interval; @@ -91,6 +82,7 @@ set_real_time(double time) { //////////////////////////////////////////////////////////////////// void ClockObject:: set_frame_time(double time) { + nassertv(Thread::get_current_pipeline_stage() == 0); #ifdef NOTIFY_DEBUG if (this == _global_clock && _mode != M_slave) { express_cat.warning() @@ -98,8 +90,9 @@ set_frame_time(double time) { << " seconds.\n"; } #endif // NOTIFY_DEBUG + CDWriter cdata(_cycler); _actual_frame_time = time; - _reported_frame_time = time; + cdata->_reported_frame_time = time; } //////////////////////////////////////////////////////////////////// @@ -111,6 +104,7 @@ set_frame_time(double time) { //////////////////////////////////////////////////////////////////// void ClockObject:: set_frame_count(int frame_count) { + nassertv(Thread::get_current_pipeline_stage() == 0); #ifdef NOTIFY_DEBUG if (this == _global_clock && _mode != M_slave) { express_cat.warning() @@ -118,7 +112,8 @@ set_frame_count(int frame_count) { << frame_count - get_frame_count() << " frames.\n"; } #endif // NOTIFY_DEBUG - _frame_count = frame_count; + CDWriter cdata(_cycler); + cdata->_frame_count = frame_count; } //////////////////////////////////////////////////////////////////// @@ -133,7 +128,9 @@ set_frame_count(int frame_count) { //////////////////////////////////////////////////////////////////// void ClockObject:: tick() { - double old_reported_time = _reported_frame_time; + nassertv(Thread::get_current_pipeline_stage() == 0); + CDWriter cdata(_cycler); + double old_reported_time = cdata->_reported_frame_time; if (_mode != M_slave) { double old_time = _actual_frame_time; @@ -142,39 +139,39 @@ tick() { switch (_mode) { case M_normal: // Time runs as it will; we simply report time elapsing. - _dt = _actual_frame_time - old_time; - _reported_frame_time = _actual_frame_time; + cdata->_dt = _actual_frame_time - old_time; + cdata->_reported_frame_time = _actual_frame_time; break; case M_non_real_time: // Ignore real time. We always report the same interval having // elapsed each frame. - _reported_frame_time += _dt; + cdata->_reported_frame_time += cdata->_dt; break; case M_forced: // If we are running faster than the desired interval, slow down. // If we are running slower than the desired interval, ignore that // and pretend we're running at the specified rate. - wait_until(old_time + _dt); - _reported_frame_time += _dt; + wait_until(old_time + cdata->_dt); + cdata->_reported_frame_time += cdata->_dt; break; case M_degrade: // Each frame, wait a certain fraction of the previous frame's // time to degrade performance uniformly. - _dt = (_actual_frame_time - old_time) * _degrade_factor; + cdata->_dt = (_actual_frame_time - old_time) * _degrade_factor; if (_degrade_factor < 1.0) { // If the degrade_factor is less than one, we want to simulate a // higher frame rate by incrementing the clock more slowly. - _reported_frame_time += _dt; + cdata->_reported_frame_time += cdata->_dt; } else { // Otherwise, we simulate a lower frame rate by waiting until // the appropriate time has elapsed. - wait_until(old_time + _dt); - _reported_frame_time = _actual_frame_time; + wait_until(old_time + cdata->_dt); + cdata->_reported_frame_time = _actual_frame_time; } break; @@ -184,13 +181,13 @@ tick() { break; } - _frame_count++; + cdata->_frame_count++; } if (_average_frame_rate_interval > 0.0) { _ticks.push_back(old_reported_time); while (!_ticks.empty() && - _reported_frame_time - _ticks.front() > _average_frame_rate_interval) { + cdata->_reported_frame_time - _ticks.front() > _average_frame_rate_interval) { _ticks.pop_front(); } } @@ -213,7 +210,8 @@ tick() { void ClockObject:: sync_frame_time() { if (_mode == M_normal) { - _reported_frame_time = get_real_time(); + CDWriter cdata(_cycler); + cdata->_reported_frame_time = get_real_time(); } } @@ -229,10 +227,7 @@ wait_until(double want_time) { double wait_interval = (want_time - _actual_frame_time) - sleep_precision; if (wait_interval > 0.0) { - struct timeval tv; - tv.tv_sec = (int)(wait_interval); - tv.tv_usec = (int)((wait_interval - tv.tv_sec) * 1000000.0); - select(0, NULL, NULL, NULL, &tv); + Thread::sleep(wait_interval); } // Now busy-wait until the actual time elapses. @@ -262,6 +257,28 @@ make_global_clock() { _global_clock->set_mode(clock_mode); } +//////////////////////////////////////////////////////////////////// +// Function: ClockObject::CData::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +ClockObject::CData:: +CData() { + _frame_count = 0; + _reported_frame_time = 0.0; + _dt = 1.0 / clock_frame_rate; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClockObject::CData::make_copy +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +CycleData *ClockObject::CData:: +make_copy() const { + return new CData(*this); +} + //////////////////////////////////////////////////////////////////// // Function: ClockObject::Mode ostream operator // Description: diff --git a/panda/src/express/clockObject.h b/panda/src/express/clockObject.h index 1c75c384b1..39a12211b9 100644 --- a/panda/src/express/clockObject.h +++ b/panda/src/express/clockObject.h @@ -23,6 +23,11 @@ #include "trueClock.h" #include "pdeque.h" +#include "cycleData.h" +#include "cycleDataReader.h" +#include "cycleDataWriter.h" +#include "cycleDataStageReader.h" +#include "pipelineCycler.h" class EXPCL_PANDAEXPRESS TimeVal { PUBLISHED: @@ -113,10 +118,7 @@ private: Mode _mode; double _start_short_time; double _start_long_time; - int _frame_count; double _actual_frame_time; - double _reported_frame_time; - double _dt; double _max_dt; double _degrade_factor; int _error_count; @@ -127,7 +129,39 @@ private: typedef pdeque Ticks; Ticks _ticks; + // This is the data that needs to be cycled each frame. + class EXPCL_PANDAEXPRESS CData : public CycleData { + public: + CData(); + INLINE CData(const CData ©); + + virtual CycleData *make_copy() const; + virtual TypeHandle get_parent_type() const { + return ClockObject::get_class_type(); + } + + int _frame_count; + double _reported_frame_time; + double _dt; + }; + + PipelineCycler _cycler; + typedef CycleDataReader CDReader; + typedef CycleDataWriter CDWriter; + typedef CycleDataStageReader CDStageReader; + static ClockObject *_global_clock; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + register_type(_type_handle, "ClockObject"); + } + +private: + static TypeHandle _type_handle; }; EXPCL_PANDAEXPRESS ostream & diff --git a/panda/src/express/config_express.cxx b/panda/src/express/config_express.cxx index 56ce275e7a..419b76ad7d 100644 --- a/panda/src/express/config_express.cxx +++ b/panda/src/express/config_express.cxx @@ -18,6 +18,7 @@ #include "config_express.h" +#include "clockObject.h" #include "datagram.h" #include "mainThread.h" #include "externalThread.h" @@ -168,6 +169,7 @@ init_libexpress() { } initialized = true; + ClockObject::init_type(); Datagram::init_type(); MainThread::init_type(); ExternalThread::init_type(); diff --git a/panda/src/express/config_express.h b/panda/src/express/config_express.h index a416b25148..1752ba2591 100644 --- a/panda/src/express/config_express.h +++ b/panda/src/express/config_express.h @@ -21,7 +21,6 @@ #include "pandabase.h" #include "notifyCategoryProxy.h" -#include "clockObject.h" #include "dconfig.h" // We include these files to force them to be instrumented by diff --git a/panda/src/express/cycleData.I b/panda/src/express/cycleData.I new file mode 100644 index 0000000000..010cd01080 --- /dev/null +++ b/panda/src/express/cycleData.I @@ -0,0 +1,27 @@ +// Filename: cycleData.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 . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: CycleData::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE CycleData:: +CycleData() { +} diff --git a/panda/src/express/cycleData.cxx b/panda/src/express/cycleData.cxx new file mode 100644 index 0000000000..5eda716b0d --- /dev/null +++ b/panda/src/express/cycleData.cxx @@ -0,0 +1,109 @@ +// Filename: cycleData.cxx +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#include "cycleData.h" + + +//////////////////////////////////////////////////////////////////// +// Function: CycleData::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +CycleData:: +~CycleData() { +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleData::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void CycleData:: +write_datagram(BamWriter *, Datagram &) const { +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleData::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void CycleData:: +write_datagram(BamWriter *, Datagram &, void *) const { +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleData::complete_pointers +// Access: Public, Virtual +// Description: Receives an array of pointers, one for each time +// manager->read_pointer() was called in fillin(). +// Returns the number of pointers processed. +//////////////////////////////////////////////////////////////////// +int CycleData:: +complete_pointers(TypedWritable **, BamReader *) { + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleData::fillin +// Access: Public, Virtual +// Description: This internal function is intended to be called by +// each class's make_from_bam() method to read in all of +// the relevant data from the BamFile for the new +// object. +//////////////////////////////////////////////////////////////////// +void CycleData:: +fillin(DatagramIterator &, BamReader *) { +} + + +//////////////////////////////////////////////////////////////////// +// Function: CycleData::fillin +// Access: Public, Virtual +// Description: This internal function is intended to be called by +// each class's make_from_bam() method to read in all of +// the relevant data from the BamFile for the new +// object. +//////////////////////////////////////////////////////////////////// +void CycleData:: +fillin(DatagramIterator &, BamReader *, void *) { +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleData::get_parent_type +// Access: Public, Virtual +// Description: Returns the type of the container that owns the +// CycleData. This is useful mainly for debugging. +//////////////////////////////////////////////////////////////////// +TypeHandle CycleData:: +get_parent_type() const { + return TypeHandle::none(); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleData::output +// Access: Public, Virtual +// Description: Formats the contents of the CycleData in some +// meaningful way for humans. This is useful mainly for +// debugging. +//////////////////////////////////////////////////////////////////// +void CycleData:: +output(ostream &out) const { + out << get_parent_type() << "::CData"; +} diff --git a/panda/src/express/cycleData.h b/panda/src/express/cycleData.h new file mode 100644 index 0000000000..47c9f91b6f --- /dev/null +++ b/panda/src/express/cycleData.h @@ -0,0 +1,81 @@ +// Filename: cycleData.h +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CYCLEDATA_H +#define CYCLEDATA_H + +#include "pandabase.h" +#include "typeHandle.h" +#include "referenceCount.h" + +class BamWriter; +class BamReader; +class TypedWritable; +class Datagram; +class DatagramIterator; + +//////////////////////////////////////////////////////////////////// +// Class : CycleData +// Description : A single page of data maintained by a PipelineCycler. +// Normally you should inherit from this class to define +// the data structures that are important to protect +// between stages of a pipeline. See PipelineCycler. +//////////////////////////////////////////////////////////////////// +#ifdef DO_PIPELINING + +// If we are compiling in pipelining support, we maintain a pointer to +// a CycleData object in each containing class, instead of the object +// itself. Thus, it should be a ReferenceCount object. +class EXPCL_PANDAEXPRESS CycleData : public ReferenceCount + +#else // !DO_PIPELINING + +// If we are *not* compiling in pipelining support, the CycleData +// object is stored directly within its containing classes, and hence +// should not be a ReferenceCount object. +class EXPCL_PANDAEXPRESS CycleData + +#endif // DO_PIPELINING +{ +public: + INLINE CycleData(); + virtual ~CycleData(); + + virtual CycleData *make_copy() const=0; + + virtual void write_datagram(BamWriter *, Datagram &) const; + virtual void write_datagram(BamWriter *, Datagram &, void *extra_data) const; + virtual int complete_pointers(TypedWritable **p_list, BamReader *manager); + virtual void fillin(DatagramIterator &scan, BamReader *manager); + virtual void fillin(DatagramIterator &scan, BamReader *manager, + void *extra_data); + + virtual TypeHandle get_parent_type() const; + virtual void output(ostream &out) const; +}; + +INLINE ostream & +operator << (ostream &out, const CycleData &cd) { + cd.output(out); + return out; +} + +#include "cycleData.I" + +#endif + diff --git a/panda/src/express/cycleDataReader.I b/panda/src/express/cycleDataReader.I new file mode 100644 index 0000000000..91c4abc4cf --- /dev/null +++ b/panda/src/express/cycleDataReader.I @@ -0,0 +1,214 @@ +// Filename: cycleDataReader.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 +// This is the implementation for full support of pipelining (as well +// as the sanity-check only implementation). + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::Constructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataReader:: +CycleDataReader(const PipelineCycler &cycler) : + _cycler(&cycler) +{ + _pointer = _cycler->read(); + nassertv(_pointer != (const CycleDataType *)NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::Copy Constructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataReader:: +CycleDataReader(const CycleDataReader ©) : + _cycler(copy._cycler), + _pointer(copy._pointer) +{ + nassertv(_pointer != (const CycleDataType *)NULL); + _cycler->increment_read(_pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::Copy Assignment (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE void CycleDataReader:: +operator = (const CycleDataReader ©) { + nassertv(_pointer == (CycleDataType *)NULL); + + _cycler = copy._cycler; + _pointer = copy._pointer; + + nassertv(_pointer != (const CycleDataType *)NULL); + _cycler->increment_read(_pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::Destructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataReader:: +~CycleDataReader() { + if (_pointer != NULL) { + _cycler->release_read(_pointer); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::operator -> (full) +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataReader:: +operator -> () const { + nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat()); + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::Typecast pointer (full) +// Access: Public +// Description: This allows the CycleDataReader to be passed to any +// function that expects a const CycleDataType pointer. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataReader:: +operator const CycleDataType * () const { + nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat()); + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::take_pointer (full) +// Access: Public +// Description: This is intended to be called only from +// CycleDataWriter when it elevates the pointer from +// read to write status. This function returns the +// reader's pointer and relinquishes ownership of the +// pointer, rendering the reader invalid for future +// reads. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataReader:: +take_pointer() { + const CycleDataType *pointer = _pointer; + _pointer = (CycleDataType *)NULL; + nassertr(pointer != (const CycleDataType *)NULL, _cycler->cheat()); + return pointer; +} + +#else // !DO_PIPELINING +// This is the trivial, do-nothing implementation. + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::Constructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataReader:: +CycleDataReader(const PipelineCycler &cycler) { + _pointer = cycler.read(); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::Copy Constructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataReader:: +CycleDataReader(const CycleDataReader ©) : + _pointer(copy._pointer) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::Copy Assignment (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE void CycleDataReader:: +operator = (const CycleDataReader ©) { + _pointer = copy._pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::Destructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataReader:: +~CycleDataReader() { +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::operator -> (trivial) +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataReader:: +operator -> () const { + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::Typecast pointer (trivial) +// Access: Public +// Description: This allows the CycleDataReader to be passed to any +// function that expects a const CycleDataType pointer. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataReader:: +operator const CycleDataType * () const { + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataReader::take_pointer (trivial) +// Access: Public +// Description: This is intended to be called only from +// CycleDataWriter when it elevates the pointer from +// read to write status. This function returns the +// reader's pointer and relinquishes ownership of the +// pointer, rendering the reader invalid for future +// reads. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataReader:: +take_pointer() { + return _pointer; +} + +#endif // DO_PIPELINING diff --git a/panda/src/express/cycleDataReader.cxx b/panda/src/express/cycleDataReader.cxx new file mode 100644 index 0000000000..7a1528823f --- /dev/null +++ b/panda/src/express/cycleDataReader.cxx @@ -0,0 +1,19 @@ +// Filename: cycleDataReader.cxx +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#include "cycleDataReader.h" diff --git a/panda/src/express/cycleDataReader.h b/panda/src/express/cycleDataReader.h new file mode 100644 index 0000000000..cbfae4d1c3 --- /dev/null +++ b/panda/src/express/cycleDataReader.h @@ -0,0 +1,67 @@ +// Filename: cycleDataReader.h +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CYCLEDATAREADER_H +#define CYCLEDATAREADER_H + +#include "pandabase.h" + +#include "cycleData.h" +#include "pipelineCycler.h" + +//////////////////////////////////////////////////////////////////// +// Class : CycleDataReader +// Description : This template class calls PipelineCycler::read() in +// the constructor and PipelineCycler::release_read() in +// the destructor. In the interim, it provides a +// transparent read-only access to the CycleData. +// +// It exists as a syntactic convenience to access the +// data in the CycleData. It also allows the whole +// system to compile down to nothing if +// SUPPORT_PIPELINING is not defined. +//////////////////////////////////////////////////////////////////// +template +class CycleDataReader { +public: + INLINE CycleDataReader(const PipelineCycler &cycler); + INLINE CycleDataReader(const CycleDataReader ©); + INLINE void operator = (const CycleDataReader ©); + + INLINE ~CycleDataReader(); + + INLINE const CycleDataType *operator -> () const; + INLINE operator const CycleDataType * () const; + + INLINE const CycleDataType *take_pointer(); + +private: +#ifdef DO_PIPELINING + // This is the data stored for a real pipelining implementation. + const PipelineCycler *_cycler; + const CycleDataType *_pointer; + CycleDataType *_write_pointer; +#else // !DO_PIPELINING + // This is all we need for the trivial, do-nothing implementation. + const CycleDataType *_pointer; +#endif // DO_PIPELINING +}; + +#include "cycleDataReader.I" + +#endif diff --git a/panda/src/express/cycleDataStageReader.I b/panda/src/express/cycleDataStageReader.I new file mode 100644 index 0000000000..9f28525980 --- /dev/null +++ b/panda/src/express/cycleDataStageReader.I @@ -0,0 +1,219 @@ +// Filename: cycleDataStageReader.I +// Created by: drose (08Feb06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +#ifdef DO_PIPELINING +// This is the implementation for full support of pipelining (as well +// as the sanity-check only implementation). + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageReader::Constructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageReader:: +CycleDataStageReader(const PipelineCycler &cycler, + int stage) : + _cycler(&cycler), + _stage(stage) +{ + _pointer = _cycler->read_stage(_stage); + nassertv(_pointer != (const CycleDataType *)NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageReader::Copy Constructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageReader:: +CycleDataStageReader(const CycleDataStageReader ©) : + _cycler(copy._cycler), + _pointer(copy._pointer), + _stage(copy._stage) +{ + nassertv(_pointer != (const CycleDataType *)NULL); + _cycler->increment_read(_pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageReader::Copy Assignment (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE void CycleDataStageReader:: +operator = (const CycleDataStageReader ©) { + nassertv(_pointer == (CycleDataType *)NULL); + + _cycler = copy._cycler; + _pointer = copy._pointer; + _stage = copy._stage; + + nassertv(_pointer != (const CycleDataType *)NULL); + _cycler->increment_read(_pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageReader::Destructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageReader:: +~CycleDataStageReader() { + if (_pointer != NULL) { + _cycler->release_read_stage(_stage, _pointer); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageReader::operator -> (full) +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataStageReader:: +operator -> () const { + nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat()); + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageReader::Typecast pointer (full) +// Access: Public +// Description: This allows the CycleDataStageReader to be passed to any +// function that expects a const CycleDataType pointer. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageReader:: +operator const CycleDataType * () const { + nassertr(_pointer != (const CycleDataType *)NULL, _cycler->cheat()); + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageReader::take_pointer (full) +// Access: Public +// Description: This is intended to be called only from +// CycleDataStageWriter when it elevates the pointer from +// read to write status. This function returns the +// reader's pointer and relinquishes ownership of the +// pointer, rendering the reader invalid for future +// reads. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataStageReader:: +take_pointer() { + const CycleDataType *pointer = _pointer; + _pointer = (CycleDataType *)NULL; + nassertr(pointer != (const CycleDataType *)NULL, _cycler->cheat()); + return pointer; +} + +#else // !DO_PIPELINING +// This is the trivial, do-nothing implementation. + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageReader::Constructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageReader:: +CycleDataStageReader(const PipelineCycler &cycler, int) { + _pointer = cycler.read(); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageReader::Copy Constructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageReader:: +CycleDataStageReader(const CycleDataStageReader ©) : + _pointer(copy._pointer) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageReader::Copy Assignment (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE void CycleDataStageReader:: +operator = (const CycleDataStageReader ©) { + _pointer = copy._pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageReader::Destructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageReader:: +~CycleDataStageReader() { +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageReader::operator -> (trivial) +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataStageReader:: +operator -> () const { + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageReader::Typecast pointer (trivial) +// Access: Public +// Description: This allows the CycleDataStageReader to be passed to any +// function that expects a const CycleDataType pointer. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageReader:: +operator const CycleDataType * () const { + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageReader::take_pointer (trivial) +// Access: Public +// Description: This is intended to be called only from +// CycleDataStageWriter when it elevates the pointer from +// read to write status. This function returns the +// reader's pointer and relinquishes ownership of the +// pointer, rendering the reader invalid for future +// reads. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataStageReader:: +take_pointer() { + return _pointer; +} + +#endif // DO_PIPELINING diff --git a/panda/src/express/cycleDataStageReader.cxx b/panda/src/express/cycleDataStageReader.cxx new file mode 100644 index 0000000000..0533924bf5 --- /dev/null +++ b/panda/src/express/cycleDataStageReader.cxx @@ -0,0 +1,19 @@ +// Filename: cycleDataStageReader.cxx +// Created by: drose (08Feb06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "cycleDataStageReader.h" diff --git a/panda/src/express/cycleDataStageReader.h b/panda/src/express/cycleDataStageReader.h new file mode 100644 index 0000000000..3bb320601c --- /dev/null +++ b/panda/src/express/cycleDataStageReader.h @@ -0,0 +1,61 @@ +// Filename: cycleDataStageReader.h +// Created by: drose (08Feb06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 CYCLEDATASTAGEREADER_H +#define CYCLEDATASTAGEREADER_H + +#include "pandabase.h" + +#include "cycleData.h" +#include "pipelineCycler.h" + +//////////////////////////////////////////////////////////////////// +// Class : CycleDataStageReader +// Description : This class is similar to CycleDataReader, except it +// allows reading from a particular stage of the +// pipeline. +//////////////////////////////////////////////////////////////////// +template +class CycleDataStageReader { +public: + INLINE CycleDataStageReader(const PipelineCycler &cycler, int stage); + INLINE CycleDataStageReader(const CycleDataStageReader ©); + INLINE void operator = (const CycleDataStageReader ©); + + INLINE ~CycleDataStageReader(); + + INLINE const CycleDataType *operator -> () const; + INLINE operator const CycleDataType * () const; + + INLINE const CycleDataType *take_pointer(); + +private: +#ifdef DO_PIPELINING + // This is the data stored for a real pipelining implementation. + const PipelineCycler *_cycler; + const CycleDataType *_pointer; + int _stage; +#else // !DO_PIPELINING + // This is all we need for the trivial, do-nothing implementation. + const CycleDataType *_pointer; +#endif // DO_PIPELINING +}; + +#include "cycleDataStageReader.I" + +#endif diff --git a/panda/src/express/cycleDataStageWriter.I b/panda/src/express/cycleDataStageWriter.I new file mode 100644 index 0000000000..ea5afa00af --- /dev/null +++ b/panda/src/express/cycleDataStageWriter.I @@ -0,0 +1,239 @@ +// Filename: cycleDataStageWriter.I +// Created by: drose (06Feb06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifdef DO_PIPELINING +// This is the implementation for full support of pipelining (as well +// as the sanity-check only implementation). + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageWriter::Constructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageWriter:: +CycleDataStageWriter(PipelineCycler &cycler, int stage) : + _cycler(&cycler), + _stage(stage) +{ + _pointer = _cycler->write_stage(_stage); + nassertv(_pointer != (CycleDataType *)NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageWriter::Copy Constructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageWriter:: +CycleDataStageWriter(const CycleDataStageWriter ©) : + _cycler(copy._cycler), + _pointer(copy._pointer), + _stage(copy._stage) +{ + nassertv(_pointer != (CycleDataType *)NULL); + _cycler->increment_write(_pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageWriter::Copy Assigment (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE void CycleDataStageWriter:: +operator = (const CycleDataStageWriter ©) { + nassertv(_pointer == (CycleDataType *)NULL); + + _cycler = copy._cycler; + _pointer = copy._pointer; + _stage = copy._stage; + + nassertv(_pointer != (CycleDataType *)NULL); + _cycler->increment_write(_pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageWriter::Constructor (full) +// Access: Public +// Description: This flavor of the constructor elevates the pointer +// from the CycleDataStageReader from a read to a write +// pointer (and invalidates the reader). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageWriter:: +CycleDataStageWriter(PipelineCycler &cycler, int stage, + CycleDataStageReader &take_from) : + _cycler(&cycler), + _stage(stage) +{ + _pointer = _cycler->elevate_read_stage(_stage, take_from.take_pointer()); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageWriter::Destructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageWriter:: +~CycleDataStageWriter() { + if (_pointer != (CycleDataType *)NULL) { + _cycler->release_write_stage(_stage, _pointer); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageWriter::operator -> (full) +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *CycleDataStageWriter:: +operator -> () { + nassertr(_pointer != (CycleDataType *)NULL, _cycler->cheat()); + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageWriter::operator -> (full) +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataStageWriter:: +operator -> () const { + nassertr(_pointer != (CycleDataType *)NULL, _cycler->cheat()); + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageWriter::Typecast pointer (full) +// Access: Public +// Description: This allows the CycleDataStageWriter to be passed to any +// function that expects a CycleDataType pointer. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageWriter:: +operator CycleDataType * () { + nassertr(_pointer != (CycleDataType *)NULL, _cycler->cheat()); + return _pointer; +} + +#else // !DO_PIPELINING +// This is the trivial, do-nothing implementation. + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageWriter::Constructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageWriter:: +CycleDataStageWriter(PipelineCycler &cycler, int) { + _pointer = cycler.write(); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageWriter::Copy Constructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageWriter:: +CycleDataStageWriter(const CycleDataStageWriter ©) : + _pointer(copy._pointer) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageWriter::Copy Assigment (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE void CycleDataStageWriter:: +operator = (const CycleDataStageWriter ©) { + _pointer = copy._pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageWriter::Constructor (trivial) +// Access: Public +// Description: This flavor of the constructor elevates the pointer +// from the CycleDataStageReader from a read to a write +// pointer (and invalidates the reader). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageWriter:: +CycleDataStageWriter(PipelineCycler &, int, + CycleDataStageReader &take_from) : + _pointer((CycleDataType *)take_from.take_pointer()) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageWriter::Destructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageWriter:: +~CycleDataStageWriter() { +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageWriter::operator -> (trivial) +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *CycleDataStageWriter:: +operator -> () { + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageWriter::operator -> (trivial) +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataStageWriter:: +operator -> () const { + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataStageWriter::Typecast pointer (trivial) +// Access: Public +// Description: This allows the CycleDataStageWriter to be passed to any +// function that expects a CycleDataType pointer. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataStageWriter:: +operator CycleDataType * () { + return _pointer; +} + +#endif // DO_PIPELINING diff --git a/panda/src/express/cycleDataStageWriter.cxx b/panda/src/express/cycleDataStageWriter.cxx new file mode 100644 index 0000000000..8b6506a32e --- /dev/null +++ b/panda/src/express/cycleDataStageWriter.cxx @@ -0,0 +1,19 @@ +// Filename: cycleDataStageWriter.cxx +// Created by: drose (06Feb06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "cycleDataStageWriter.h" diff --git a/panda/src/express/cycleDataStageWriter.h b/panda/src/express/cycleDataStageWriter.h new file mode 100644 index 0000000000..ccff660b86 --- /dev/null +++ b/panda/src/express/cycleDataStageWriter.h @@ -0,0 +1,68 @@ +// Filename: cycleDataStageWriter.h +// Created by: drose (06Feb06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 CYCLEDATASTAGEWRITER_H +#define CYCLEDATASTAGEWRITER_H + +#include "pandabase.h" + +#include "cycleData.h" +#include "pipelineCycler.h" +#include "cycleDataStageReader.h" + +//////////////////////////////////////////////////////////////////// +// Class : CycleDataStageWriter +// Description : This class is similar to CycleDataWriter, except it +// allows writing to a particular stage of the pipeline. +// Usually this is used to implement writing directly to +// an upstream pipeline value, to recompute a cached +// value there (otherwise, the cached value would go +// away with the next pipeline cycle). +//////////////////////////////////////////////////////////////////// +template +class CycleDataStageWriter { +public: + INLINE CycleDataStageWriter(PipelineCycler &cycler, int stage); + INLINE CycleDataStageWriter(const CycleDataStageWriter ©); + INLINE void operator = (const CycleDataStageWriter ©); + + INLINE CycleDataStageWriter(PipelineCycler &cycler, int stage, + CycleDataStageReader &take_from); + + INLINE ~CycleDataStageWriter(); + + INLINE CycleDataType *operator -> (); + INLINE const CycleDataType *operator -> () const; + + INLINE operator CycleDataType * (); + +private: +#ifdef DO_PIPELINING + // This is the data stored for a real pipelining implementation. + PipelineCycler *_cycler; + CycleDataType *_pointer; + int _stage; +#else // !DO_PIPELINING + // This is all we need for the trivial, do-nothing implementation. + CycleDataType *_pointer; +#endif // DO_PIPELINING +}; + +#include "cycleDataStageWriter.I" + +#endif diff --git a/panda/src/express/cycleDataWriter.I b/panda/src/express/cycleDataWriter.I new file mode 100644 index 0000000000..d33b9db49f --- /dev/null +++ b/panda/src/express/cycleDataWriter.I @@ -0,0 +1,309 @@ +// Filename: cycleDataWriter.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 +// This is the implementation for full support of pipelining (as well +// as the sanity-check only implementation). + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Constructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +CycleDataWriter(PipelineCycler &cycler) : + _cycler(&cycler) +{ + _pointer = _cycler->write(); + nassertv(_pointer != (CycleDataType *)NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Constructor (full) +// Access: Public +// Description: This two-parameter constructor, with a bool parameter +// for the second parameter, automatically propagates +// the CycleData pointer upstream from the current +// stage, either stopping at the first pointer +// encountered that's different, going or all the way to +// stage 0, according to force_to_0. See +// PipelineCycler::write_upstream(). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +CycleDataWriter(PipelineCycler &cycler, bool force_to_0) : + _cycler(&cycler) +{ + _pointer = _cycler->write_upstream(force_to_0); + nassertv(_pointer != (CycleDataType *)NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Copy Constructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +CycleDataWriter(const CycleDataWriter ©) : + _cycler(copy._cycler), + _pointer(copy._pointer) +{ + nassertv(_pointer != (CycleDataType *)NULL); + _cycler->increment_write(_pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Copy Assigment (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE void CycleDataWriter:: +operator = (const CycleDataWriter ©) { + nassertv(_pointer == (CycleDataType *)NULL); + + _cycler = copy._cycler; + _pointer = copy._pointer; + + nassertv(_pointer != (CycleDataType *)NULL); + _cycler->increment_write(_pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Constructor (full) +// Access: Public +// Description: This flavor of the constructor elevates the pointer +// from the CycleDataReader from a read to a write +// pointer (and invalidates the reader). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +CycleDataWriter(PipelineCycler &cycler, + CycleDataReader &take_from) : + _cycler(&cycler) +{ + _pointer = _cycler->elevate_read(take_from.take_pointer()); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Constructor (full) +// Access: Public +// Description: This flavor of the constructor elevates the pointer +// from the CycleDataReader from a read to a write +// pointer (and invalidates the reader). It also +// propagates the pointer back upstream; see +// PipelineCycler::write_upstream(). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +CycleDataWriter(PipelineCycler &cycler, + CycleDataReader &take_from, + bool force_to_0) : + _cycler(&cycler) +{ + _pointer = _cycler->elevate_read_upstream(take_from.take_pointer(), force_to_0); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Destructor (full) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +~CycleDataWriter() { + if (_pointer != (CycleDataType *)NULL) { + _cycler->release_write(_pointer); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::operator -> (full) +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *CycleDataWriter:: +operator -> () { + nassertr(_pointer != (CycleDataType *)NULL, _cycler->cheat()); + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::operator -> (full) +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataWriter:: +operator -> () const { + nassertr(_pointer != (CycleDataType *)NULL, _cycler->cheat()); + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Typecast pointer (full) +// Access: Public +// Description: This allows the CycleDataWriter to be passed to any +// function that expects a CycleDataType pointer. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +operator CycleDataType * () { + nassertr(_pointer != (CycleDataType *)NULL, _cycler->cheat()); + return _pointer; +} + +#else // !DO_PIPELINING +// This is the trivial, do-nothing implementation. + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Constructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +CycleDataWriter(PipelineCycler &cycler) { + _pointer = cycler.write(); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Constructor (full) +// Access: Public +// Description: This two-parameter constructor, with a bool parameter +// for the second parameter, automatically propagates +// the CycleData pointer upstream from the current +// stage, either stopping at the first pointer +// encountered that's different, going or all the way to +// stage 0, according to force_to_0. See +// PipelineCycler::write_upstream(). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +CycleDataWriter(PipelineCycler &cycler, bool) { + _pointer = cycler.write(); +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Copy Constructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +CycleDataWriter(const CycleDataWriter ©) : + _pointer(copy._pointer) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Copy Assigment (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE void CycleDataWriter:: +operator = (const CycleDataWriter ©) { + _pointer = copy._pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Constructor (trivial) +// Access: Public +// Description: This flavor of the constructor elevates the pointer +// from the CycleDataReader from a read to a write +// pointer (and invalidates the reader). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +CycleDataWriter(PipelineCycler &, + CycleDataReader &take_from) : + _pointer((CycleDataType *)take_from.take_pointer()) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Constructor (trivial) +// Access: Public +// Description: This flavor of the constructor elevates the pointer +// from the CycleDataReader from a read to a write +// pointer (and invalidates the reader). It also +// propagates the pointer back upstream; see +// PipelineCycler::write_upstream(). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +CycleDataWriter(PipelineCycler &, + CycleDataReader &take_from, + bool force_to_0) : + _pointer((CycleDataType *)take_from.take_pointer()) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Destructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +~CycleDataWriter() { +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::operator -> (trivial) +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *CycleDataWriter:: +operator -> () { + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::operator -> (trivial) +// Access: Public +// Description: This provides an indirect member access to the actual +// CycleData data. +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *CycleDataWriter:: +operator -> () const { + return _pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: CycleDataWriter::Typecast pointer (trivial) +// Access: Public +// Description: This allows the CycleDataWriter to be passed to any +// function that expects a CycleDataType pointer. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataWriter:: +operator CycleDataType * () { + return _pointer; +} + +#endif // DO_PIPELINING diff --git a/panda/src/express/cycleDataWriter.cxx b/panda/src/express/cycleDataWriter.cxx new file mode 100644 index 0000000000..49c4bed5c4 --- /dev/null +++ b/panda/src/express/cycleDataWriter.cxx @@ -0,0 +1,19 @@ +// Filename: cycleDataWriter.cxx +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#include "cycleDataWriter.h" diff --git a/panda/src/express/cycleDataWriter.h b/panda/src/express/cycleDataWriter.h new file mode 100644 index 0000000000..fbddff3101 --- /dev/null +++ b/panda/src/express/cycleDataWriter.h @@ -0,0 +1,71 @@ +// Filename: cycleDataWriter.h +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CYCLEDATAWRITER_H +#define CYCLEDATAWRITER_H + +#include "pandabase.h" + +#include "cycleData.h" +#include "pipelineCycler.h" +#include "cycleDataReader.h" + +//////////////////////////////////////////////////////////////////// +// Class : CycleDataWriter +// Description : This template class calls PipelineCycler::write() in +// the constructor and PipelineCycler::release_write() in +// the destructor. In the interim, it provides a +// transparent read-write access to the CycleData. +// +// It exists as a syntactic convenience to access the +// data in the CycleData. It also allows the whole +// system to compile down to nothing if +// SUPPORT_PIPELINING is not defined. +//////////////////////////////////////////////////////////////////// +template +class CycleDataWriter { +public: + INLINE CycleDataWriter(PipelineCycler &cycler); + INLINE CycleDataWriter(PipelineCycler &cycler, bool force_to_0); + INLINE CycleDataWriter(const CycleDataWriter ©); + INLINE void operator = (const CycleDataWriter ©); + + INLINE CycleDataWriter(PipelineCycler &cycler, CycleDataReader &take_from); + INLINE CycleDataWriter(PipelineCycler &cycler, CycleDataReader &take_from, bool force_to_0); + + INLINE ~CycleDataWriter(); + + INLINE CycleDataType *operator -> (); + INLINE const CycleDataType *operator -> () const; + + INLINE operator CycleDataType * (); + +private: +#ifdef DO_PIPELINING + // This is the data stored for a real pipelining implementation. + PipelineCycler *_cycler; + CycleDataType *_pointer; +#else // !DO_PIPELINING + // This is all we need for the trivial, do-nothing implementation. + CycleDataType *_pointer; +#endif // DO_PIPELINING +}; + +#include "cycleDataWriter.I" + +#endif diff --git a/panda/src/express/cyclerHolder.I b/panda/src/express/cyclerHolder.I new file mode 100644 index 0000000000..8285fdfca1 --- /dev/null +++ b/panda/src/express/cyclerHolder.I @@ -0,0 +1,63 @@ +// Filename: cyclerHolder.I +// Created by: drose (09Feb06) +// +//////////////////////////////////////////////////////////////////// +// +// 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: CyclerHolder::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE CyclerHolder:: +CyclerHolder(PipelineCyclerBase &cycler) { +#ifdef DO_PIPELINING + _cycler = &cycler; + _cycler->lock(); +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: CyclerHolder::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE CyclerHolder:: +~CyclerHolder() { +#ifdef DO_PIPELINING + _cycler->release(); +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: CyclerHolder::Copy Constructor +// Access: Private +// Description: Do not attempt to copy CyclerHolders. +//////////////////////////////////////////////////////////////////// +INLINE CyclerHolder:: +CyclerHolder(const CyclerHolder ©) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: CyclerHolder::Copy Assignment Operator +// Access: Private +// Description: Do not attempt to copy CyclerHolders. +//////////////////////////////////////////////////////////////////// +INLINE void CyclerHolder:: +operator = (const CyclerHolder ©) { + nassertv(false); +} diff --git a/panda/src/express/cyclerHolder.cxx b/panda/src/express/cyclerHolder.cxx new file mode 100644 index 0000000000..9f147f4b70 --- /dev/null +++ b/panda/src/express/cyclerHolder.cxx @@ -0,0 +1,19 @@ +// Filename: cyclerHolder.cxx +// Created by: drose (09Feb06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "cyclerHolder.h" diff --git a/panda/src/express/cyclerHolder.h b/panda/src/express/cyclerHolder.h new file mode 100644 index 0000000000..5ae85fb0ef --- /dev/null +++ b/panda/src/express/cyclerHolder.h @@ -0,0 +1,48 @@ +// Filename: cyclerHolder.h +// Created by: drose (09Feb06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 CYCLERHOLDER_H +#define CYCLERHOLDER_H + +#include "pandabase.h" +#include "pipelineCyclerBase.h" + +//////////////////////////////////////////////////////////////////// +// Class : CyclerHolder +// Description : A lightweight C++ object whose constructor calls +// lock() and whose destructor calls release() on a +// PipelineCyclerBase object. This is similar to a +// MutexHolder. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDAEXPRESS CyclerHolder { +public: + INLINE CyclerHolder(PipelineCyclerBase &cycler); + INLINE ~CyclerHolder(); +private: + INLINE CyclerHolder(const CyclerHolder ©); + INLINE void operator = (const CyclerHolder ©); + +private: +#ifdef DO_PIPELINING + PipelineCyclerBase *_cycler; +#endif +}; + +#include "cyclerHolder.I" + +#endif diff --git a/panda/src/express/express_composite1.cxx b/panda/src/express/express_composite1.cxx index 62fc200954..07e8d034b0 100644 --- a/panda/src/express/express_composite1.cxx +++ b/panda/src/express/express_composite1.cxx @@ -14,6 +14,12 @@ #include "conditionVarPosixImpl.cxx" #include "conditionVarWin32Impl.cxx" #include "config_express.cxx" +#include "cycleData.cxx" +#include "cycleDataReader.cxx" +#include "cycleDataStageReader.cxx" +#include "cycleDataStageWriter.cxx" +#include "cycleDataWriter.cxx" +#include "cyclerHolder.cxx" #include "datagram.cxx" #include "datagramGenerator.cxx" #include "datagramIterator.cxx" @@ -37,3 +43,5 @@ #include "namable.cxx" #include "nativeNumericData.cxx" #include "ordered_vector.cxx" +#include "patchfile.cxx" +#include "password_hash.cxx" diff --git a/panda/src/express/express_composite2.cxx b/panda/src/express/express_composite2.cxx index a3f64bae9b..fdc96afcb1 100644 --- a/panda/src/express/express_composite2.cxx +++ b/panda/src/express/express_composite2.cxx @@ -1,5 +1,8 @@ -#include "patchfile.cxx" -#include "password_hash.cxx" +#include "pipeline.cxx" +#include "pipelineCycler.cxx" +#include "pipelineCyclerDummyImpl.cxx" +#include "pipelineCyclerTrivialImpl.cxx" +#include "pipelineCyclerTrueImpl.cxx" #include "pmutex.cxx" #include "pointerTo.cxx" #include "pointerToArray.cxx" @@ -42,4 +45,3 @@ #include "windowsRegistry.cxx" #include "zStream.cxx" #include "zStreamBuf.cxx" - diff --git a/panda/src/express/pipeline.I b/panda/src/express/pipeline.I new file mode 100644 index 0000000000..da4c28dfef --- /dev/null +++ b/panda/src/express/pipeline.I @@ -0,0 +1,84 @@ +// Filename: pipeline.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 . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::get_render_pipeline +// Access: Public, Static +// Description: Returns a pointer to the global render pipeline. +//////////////////////////////////////////////////////////////////// +INLINE Pipeline *Pipeline:: +get_render_pipeline() { + if (_render_pipeline == (Pipeline *)NULL) { + make_render_pipeline(); + } + return _render_pipeline; +} + +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::set_min_stages +// Access: Public +// Description: Ensures that at least the indicated number of stages +// are in the pipeline. +//////////////////////////////////////////////////////////////////// +INLINE void Pipeline:: +set_min_stages(int min_stages) { + set_num_stages(max(min_stages, get_num_stages())); +} + +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::get_num_stages +// Access: Public +// Description: Returns the number of stages required for the +// pipeline. +//////////////////////////////////////////////////////////////////// +INLINE int Pipeline:: +get_num_stages() const { + return _num_stages; +} + +#ifdef THREADED_PIPELINE +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::get_num_cyclers +// Access: Public +// Description: Returns the number of PipelineCyclers in the universe +// that reference this Pipeline object. +//////////////////////////////////////////////////////////////////// +INLINE int Pipeline:: +get_num_cyclers() const { + ReMutexHolder holder(_lock); + return _num_cyclers; +} +#endif // THREADED_PIPELINE + +#ifdef THREADED_PIPELINE +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::get_num_dirty_cyclers +// Access: Public +// Description: Returns the number of PipelineCyclers in the universe +// that reference this Pipeline object and are currently +// marked "dirty"; that is, there is a difference in +// pointer value between some of their stages. +//////////////////////////////////////////////////////////////////// +INLINE int Pipeline:: +get_num_dirty_cyclers() const { + ReMutexHolder holder(_lock); + return _dirty_cyclers.size(); +} +#endif // THREADED_PIPELINE + diff --git a/panda/src/express/pipeline.cxx b/panda/src/express/pipeline.cxx new file mode 100644 index 0000000000..57bdf7543f --- /dev/null +++ b/panda/src/express/pipeline.cxx @@ -0,0 +1,377 @@ +// Filename: pipeline.cxx +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#include "pipeline.h" +#include "pipelineCyclerTrueImpl.h" +#include "reMutexHolder.h" +#include "configVariableInt.h" +#include "config_express.h" + +Pipeline *Pipeline::_render_pipeline = (Pipeline *)NULL; + +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +Pipeline:: +Pipeline(const string &name, int num_stages) : + Namable(name) +{ +#ifdef THREADED_PIPELINE + // Set up the linked list of cyclers to be a circular list that + // begins with this object. + _prev = this; + _next = this; + + _num_cyclers = 0; + _cycling = false; + +#endif // THREADED_PIPELINE + + set_num_stages(num_stages); +} + +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +Pipeline:: +~Pipeline() { +#ifdef THREADED_PIPELINE + nassertv(_num_cyclers == 0); + nassertv(_prev == this && _next == this); + _prev = NULL; + _next = NULL; + nassertv(!_cycling); +#endif // THREADED_PIPELINE +} + +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::cycle +// Access: Public +// Description: Flows all the pipeline data down to the next stage. +//////////////////////////////////////////////////////////////////// +void Pipeline:: +cycle() { +#ifdef THREADED_PIPELINE + pvector< PT(CycleData) > saved_cdatas; + saved_cdatas.reserve(_dirty_cyclers.size()); + { + ReMutexHolder holder(_lock); + if (_num_stages == 1) { + // No need to cycle if there's only one stage. + nassertv(_dirty_cyclers.empty()); + return; + } + + nassertv(!_cycling); + _cycling = true; + + Cyclers next_dirty_cyclers; + + Cyclers::iterator ci; + switch (_num_stages) { + case 2: + for (ci = _dirty_cyclers.begin(); ci != _dirty_cyclers.end(); ++ci) { + PipelineCyclerTrueImpl *cycler = (*ci); + ReMutexHolder holder2(cycler->_lock); + + // We save the result of cycle(), so that we can defer the + // side-effects that might occur when CycleDatas destruct, at + // least until the end of this loop. + saved_cdatas.push_back(cycler->cycle_2()); + + if (cycler->_dirty) { + // The cycler is still dirty after cycling. Preserve it in the + // set for next time. + bool inserted = next_dirty_cyclers.insert(cycler).second; + nassertv(inserted); + } else { +#ifdef DEBUG_THREADS + inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1); +#endif + } + } + break; + + case 3: + for (ci = _dirty_cyclers.begin(); ci != _dirty_cyclers.end(); ++ci) { + PipelineCyclerTrueImpl *cycler = (*ci); + ReMutexHolder holder2(cycler->_lock); + + saved_cdatas.push_back(cycler->cycle_3()); + if (cycler->_dirty) { + bool inserted = next_dirty_cyclers.insert(cycler).second; + nassertv(inserted); + } else { +#ifdef DEBUG_THREADS + inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1); +#endif + } + } + break; + + default: + for (ci = _dirty_cyclers.begin(); ci != _dirty_cyclers.end(); ++ci) { + PipelineCyclerTrueImpl *cycler = (*ci); + ReMutexHolder holder2(cycler->_lock); + + saved_cdatas.push_back(cycler->cycle()); + if (cycler->_dirty) { + bool inserted = next_dirty_cyclers.insert(cycler).second; + nassertv(inserted); + } else { +#ifdef DEBUG_THREADS + inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1); +#endif + } + } + break; + } + + // Finally, we're ready for the next frame. + _dirty_cyclers.swap(next_dirty_cyclers); + _cycling = false; + } + + // And now it's safe to let the CycleData pointers in saved_cdatas + // destruct, which may cause cascading deletes, and which will in + // turn case PipelineCyclers to remove themselves from (or add + // themselves to) the _dirty_cyclers list. + +#endif // THREADED_PIPELINE +} + +//////////////////////////////////////////////////////////////////// +// 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); +#ifdef THREADED_PIPELINE + ReMutexHolder holder(_lock); + if (num_stages != _num_stages) { + + // We need to lock every PipelineCycler object attached to this + // pipeline before we can adjust the number of stages. + PipelineCyclerLinks *links; + for (links = this->_next; links != this; links = links->_next) { + PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links; + cycler->_lock.lock(); + } + + _num_stages = num_stages; + + for (links = this->_next; links != this; links = links->_next) { + PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links; + cycler->set_num_stages(num_stages); + } + + // Now release them all. + int count = 0; + for (links = this->_next; links != this; links = links->_next) { + PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links; + cycler->_lock.release(); + ++count; + } + nassertv(count == _num_cyclers); + } + +#else // THREADED_PIPELINE + if (num_stages != 1) { + express_cat.warning() + << "Requested " << num_stages + << " pipeline stages but multithreaded render pipelines not enabled in build.\n"; + } + _num_stages = 1; +#endif // THREADED_PIPELINE +} + +#ifdef THREADED_PIPELINE +//////////////////////////////////////////////////////////////////// +// 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) { + ReMutexHolder holder(_lock); + nassertv(!cycler->_dirty); + nassertv(!_cycling); + ++_num_cyclers; + cycler->insert_before(this); + +#ifdef DEBUG_THREADS + inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), 1); +#endif +} +#endif // THREADED_PIPELINE + +#ifdef THREADED_PIPELINE +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::add_dirty_cycler +// Access: Public +// Description: Marks the indicated cycler as "dirty", meaning it +// will need to be cycled next frame. This both adds it +// to the "dirty" set and also sets the "dirty" flag +// within the cycler. This method only exists when true +// pipelining is configured on. +//////////////////////////////////////////////////////////////////// +void Pipeline:: +add_dirty_cycler(PipelineCyclerTrueImpl *cycler) { + nassertv(cycler->_lock.debug_is_locked()); + + ReMutexHolder holder(_lock); + nassertv(!_cycling); + nassertv(!cycler->_dirty); + cycler->_dirty = true; + + bool inserted = _dirty_cyclers.insert(cycler).second; + nassertv(inserted); + +#ifdef DEBUG_THREADS + inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), 1); +#endif +} +#endif // THREADED_PIPELINE + +#ifdef THREADED_PIPELINE +//////////////////////////////////////////////////////////////////// +// 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) { + nassertv(cycler->_lock.debug_is_locked()); + + ReMutexHolder holder(_lock); + nassertv(!_cycling); + + --_num_cyclers; + cycler->remove_from_list(); + +#ifdef DEBUG_THREADS + inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), -1); +#endif + + if (cycler->_dirty) { + cycler->_dirty = false; + Cyclers::iterator ci = _dirty_cyclers.find(cycler); + nassertv(ci != _dirty_cyclers.end()); + _dirty_cyclers.erase(ci); +#ifdef DEBUG_THREADS + inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1); +#endif + } +} +#endif // THREADED_PIPELINE + +#if defined(THREADED_PIPELINE) && defined(DEBUG_THREADS) +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::iterate_all_cycler_types +// Access: Public +// Description: Walks through the list of all the different +// PipelineCycler types in the universe. For each one, +// calls the indicated callback function with the +// TypeHandle of the respective type (actually, the +// result of cycler::get_parent_type()) and the count of +// pipeline cyclers of that type. Mainly used for +// PStats reporting. +//////////////////////////////////////////////////////////////////// +void Pipeline:: +iterate_all_cycler_types(CallbackFunc *func, void *data) const { + ReMutexHolder holder(_lock); + TypeCount::const_iterator ci; + for (ci = _all_cycler_types.begin(); ci != _all_cycler_types.end(); ++ci) { + func((*ci).first, (*ci).second, data); + } +} +#endif // THREADED_PIPELINE && DEBUG_THREADS + +#if defined(THREADED_PIPELINE) && defined(DEBUG_THREADS) +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::iterate_dirty_cycler_types +// Access: Public +// Description: Walks through the list of all the different +// PipelineCycler types, for only the dirty +// PipelineCyclers. See also +// iterate_all_cycler_types(). +//////////////////////////////////////////////////////////////////// +void Pipeline:: +iterate_dirty_cycler_types(CallbackFunc *func, void *data) const { + ReMutexHolder holder(_lock); + TypeCount::const_iterator ci; + for (ci = _dirty_cycler_types.begin(); ci != _dirty_cycler_types.end(); ++ci) { + func((*ci).first, (*ci).second, data); + } +} +#endif // THREADED_PIPELINE && DEBUG_THREADS + +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::make_render_pipeline +// Access: Private, Static +// Description: +//////////////////////////////////////////////////////////////////// +void Pipeline:: +make_render_pipeline() { + ConfigVariableInt pipeline_stages + ("pipeline-stages", 1, + PRC_DESC("The initial number of stages in the render pipeline. This is " + "only meaningful if threaded pipelining is compiled into " + "Panda. In most cases, you should not set this at all anyway, " + "since the pipeline can automatically grow stages as needed, " + "but it will not remove stages automatically, and having more " + "pipeline stages than your application requires will incur " + "additional runtime overhead.")); + + nassertv(_render_pipeline == (Pipeline *)NULL); + _render_pipeline = new Pipeline("render", pipeline_stages); +} + +#if defined(THREADED_PIPELINE) && defined(DEBUG_THREADS) +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::inc_cycler_type +// Access: Private, Static +// Description: Increments (or decrements, according to added) the +// value for TypeHandle in the indicated TypeCount map. +// This is used in DEBUG_THREADS mode to track the types +// of PipelineCyclers that are coming and going, mainly +// for PStats reporting. +// +// It is assumed the lock is held during this call. +//////////////////////////////////////////////////////////////////// +void Pipeline:: +inc_cycler_type(TypeCount &count, TypeHandle type, int addend) { + TypeCount::iterator ci = count.find(type); + if (ci == count.end()) { + ci = count.insert(TypeCount::value_type(type, 0)).first; + } + (*ci).second += addend; + nassertv((*ci).second >= 0); +} +#endif // THREADED_PIPELINE && DEBUG_THREADS diff --git a/panda/src/express/pipeline.h b/panda/src/express/pipeline.h new file mode 100644 index 0000000000..c4f16d1b23 --- /dev/null +++ b/panda/src/express/pipeline.h @@ -0,0 +1,101 @@ +// Filename: pipeline.h +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#ifndef PIPELINE_H +#define PIPELINE_H + +#include "pandabase.h" +#include "pipelineCyclerLinks.h" +#include "namable.h" +#include "pset.h" +#include "reMutex.h" +#include "reMutexHolder.h" + +struct PipelineCyclerTrueImpl; + +//////////////////////////////////////////////////////////////////// +// Class : Pipeline +// Description : This class manages a staged pipeline of data, for +// instance the render pipeline, so that each stage of +// the pipeline can simultaneously access different +// copies of the same data. It actually maintains a +// collection of PipelineCycler objects, and manages the +// turning of all of them at once. +// +// There is one default Pipeline object, the render +// pipeline. Other specialty pipelines may be created +// as needed. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDAEXPRESS Pipeline : public PipelineCyclerLinks, public Namable { +public: + Pipeline(const string &name, int num_stages); + ~Pipeline(); + + INLINE static Pipeline *get_render_pipeline(); + + void cycle(); + + void set_num_stages(int num_stages); + INLINE void set_min_stages(int min_stages); + INLINE int get_num_stages() const; + +#ifdef THREADED_PIPELINE + void add_cycler(PipelineCyclerTrueImpl *cycler); + void add_dirty_cycler(PipelineCyclerTrueImpl *cycler); + void remove_cycler(PipelineCyclerTrueImpl *cycler); + + INLINE int get_num_cyclers() const; + INLINE int get_num_dirty_cyclers() const; + +#ifdef DEBUG_THREADS + typedef void CallbackFunc(TypeHandle type, int count, void *data); + void iterate_all_cycler_types(CallbackFunc *func, void *data) const; + void iterate_dirty_cycler_types(CallbackFunc *func, void *data) const; +#endif // DEBUG_THREADS + +#endif // THREADED_PIPELINE + +private: + int _num_stages; + + static void make_render_pipeline(); + static Pipeline *_render_pipeline; + +#ifdef THREADED_PIPELINE + int _num_cyclers; + typedef pset Cyclers; + Cyclers _dirty_cyclers; + +#ifdef DEBUG_THREADS + typedef pmap TypeCount; + TypeCount _all_cycler_types, _dirty_cycler_types; + + static void inc_cycler_type(TypeCount &count, TypeHandle type, int addend); +#endif // DEBUG_THREADS + + // This is true only during cycle(). + bool _cycling; + + ReMutex _lock; +#endif // THREADED_PIPELINE +}; + +#include "pipeline.I" + +#endif + diff --git a/panda/src/express/pipelineCycler.I b/panda/src/express/pipelineCycler.I new file mode 100644 index 0000000000..0d82a03bc2 --- /dev/null +++ b/panda/src/express/pipelineCycler.I @@ -0,0 +1,287 @@ +// Filename: pipelineCycler.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 the +// PipelineCyclerDummyImpl or the PipelineCyclerTrueImpl. + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::Constructor (dummy or true) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE PipelineCycler:: +PipelineCycler(Pipeline *pipeline) : + PipelineCyclerBase(new CycleDataType, pipeline) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::Copy Constructor (dummy or true) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE PipelineCycler:: +PipelineCycler(const PipelineCycler ©) : + PipelineCyclerBase(copy) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::Copy Assignment (dummy or true) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE void PipelineCycler:: +operator = (const PipelineCycler ©) { + PipelineCyclerBase::operator = (copy); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::read (dummy or true) +// Access: Public +// Description: See PipelineCyclerBase::read(). +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *PipelineCycler:: +read() const { + return (const CycleDataType *)PipelineCyclerBase::read(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::read (dummy or true) +// Access: Public +// Description: See PipelineCyclerBase::read_stage(). +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *PipelineCycler:: +read_stage(int n) const { + return (const CycleDataType *)PipelineCyclerBase::read_stage(n); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::write (dummy or true) +// Access: Public +// Description: See PipelineCyclerBase::write(). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *PipelineCycler:: +write() { + return (CycleDataType *)PipelineCyclerBase::write(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::elevate_read (dummy or true) +// Access: Public +// Description: See PipelineCyclerBase::elevate_read(). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *PipelineCycler:: +elevate_read(const CycleDataType *pointer) { + return (CycleDataType *)PipelineCyclerBase::elevate_read(pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::elevate_read_upstream (dummy or true) +// Access: Public +// Description: See PipelineCyclerBase::elevate_read_upstream(). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *PipelineCycler:: +elevate_read_upstream(const CycleDataType *pointer, bool force_to_0) { + return (CycleDataType *)PipelineCyclerBase::elevate_read_upstream(pointer, force_to_0); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::elevate_read_stage (dummy or true) +// Access: Public +// Description: See PipelineCyclerBase::elevate_read_stage(). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *PipelineCycler:: +elevate_read_stage(int n, const CycleDataType *pointer) { + return (CycleDataType *)PipelineCyclerBase::elevate_read_stage(n, pointer); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::write_upstream (dummy or true) +// Access: Public +// Description: See PipelineCyclerBase::write_upstream(). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *PipelineCycler:: +write_upstream(bool force_to_0) { + return (CycleDataType *)PipelineCyclerBase::write_upstream(force_to_0); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::write_stage (dummy or true) +// Access: Public +// Description: See PipelineCyclerBase::write_stage(). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *PipelineCycler:: +write_stage(int n) { + return (CycleDataType *)PipelineCyclerBase::write_stage(n); +} + +//////////////////////////////////////////////////////////////////// +// 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 +// 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. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *PipelineCycler:: +cheat() const { + return (CycleDataType *)PipelineCyclerBase::cheat(); +} + +#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: PipelineCycler::Constructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE PipelineCycler:: +PipelineCycler(Pipeline *pipeline) : + PipelineCyclerBase(&_typed_data, pipeline) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::Copy Constructor (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE PipelineCycler:: +PipelineCycler(const PipelineCycler ©) : + PipelineCyclerBase(&_typed_data), + _typed_data(copy._typed_data) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::Copy Assignment (trivial) +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE void PipelineCycler:: +operator = (const PipelineCycler ©) { + _typed_data = copy._typed_data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::read (trivial) +// Access: Public +// Description: See PipelineCyclerBase::read(). +//////////////////////////////////////////////////////////////////// +template +INLINE const CycleDataType *PipelineCycler:: +read() const { + return &_typed_data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::write (trivial) +// Access: Public +// Description: See PipelineCyclerBase::write(). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *PipelineCycler:: +write() { + return &_typed_data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::elevate_read (trivial) +// Access: Public +// Description: See PipelineCyclerBase::elevate_read(). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *PipelineCycler:: +elevate_read(const CycleDataType *) { + return &_typed_data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::elevate_read_upstream (trivial) +// Access: Public +// Description: See PipelineCyclerBase::elevate_read_upstream(). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *PipelineCycler:: +elevate_read_upstream(const CycleDataType *, bool) { + return &_typed_data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::write_upstream (trivial) +// Access: Public +// Description: See PipelineCyclerBase::write_upstream(). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *PipelineCycler:: +write_upstream(bool) { + return &_typed_data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::write_stage (trivial) +// Access: Public +// Description: See PipelineCyclerBase::write_stage(). +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *PipelineCycler:: +write_stage(int) { + return &_typed_data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCycler::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. +//////////////////////////////////////////////////////////////////// +template +INLINE CycleDataType *PipelineCycler:: +cheat() const { + return (CycleDataType *)&_typed_data; +} + + +#endif // DO_PIPELINING diff --git a/panda/src/express/pipelineCycler.cxx b/panda/src/express/pipelineCycler.cxx new file mode 100644 index 0000000000..a2d8f51b02 --- /dev/null +++ b/panda/src/express/pipelineCycler.cxx @@ -0,0 +1,19 @@ +// Filename: pipelineCycler.cxx +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#include "pipelineCycler.h" diff --git a/panda/src/express/pipelineCycler.h b/panda/src/express/pipelineCycler.h new file mode 100644 index 0000000000..99f6428cf9 --- /dev/null +++ b/panda/src/express/pipelineCycler.h @@ -0,0 +1,171 @@ +// Filename: pipelineCycler.h +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#ifndef PIPELINECYCLER_H +#define PIPELINECYCLER_H + +#include "pandabase.h" +#include "pipelineCyclerBase.h" +#include "cyclerHolder.h" + +//////////////////////////////////////////////////////////////////// +// Class : PipelineCycler +// Description : This class maintains different copies of a page of +// data between stages of the graphics pipeline (or any +// other pipelining context). +// +// The class object maintains up to n copies of a +// CycleData structure, one for each stage of the +// pipeline. The head of the pipeline is responsible +// for making changes to its copy, which are then cycled +// through the pipeline at each frame. +// +// To access the data, you must first ask for a readable +// pointer. In order to make changes to the data, you +// must ask for a writable pointer. Both kinds of +// pointers should be released when you are done, as a +// sanity check. The CycleDataReader and +// CycleDataWriter classes transparently handle this. +// +// If pipelining support is not enabled at compile time +// (that is, SUPPORT_PIPELINING is not defined), this +// object compiles to a minimum object that presents the +// same interface but with minimal runtime overhead. +// (Actually, this isn't true yet, but it will be one +// day.) +// +// 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. +//////////////////////////////////////////////////////////////////// +template +struct PipelineCycler : public PipelineCyclerBase { +public: + INLINE PipelineCycler(Pipeline *pipeline = NULL); + INLINE PipelineCycler(const PipelineCycler ©); + INLINE void operator = (const PipelineCycler ©); + + INLINE const CycleDataType *read() const; + INLINE const CycleDataType *read_stage(int n) const; + INLINE CycleDataType *write(); + INLINE CycleDataType *elevate_read(const CycleDataType *pointer); + INLINE CycleDataType *elevate_read_upstream(const CycleDataType *pointer, bool force_to_0); + INLINE CycleDataType *elevate_read_stage(int n, const CycleDataType *pointer); + INLINE CycleDataType *write_upstream(bool force_to_0); + INLINE CycleDataType *write_stage(int n); + + INLINE CycleDataType *cheat() const; + +#ifndef DO_PIPELINING +private: + // If we are *not* compiling in support for pipelining, we just + // store the CycleData object right here. No pointers needed. + CycleDataType _typed_data; +#endif // !DO_PIPELINING +}; + +// These macros are handy for iterating through the set of pipeline +// stages. They're particularly useful for updating cache values +// upstream of the current stage, or for removing bad pointers from +// all stages of the pipeline. In each case, the variable +// pipeline_stage is defined within the loop to be the current stage +// of the pipeline traversed by the loop. +#ifdef DO_PIPELINING + +// Iterates through all of the pipeline stages upstream of the current +// stage, but not including the current stage. +#define OPEN_ITERATE_UPSTREAM_ONLY(cycler) { \ + CyclerHolder cholder(cycler); \ + int pipeline_stage; \ + for (pipeline_stage = Thread::get_current_pipeline_stage() - 1; \ + pipeline_stage >= 0; \ + --pipeline_stage) + +#define CLOSE_ITERATE_UPSTREAM_ONLY(cycler) \ + } + +// Iterates through all of the pipeline stages upstream of the current +// stage, and including the current stage. +#define OPEN_ITERATE_CURRENT_AND_UPSTREAM(cycler) { \ + CyclerHolder cholder(cycler); \ + int pipeline_stage; \ + for (pipeline_stage = Thread::get_current_pipeline_stage(); \ + pipeline_stage >= 0; \ + --pipeline_stage) + +#define CLOSE_ITERATE_CURRENT_AND_UPSTREAM(cycler) \ + } + +// As above, but without holding the cycler lock during the loop. +#define OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(cycler) { \ + int pipeline_stage; \ + for (pipeline_stage = Thread::get_current_pipeline_stage(); \ + pipeline_stage >= 0; \ + --pipeline_stage) + +#define CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(cycler) \ + } + +// Iterates through all of the pipeline stages. +#define OPEN_ITERATE_ALL_STAGES(cycler) { \ + int pipeline_stage; \ + for (pipeline_stage = (cycler).get_num_stages() - 1; \ + pipeline_stage >= 0; \ + --pipeline_stage) + +#define CLOSE_ITERATE_ALL_STAGES(cycler) \ + } + +#else // DO_PIPELINING + +// These are trivial implementations of the above macros, defined when +// pipelining is not enabled, that simply operate on stage 0 without +// bothering to create a for loop. +#define OPEN_ITERATE_UPSTREAM_ONLY(cycler) \ + if (false) { \ + const int pipeline_stage = -1; + +#define CLOSE_ITERATE_UPSTREAM_ONLY(cycler) \ + } + +#define OPEN_ITERATE_CURRENT_AND_UPSTREAM(cycler) { \ + const int pipeline_stage = 0; \ + +#define CLOSE_ITERATE_CURRENT_AND_UPSTREAM(cycler) \ + } + +#define OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(cycler) { \ + const int pipeline_stage = 0; \ + +#define CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(cycler) \ + } + +#define OPEN_ITERATE_ALL_STAGES(cycler) { \ + const int pipeline_stage = 0; \ + +#define CLOSE_ITERATE_ALL_STAGES(cycler) \ + } + +#endif // DO_PIPELINING + +#include "pipelineCycler.I" + +#endif + diff --git a/panda/src/express/pipelineCyclerBase.h b/panda/src/express/pipelineCyclerBase.h new file mode 100644 index 0000000000..4dcded70f7 --- /dev/null +++ b/panda/src/express/pipelineCyclerBase.h @@ -0,0 +1,52 @@ +// Filename: pipelineCyclerBase.h +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#ifndef PIPELINECYCLERBASE_H +#define PIPELINECYCLERBASE_H + +#include "pandabase.h" + +#ifdef DO_PIPELINING + +#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 + +#endif + diff --git a/panda/src/express/pipelineCyclerDummyImpl.I b/panda/src/express/pipelineCyclerDummyImpl.I new file mode 100644 index 0000000000..b1c83ad6a2 --- /dev/null +++ b/panda/src/express/pipelineCyclerDummyImpl.I @@ -0,0 +1,420 @@ +// 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 +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PipelineCyclerDummyImpl:: +PipelineCyclerDummyImpl(CycleData *initial_data, Pipeline *pipeline) : + _data(initial_data), + _pipeline(pipeline), + _read_count(0), + _write_count(0), + _locked(false) +{ + if (_pipeline == (Pipeline *)NULL) { + _pipeline = Pipeline::get_render_pipeline(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PipelineCyclerDummyImpl:: +PipelineCyclerDummyImpl(const PipelineCyclerDummyImpl ©) : + _data(copy._data->make_copy()), + _pipeline(copy._pipeline), + _read_count(0), + _write_count(0), + _locked(false) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::Copy Assignment +// 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 +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PipelineCyclerDummyImpl:: +~PipelineCyclerDummyImpl() { + nassertv(_read_count == 0 && _write_count == 0 && !_locked); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::lock +// Access: Public +// Description: Grabs an overall lock on the cycler. Release it with +// a call to release(). This lock should be held while +// walking the list of stages. +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerDummyImpl:: +lock() { + nassertv(!_locked); + _locked = true; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::release +// Access: Public +// Description: Release the overall lock on the cycler that was +// grabbed via lock(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerDummyImpl:: +release() { + nassertv(_locked); + _locked = false; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::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 *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 +// 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 +// 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 +// 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 +// 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::elevate_read_upstream +// Access: Public +// Description: Elevates a currently-held read pointer into a write +// pointer, like elevate_read(), but also propagates the +// pointer back to upstream stages, like +// write_upstream(). +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerDummyImpl:: +elevate_read_upstream(const CycleData *pointer, bool force_to_0) { + release_read(pointer); + return write_upstream(force_to_0); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::increment_write +// Access: Public +// Description: Increments the count on a pointer previously +// retrieved by write(); now the pointer will need to be +// released twice. +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerDummyImpl:: +increment_write(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(_write_count > 0); + ((PipelineCyclerDummyImpl *)this)->_write_count++; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::release_write +// 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 +// Access: Public +// Description: Returns the number of stages in the pipeline. +//////////////////////////////////////////////////////////////////// +INLINE int PipelineCyclerDummyImpl:: +get_num_stages() { + return 1; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::read_stage +// Access: Public +// Description: Returns a const CycleData pointer, filled with the +// data for the indicated stage of the pipeline. This +// pointer should eventually be released by calling +// release_read_stage(). +// +// There should be no outstanding write pointers on the +// data when this function is called. +//////////////////////////////////////////////////////////////////// +INLINE const CycleData *PipelineCyclerDummyImpl:: +read_stage(int n) const { + // This function isn't truly const, but it doesn't change the data + // in any meaningful way, so we pretend it is. + nassertr(n == 0, NULL); + ((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::release_read_stage +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// read_stage(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerDummyImpl:: +release_read_stage(int n, 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(n == 0); + nassertv(pointer == _data); + nassertv(_read_count > 0); + ((PipelineCyclerDummyImpl *)this)->_read_count--; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::write_upstream +// Access: Public +// Description: This special variant on write() will automatically +// propagate changes back to upstream pipeline stages. +// If force_to_0 is false, then it propagates back only +// as long as the CycleData pointers are equivalent, +// guaranteeing that it does not modify upstream data +// (other than the modification that will be performed +// by the code that returns this pointer). This is +// particularly appropriate for minor updates, where it +// doesn't matter much if the update is lost, such as +// storing a cached value. +// +// If force_to_0 is dummy, then the CycleData pointer for +// the current pipeline stage is propagated all the way +// back up to stage 0; after this call, there will be +// only one CycleData pointer that is duplicated in all +// stages between stage 0 and the current stage. This +// may undo some recent changes that were made +// independently at pipeline stage 0 (or any other +// upstream stage). However, it guarantees that the +// change that is to be applied at this pipeline stage +// will stick. This is slightly dangerous because of +// the risk of losing upstream changes; generally, this +// should only be done when you are confident that there +// are no upstream changes to be lost (for instance, for +// an object that has been recently created). +//////////////////////////////////////////////////////////////////// +CycleData *PipelineCyclerDummyImpl:: +write_upstream(bool) { + _write_count++; + return _data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::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 *PipelineCyclerDummyImpl:: +write_stage(int n) { + nassertr(n == 0, (CycleData *)NULL); + _write_count++; + return _data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::elevate_read_stage +// 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_stage(int n, const CycleData *pointer) { + nassertr(n == 0, NULL); + release_read(pointer); + return write(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::release_write_stage +// 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::get_parent_type +// Access: Public +// Description: Returns the type of object that owns this cycler, as +// reported by CycleData::get_parent_type(). +//////////////////////////////////////////////////////////////////// +INLINE TypeHandle PipelineCyclerDummyImpl:: +get_parent_type() const { + return _data->get_parent_type(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::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 *PipelineCyclerDummyImpl:: +cheat() const { + return _data; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::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 PipelineCyclerDummyImpl:: +get_read_count() const { + return _read_count; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerDummyImpl::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 PipelineCyclerDummyImpl:: +get_write_count() const { + return _write_count; +} diff --git a/panda/src/express/pipelineCyclerDummyImpl.cxx b/panda/src/express/pipelineCyclerDummyImpl.cxx new file mode 100644 index 0000000000..e66d164b89 --- /dev/null +++ b/panda/src/express/pipelineCyclerDummyImpl.cxx @@ -0,0 +1,19 @@ +// Filename: pipelineCyclerDummyImpl.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 "pipelineCyclerDummyImpl.h" diff --git a/panda/src/express/pipelineCyclerDummyImpl.h b/panda/src/express/pipelineCyclerDummyImpl.h new file mode 100644 index 0000000000..1481450859 --- /dev/null +++ b/panda/src/express/pipelineCyclerDummyImpl.h @@ -0,0 +1,94 @@ +// 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_PANDAEXPRESS PipelineCyclerDummyImpl { +public: + INLINE PipelineCyclerDummyImpl(CycleData *initial_data, Pipeline *pipeline = NULL); + INLINE PipelineCyclerDummyImpl(const PipelineCyclerDummyImpl ©); + INLINE void operator = (const PipelineCyclerDummyImpl ©); + INLINE ~PipelineCyclerDummyImpl(); + + INLINE void lock(); + INLINE void release(); + + 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 CycleData *elevate_read_upstream(const CycleData *pointer, bool force_to_0); + INLINE void increment_write(CycleData *pointer) const; + INLINE void release_write(CycleData *pointer); + + INLINE int get_num_stages(); + INLINE const CycleData *read_stage(int n) const; + INLINE void release_read_stage(int n, const CycleData *pointer) const; + INLINE CycleData *write_upstream(bool force_to_0); + INLINE CycleData *write_stage(int n); + INLINE CycleData *elevate_read_stage(int n, const CycleData *pointer); + INLINE void release_write_stage(int n, CycleData *pointer); + + INLINE TypeHandle get_parent_type() const; + + 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; + short _locked; +}; + +#include "pipelineCyclerDummyImpl.I" + +#endif // DO_PIPELINING && !HAVE_THREADS + +#endif + diff --git a/panda/src/express/pipelineCyclerLinks.I b/panda/src/express/pipelineCyclerLinks.I new file mode 100644 index 0000000000..07d2337c6c --- /dev/null +++ b/panda/src/express/pipelineCyclerLinks.I @@ -0,0 +1,83 @@ +// Filename: pipelineCyclerLinks.I +// Created by: drose (16Feb06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 THREADED_PIPELINE +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerLinks::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PipelineCyclerLinks:: +PipelineCyclerLinks() { +#ifndef NDEBUG + _next = NULL; + _prev = NULL; +#endif +} +#endif // THREADED_PIPELINE + +#ifdef THREADED_PIPELINE +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerLinks::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PipelineCyclerLinks:: +~PipelineCyclerLinks() { + nassertv(_next == NULL && _prev == NULL); +} +#endif // THREADED_PIPELINE + +#ifdef THREADED_PIPELINE +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerLinks::remove_from_list +// Access: Private +// Description: Removes a PipelineCyclerLinks record from the +// doubly-linked list. +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerLinks:: +remove_from_list() { + nassertv(_prev->_next == this && _next->_prev == this); + _prev->_next = _next; + _next->_prev = _prev; +#ifndef NDEBUG + _next = NULL; + _prev = NULL; +#endif +} +#endif // THREADED_PIPELINE + +#ifdef THREADED_PIPELINE +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerLinks::insert_before +// Access: Private +// Description: Adds a PipelineCyclerLinks record before the indicated +// node in the doubly-linked list. +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerLinks:: +insert_before(PipelineCyclerLinks *node) { + nassertv(node->_prev->_next == node && node->_next->_prev == node); + nassertv(_prev == (PipelineCyclerLinks *)NULL && + _next == (PipelineCyclerLinks *)NULL); + _prev = node->_prev; + _next = node; + _prev->_next = this; + node->_prev = this; +} +#endif // THREADED_PIPELINE diff --git a/panda/src/express/pipelineCyclerLinks.h b/panda/src/express/pipelineCyclerLinks.h new file mode 100644 index 0000000000..b26b20a2c5 --- /dev/null +++ b/panda/src/express/pipelineCyclerLinks.h @@ -0,0 +1,55 @@ +// Filename: pipelineCyclerLinks.h +// Created by: drose (16Feb06) +// +//////////////////////////////////////////////////////////////////// +// +// 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 PIPELINECYCLERLINKS_H +#define PIPELINECYCLERLINKS_H + +#include "pandabase.h" +#include "selectThreadImpl.h" // for THREADED_PIPELINE definition +#include "notify.h" + +//////////////////////////////////////////////////////////////////// +// Class : PipelineCyclerLinks +// Description : This just stores the pointers to implement a +// doubly-linked list of PipelineCyclers for a +// particular Pipeline object. We use a hand-rolled +// linked list rather than any STL container, because we +// want PipelineCyclers to be able to add and remove +// themselves from this list very quickly. +// +// These pointers are inherited from this separate class +// so the Pipeline object itself can be the root of the +// linked list. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDAEXPRESS PipelineCyclerLinks { +protected: +#ifdef THREADED_PIPELINE + INLINE PipelineCyclerLinks(); + INLINE ~PipelineCyclerLinks(); + + INLINE void remove_from_list(); + INLINE void insert_before(PipelineCyclerLinks *node); + + PipelineCyclerLinks *_prev, *_next; +#endif + friend class Pipeline; +}; + +#include "pipelineCyclerLinks.I" + +#endif diff --git a/panda/src/express/pipelineCyclerTrivialImpl.I b/panda/src/express/pipelineCyclerTrivialImpl.I new file mode 100644 index 0000000000..19cc5483d5 --- /dev/null +++ b/panda/src/express/pipelineCyclerTrivialImpl.I @@ -0,0 +1,396 @@ +// 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 +// 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 +// 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 +// 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 +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PipelineCyclerTrivialImpl:: +~PipelineCyclerTrivialImpl() { +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::lock +// Access: Public +// Description: Grabs an overall lock on the cycler. Release it with +// a call to release(). This lock should be held while +// walking the list of stages. +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrivialImpl:: +lock() { +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::release +// Access: Public +// Description: Release the overall lock on the cycler that was +// grabbed via lock(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrivialImpl:: +release() { +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::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(). +//////////////////////////////////////////////////////////////////// +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 +// 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 +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// read(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrivialImpl:: +release_read(const CycleData *) const { +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::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 *PipelineCyclerTrivialImpl:: +write() { +#ifdef SIMPLE_STRUCT_POINTERS + return (CycleData *)this; +#else + return _data; +#endif // SIMPLE_STRUCT_POINTERS +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::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 *PipelineCyclerTrivialImpl:: +elevate_read(const CycleData *) { +#ifdef SIMPLE_STRUCT_POINTERS + return (CycleData *)this; +#else + return _data; +#endif // SIMPLE_STRUCT_POINTERS +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::elevate_read_upstream +// Access: Public +// Description: Elevates a currently-held read pointer into a write +// pointer, like elevate_read(), but also propagates the +// pointer back to upstream stages, like +// write_upstream(). +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerTrivialImpl:: +elevate_read_upstream(const CycleData *, bool) { +#ifdef SIMPLE_STRUCT_POINTERS + return (CycleData *)this; +#else + return _data; +#endif // SIMPLE_STRUCT_POINTERS +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::increment_write +// Access: Public +// Description: Increments the count on a pointer previously +// retrieved by write(); now the pointer will need to be +// released twice. +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrivialImpl:: +increment_write(CycleData *) const { +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::release_write +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// write(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrivialImpl:: +release_write(CycleData *) { +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::get_num_stages +// Access: Public +// Description: Returns the number of stages in the pipeline. +//////////////////////////////////////////////////////////////////// +INLINE int PipelineCyclerTrivialImpl:: +get_num_stages() { + return 1; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::read_stage +// Access: Public +// Description: Returns a const CycleData pointer, filled with the +// data for the indicated pipeline stage. This pointer +// should eventually be released by calling +// release_read(). +//////////////////////////////////////////////////////////////////// +INLINE const CycleData *PipelineCyclerTrivialImpl:: +read_stage(int) const { +#ifdef SIMPLE_STRUCT_POINTERS + return (const CycleData *)this; +#else + return _data; +#endif // SIMPLE_STRUCT_POINTERS +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::release_read_stage +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// read_stage(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrivialImpl:: +release_read_stage(int, const CycleData *) const { +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::write_upstream +// Access: Public +// Description: This special variant on write() will automatically +// propagate changes back to upstream pipeline stages. +// If force_to_0 is false, then it propagates back only +// as long as the CycleData pointers are equivalent, +// guaranteeing that it does not modify upstream data +// (other than the modification that will be performed +// by the code that returns this pointer). This is +// particularly appropriate for minor updates, where it +// doesn't matter much if the update is lost, such as +// storing a cached value. +// +// If force_to_0 is trivial, then the CycleData pointer for +// the current pipeline stage is propagated all the way +// back up to stage 0; after this call, there will be +// only one CycleData pointer that is duplicated in all +// stages between stage 0 and the current stage. This +// may undo some recent changes that were made +// independently at pipeline stage 0 (or any other +// upstream stage). However, it guarantees that the +// change that is to be applied at this pipeline stage +// will stick. This is slightly dangerous because of +// the risk of losing upstream changes; generally, this +// should only be done when you are confident that there +// are no upstream changes to be lost (for instance, for +// an object that has been recently created). +//////////////////////////////////////////////////////////////////// +CycleData *PipelineCyclerTrivialImpl:: +write_upstream(bool) { +#ifdef SIMPLE_STRUCT_POINTERS + return (CycleData *)this; +#else + return _data; +#endif // SIMPLE_STRUCT_POINTERS +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::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 *PipelineCyclerTrivialImpl:: +write_stage(int) { +#ifdef SIMPLE_STRUCT_POINTERS + return (CycleData *)this; +#else + return _data; +#endif // SIMPLE_STRUCT_POINTERS +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::elevate_read_stage +// 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_stage(int, const CycleData *) { +#ifdef SIMPLE_STRUCT_POINTERS + return (CycleData *)this; +#else + return _data; +#endif // SIMPLE_STRUCT_POINTERS +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::release_write_stage +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// write_stage(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrivialImpl:: +release_write_stage(int, CycleData *) { +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::get_parent_type +// Access: Public +// Description: Returns the type of object that owns this cycler, as +// reported by CycleData::get_parent_type(). +//////////////////////////////////////////////////////////////////// +INLINE TypeHandle PipelineCyclerTrivialImpl:: +get_parent_type() const { + return cheat()->get_parent_type(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::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 *PipelineCyclerTrivialImpl:: +cheat() const { +#ifdef SIMPLE_STRUCT_POINTERS + return (CycleData *)this; +#else + return _data; +#endif // SIMPLE_STRUCT_POINTERS +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::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 PipelineCyclerTrivialImpl:: +get_read_count() const { + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrivialImpl::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 PipelineCyclerTrivialImpl:: +get_write_count() const { + return 0; +} + diff --git a/panda/src/express/pipelineCyclerTrivialImpl.cxx b/panda/src/express/pipelineCyclerTrivialImpl.cxx new file mode 100644 index 0000000000..cbbe4187b0 --- /dev/null +++ b/panda/src/express/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/express/pipelineCyclerTrivialImpl.h b/panda/src/express/pipelineCyclerTrivialImpl.h new file mode 100644 index 0000000000..44e4cd1b59 --- /dev/null +++ b/panda/src/express/pipelineCyclerTrivialImpl.h @@ -0,0 +1,100 @@ +// 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 + +#include "cycleData.h" + +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_PANDAEXPRESS PipelineCyclerTrivialImpl { +public: + INLINE PipelineCyclerTrivialImpl(CycleData *initial_data, Pipeline *pipeline = NULL); +private: + INLINE PipelineCyclerTrivialImpl(const PipelineCyclerTrivialImpl ©); + INLINE void operator = (const PipelineCyclerTrivialImpl ©); +public: + INLINE ~PipelineCyclerTrivialImpl(); + + INLINE void lock(); + INLINE void release(); + + 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 CycleData *elevate_read_upstream(const CycleData *pointer, bool force_to_0); + INLINE void increment_write(CycleData *pointer) const; + INLINE void release_write(CycleData *pointer); + + INLINE int get_num_stages(); + INLINE const CycleData *read_stage(int n) const; + INLINE void release_read_stage(int n, const CycleData *pointer) const; + INLINE CycleData *write_upstream(bool force_to_0); + INLINE CycleData *write_stage(int n); + INLINE CycleData *elevate_read_stage(int n, const CycleData *pointer); + INLINE void release_write_stage(int n, CycleData *pointer); + + INLINE TypeHandle get_parent_type() const; + + 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/express/pipelineCyclerTrueImpl.I b/panda/src/express/pipelineCyclerTrueImpl.I new file mode 100644 index 0000000000..8f7d7dcf8d --- /dev/null +++ b/panda/src/express/pipelineCyclerTrueImpl.I @@ -0,0 +1,381 @@ +// 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::lock +// Access: Public +// Description: Grabs an overall lock on the cycler. Release it with +// a call to release(). This lock should be held while +// walking the list of stages. +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrueImpl:: +lock() { + _lock.lock(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::release +// Access: Public +// Description: Release the overall lock on the cycler that was +// grabbed via lock(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrueImpl:: +release() { + _lock.release(); +} + +//////////////////////////////////////////////////////////////////// +// 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_pipeline_stage(); + nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); + _lock.lock(); + return _data[pipeline_stage]; +} + +//////////////////////////////////////////////////////////////////// +// 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 { +#ifndef NDEBUG + int pipeline_stage = Thread::get_current_pipeline_stage(); + nassertv(pipeline_stage >= 0 && pipeline_stage < _num_stages); + nassertv(_data[pipeline_stage] == pointer); +#endif + _lock.lock(); +} + +//////////////////////////////////////////////////////////////////// +// 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 { +#ifndef NDEBUG + int pipeline_stage = Thread::get_current_pipeline_stage(); + nassertv(pipeline_stage >= 0 && pipeline_stage < _num_stages); + nassertv(_data[pipeline_stage] == pointer); +#endif + _lock.release(); +} + +//////////////////////////////////////////////////////////////////// +// 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_pipeline_stage(); + return write_stage(pipeline_stage); +} + +//////////////////////////////////////////////////////////////////// +// 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) { +#ifndef NDEBUG + int pipeline_stage = Thread::get_current_pipeline_stage(); + nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); + nassertr(_data[pipeline_stage] == pointer, NULL); +#endif + CycleData *new_pointer = write(); + _lock.release(); + return new_pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::elevate_read_upstream +// Access: Public +// Description: Elevates a currently-held read pointer into a write +// pointer, like elevate_read(), but also propagates the +// pointer back to upstream stages, like +// write_upstream(). +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerTrueImpl:: +elevate_read_upstream(const CycleData *pointer, bool force_to_0) { +#ifndef NDEBUG + int pipeline_stage = Thread::get_current_pipeline_stage(); + nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); + nassertr(_data[pipeline_stage] == pointer, NULL); +#endif + CycleData *new_pointer = write_upstream(force_to_0); + _lock.release(); + return new_pointer; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::increment_write +// Access: Public +// Description: Increments the count on a pointer previously +// retrieved by write(); now the pointer will need to be +// released twice. +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrueImpl:: +increment_write(CycleData *pointer) const { +#ifndef NDEBUG + int pipeline_stage = Thread::get_current_pipeline_stage(); + nassertv(pipeline_stage >= 0 && pipeline_stage < _num_stages); + nassertv(_data[pipeline_stage] == pointer); +#endif + _lock.lock(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::release_write +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// write(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrueImpl:: +release_write(CycleData *pointer) { +#ifdef NDEBUG + int pipeline_stage = Thread::get_current_pipeline_stage(); + return release_write_stage(pipeline_stage, pointer); +#else + _lock.release(); +#endif +} + +//////////////////////////////////////////////////////////////////// +// 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::read_stage +// Access: Public +// Description: Returns a const CycleData pointer, filled with the +// data for the indicated stage of the pipeline. This +// pointer should eventually be released by calling +// release_read_stage(). +// +// There should be no outstanding write pointers on the +// data when this function is called. +//////////////////////////////////////////////////////////////////// +INLINE const CycleData *PipelineCyclerTrueImpl:: +read_stage(int n) const { + nassertr(n >= 0 && n < _num_stages, NULL); + _lock.lock(); + return _data[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::release_read_stage +// Access: Public +// Description: Releases a pointer previously obtained via a call to +// read_stage(). +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerTrueImpl:: +release_read_stage(int n, const CycleData *pointer) const { +#ifndef NDEBUG + nassertv(n >= 0 && n < _num_stages); + nassertv(_data[n] == pointer); +#endif + _lock.release(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::elevate_read_stage +// 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 +// indicated stage. +//////////////////////////////////////////////////////////////////// +INLINE CycleData *PipelineCyclerTrueImpl:: +elevate_read_stage(int n, const CycleData *pointer) { +#ifndef NDEBUG + nassertr(n >= 0 && n < _num_stages, NULL); + nassertr(_data[n] == pointer, NULL); +#endif + CycleData *new_pointer = write_stage(n); + _lock.release(); + return new_pointer; +} + +//////////////////////////////////////////////////////////////////// +// 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) { +#ifndef NDEBUG + nassertv(n >= 0 && n < _num_stages); + nassertv(_data[n] == pointer); +#endif + _lock.release(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::get_parent_type +// Access: Public +// Description: Returns the type of object that owns this cycler, as +// reported by CycleData::get_parent_type(). +//////////////////////////////////////////////////////////////////// +INLINE TypeHandle PipelineCyclerTrueImpl:: +get_parent_type() const { + return _data[0]->get_parent_type(); +} + +//////////////////////////////////////////////////////////////////// +// 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_pipeline_stage(); + nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); + return _data[pipeline_stage]; +} + +//////////////////////////////////////////////////////////////////// +// 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; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::cycle_2 +// Access: Private +// Description: This is a special implementation of cycle() for the +// special case of just two stages to the pipeline. It +// does the same thing as cycle(), but is a little bit +// faster because it knows there are exactly two stages. +//////////////////////////////////////////////////////////////////// +INLINE PT(CycleData) PipelineCyclerTrueImpl:: +cycle_2() { + PT(CycleData) last_val = _data[1]; + nassertr(_lock.debug_is_locked(), last_val); + nassertr(_dirty, last_val); + nassertr(_num_stages == 2, last_val); + + _data[1] = _data[0]; + + // No longer dirty. + _dirty = false; + return last_val; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::cycle_3 +// Access: Private +// Description: This is a special implementation of cycle() for the +// special case of exactly three stages to the pipeline. +// It does the same thing as cycle(), but is a little +// bit faster because it knows there are exactly three +// stages. +//////////////////////////////////////////////////////////////////// +INLINE PT(CycleData) PipelineCyclerTrueImpl:: +cycle_3() { + PT(CycleData) last_val = _data[2]; + nassertr(_lock.debug_is_locked(), last_val); + nassertr(_dirty, last_val); + nassertr(_num_stages == 3, last_val); + + _data[2] = _data[1]; + _data[1] = _data[0]; + + if (_data[2] == _data[1]) { + // No longer dirty. + _dirty = false; + } + + return last_val; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::CyclerMutex::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PipelineCyclerTrueImpl::CyclerMutex:: +CyclerMutex(PipelineCyclerTrueImpl *cycler) { +#ifdef DEBUG_THREADS + _cycler = cycler; +#endif +} diff --git a/panda/src/express/pipelineCyclerTrueImpl.cxx b/panda/src/express/pipelineCyclerTrueImpl.cxx new file mode 100644 index 0000000000..d92a5098d0 --- /dev/null +++ b/panda/src/express/pipelineCyclerTrueImpl.cxx @@ -0,0 +1,350 @@ +// 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" + +#ifdef THREADED_PIPELINE + +#include "config_express.h" +#include "pipeline.h" + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PipelineCyclerTrueImpl:: +PipelineCyclerTrueImpl(CycleData *initial_data, Pipeline *pipeline) : + _pipeline(pipeline), + _dirty(false), + _lock(this) +{ + if (_pipeline == (Pipeline *)NULL) { + _pipeline = Pipeline::get_render_pipeline(); + } + + _num_stages = _pipeline->get_num_stages(); + _data = new PT(CycleData)[_num_stages]; + for (int i = 0; i < _num_stages; ++i) { + _data[i] = initial_data; + } + + _pipeline->add_cycler(this); +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PipelineCyclerTrueImpl:: +PipelineCyclerTrueImpl(const PipelineCyclerTrueImpl ©) : + _pipeline(copy._pipeline), + _dirty(false), + _lock(this) +{ + ReMutexHolder holder(_lock); + ReMutexHolder holder2(copy._lock); + + _num_stages = _pipeline->get_num_stages(); + nassertv(_num_stages == copy._num_stages); + _data = new PT(CycleData)[_num_stages]; + + // It's no longer critically important that we preserve pointerwise + // equivalence between different stages in the copy, but it doesn't + // cost much and might be a little more efficient, so we do it + // anyway. + typedef pmap Pointers; + Pointers pointers; + + for (int i = 0; i < _num_stages; ++i) { + PT(CycleData) &new_pt = pointers[copy._data[i]]; + if (new_pt == NULL) { + new_pt = copy._data[i]->make_copy(); + } + _data[i] = new_pt; + } + + _pipeline->add_cycler(this); + if (copy._dirty) { + _pipeline->add_dirty_cycler(this); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::Copy Assignment +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void PipelineCyclerTrueImpl:: +operator = (const PipelineCyclerTrueImpl ©) { + ReMutexHolder holder1(_lock); + ReMutexHolder holder2(copy._lock); + nassertv(get_parent_type() == copy.get_parent_type()); + + typedef pmap Pointers; + Pointers pointers; + + for (int i = 0; i < _num_stages; ++i) { + PT(CycleData) &new_pt = pointers[copy._data[i]]; + if (new_pt == NULL) { + new_pt = copy._data[i]->make_copy(); + } + _data[i] = new_pt; + } + + if (copy._dirty && !_dirty) { + _pipeline->add_dirty_cycler(this); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PipelineCyclerTrueImpl:: +~PipelineCyclerTrueImpl() { + ReMutexHolder holder(_lock); + + _pipeline->remove_cycler(this); + + delete[] _data; + _data = NULL; + _num_stages = 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::write_upstream +// Access: Public +// Description: This special variant on write() will automatically +// propagate changes back to upstream pipeline stages. +// If force_to_0 is false, then it propagates back only +// as long as the CycleData pointers are equivalent, +// guaranteeing that it does not modify upstream data +// (other than the modification that will be performed +// by the code that returns this pointer). This is +// particularly appropriate for minor updates, where it +// doesn't matter much if the update is lost, such as +// storing a cached value. +// +// If force_to_0 is true, then the CycleData pointer for +// the current pipeline stage is propagated all the way +// back up to stage 0; after this call, there will be +// only one CycleData pointer that is duplicated in all +// stages between stage 0 and the current stage. This +// may undo some recent changes that were made +// independently at pipeline stage 0 (or any other +// upstream stage). However, it guarantees that the +// change that is to be applied at this pipeline stage +// will stick. This is slightly dangerous because of +// the risk of losing upstream changes; generally, this +// should only be done when you are confident that there +// are no upstream changes to be lost (for instance, for +// an object that has been recently created). +//////////////////////////////////////////////////////////////////// +CycleData *PipelineCyclerTrueImpl:: +write_upstream(bool force_to_0) { + _lock.lock(); + + int pipeline_stage = Thread::get_current_pipeline_stage(); + +#ifndef NDEBUG + nassertd(pipeline_stage >= 0 && pipeline_stage < _num_stages) { + _lock.release(); + return NULL; + } +#endif // NDEBUG + + CycleData *old_data = _data[pipeline_stage]; + + if (old_data->get_ref_count() != 1 || force_to_0) { + // Count the number of references before the current stage, and + // the number of references remaining other than those. + int external_count = old_data->get_ref_count() - 1; + int k = pipeline_stage - 1; + while (k >= 0 && _data[k] == old_data) { + --k; + --external_count; + } + + if (external_count > 0) { + // There are references other than the ones before this stage in + // the pipeline; perform a copy-on-write. + PT(CycleData) new_data = old_data->make_copy(); + + k = pipeline_stage - 1; + while (k >= 0 && (_data[k] == old_data || force_to_0)) { + _data[k] = new_data; + --k; + } + + _data[pipeline_stage] = new_data; + + if (k >= 0 || pipeline_stage + 1 < _num_stages) { + // Now we have differences between some of the data pointers, + // which makes us "dirty". + if (!_dirty) { + _pipeline->add_dirty_cycler(this); + } + } + + } else if (k >= 0 && force_to_0) { + // There are no external pointers, so no need to copy-on-write, + // but the current pointer doesn't go all the way back. Make it + // do so. + while (k >= 0) { + _data[k] = old_data; + --k; + } + } + } + + return _data[pipeline_stage]; +} + +//////////////////////////////////////////////////////////////////// +// 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(). +//////////////////////////////////////////////////////////////////// +CycleData *PipelineCyclerTrueImpl:: +write_stage(int pipeline_stage) { + _lock.lock(); + +#ifndef NDEBUG + nassertd(pipeline_stage >= 0 && pipeline_stage < _num_stages) { + _lock.release(); + return NULL; + } +#endif // NDEBUG + + CycleData *old_data = _data[pipeline_stage]; + + if (old_data->get_ref_count() != 1) { + // Copy-on-write. + _data[pipeline_stage] = old_data->make_copy(); + + // Now we have differences between some of the data pointers, so + // we're "dirty". Mark it so. + if (!_dirty) { + _pipeline->add_dirty_cycler(this); + } + } + + return _data[pipeline_stage]; +} + +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::cycle +// Access: Private +// Description: Cycles the data between frames. This is only called +// from Pipeline::cycle(), and presumably it is only +// called if the cycler is "dirty". +// +// At the conclusion of this method, the cycler should +// clear its dirty flag if it is no longer "dirty"--that +// is, if all of the pipeline pointers are the same. +// +// The return value is the CycleData pointer which fell +// off the end of the cycle. If this is allowed to +// destruct immediately, there may be side-effects that +// cascade through the system, so the caller may choose +// to hold the pointer until it can safely be released +// later. +//////////////////////////////////////////////////////////////////// +PT(CycleData) PipelineCyclerTrueImpl:: +cycle() { + PT(CycleData) last_val = _data[_num_stages - 1]; + nassertr(_lock.debug_is_locked(), last_val); + nassertr(_dirty, last_val); + + int i; + for (i = _num_stages - 1; i > 0; --i) { + _data[i] = _data[i - 1]; + } + + for (i = 1; i < _num_stages; ++i) { + if (_data[i] != _data[i - 1]) { + // Still dirty. + return last_val; + } + } + + // No longer dirty. + _dirty = false; + return last_val; +} + +//////////////////////////////////////////////////////////////////// +// 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) { + nassertv(_lock.debug_is_locked()); + + if (num_stages <= _num_stages) { + // Don't bother to reallocate the array smaller; we just won't use + // the rest of the array. + for (int i = _num_stages; i < num_stages; ++i) { + _data[i].clear(); + } + + _num_stages = num_stages; + + + } else { + // To increase the array, we must reallocate it larger. + PT(CycleData) *new_data = new PT(CycleData)[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] = _data[_num_stages - 1]; + } + delete[] _data; + + _num_stages = num_stages; + _data = new_data; + } +} + +#ifdef DEBUG_THREADS +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerTrueImpl::CyclerMutex::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void PipelineCyclerTrueImpl::CyclerMutex:: +output(ostream &out) const { + _cycler->cheat()->output(out); +} +#endif // DEBUG_THREADS + +#endif // THREADED_PIPELINE + + diff --git a/panda/src/express/pipelineCyclerTrueImpl.h b/panda/src/express/pipelineCyclerTrueImpl.h new file mode 100644 index 0000000000..c685f66316 --- /dev/null +++ b/panda/src/express/pipelineCyclerTrueImpl.h @@ -0,0 +1,124 @@ +// 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" + +#ifdef THREADED_PIPELINE + +#include "pipelineCyclerLinks.h" +#include "cycleData.h" +#include "pointerTo.h" +#include "thread.h" +#include "reMutex.h" +#include "reMutexHolder.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_PANDAEXPRESS PipelineCyclerTrueImpl : public PipelineCyclerLinks { +private: + PipelineCyclerTrueImpl(); +public: + PipelineCyclerTrueImpl(CycleData *initial_data, Pipeline *pipeline = NULL); + PipelineCyclerTrueImpl(const PipelineCyclerTrueImpl ©); + void operator = (const PipelineCyclerTrueImpl ©); + ~PipelineCyclerTrueImpl(); + + INLINE void lock(); + INLINE void release(); + + 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 CycleData *elevate_read_upstream(const CycleData *pointer, bool force_to_0); + INLINE void increment_write(CycleData *pointer) const; + INLINE void release_write(CycleData *pointer); + + INLINE int get_num_stages(); + INLINE const CycleData *read_stage(int n) const; + INLINE void release_read_stage(int n, const CycleData *pointer) const; + CycleData *write_upstream(bool force_to_0); + CycleData *write_stage(int pipeline_stage); + INLINE CycleData *elevate_read_stage(int n, const CycleData *pointer); + INLINE void release_write_stage(int n, CycleData *pointer); + + INLINE TypeHandle get_parent_type() const; + + INLINE CycleData *cheat() const; + INLINE int get_read_count() const; + INLINE int get_write_count() const; + +public: + // We redefine the ReMutex class, solely so we can define the + // output() operator. This is only useful for debugging, but does + // no harm in the production case. + class CyclerMutex : public ReMutex { + public: + INLINE CyclerMutex(PipelineCyclerTrueImpl *cycler); + +#ifdef DEBUG_THREADS + virtual void output(ostream &out) const; + PipelineCyclerTrueImpl *_cycler; +#endif // DEBUG_THREADS + }; + +private: + PT(CycleData) cycle(); + INLINE PT(CycleData) cycle_2(); + INLINE PT(CycleData) cycle_3(); + void set_num_stages(int num_stages); + +private: + Pipeline *_pipeline; + + // An array of PT(CycleData) objects. + PT(CycleData) *_data; + int _num_stages; + bool _dirty; + + CyclerMutex _lock; + + friend class Pipeline; +}; + +#include "pipelineCyclerTrueImpl.I" + +#endif // THREADED_PIPELINE + +#endif +