move Pipeline* and Cycle* from putil, in order to pipeline the ClockObject class

This commit is contained in:
David Rose 2006-02-22 02:12:08 +00:00
parent 8c4afe0e13
commit 851eb4cd8b
44 changed files with 4998 additions and 52 deletions

View File

@ -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 \

View File

@ -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 &copy) :
_frame_count(copy._frame_count),
_reported_frame_time(copy._reported_frame_time),
_dt(copy._dt)
{
}
////////////////////////////////////////////////////////////////////
// Function: TimeVal::contructor
// Access: Published

View File

@ -20,16 +20,10 @@
#include "clockObject.h"
#include "config_express.h"
#include "configVariableEnum.h"
#if defined(WIN32)
#define WINDOWS_LEAN_AND_MEAN
#include <wtypes.h> // For select()
#undef WINDOWS_LEAN_AND_MEAN
#else
#include <sys/time.h> // 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:

View File

@ -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<double> 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 &copy);
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<CData> _cycler;
typedef CycleDataReader<CData> CDReader;
typedef CycleDataWriter<CData> CDWriter;
typedef CycleDataStageReader<CData> 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 &

View File

@ -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();

View File

@ -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

View File

@ -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() {
}

View File

@ -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";
}

View File

@ -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

View File

@ -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<class CycleDataType>
INLINE CycleDataReader<CycleDataType>::
CycleDataReader(const PipelineCycler<CycleDataType> &cycler) :
_cycler(&cycler)
{
_pointer = _cycler->read();
nassertv(_pointer != (const CycleDataType *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataReader::Copy Constructor (full)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataReader<CycleDataType>::
CycleDataReader(const CycleDataReader<CycleDataType> &copy) :
_cycler(copy._cycler),
_pointer(copy._pointer)
{
nassertv(_pointer != (const CycleDataType *)NULL);
_cycler->increment_read(_pointer);
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataReader::Copy Assignment (full)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE void CycleDataReader<CycleDataType>::
operator = (const CycleDataReader<CycleDataType> &copy) {
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<class CycleDataType>
INLINE CycleDataReader<CycleDataType>::
~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<class CycleDataType>
INLINE const CycleDataType *CycleDataReader<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataReader<CycleDataType>::
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<class CycleDataType>
INLINE const CycleDataType *CycleDataReader<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataReader<CycleDataType>::
CycleDataReader(const PipelineCycler<CycleDataType> &cycler) {
_pointer = cycler.read();
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataReader::Copy Constructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataReader<CycleDataType>::
CycleDataReader(const CycleDataReader<CycleDataType> &copy) :
_pointer(copy._pointer)
{
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataReader::Copy Assignment (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE void CycleDataReader<CycleDataType>::
operator = (const CycleDataReader<CycleDataType> &copy) {
_pointer = copy._pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataReader::Destructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataReader<CycleDataType>::
~CycleDataReader() {
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataReader::operator -> (trivial)
// Access: Public
// Description: This provides an indirect member access to the actual
// CycleData data.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataReader<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataReader<CycleDataType>::
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<class CycleDataType>
INLINE const CycleDataType *CycleDataReader<CycleDataType>::
take_pointer() {
return _pointer;
}
#endif // DO_PIPELINING

View File

@ -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"

View File

@ -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 CycleDataType>
class CycleDataReader {
public:
INLINE CycleDataReader(const PipelineCycler<CycleDataType> &cycler);
INLINE CycleDataReader(const CycleDataReader<CycleDataType> &copy);
INLINE void operator = (const CycleDataReader<CycleDataType> &copy);
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<CycleDataType> *_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

View File

@ -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<class CycleDataType>
INLINE CycleDataStageReader<CycleDataType>::
CycleDataStageReader(const PipelineCycler<CycleDataType> &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<class CycleDataType>
INLINE CycleDataStageReader<CycleDataType>::
CycleDataStageReader(const CycleDataStageReader<CycleDataType> &copy) :
_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<class CycleDataType>
INLINE void CycleDataStageReader<CycleDataType>::
operator = (const CycleDataStageReader<CycleDataType> &copy) {
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<class CycleDataType>
INLINE CycleDataStageReader<CycleDataType>::
~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<class CycleDataType>
INLINE const CycleDataType *CycleDataStageReader<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataStageReader<CycleDataType>::
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<class CycleDataType>
INLINE const CycleDataType *CycleDataStageReader<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataStageReader<CycleDataType>::
CycleDataStageReader(const PipelineCycler<CycleDataType> &cycler, int) {
_pointer = cycler.read();
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataStageReader::Copy Constructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataStageReader<CycleDataType>::
CycleDataStageReader(const CycleDataStageReader<CycleDataType> &copy) :
_pointer(copy._pointer)
{
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataStageReader::Copy Assignment (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE void CycleDataStageReader<CycleDataType>::
operator = (const CycleDataStageReader<CycleDataType> &copy) {
_pointer = copy._pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataStageReader::Destructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataStageReader<CycleDataType>::
~CycleDataStageReader() {
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataStageReader::operator -> (trivial)
// Access: Public
// Description: This provides an indirect member access to the actual
// CycleData data.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataStageReader<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataStageReader<CycleDataType>::
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<class CycleDataType>
INLINE const CycleDataType *CycleDataStageReader<CycleDataType>::
take_pointer() {
return _pointer;
}
#endif // DO_PIPELINING

View File

@ -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"

View File

@ -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 CycleDataType>
class CycleDataStageReader {
public:
INLINE CycleDataStageReader(const PipelineCycler<CycleDataType> &cycler, int stage);
INLINE CycleDataStageReader(const CycleDataStageReader<CycleDataType> &copy);
INLINE void operator = (const CycleDataStageReader<CycleDataType> &copy);
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<CycleDataType> *_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

View File

@ -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<class CycleDataType>
INLINE CycleDataStageWriter<CycleDataType>::
CycleDataStageWriter(PipelineCycler<CycleDataType> &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<class CycleDataType>
INLINE CycleDataStageWriter<CycleDataType>::
CycleDataStageWriter(const CycleDataStageWriter<CycleDataType> &copy) :
_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<class CycleDataType>
INLINE void CycleDataStageWriter<CycleDataType>::
operator = (const CycleDataStageWriter<CycleDataType> &copy) {
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<class CycleDataType>
INLINE CycleDataStageWriter<CycleDataType>::
CycleDataStageWriter(PipelineCycler<CycleDataType> &cycler, int stage,
CycleDataStageReader<CycleDataType> &take_from) :
_cycler(&cycler),
_stage(stage)
{
_pointer = _cycler->elevate_read_stage(_stage, take_from.take_pointer());
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataStageWriter::Destructor (full)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataStageWriter<CycleDataType>::
~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<class CycleDataType>
INLINE CycleDataType *CycleDataStageWriter<CycleDataType>::
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<class CycleDataType>
INLINE const CycleDataType *CycleDataStageWriter<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataStageWriter<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataStageWriter<CycleDataType>::
CycleDataStageWriter(PipelineCycler<CycleDataType> &cycler, int) {
_pointer = cycler.write();
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataStageWriter::Copy Constructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataStageWriter<CycleDataType>::
CycleDataStageWriter(const CycleDataStageWriter<CycleDataType> &copy) :
_pointer(copy._pointer)
{
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataStageWriter::Copy Assigment (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE void CycleDataStageWriter<CycleDataType>::
operator = (const CycleDataStageWriter<CycleDataType> &copy) {
_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<class CycleDataType>
INLINE CycleDataStageWriter<CycleDataType>::
CycleDataStageWriter(PipelineCycler<CycleDataType> &, int,
CycleDataStageReader<CycleDataType> &take_from) :
_pointer((CycleDataType *)take_from.take_pointer())
{
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataStageWriter::Destructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataStageWriter<CycleDataType>::
~CycleDataStageWriter() {
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataStageWriter::operator -> (trivial)
// Access: Public
// Description: This provides an indirect member access to the actual
// CycleData data.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataType *CycleDataStageWriter<CycleDataType>::
operator -> () {
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataStageWriter::operator -> (trivial)
// Access: Public
// Description: This provides an indirect member access to the actual
// CycleData data.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataStageWriter<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataStageWriter<CycleDataType>::
operator CycleDataType * () {
return _pointer;
}
#endif // DO_PIPELINING

View File

@ -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"

View File

@ -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 CycleDataType>
class CycleDataStageWriter {
public:
INLINE CycleDataStageWriter(PipelineCycler<CycleDataType> &cycler, int stage);
INLINE CycleDataStageWriter(const CycleDataStageWriter<CycleDataType> &copy);
INLINE void operator = (const CycleDataStageWriter<CycleDataType> &copy);
INLINE CycleDataStageWriter(PipelineCycler<CycleDataType> &cycler, int stage,
CycleDataStageReader<CycleDataType> &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<CycleDataType> *_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

View File

@ -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<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
CycleDataWriter(PipelineCycler<CycleDataType> &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<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
CycleDataWriter(PipelineCycler<CycleDataType> &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<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
CycleDataWriter(const CycleDataWriter<CycleDataType> &copy) :
_cycler(copy._cycler),
_pointer(copy._pointer)
{
nassertv(_pointer != (CycleDataType *)NULL);
_cycler->increment_write(_pointer);
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataWriter::Copy Assigment (full)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE void CycleDataWriter<CycleDataType>::
operator = (const CycleDataWriter<CycleDataType> &copy) {
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<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
CycleDataWriter(PipelineCycler<CycleDataType> &cycler,
CycleDataReader<CycleDataType> &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<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
CycleDataWriter(PipelineCycler<CycleDataType> &cycler,
CycleDataReader<CycleDataType> &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<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
~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<class CycleDataType>
INLINE CycleDataType *CycleDataWriter<CycleDataType>::
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<class CycleDataType>
INLINE const CycleDataType *CycleDataWriter<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
CycleDataWriter(PipelineCycler<CycleDataType> &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<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
CycleDataWriter(PipelineCycler<CycleDataType> &cycler, bool) {
_pointer = cycler.write();
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataWriter::Copy Constructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
CycleDataWriter(const CycleDataWriter<CycleDataType> &copy) :
_pointer(copy._pointer)
{
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataWriter::Copy Assigment (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE void CycleDataWriter<CycleDataType>::
operator = (const CycleDataWriter<CycleDataType> &copy) {
_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<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
CycleDataWriter(PipelineCycler<CycleDataType> &,
CycleDataReader<CycleDataType> &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<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
CycleDataWriter(PipelineCycler<CycleDataType> &,
CycleDataReader<CycleDataType> &take_from,
bool force_to_0) :
_pointer((CycleDataType *)take_from.take_pointer())
{
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataWriter::Destructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
~CycleDataWriter() {
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataWriter::operator -> (trivial)
// Access: Public
// Description: This provides an indirect member access to the actual
// CycleData data.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataType *CycleDataWriter<CycleDataType>::
operator -> () {
return _pointer;
}
////////////////////////////////////////////////////////////////////
// Function: CycleDataWriter::operator -> (trivial)
// Access: Public
// Description: This provides an indirect member access to the actual
// CycleData data.
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *CycleDataWriter<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataWriter<CycleDataType>::
operator CycleDataType * () {
return _pointer;
}
#endif // DO_PIPELINING

View File

@ -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"

View File

@ -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 CycleDataType>
class CycleDataWriter {
public:
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler);
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler, bool force_to_0);
INLINE CycleDataWriter(const CycleDataWriter<CycleDataType> &copy);
INLINE void operator = (const CycleDataWriter<CycleDataType> &copy);
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler, CycleDataReader<CycleDataType> &take_from);
INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler, CycleDataReader<CycleDataType> &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<CycleDataType> *_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

View File

@ -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 &copy) {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: CyclerHolder::Copy Assignment Operator
// Access: Private
// Description: Do not attempt to copy CyclerHolders.
////////////////////////////////////////////////////////////////////
INLINE void CyclerHolder::
operator = (const CyclerHolder &copy) {
nassertv(false);
}

View File

@ -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"

View File

@ -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 &copy);
INLINE void operator = (const CyclerHolder &copy);
private:
#ifdef DO_PIPELINING
PipelineCyclerBase *_cycler;
#endif
};
#include "cyclerHolder.I"
#endif

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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<PipelineCyclerTrueImpl *> Cyclers;
Cyclers _dirty_cyclers;
#ifdef DEBUG_THREADS
typedef pmap<TypeHandle, int> 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

View File

@ -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<class CycleDataType>
INLINE PipelineCycler<CycleDataType>::
PipelineCycler(Pipeline *pipeline) :
PipelineCyclerBase(new CycleDataType, pipeline)
{
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::Copy Constructor (dummy or true)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE PipelineCycler<CycleDataType>::
PipelineCycler(const PipelineCycler<CycleDataType> &copy) :
PipelineCyclerBase(copy)
{
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::Copy Assignment (dummy or true)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE void PipelineCycler<CycleDataType>::
operator = (const PipelineCycler<CycleDataType> &copy) {
PipelineCyclerBase::operator = (copy);
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::read (dummy or true)
// Access: Public
// Description: See PipelineCyclerBase::read().
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *PipelineCycler<CycleDataType>::
read() const {
return (const CycleDataType *)PipelineCyclerBase::read();
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::read (dummy or true)
// Access: Public
// Description: See PipelineCyclerBase::read_stage().
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *PipelineCycler<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
write() {
return (CycleDataType *)PipelineCyclerBase::write();
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::elevate_read (dummy or true)
// Access: Public
// Description: See PipelineCyclerBase::elevate_read().
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
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<class CycleDataType>
INLINE PipelineCycler<CycleDataType>::
PipelineCycler(Pipeline *pipeline) :
PipelineCyclerBase(&_typed_data, pipeline)
{
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::Copy Constructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE PipelineCycler<CycleDataType>::
PipelineCycler(const PipelineCycler<CycleDataType> &copy) :
PipelineCyclerBase(&_typed_data),
_typed_data(copy._typed_data)
{
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::Copy Assignment (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE void PipelineCycler<CycleDataType>::
operator = (const PipelineCycler<CycleDataType> &copy) {
_typed_data = copy._typed_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::read (trivial)
// Access: Public
// Description: See PipelineCyclerBase::read().
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE const CycleDataType *PipelineCycler<CycleDataType>::
read() const {
return &_typed_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::write (trivial)
// Access: Public
// Description: See PipelineCyclerBase::write().
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
write() {
return &_typed_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::elevate_read (trivial)
// Access: Public
// Description: See PipelineCyclerBase::elevate_read().
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
elevate_read(const CycleDataType *) {
return &_typed_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::elevate_read_upstream (trivial)
// Access: Public
// Description: See PipelineCyclerBase::elevate_read_upstream().
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
elevate_read_upstream(const CycleDataType *, bool) {
return &_typed_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::write_upstream (trivial)
// Access: Public
// Description: See PipelineCyclerBase::write_upstream().
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
write_upstream(bool) {
return &_typed_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::write_stage (trivial)
// Access: Public
// Description: See PipelineCyclerBase::write_stage().
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
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<class CycleDataType>
INLINE CycleDataType *PipelineCycler<CycleDataType>::
cheat() const {
return (CycleDataType *)&_typed_data;
}
#endif // DO_PIPELINING

View File

@ -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"

View File

@ -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<class CycleDataType>
struct PipelineCycler : public PipelineCyclerBase {
public:
INLINE PipelineCycler(Pipeline *pipeline = NULL);
INLINE PipelineCycler(const PipelineCycler<CycleDataType> &copy);
INLINE void operator = (const PipelineCycler<CycleDataType> &copy);
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

View File

@ -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

View File

@ -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 &copy) :
_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 &copy) {
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;
}

View File

@ -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"

View File

@ -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 &copy);
INLINE void operator = (const PipelineCyclerDummyImpl &copy);
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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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"

View File

@ -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 &copy);
INLINE void operator = (const PipelineCyclerTrivialImpl &copy);
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

View File

@ -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
}

View File

@ -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 &copy) :
_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<CycleData *, PT(CycleData) > 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 &copy) {
ReMutexHolder holder1(_lock);
ReMutexHolder holder2(copy._lock);
nassertv(get_parent_type() == copy.get_parent_type());
typedef pmap<CycleData *, PT(CycleData) > 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

View File

@ -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 &copy);
void operator = (const PipelineCyclerTrueImpl &copy);
~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