first pass at cheesy pipelining

This commit is contained in:
David Rose 2006-02-01 19:44:03 +00:00
parent ad72a2b2fd
commit 629a2f087a
35 changed files with 1656 additions and 788 deletions

View File

@ -33,6 +33,8 @@
#include "cullFaceAttrib.h"
#include "string_utils.h"
#include "geomCacheManager.h"
#include "thread.h"
#include "pipeline.h"
#include "throw_event.h"
#if defined(WIN32)
@ -1413,6 +1415,9 @@ get_window_renderer(const string &name) {
}
PT(RenderThread) thread = new RenderThread(name, this);
thread->set_pipeline_stage(1);
Pipeline::get_render_pipeline()->set_num_stages(2);
thread->start(TP_normal, true, true);
_threads[name] = thread;

View File

@ -20,6 +20,7 @@
#include "config_express.h"
#include "datagram.h"
#include "mainThread.h"
#include "externalThread.h"
#include "referenceCount.h"
#include "textEncoder.h"
#include "thread.h"
@ -169,6 +170,7 @@ init_libexpress() {
Datagram::init_type();
MainThread::init_type();
ExternalThread::init_type();
ReferenceCount::init_type();
TextEncoder::init_type();
Thread::init_type();

View File

@ -23,12 +23,29 @@ TypeHandle ExternalThread::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: ExternalThread::Constructor
// Access: Private
// Description:
// Description: This constructor is used to create the one global
// ExternalThread object that is shared by all
// externally-created threads that are not specifically
// bound to a particular Thread object.
////////////////////////////////////////////////////////////////////
ExternalThread::
ExternalThread() : Thread("External", "External") {
_started = true;
}
////////////////////////////////////////////////////////////////////
// Function: ExternalThread::Constructor
// Access: Private
// Description: This constructor is used to create the particular
// Thread object for each external thread that is bound
// via Thread::bind_thread().
////////////////////////////////////////////////////////////////////
ExternalThread::
ExternalThread(const string &name, const string &sync_name) :
Thread(name, sync_name)
{
_started = true;
}
////////////////////////////////////////////////////////////////////
// Function: ExternalThread::thread_main

View File

@ -31,12 +31,14 @@
class EXPCL_PANDAEXPRESS ExternalThread : public Thread {
private:
ExternalThread();
ExternalThread(const string &name, const string &sync_name);
virtual void thread_main();
public:
PUBLISHED:
static TypeHandle get_class_type() {
return _type_handle;
}
public:
static void init_type() {
Thread::init_type();
register_type(_type_handle, "ExternalThread",

View File

@ -33,10 +33,11 @@ private:
MainThread();
virtual void thread_main();
public:
PUBLISHED:
static TypeHandle get_class_type() {
return _type_handle;
}
public:
static void init_type() {
Thread::init_type();
register_type(_type_handle, "MainThread",

View File

@ -19,7 +19,7 @@
////////////////////////////////////////////////////////////////////
// Function: Thread::Constructor
// Access: Public
// Access: Protected
// Description: Creates a new Thread object, but does not
// immediately start executing it. This gives the
// caller a chance to store it in a PT(Thread) object,
@ -43,6 +43,7 @@ Thread(const string &name, const string &sync_name) :
{
_started = false;
_pstats_index = -1;
_pipeline_stage = 0;
}
////////////////////////////////////////////////////////////////////
@ -67,7 +68,7 @@ operator = (const Thread &copy) {
////////////////////////////////////////////////////////////////////
// Function: Thread::get_name
// Access: Public
// Access: Published
// Description: Returns the name of the thread. Each thread should
// probably have a unique name, but this is not enforced
// (and not strictly required).
@ -79,7 +80,7 @@ get_name() const {
////////////////////////////////////////////////////////////////////
// Function: Thread::get_sync_name
// Access: Public
// Access: Published
// Description: Returns the sync name of the thread. This name
// collects threads into "sync groups", which are
// expected to run synchronously. This is mainly used
@ -94,7 +95,7 @@ get_sync_name() const {
////////////////////////////////////////////////////////////////////
// Function: Thread::get_pstats_index
// Access: Public
// Access: Published
// Description: Returns the PStats index associated with this thread,
// or -1 if no index has yet been associated with this
// thread. This is used internally by the PStatClient;
@ -107,7 +108,7 @@ get_pstats_index() const {
////////////////////////////////////////////////////////////////////
// Function: Thread::set_pstats_index
// Access: Public
// Access: Published
// Description: Stores a PStats index to be associated with this
// thread. This is used internally by the PStatClient;
// you should not need to call this directly.
@ -117,6 +118,120 @@ set_pstats_index(int pstats_index) {
_pstats_index = pstats_index;
}
////////////////////////////////////////////////////////////////////
// Function: Thread::get_pipeline_stage
// Access: Published
// Description: Returns the Pipeline stage number associated with
// this thread. The default stage is 0 if no stage is
// specified otherwise. See set_pipeline_stage().
////////////////////////////////////////////////////////////////////
INLINE int Thread::
get_pipeline_stage() const {
return _pipeline_stage;
}
////////////////////////////////////////////////////////////////////
// Function: Thread::set_pipeline_stage
// Access: Published
// Description: Specifies the Pipeline stage number associated with
// this thread. The default stage is 0 if no stage is
// specified otherwise.
//
// This must be a value in the range [0
// .. pipeline->get_num_stages() - 1]. It specifies the
// values that this thread observes for all pipelined
// data. Typically, an application thread will leave
// this at 0, but a render thread may set it to 1 or 2
// (to operate on the previous frame's data, or the
// second previous frame's data).
////////////////////////////////////////////////////////////////////
INLINE void Thread::
set_pipeline_stage(int pipeline_stage) {
_pipeline_stage = pipeline_stage;
}
////////////////////////////////////////////////////////////////////
// Function: Thread::get_main_thread
// Access: Published, Static
// Description: Returns a pointer to the "main" Thread object--this
// is the Thread that started the whole process.
////////////////////////////////////////////////////////////////////
INLINE Thread *Thread::
get_main_thread() {
if (_main_thread == (Thread *)NULL) {
init_main_thread();
}
return _main_thread;
}
////////////////////////////////////////////////////////////////////
// Function: Thread::get_external_thread
// Access: Published, Static
// Description: Returns a pointer to the "external" Thread
// object--this is a special Thread object that
// corresponds to any thread spawned outside of Panda's
// threading interface. Note that multiple different
// threads may share this same pointer.
////////////////////////////////////////////////////////////////////
INLINE Thread *Thread::
get_external_thread() {
if (_external_thread == (Thread *)NULL) {
init_external_thread();
}
return _external_thread;
}
////////////////////////////////////////////////////////////////////
// Function: Thread::get_current_thread
// Access: Published, Static
// Description: Returns a pointer to the currently-executing Thread
// object. If this is called from the main thread, this
// will return the same value as get_main_thread().
//
// This will always return some valid Thread pointer.
// It will never return NULL, even if the current thread
// was spawned outside of Panda's threading system,
// although all non-Panda threads will return the exact
// same Thread pointer.
////////////////////////////////////////////////////////////////////
INLINE Thread *Thread::
get_current_thread() {
#ifndef HAVE_THREADS
return get_main_thread();
#else // HAVE_THREADS
Thread *thread = ThreadImpl::get_current_thread();
if (thread == (Thread *)NULL) {
return Thread::get_external_thread();
}
return thread;
#endif // HAVE_THREADS
}
////////////////////////////////////////////////////////////////////
// Function: Thread::is_threading_supported
// Access: Published, Static
// Description: Returns true if a real threading library is available
// that supports threads, or false if no threading
// library is available (and Thread::start() will always
// fail).
////////////////////////////////////////////////////////////////////
INLINE bool Thread::
is_threading_supported() {
return ThreadImpl::is_threading_supported();
}
////////////////////////////////////////////////////////////////////
// Function: Thread::sleep
// Access: Published, Static
// Description: Suspends the current thread for at least the
// indicated amount of time. It might be suspended for
// longer.
////////////////////////////////////////////////////////////////////
INLINE void Thread::
sleep(double seconds) {
ThreadImpl::sleep(seconds);
}
////////////////////////////////////////////////////////////////////
// Function: Thread::start
// Access: Public
@ -187,88 +302,6 @@ prepare_for_exit() {
ThreadImpl::prepare_for_exit();
}
////////////////////////////////////////////////////////////////////
// Function: Thread::get_main_thread
// Access: Public, Static
// Description: Returns a pointer to the "main" Thread object--this
// is the Thread that started the whole process.
////////////////////////////////////////////////////////////////////
INLINE Thread *Thread::
get_main_thread() {
if (_main_thread == (Thread *)NULL) {
init_main_thread();
}
return _main_thread;
}
////////////////////////////////////////////////////////////////////
// Function: Thread::get_external_thread
// Access: Public, Static
// Description: Returns a pointer to the "external" Thread
// object--this is a special Thread object that
// corresponds to any thread spawned outside of Panda's
// threading interface. Note that multiple different
// threads may share this same pointer.
////////////////////////////////////////////////////////////////////
INLINE Thread *Thread::
get_external_thread() {
if (_external_thread == (Thread *)NULL) {
init_external_thread();
}
return _external_thread;
}
////////////////////////////////////////////////////////////////////
// Function: Thread::get_current_thread
// Access: Public, Static
// Description: Returns a pointer to the currently-executing Thread
// object. If this is called from the main thread, this
// will return the same value as get_main_thread().
//
// This will always return some valid Thread pointer.
// It will never return NULL, even if the current thread
// was spawned outside of Panda's threading system,
// although all non-Panda threads will return the exact
// same Thread pointer.
////////////////////////////////////////////////////////////////////
INLINE Thread *Thread::
get_current_thread() {
#ifndef HAVE_THREADS
return get_main_thread();
#else // HAVE_THREADS
Thread *thread = ThreadImpl::get_current_thread();
if (thread == (Thread *)NULL) {
return Thread::get_external_thread();
}
return thread;
#endif // HAVE_THREADS
}
////////////////////////////////////////////////////////////////////
// Function: Thread::is_threading_supported
// Access: Public, Static
// Description: Returns true if a real threading library is available
// that supports threads, or false if no threading
// library is available (and Thread::start() will always
// fail).
////////////////////////////////////////////////////////////////////
INLINE bool Thread::
is_threading_supported() {
return ThreadImpl::is_threading_supported();
}
////////////////////////////////////////////////////////////////////
// Function: Thread::sleep
// Access: Public, Static
// Description: Suspends the current thread for at least the
// indicated amount of time. It might be suspended for
// longer.
////////////////////////////////////////////////////////////////////
INLINE void Thread::
sleep(double seconds) {
ThreadImpl::sleep(seconds);
}
INLINE ostream &
operator << (ostream &out, const Thread &thread) {
thread.output(out);

View File

@ -26,16 +26,57 @@ TypeHandle Thread::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: Thread::Destructor
// Access: Public, Virtual
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
Thread::
~Thread() {
}
////////////////////////////////////////////////////////////////////
// Function: Thread::bind_thread
// Access: Published, Static
// Description: Returns a new Panda Thread object associated with the
// current thread (which has been created externally).
// This can be used to bind a unique Panda Thread object
// with an external thread, such as a new Python thread.
//
// It is particularly useful to bind a Panda Thread
// object to an external thread for the purposes of
// PStats monitoring. Without this call, each external
// thread will be assigned the same global
// ExternalThread object, which means they will all
// appear in the same PStats graph.
//
// It is the caller's responsibility to save the
// returned Thread pointer for the lifetime of the
// external thread. It is an error for the Thread
// pointer to destruct while the external thread is
// still in the system.
//
// It is also an error to call this method from the main
// thread, or twice within a given thread, unless it is
// given the same name each time (in which case the same
// pointer will be returned each time).
////////////////////////////////////////////////////////////////////
PT(Thread) Thread::
bind_thread(const string &name, const string &sync_name) {
Thread *current_thread = get_current_thread();
if (current_thread != get_external_thread()) {
// This thread already has an associated thread.
nassertr(current_thread->get_name() == name &&
current_thread->get_sync_name() == sync_name, current_thread);
return current_thread;
}
PT(Thread) thread = new ExternalThread(name, sync_name);
ThreadImpl::bind_thread(thread);
return thread;
}
////////////////////////////////////////////////////////////////////
// Function: Thread::output
// Access: Public, Virtual
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void Thread::

View File

@ -21,6 +21,7 @@
#include "pandabase.h"
#include "typedReferenceCount.h"
#include "pointerTo.h"
#include "threadPriority.h"
#include "threadImpl.h"
#include "notify.h"
@ -38,8 +39,10 @@
// are referencing it.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS Thread : public TypedReferenceCount {
public:
protected:
INLINE Thread(const string &name, const string &sync_name);
PUBLISHED:
virtual ~Thread();
private:
@ -49,18 +52,17 @@ private:
protected:
virtual void thread_main()=0;
public:
PUBLISHED:
static PT(Thread) bind_thread(const string &name, const string &sync_name);
INLINE const string &get_name() const;
INLINE const string &get_sync_name() const;
INLINE int get_pstats_index() const;
INLINE void set_pstats_index(int pstats_index);
INLINE bool start(ThreadPriority priority, bool global, bool joinable);
INLINE void interrupt();
INLINE void join();
INLINE static void prepare_for_exit();
INLINE int get_pipeline_stage() const;
INLINE void set_pipeline_stage(int pipeline_stage);
INLINE static Thread *get_main_thread();
INLINE static Thread *get_external_thread();
@ -70,6 +72,13 @@ public:
virtual void output(ostream &out) const;
public:
INLINE bool start(ThreadPriority priority, bool global, bool joinable);
INLINE void interrupt();
INLINE void join();
INLINE static void prepare_for_exit();
private:
static void init_main_thread();
static void init_external_thread();
@ -80,6 +89,7 @@ protected:
string _sync_name;
ThreadImpl _impl;
int _pstats_index;
int _pipeline_stage;
private:
static Thread *_main_thread;

View File

@ -72,6 +72,19 @@ INLINE void ThreadDummyImpl::
prepare_for_exit() {
}
////////////////////////////////////////////////////////////////////
// Function: ThreadDummyImpl::bind_thread
// Access: Public, Static
// Description: Associates the indicated Thread object with the
// currently-executing thread. You should not call this
// directly; use Thread::bind_thread() instead.
////////////////////////////////////////////////////////////////////
INLINE void ThreadDummyImpl::
bind_thread(Thread *thread) {
// This method shouldn't be called in the non-threaded case.
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: ThreadDummyImpl::is_threading_supported
// Access: Public, Static

View File

@ -53,6 +53,7 @@ public:
INLINE static void prepare_for_exit();
static Thread *get_current_thread();
INLINE static void bind_thread(Thread *thread);
INLINE static bool is_threading_supported();
INLINE static void sleep(double seconds);

View File

@ -41,7 +41,7 @@ prepare_for_exit() {
}
////////////////////////////////////////////////////////////////////
// Function: ThreadNsprImpl::Constructor
// Function: ThreadNsprImpl::get_current_thread
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
@ -53,6 +53,22 @@ get_current_thread() {
return (Thread *)PR_GetThreadPrivate(_pt_ptr_index);
}
////////////////////////////////////////////////////////////////////
// Function: ThreadNsprImpl::bind_thread
// Access: Public, Static
// Description: Associates the indicated Thread object with the
// currently-executing thread. You should not call this
// directly; use Thread::bind_thread() instead.
////////////////////////////////////////////////////////////////////
INLINE void ThreadNsprImpl::
bind_thread(Thread *thread) {
if (!_got_pt_ptr_index) {
init_pt_ptr_index();
}
PRStatus result = PR_SetThreadPrivate(_pt_ptr_index, thread);
nassertv(result == PR_SUCCESS);
}
////////////////////////////////////////////////////////////////////
// Function: ThreadNsprImpl::is_threading_supported
// Access: Public, Static

View File

@ -49,6 +49,7 @@ public:
INLINE static void prepare_for_exit();
INLINE static Thread *get_current_thread();
INLINE static void bind_thread(Thread *thread);
INLINE static bool is_threading_supported();
INLINE static void sleep(double seconds);

View File

@ -799,7 +799,7 @@ Registry() {
(InternalName::get_vertex(), 3,
NT_float32, C_point,
InternalName::get_normal(), 3,
NT_float32, C_point,
NT_float32, C_vector,
InternalName::get_color(), 1,
NT_packed_dabc, C_color));
@ -815,7 +815,7 @@ Registry() {
(InternalName::get_vertex(), 3,
NT_float32, C_point,
InternalName::get_normal(), 3,
NT_float32, C_point,
NT_float32, C_vector,
InternalName::get_color(), 1,
NT_packed_dabc, C_color,
InternalName::get_texcoord(), 2,
@ -834,7 +834,7 @@ Registry() {
(InternalName::get_vertex(), 3,
NT_float32, C_point,
InternalName::get_normal(), 3,
NT_float32, C_point,
NT_float32, C_vector,
InternalName::get_color(), 4,
NT_uint8, C_color));
@ -850,7 +850,7 @@ Registry() {
(InternalName::get_vertex(), 3,
NT_float32, C_point,
InternalName::get_normal(), 3,
NT_float32, C_point,
NT_float32, C_vector,
InternalName::get_color(), 4,
NT_uint8, C_color,
InternalName::get_texcoord(), 2,

View File

@ -125,33 +125,6 @@ CData() {
_fixed_internal_bound = false;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PandaNode::CData::
CData(const PandaNode::CData &copy) :
_down(copy._down),
_stashed(copy._stashed),
_up(copy._up),
_paths(copy._paths),
_state(copy._state),
_effects(copy._effects),
_transform(copy._transform),
_prev_transform(copy._prev_transform),
_tag_data(copy._tag_data),
_draw_mask(copy._draw_mask),
_into_collide_mask(copy._into_collide_mask),
_fixed_internal_bound(copy._fixed_internal_bound)
{
_net_collide_mask = CollideMask::all_off();
// Note that this copy constructor is not used by the PandaNode copy
// constructor! Any elements that must be copied between nodes
// should also be explicitly copied there.
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::Children::Constructor
// Access: Public

View File

@ -55,6 +55,53 @@ TypeHandle PandaNode::_type_handle;
//
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PandaNode::CData::
CData(const PandaNode::CData &copy) :
_down(copy._down),
_stashed(copy._stashed),
_up(copy._up),
_paths(copy._paths),
_state(copy._state),
_effects(copy._effects),
_transform(copy._transform),
_prev_transform(copy._prev_transform),
_tag_data(copy._tag_data),
_draw_mask(copy._draw_mask),
_into_collide_mask(copy._into_collide_mask),
_net_collide_mask(copy._net_collide_mask),
_off_clip_planes(copy._off_clip_planes),
_fixed_internal_bound(copy._fixed_internal_bound)
{
// Note that this copy constructor is not used by the PandaNode copy
// constructor! Any elements that must be copied between nodes
// should also be explicitly copied there.
#ifdef HAVE_PYTHON
// Copy and increment all of the Python objects held by the other
// node.
_python_tag_data = _python_tag_data;
inc_py_refs();
#endif // HAVE_PYTHON
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
PandaNode::CData::
~CData() {
#ifdef HAVE_PYTHON
// Free all of the Python objects held by this node.
dec_py_refs();
#endif // HAVE_PYTHON
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::make_copy
// Access: Public, Virtual
@ -160,9 +207,47 @@ fillin(DatagramIterator &scan, BamReader *manager) {
}
}
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::inc_py_refs
// Access: Public
// Description: Increments the reference counts on all held Python
// objects.
////////////////////////////////////////////////////////////////////
void PandaNode::CData::
inc_py_refs() {
PythonTagData::const_iterator ti;
for (ti = _python_tag_data.begin();
ti != _python_tag_data.end();
++ti) {
PyObject *value = (*ti).second;
Py_XINCREF(value);
}
}
#endif // HAVE_PYTHON
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::dec_py_refs
// Access: Public
// Description: Decrements the reference counts on all held Python
// objects.
////////////////////////////////////////////////////////////////////
void PandaNode::CData::
dec_py_refs() {
PythonTagData::const_iterator ti;
for (ti = _python_tag_data.begin();
ti != _python_tag_data.end();
++ti) {
PyObject *value = (*ti).second;
Py_XDECREF(value);
}
}
#endif // HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::write_up_list
// Access: Private
// Access: Public
// Description: Writes the indicated list of parent node pointers to
// the datagram.
////////////////////////////////////////////////////////////////////
@ -198,7 +283,7 @@ write_up_list(const PandaNode::Up &up_list,
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::write_down_list
// Access: Private
// Access: Public
// Description: Writes the indicated list of child node pointers to
// the datagram.
////////////////////////////////////////////////////////////////////
@ -222,7 +307,7 @@ write_down_list(const PandaNode::Down &down_list,
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::complete_up_list
// Access: Private
// Access: Public
// Description: Calls complete_pointers() on the list of parent node
// pointers.
////////////////////////////////////////////////////////////////////
@ -254,7 +339,7 @@ complete_up_list(PandaNode::Up &up_list,
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::complete_down_list
// Access: Private
// Access: Public
// Description: Calls complete_pointers() on the list of child node
// pointers.
////////////////////////////////////////////////////////////////////
@ -279,7 +364,7 @@ complete_down_list(PandaNode::Down &down_list,
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::fillin_up_list
// Access: Private
// Access: Public
// Description: Reads the indicated list parent node pointers from
// the datagram (or at least calls read_pointer() for
// each one).
@ -298,7 +383,7 @@ fillin_up_list(PandaNode::Up &up_list,
////////////////////////////////////////////////////////////////////
// Function: PandaNode::CData::fillin_down_list
// Access: Private
// Access: Public
// Description: Reads the indicated list child node pointers from
// the datagram (or at least calls read_pointer() for
// each one).
@ -370,20 +455,6 @@ PandaNode::
#endif // NDEBUG
remove_all_children();
#ifdef HAVE_PYTHON
{
// Free all of the Python objects held by this node.
CDReader cdata(_cycler);
PythonTagData::const_iterator ti;
for (ti = cdata->_python_tag_data.begin();
ti != cdata->_python_tag_data.end();
++ti) {
PyObject *value = (*ti).second;
Py_XDECREF(value);
}
}
#endif // HAVE_PYTHON
}
////////////////////////////////////////////////////////////////////
@ -418,21 +489,16 @@ PandaNode(const PandaNode &copy) :
cdata->_tag_data = copy_cdata->_tag_data;
cdata->_draw_mask = copy_cdata->_draw_mask;
cdata->_into_collide_mask = copy_cdata->_into_collide_mask;
cdata->_net_collide_mask = CollideMask::all_off();
cdata->_off_clip_planes = NULL;
cdata->_fixed_internal_bound = copy_cdata->_fixed_internal_bound;
#ifdef HAVE_PYTHON
// Copy and increment all of the Python objects held by the other
// node.
cdata->_python_tag_data = copy_cdata->_python_tag_data;
PythonTagData::const_iterator ti;
for (ti = cdata->_python_tag_data.begin();
ti != cdata->_python_tag_data.end();
++ti) {
PyObject *value = (*ti).second;
Py_XINCREF(value);
}
cdata->inc_py_refs();
#endif // HAVE_PYTHON
}
////////////////////////////////////////////////////////////////////

View File

@ -315,12 +315,19 @@ private:
class EXPCL_PANDA CData : public CycleData {
public:
INLINE CData();
INLINE CData(const CData &copy);
CData(const CData &copy);
virtual ~CData();
virtual CycleData *make_copy() const;
virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
virtual void fillin(DatagramIterator &scan, BamReader *manager);
#ifdef HAVE_PYTHON
void inc_py_refs();
void dec_py_refs();
#endif
void write_up_list(const Up &up_list,
BamWriter *manager, Datagram &dg) const;
void write_down_list(const Down &down_list,

View File

@ -25,7 +25,7 @@
// Description: Returns the Panda Thread object associated with this
// particular PStatThread.
////////////////////////////////////////////////////////////////////
INLINE Thread *PStatThread::
Thread *PStatThread::
get_thread() const {
return _client->get_thread_object(_index);
}

View File

@ -48,7 +48,10 @@
nodePointerTo.h nodePointerTo.I \
pipeline.h pipeline.I \
pipelineCycler.h pipelineCycler.I \
pipelineCyclerBase.h pipelineCyclerBase.I \
pipelineCyclerBase.h \
pipelineCyclerDummyImpl.h pipelineCyclerDummyImpl.I \
pipelineCyclerTrivialImpl.h pipelineCyclerTrivialImpl.I \
pipelineCyclerTrueImpl.h pipelineCyclerTrueImpl.I \
pta_double.h \
pta_float.h pta_int.h \
string_utils.I string_utils.N string_utils.h \
@ -88,7 +91,9 @@
nodePointerTo.cxx \
pipeline.cxx \
pipelineCycler.cxx \
pipelineCyclerBase.cxx \
pipelineCyclerDummyImpl.cxx \
pipelineCyclerTrivialImpl.cxx \
pipelineCyclerTrueImpl.cxx \
pta_double.cxx pta_float.cxx \
pta_int.cxx pta_ushort.cxx \
string_utils.cxx timedCycle.cxx typedWritable.cxx \
@ -138,7 +143,10 @@
nodePointerTo.h nodePointerTo.I \
pipeline.h pipeline.I \
pipelineCycler.h pipelineCycler.I \
pipelineCyclerBase.h pipelineCyclerBase.I \
pipelineCyclerBase.h \
pipelineCyclerDummyImpl.h pipelineCyclerDummyImpl.I \
pipelineCyclerTrivialImpl.h pipelineCyclerTrivialImpl.I \
pipelineCyclerTrueImpl.h pipelineCyclerTrueImpl.I \
pta_double.h \
pta_float.h pta_int.h pta_ushort.h \
string_utils.I \

View File

@ -32,11 +32,10 @@
#include "pset.h"
#include "pmap.h"
#include "dcast.h"
#include "pipelineCyclerBase.h"
#include <algorithm>
struct PipelineCyclerBase;
// A handy macro for reading PointerToArrays.
#define READ_PTA(Manager, source, Read_func, array) \

View File

@ -28,8 +28,8 @@
#include "pset.h"
#include "pmap.h"
#include "vector_int.h"
#include "pipelineCyclerBase.h"
struct PipelineCyclerBase;
// A handy macro for writing PointerToArrays.
#define WRITE_PTA(Manager, dest, Write_func, array) \

View File

@ -17,6 +17,7 @@
////////////////////////////////////////////////////////////////////
#include "pipeline.h"
#include "pipelineCyclerTrueImpl.h"
Pipeline *Pipeline::_render_pipeline = (Pipeline *)NULL;
@ -29,26 +30,100 @@ Pipeline::
Pipeline(const string &name) :
Namable(name)
{
_num_stages = 1;
}
////////////////////////////////////////////////////////////////////
// Function: Pipeline::Destructor
// Access: Public, Virtual
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
Pipeline::
~Pipeline() {
#if defined(DO_PIPELINING) && defined(HAVE_THREADS)
nassertv(_cyclers.empty());
#endif // DO_PIPELINING && HAVE_THREADS
}
////////////////////////////////////////////////////////////////////
// Function: Pipeline::cycle
// Access: Public, Virtual
// Access: Public
// Description: Flows all the pipeline data down to the next stage.
////////////////////////////////////////////////////////////////////
void Pipeline::
cycle() {
#if defined(DO_PIPELINING) && defined(HAVE_THREADS)
Cyclers::iterator ci;
for (ci = _cyclers.begin(); ci != _cyclers.end(); ++ci) {
(*ci)->cycle();
}
#endif // DO_PIPELINING && HAVE_THREADS
}
////////////////////////////////////////////////////////////////////
// Function: Pipeline::set_num_stages
// Access: Public
// Description: Specifies the number of stages required for the
// pipeline.
////////////////////////////////////////////////////////////////////
void Pipeline::
set_num_stages(int num_stages) {
nassertv(num_stages >= 1);
if (num_stages != _num_stages) {
_num_stages = num_stages;
#if defined(DO_PIPELINING) && defined(HAVE_THREADS)
Cyclers::iterator ci;
for (ci = _cyclers.begin(); ci != _cyclers.end(); ++ci) {
(*ci)->set_num_stages(num_stages);
}
#endif // DO_PIPELINING && HAVE_THREADS
}
}
////////////////////////////////////////////////////////////////////
// Function: Pipeline::get_num_stages
// Access: Public
// Description: Returns the number of stages required for the
// pipeline.
////////////////////////////////////////////////////////////////////
int Pipeline::
get_num_stages() const {
return _num_stages;
}
#if defined(DO_PIPELINING) && defined(HAVE_THREADS)
////////////////////////////////////////////////////////////////////
// Function: Pipeline::add_cycler
// Access: Public
// Description: Adds the indicated cycler to the list of cyclers
// associated with the pipeline. This method only
// exists when true pipelining is configured on.
////////////////////////////////////////////////////////////////////
void Pipeline::
add_cycler(PipelineCyclerTrueImpl *cycler) {
bool inserted = _cyclers.insert(cycler).second;
nassertv(inserted);
}
#endif // DO_PIPELINING && HAVE_THREADS
#if defined(DO_PIPELINING) && defined(HAVE_THREADS)
////////////////////////////////////////////////////////////////////
// Function: Pipeline::remove_cycler
// Access: Public
// Description: Removes the indicated cycler from the list of cyclers
// associated with the pipeline. This method only
// exists when true pipelining is configured on.
////////////////////////////////////////////////////////////////////
void Pipeline::
remove_cycler(PipelineCyclerTrueImpl *cycler) {
Cyclers::iterator ci = _cyclers.find(cycler);
nassertv(ci != _cyclers.end());
_cyclers.erase(ci);
}
#endif // DO_PIPELINING && HAVE_THREADS
////////////////////////////////////////////////////////////////////
// Function: Pipeline::make_render_pipeline
// Access: Private, Static
@ -59,4 +134,3 @@ make_render_pipeline() {
nassertv(_render_pipeline == (Pipeline *)NULL);
_render_pipeline = new Pipeline("render");
}

View File

@ -21,6 +21,9 @@
#include "pandabase.h"
#include "namable.h"
#include "pset.h"
class PipelineCyclerTrueImpl;
////////////////////////////////////////////////////////////////////
// Class : Pipeline
@ -38,15 +41,30 @@
class EXPCL_PANDA Pipeline : public Namable {
public:
Pipeline(const string &name);
virtual ~Pipeline();
~Pipeline();
INLINE static Pipeline *get_render_pipeline();
virtual void cycle();
void cycle();
void set_num_stages(int num_stages);
int get_num_stages() const;
#if defined(DO_PIPELINING) && defined(HAVE_THREADS)
void add_cycler(PipelineCyclerTrueImpl *cycler);
void remove_cycler(PipelineCyclerTrueImpl *cycler);
#endif // DO_PIPELINING && HAVE_THREADS
private:
int _num_stages;
static void make_render_pipeline();
static Pipeline *_render_pipeline;
#if defined(DO_PIPELINING) && defined(HAVE_THREADS)
typedef pset<PipelineCyclerTrueImpl *> Cyclers;
Cyclers _cyclers;
#endif // DO_PIPELINING && HAVE_THREADS
};
#include "pipeline.I"

View File

@ -18,11 +18,11 @@
#ifdef DO_PIPELINING
// The following implementations are to support compiled-in pipeline
// sanity checks.
// The following implementations are to support the
// PipelineCyclerDummyImpl or the PipelineCyclerTrueImpl.
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::Constructor (sanity-check)
// Function: PipelineCycler::Constructor (dummy or true)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
@ -34,20 +34,19 @@ PipelineCycler(Pipeline *pipeline) :
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::Copy Constructor (sanity-check)
// Function: PipelineCycler::Copy Constructor (dummy or true)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
template<class CycleDataType>
INLINE PipelineCycler<CycleDataType>::
PipelineCycler(const PipelineCycler<CycleDataType> &copy) :
// In the DO_PIPELINING copy constructor, the pointer value is ignored.
PipelineCyclerBase(NULL, copy)
PipelineCyclerBase(copy)
{
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::Copy Assignment (sanity-check)
// Function: PipelineCycler::Copy Assignment (dummy or true)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
@ -58,7 +57,7 @@ operator = (const PipelineCycler<CycleDataType> &copy) {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::read (sanity-check)
// Function: PipelineCycler::read (dummy or true)
// Access: Public
// Description: See PipelineCyclerBase::read().
////////////////////////////////////////////////////////////////////
@ -69,7 +68,7 @@ read() const {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::write (sanity-check)
// Function: PipelineCycler::write (dummy or true)
// Access: Public
// Description: See PipelineCyclerBase::write().
////////////////////////////////////////////////////////////////////
@ -80,7 +79,7 @@ write() {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::elevate_read (sanity-check)
// Function: PipelineCycler::elevate_read (dummy or true)
// Access: Public
// Description: See PipelineCyclerBase::elevate_read().
////////////////////////////////////////////////////////////////////
@ -91,7 +90,7 @@ elevate_read(const CycleDataType *pointer) {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::write_stage (sanity-check)
// Function: PipelineCycler::write_stage (dummy or true)
// Access: Public
// Description: See PipelineCyclerBase::write_stage().
////////////////////////////////////////////////////////////////////
@ -102,7 +101,7 @@ write_stage(int n) {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCycler::cheat (sanity-check)
// Function: PipelineCycler::cheat (dummy or true)
// Access: Public
// Description: Returns a pointer without counting it. This is only
// intended for use as the return value for certain
@ -142,7 +141,7 @@ PipelineCycler(Pipeline *pipeline) :
template<class CycleDataType>
INLINE PipelineCycler<CycleDataType>::
PipelineCycler(const PipelineCycler<CycleDataType> &copy) :
PipelineCyclerBase(&_typed_data, copy),
PipelineCyclerBase(&_typed_data),
_typed_data(copy._typed_data)
{
}
@ -155,7 +154,6 @@ PipelineCycler(const PipelineCycler<CycleDataType> &copy) :
template<class CycleDataType>
INLINE void PipelineCycler<CycleDataType>::
operator = (const PipelineCycler<CycleDataType> &copy) {
PipelineCyclerBase::operator = (copy);
_typed_data = copy._typed_data;
}

View File

@ -1,527 +0,0 @@
// Filename: pipelineCyclerBase.I
// Created by: drose (21Feb02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifdef DO_PIPELINING
// The following implementations are to support compiled-in pipeline
// sanity checks.
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Constructor (sanity-check)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerBase::
PipelineCyclerBase(CycleData *initial_data, Pipeline *pipeline) :
_data(initial_data),
_pipeline(pipeline),
_read_count(0),
_write_count(0)
{
if (_pipeline == (Pipeline *)NULL) {
_pipeline = Pipeline::get_render_pipeline();
}
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Copy Constructor (sanity-check)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerBase::
PipelineCyclerBase(CycleData *, const PipelineCyclerBase &copy) :
_data(copy._data->make_copy()),
_pipeline(copy._pipeline),
_read_count(0),
_write_count(0)
{
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Copy Assignment (sanity-check)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerBase::
operator = (const PipelineCyclerBase &copy) {
nassertv(_read_count == 0 && _write_count == 0);
_data = copy._data->make_copy();
_pipeline = copy._pipeline;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Destructor (sanity-check)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerBase::
~PipelineCyclerBase() {
nassertv(_read_count == 0 && _write_count == 0);
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::read (sanity-check)
// Access: Public
// Description: Returns a const CycleData pointer, filled with the
// data for the current stage of the pipeline as seen by
// this thread. This pointer should eventually be
// released by calling release_read().
//
// There should be no outstanding write pointers on the
// data when this function is called.
////////////////////////////////////////////////////////////////////
INLINE const CycleData *PipelineCyclerBase::
read() const {
// This function isn't truly const, but it doesn't change the data
// in any meaningful way, so we pretend it is.
((PipelineCyclerBase *)this)->_read_count++;
// It's not an error to grab a read pointer while someone else holds
// a read or a write pointer.
return _data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::increment_read (sanity-check)
// Access: Public
// Description: Increments the count on a pointer previously
// retrieved by read(); now the pointer will need to be
// released twice.
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerBase::
increment_read(const CycleData *pointer) const {
// This function isn't truly const, but it doesn't change the data
// in any meaningful way, so we pretend it is.
nassertv(pointer == _data);
nassertv(_read_count > 0);
((PipelineCyclerBase *)this)->_read_count++;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::release_read (sanity-check)
// Access: Public
// Description: Releases a pointer previously obtained via a call to
// read().
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerBase::
release_read(const CycleData *pointer) const {
// This function isn't truly const, but it doesn't change the data
// in any meaningful way, so we pretend it is.
nassertv(pointer == _data);
nassertv(_read_count > 0);
((PipelineCyclerBase *)this)->_read_count--;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::write (sanity-check)
// Access: Public
// Description: Returns a non-const CycleData pointer, filled with a
// unique copy of the data for the current stage of the
// pipeline as seen by this thread. This pointer may
// now be used to write to the data, and that copy of
// the data will be propagate to all later stages of the
// pipeline. This pointer should eventually be released
// by calling release_write().
//
// There may only be one outstanding write pointer on a
// given stage at a time, and if there is a write
// pointer there may be no read pointers on the same
// stage (but see elevate_read).
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerBase::
write() {
_write_count++;
// It's an error to grab a write pointer while someone else holds a
// read pointer, because doing so may invalidate the read pointer.
nassertr(_read_count == 0, _data);
// It's not an error to do this while someone else holds a write
// pointer, however.
return _data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::elevate_read (sanity-check)
// Access: Public
// Description: Elevates a currently-held read pointer into a write
// pointer. This may or may not change the value of the
// pointer. It is only valid to do this if this is the
// only currently-outstanding read pointer on the
// current stage.
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerBase::
elevate_read(const CycleData *pointer) {
release_read(pointer);
return write();
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::release_write (sanity-check)
// Access: Public
// Description: Releases a pointer previously obtained via a call to
// write().
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerBase::
release_write(CycleData *pointer) {
nassertv(pointer == _data);
nassertv(_write_count > 0);
_write_count--;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::get_num_stages (sanity-check)
// Access: Public
// Description: Returns the number of stages in the pipeline.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerBase::
get_num_stages() {
return 1;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::is_stage_unique (sanity-check)
// Access: Public
// Description: Returns true if the nth stage is a different pointer
// than the previous stage, or false if its pointer is
// shared with the previous one.
////////////////////////////////////////////////////////////////////
INLINE bool PipelineCyclerBase::
is_stage_unique(int n) const {
nassertr(n == 0, false);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::write_stage (sanity-check)
// Access: Public
// Description: Returns a pointer suitable for writing to the nth
// stage of the pipeline. This is for special
// applications that need to update the entire pipeline
// at once (for instance, to remove an invalid pointer).
// This pointer should later be released with
// release_write_stage().
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerBase::
write_stage(int n) {
nassertr(n == 0, (CycleData *)NULL);
_write_count++;
return _data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::release_write_stage (sanity-check)
// Access: Public
// Description: Releases a pointer previously obtained via a call to
// write_stage().
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerBase::
release_write_stage(int n, CycleData *pointer) {
nassertv(n == 0 && pointer == _data);
nassertv(_write_count > 0);
_write_count--;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::cheat (sanity-check)
// Access: Public
// Description: Returns a pointer without counting it. This is only
// intended for use as the return value for certain
// nassertr() functions, so the application can recover
// after a failure to manage the read and write pointers
// correctly. You should never call this function
// directly.
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerBase::
cheat() const {
return _data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::get_read_count (sanity-check)
// Access: Public
// Description: Returns the number of handles currently outstanding
// to read the current stage of the data. This should
// only be used for debugging purposes.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerBase::
get_read_count() const {
return _read_count;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::get_write_count (sanity-check)
// Access: Public
// Description: Returns the number of handles currently outstanding
// to read the current stage of the data. This will
// normally only be either 0 or 1. This should only be
// used for debugging purposes.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerBase::
get_write_count() const {
return _write_count;
}
#else // !DO_PIPELINING
// The following implementations are provided for when pipelining is
// not compiled in. They are trivial functions that do as little as
// possible.
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Constructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerBase::
PipelineCyclerBase(CycleData *initial_data, Pipeline *) {
// In the trivial implementation, a derived class (the
// PipelineCycler template class) stores the CycleData object
// directly within itself, and since we have no data members or
// virtual functions, we get away with assuming the pointer is the
// same as the 'this' pointer.
// If this turns out not to be true on a particular platform, we
// will have to store the pointer in this class, for a little bit of
// extra overhead.
#ifdef SIMPLE_STRUCT_POINTERS
nassertv(initial_data == (CycleData *)this);
#else
_data = initial_data;
#endif // SIMPLE_STRUCT_POINTERS
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Copy Constructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerBase::
PipelineCyclerBase(CycleData *initial_data, const PipelineCyclerBase &) {
// The copy constructor for the DO_PIPELINING case is
#ifdef SIMPLE_STRUCT_POINTERS
nassertv(initial_data == (CycleData *)this);
#else
_data = initial_data;
#endif // SIMPLE_STRUCT_POINTERS
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Copy Assignment (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerBase::
operator = (const PipelineCyclerBase &) {
// We don't reassign the _data pointer here; we assume it was set
// correctly previously.
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::Destructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerBase::
~PipelineCyclerBase() {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::read (trivial)
// Access: Public
// Description: Returns a const CycleData pointer, filled with the
// data for the current stage of the pipeline as seen by
// this thread. This pointer should eventually be
// released by calling release_read().
////////////////////////////////////////////////////////////////////
INLINE const CycleData *PipelineCyclerBase::
read() const {
#ifdef SIMPLE_STRUCT_POINTERS
return (const CycleData *)this;
#else
return _data;
#endif // SIMPLE_STRUCT_POINTERS
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::increment_read (trivial)
// Access: Public
// Description: Increments the count on a pointer previously
// retrieved by read(); now the pointer will need to be
// released twice.
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerBase::
increment_read(const CycleData *) const {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::release_read (trivial)
// Access: Public
// Description: Releases a pointer previously obtained via a call to
// read().
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerBase::
release_read(const CycleData *) const {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::write (trivial)
// Access: Public
// Description: Returns a non-const CycleData pointer, filled with a
// unique copy of the data for the current stage of the
// pipeline as seen by this thread. This pointer may
// now be used to write to the data, and that copy of
// the data will be propagate to all later stages of the
// pipeline. This pointer should eventually be released
// by calling release_write().
//
// There may only be one outstanding write pointer on a
// given stage at a time, and if there is a write
// pointer there may be no read pointers on the same
// stage (but see elevate_read).
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerBase::
write() {
#ifdef SIMPLE_STRUCT_POINTERS
return (CycleData *)this;
#else
return _data;
#endif // SIMPLE_STRUCT_POINTERS
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::elevate_read (trivial)
// Access: Public
// Description: Elevates a currently-held read pointer into a write
// pointer. This may or may not change the value of the
// pointer. It is only valid to do this if this is the
// only currently-outstanding read pointer on the
// current stage.
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerBase::
elevate_read(const CycleData *) {
#ifdef SIMPLE_STRUCT_POINTERS
return (CycleData *)this;
#else
return _data;
#endif // SIMPLE_STRUCT_POINTERS
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::release_write (trivial)
// Access: Public
// Description: Releases a pointer previously obtained via a call to
// write().
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerBase::
release_write(CycleData *) {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::get_num_stages (trivial)
// Access: Public
// Description: Returns the number of stages in the pipeline.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerBase::
get_num_stages() {
return 1;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::is_stage_unique (trivial)
// Access: Public
// Description: Returns true if the nth stage is a different pointer
// than the previous stage, or false if its pointer is
// shared with the previous one.
////////////////////////////////////////////////////////////////////
INLINE bool PipelineCyclerBase::
is_stage_unique(int n) const {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::write_stage (trivial)
// Access: Public
// Description: Returns a pointer suitable for writing to the nth
// stage of the pipeline. This is for special
// applications that need to update the entire pipeline
// at once (for instance, to remove an invalid pointer).
// This pointer should later be released with
// release_write_stage().
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerBase::
write_stage(int) {
return (CycleData *)this;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::release_write_stage (trivial)
// Access: Public
// Description: Releases a pointer previously obtained via a call to
// write_stage().
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerBase::
release_write_stage(int, CycleData *) {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::cheat (trivial)
// Access: Public
// Description: Returns a pointer without counting it. This is only
// intended for use as the return value for certain
// nassertr() functions, so the application can recover
// after a failure to manage the read and write pointers
// correctly. You should never call this function
// directly.
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerBase::
cheat() const {
#ifdef SIMPLE_STRUCT_POINTERS
return (CycleData *)this;
#else
return _data;
#endif // SIMPLE_STRUCT_POINTERS
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::get_read_count (trivial)
// Access: Public
// Description: Returns the number of handles currently outstanding
// to read the current stage of the data. This should
// only be used for debugging purposes.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerBase::
get_read_count() const {
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerBase::get_write_count (trivial)
// Access: Public
// Description: Returns the number of handles currently outstanding
// to read the current stage of the data. This will
// normally only be either 0 or 1. This should only be
// used for debugging purposes.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerBase::
get_write_count() const {
return 0;
}
#endif // DO_PIPELINING

View File

@ -21,68 +21,32 @@
#include "pandabase.h"
#include "cycleData.h"
#include "pipeline.h"
#include "pointerTo.h"
////////////////////////////////////////////////////////////////////
// Class : PipelineCyclerBase
// Description : This is the non-template part of the implementation
// of PipelineCycler. See PipelineCycler.
//
// We define this as a struct instead of a class to
// guarantee byte placement within the object, so that
// (particularly for the trivial implementation) the
// inherited struct's data is likely to be placed by the
// compiler at the "this" pointer.
////////////////////////////////////////////////////////////////////
struct EXPCL_PANDA PipelineCyclerBase {
public:
INLINE PipelineCyclerBase(CycleData *initial_data, Pipeline *pipeline = NULL);
INLINE PipelineCyclerBase(CycleData *initial_data, const PipelineCyclerBase &copy);
INLINE void operator = (const PipelineCyclerBase &copy);
INLINE ~PipelineCyclerBase();
INLINE const CycleData *read() const;
INLINE void increment_read(const CycleData *pointer) const;
INLINE void release_read(const CycleData *pointer) const;
INLINE CycleData *write();
INLINE CycleData *elevate_read(const CycleData *pointer);
INLINE void release_write(CycleData *pointer);
INLINE int get_num_stages();
INLINE bool is_stage_unique(int n) const;
INLINE CycleData *write_stage(int n);
INLINE void release_write_stage(int n, CycleData *pointer);
INLINE CycleData *cheat() const;
INLINE int get_read_count() const;
INLINE int get_write_count() const;
#ifdef DO_PIPELINING
// This private data is only stored here if we have pipelining
// compiled in. Actually, this particular data is only used for
// sanity checking the pipelining code; it doesn't do anything
// useful.
private:
PT(CycleData) _data;
Pipeline *_pipeline;
short _read_count, _write_count;
#else // !DO_PIPELINING
// In a trivial implementation, we only need to store the CycleData
// pointer. Actually, we don't even need to do that, if we're lucky
// and the compiler doesn't do anything funny with the struct
// layout.
#ifndef SIMPLE_STRUCT_POINTERS
CycleData *_data;
#endif // SIMPLE_STRUCT_POINTERS
#ifdef HAVE_THREADS
// With DO_PIPELINING and threads available, we want the true cycler
// implementation.
#include "pipelineCyclerTrueImpl.h"
typedef PipelineCyclerTrueImpl PipelineCyclerBase;
#else // HAVE_THREADS
// With DO_PIPELINING but no threads available, we want the dummy,
// self-validating cycler implementation.
#include "pipelineCyclerDummyImpl.h"
typedef PipelineCyclerDummyImpl PipelineCyclerBase;
#endif // HAVE_THREADS
#else // DO_PIPELINING
// Without DO_PIPELINING, we only want the trivial, do-nothing
// implementation.
#include "pipelineCyclerTrivialImpl.h"
typedef PipelineCyclerTrivialImpl PipelineCyclerBase;
#endif // DO_PIPELINING
};
#include "pipelineCyclerBase.I"
#endif

View File

@ -0,0 +1,275 @@
// Filename: pipelineCyclerDummyImpl.I
// Created by: drose (31Jan06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::Constructor (sanity-check)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerDummyImpl::
PipelineCyclerDummyImpl(CycleData *initial_data, Pipeline *pipeline) :
_data(initial_data),
_pipeline(pipeline),
_read_count(0),
_write_count(0)
{
if (_pipeline == (Pipeline *)NULL) {
_pipeline = Pipeline::get_render_pipeline();
}
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::Copy Constructor (sanity-check)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerDummyImpl::
PipelineCyclerDummyImpl(const PipelineCyclerDummyImpl &copy) :
_data(copy._data->make_copy()),
_pipeline(copy._pipeline),
_read_count(0),
_write_count(0)
{
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::Copy Assignment (sanity-check)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerDummyImpl::
operator = (const PipelineCyclerDummyImpl &copy) {
nassertv(_read_count == 0 && _write_count == 0);
_data = copy._data->make_copy();
_pipeline = copy._pipeline;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::Destructor (sanity-check)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerDummyImpl::
~PipelineCyclerDummyImpl() {
nassertv(_read_count == 0 && _write_count == 0);
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::read (sanity-check)
// Access: Public
// Description: Returns a const CycleData pointer, filled with the
// data for the current stage of the pipeline as seen by
// this thread. This pointer should eventually be
// released by calling release_read().
//
// There should be no outstanding write pointers on the
// data when this function is called.
////////////////////////////////////////////////////////////////////
INLINE const CycleData *PipelineCyclerDummyImpl::
read() const {
// This function isn't truly const, but it doesn't change the data
// in any meaningful way, so we pretend it is.
((PipelineCyclerDummyImpl *)this)->_read_count++;
// It's not an error to grab a read pointer while someone else holds
// a read or a write pointer.
return _data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::increment_read (sanity-check)
// Access: Public
// Description: Increments the count on a pointer previously
// retrieved by read(); now the pointer will need to be
// released twice.
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerDummyImpl::
increment_read(const CycleData *pointer) const {
// This function isn't truly const, but it doesn't change the data
// in any meaningful way, so we pretend it is.
nassertv(pointer == _data);
nassertv(_read_count > 0);
((PipelineCyclerDummyImpl *)this)->_read_count++;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::release_read (sanity-check)
// Access: Public
// Description: Releases a pointer previously obtained via a call to
// read().
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerDummyImpl::
release_read(const CycleData *pointer) const {
// This function isn't truly const, but it doesn't change the data
// in any meaningful way, so we pretend it is.
nassertv(pointer == _data);
nassertv(_read_count > 0);
((PipelineCyclerDummyImpl *)this)->_read_count--;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::write (sanity-check)
// Access: Public
// Description: Returns a non-const CycleData pointer, filled with a
// unique copy of the data for the current stage of the
// pipeline as seen by this thread. This pointer may
// now be used to write to the data, and that copy of
// the data will be propagated to all later stages of the
// pipeline. This pointer should eventually be released
// by calling release_write().
//
// There may only be one outstanding write pointer on a
// given stage at a time, and if there is a write
// pointer there may be no read pointers on the same
// stage (but see elevate_read).
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerDummyImpl::
write() {
_write_count++;
// It's an error to grab a write pointer while someone else holds a
// read pointer, because doing so may invalidate the read pointer.
nassertr(_read_count == 0, _data);
// It's not an error to do this while someone else holds a write
// pointer, however.
return _data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::elevate_read (sanity-check)
// Access: Public
// Description: Elevates a currently-held read pointer into a write
// pointer. This may or may not change the value of the
// pointer. It is only valid to do this if this is the
// only currently-outstanding read pointer on the
// current stage.
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerDummyImpl::
elevate_read(const CycleData *pointer) {
release_read(pointer);
return write();
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::release_write (sanity-check)
// Access: Public
// Description: Releases a pointer previously obtained via a call to
// write().
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerDummyImpl::
release_write(CycleData *pointer) {
nassertv(pointer == _data);
nassertv(_write_count > 0);
_write_count--;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::get_num_stages (sanity-check)
// Access: Public
// Description: Returns the number of stages in the pipeline.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerDummyImpl::
get_num_stages() {
return 1;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::is_stage_unique (sanity-check)
// Access: Public
// Description: Returns true if the nth stage is a different pointer
// than the previous stage, or false if its pointer is
// shared with the previous one.
////////////////////////////////////////////////////////////////////
INLINE bool PipelineCyclerDummyImpl::
is_stage_unique(int n) const {
nassertr(n == 0, false);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::write_stage (sanity-check)
// Access: Public
// Description: Returns a pointer suitable for writing to the nth
// stage of the pipeline. This is for special
// applications that need to update the entire pipeline
// at once (for instance, to remove an invalid pointer).
// This pointer should later be released with
// release_write_stage().
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerDummyImpl::
write_stage(int n) {
nassertr(n == 0, (CycleData *)NULL);
_write_count++;
return _data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::release_write_stage (sanity-check)
// Access: Public
// Description: Releases a pointer previously obtained via a call to
// write_stage().
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerDummyImpl::
release_write_stage(int n, CycleData *pointer) {
nassertv(n == 0 && pointer == _data);
nassertv(_write_count > 0);
_write_count--;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::cheat (sanity-check)
// Access: Public
// Description: Returns a pointer without counting it. This is only
// intended for use as the return value for certain
// nassertr() functions, so the application can recover
// after a failure to manage the read and write pointers
// correctly. You should never call this function
// directly.
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerDummyImpl::
cheat() const {
return _data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::get_read_count (sanity-check)
// Access: Public
// Description: Returns the number of handles currently outstanding
// to read the current stage of the data. This should
// only be used for debugging purposes.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerDummyImpl::
get_read_count() const {
return _read_count;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerDummyImpl::get_write_count (sanity-check)
// Access: Public
// Description: Returns the number of handles currently outstanding
// to read the current stage of the data. This will
// normally only be either 0 or 1. This should only be
// used for debugging purposes.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerDummyImpl::
get_write_count() const {
return _write_count;
}

View File

@ -1,5 +1,5 @@
// Filename: pipelineCyclerBase.cxx
// Created by: drose (21Feb02)
// Filename: pipelineCyclerDummyImpl.cxx
// Created by: drose (31Jan06)
//
////////////////////////////////////////////////////////////////////
//
@ -16,17 +16,4 @@
//
////////////////////////////////////////////////////////////////////
#include "pipelineCyclerBase.h"
#ifdef DO_PIPELINING
// The following implementations are to support compiled-in pipeline
// sanity checks.
#else // !DO_PIPELINING
// The following implementations are provided for when pipelining is
// not compiled in. They are trivial functions that do as little as
// possible.
#endif
#include "pipelineCyclerDummyImpl.h"

View File

@ -0,0 +1,83 @@
// Filename: pipelineCyclerDummyImpl.h
// Created by: drose (31Jan06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef PIPELINECYCLERDUMMYIMPL_H
#define PIPELINECYCLERDUMMYIMPL_H
#include "pandabase.h"
#if defined(DO_PIPELINING) && !defined(HAVE_THREADS)
#include "cycleData.h"
#include "pipeline.h"
#include "pointerTo.h"
////////////////////////////////////////////////////////////////////
// Class : PipelineCyclerDummyImpl
// Description : This is a simple, single-threaded-only implementation
// of PipelineCyclerBase. It is only compiled when
// DO_PIPELINING is defined, but threading is not
// available, which is usually the case only in
// development mode.
//
// This implmentation is similar in principle to
// PipelineCyclerTrivialImpl, except it does basic
// sanity checking to ensure that you use the interface
// in a reasonable way consistent with its design (e.g.,
// read() is balanced with release_read(), etc.).
//
// This is defined as a struct instead of a class,
// mainly to be consistent with
// PipelineCyclerTrivialImpl.
////////////////////////////////////////////////////////////////////
struct EXPCL_PANDA PipelineCyclerDummyImpl {
public:
INLINE PipelineCyclerDummyImpl(CycleData *initial_data, Pipeline *pipeline = NULL);
INLINE PipelineCyclerDummyImpl(const PipelineCyclerDummyImpl &copy);
INLINE void operator = (const PipelineCyclerDummyImpl &copy);
INLINE ~PipelineCyclerDummyImpl();
INLINE const CycleData *read() const;
INLINE void increment_read(const CycleData *pointer) const;
INLINE void release_read(const CycleData *pointer) const;
INLINE CycleData *write();
INLINE CycleData *elevate_read(const CycleData *pointer);
INLINE void release_write(CycleData *pointer);
INLINE int get_num_stages();
INLINE bool is_stage_unique(int n) const;
INLINE CycleData *write_stage(int n);
INLINE void release_write_stage(int n, CycleData *pointer);
INLINE CycleData *cheat() const;
INLINE int get_read_count() const;
INLINE int get_write_count() const;
private:
PT(CycleData) _data;
Pipeline *_pipeline;
short _read_count, _write_count;
};
#include "pipelineCyclerDummyImpl.I"
#endif // DO_PIPELINING && !HAVE_THREADS
#endif

View File

@ -0,0 +1,261 @@
// Filename: pipelineCyclerTrivialImpl.I
// Created by: drose (31Jan06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::Constructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerTrivialImpl::
PipelineCyclerTrivialImpl(CycleData *initial_data, Pipeline *) {
// In the trivial implementation, a derived class (the
// PipelineCycler template class) stores the CycleData object
// directly within itself, and since we have no data members or
// virtual functions, we get away with assuming the pointer is the
// same as the 'this' pointer.
// If this turns out not to be true on a particular platform, we
// will have to store the pointer in this class, for a little bit of
// extra overhead.
#ifdef SIMPLE_STRUCT_POINTERS
nassertv(initial_data == (CycleData *)this);
#else
_data = initial_data;
#endif // SIMPLE_STRUCT_POINTERS
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::Copy Constructor (trivial)
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerTrivialImpl::
PipelineCyclerTrivialImpl(const PipelineCyclerTrivialImpl &) {
// The copy constructor for the PipelineCyclerTrivialImpl case
// doesn't work. Don't try to use it. The PipelineCycler template
// class is #ifdeffed appropriately to call the normal constructor
// instead.
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::Copy Assignment (trivial)
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerTrivialImpl::
operator = (const PipelineCyclerTrivialImpl &) {
// The copy assignment operator for the PipelineCyclerTrivialImpl
// case doesn't work. Don't try to use it. The PipelineCycler
// template class is #ifdeffed appropriately not to call this
// method.
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::Destructor (trivial)
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PipelineCyclerTrivialImpl::
~PipelineCyclerTrivialImpl() {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::read (trivial)
// Access: Public
// Description: Returns a const CycleData pointer, filled with the
// data for the current stage of the pipeline as seen by
// this thread. This pointer should eventually be
// released by calling release_read().
////////////////////////////////////////////////////////////////////
INLINE const CycleData *PipelineCyclerTrivialImpl::
read() const {
#ifdef SIMPLE_STRUCT_POINTERS
return (const CycleData *)this;
#else
return _data;
#endif // SIMPLE_STRUCT_POINTERS
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::increment_read (trivial)
// Access: Public
// Description: Increments the count on a pointer previously
// retrieved by read(); now the pointer will need to be
// released twice.
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerTrivialImpl::
increment_read(const CycleData *) const {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::release_read (trivial)
// Access: Public
// Description: Releases a pointer previously obtained via a call to
// read().
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerTrivialImpl::
release_read(const CycleData *) const {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::write (trivial)
// Access: Public
// Description: Returns a non-const CycleData pointer, filled with a
// unique copy of the data for the current stage of the
// pipeline as seen by this thread. This pointer may
// now be used to write to the data, and that copy of
// the data will be propagated to all later stages of the
// pipeline. This pointer should eventually be released
// by calling release_write().
//
// There may only be one outstanding write pointer on a
// given stage at a time, and if there is a write
// pointer there may be no read pointers on the same
// stage (but see elevate_read).
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerTrivialImpl::
write() {
#ifdef SIMPLE_STRUCT_POINTERS
return (CycleData *)this;
#else
return _data;
#endif // SIMPLE_STRUCT_POINTERS
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::elevate_read (trivial)
// Access: Public
// Description: Elevates a currently-held read pointer into a write
// pointer. This may or may not change the value of the
// pointer. It is only valid to do this if this is the
// only currently-outstanding read pointer on the
// current stage.
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerTrivialImpl::
elevate_read(const CycleData *) {
#ifdef SIMPLE_STRUCT_POINTERS
return (CycleData *)this;
#else
return _data;
#endif // SIMPLE_STRUCT_POINTERS
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::release_write (trivial)
// Access: Public
// Description: Releases a pointer previously obtained via a call to
// write().
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerTrivialImpl::
release_write(CycleData *) {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::get_num_stages (trivial)
// Access: Public
// Description: Returns the number of stages in the pipeline.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerTrivialImpl::
get_num_stages() {
return 1;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::is_stage_unique (trivial)
// Access: Public
// Description: Returns true if the nth stage is a different pointer
// than the previous stage, or false if its pointer is
// shared with the previous one.
////////////////////////////////////////////////////////////////////
INLINE bool PipelineCyclerTrivialImpl::
is_stage_unique(int n) const {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::write_stage (trivial)
// Access: Public
// Description: Returns a pointer suitable for writing to the nth
// stage of the pipeline. This is for special
// applications that need to update the entire pipeline
// at once (for instance, to remove an invalid pointer).
// This pointer should later be released with
// release_write_stage().
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerTrivialImpl::
write_stage(int) {
return (CycleData *)this;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::release_write_stage (trivial)
// Access: Public
// Description: Releases a pointer previously obtained via a call to
// write_stage().
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerTrivialImpl::
release_write_stage(int, CycleData *) {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::cheat (trivial)
// Access: Public
// Description: Returns a pointer without counting it. This is only
// intended for use as the return value for certain
// nassertr() functions, so the application can recover
// after a failure to manage the read and write pointers
// correctly. You should never call this function
// directly.
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerTrivialImpl::
cheat() const {
#ifdef SIMPLE_STRUCT_POINTERS
return (CycleData *)this;
#else
return _data;
#endif // SIMPLE_STRUCT_POINTERS
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::get_read_count (trivial)
// Access: Public
// Description: Returns the number of handles currently outstanding
// to read the current stage of the data. This should
// only be used for debugging purposes.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerTrivialImpl::
get_read_count() const {
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrivialImpl::get_write_count (trivial)
// Access: Public
// Description: Returns the number of handles currently outstanding
// to read the current stage of the data. This will
// normally only be either 0 or 1. This should only be
// used for debugging purposes.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerTrivialImpl::
get_write_count() const {
return 0;
}

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,89 @@
// Filename: pipelineCyclerTrivialImpl.h
// Created by: drose (31Jan06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef PIPELINECYCLERTRIVIALIMPL_H
#define PIPELINECYCLERTRIVIALIMPL_H
#include "pandabase.h"
#ifndef DO_PIPELINING
class CycleData;
class Pipeline;
////////////////////////////////////////////////////////////////////
// Class : PipelineCyclerTrivialImpl
// Description : This is the trivial, non-threaded implementation of
// PipelineCyclerBase. It is only compiled when
// DO_PIPELINING is not defined (which usually implies
// that threading is not available).
//
// This implementation is designed to do as little as
// possible, and to compile to nothing, or almost
// nothing. It doesn't actually support pipelining in
// any way. It doesn't even perform any sanity checks
// to speak of. It's designed for a strictly
// single-threaded application, and its purpose is to be
// as low-overhead as possible.
//
// We define this as a struct instead of a class to
// emphasize the importance of byte placement within the
// object, so that the inherited struct's data is likely
// to be placed by the compiler at the "this" pointer.
////////////////////////////////////////////////////////////////////
struct EXPCL_PANDA PipelineCyclerTrivialImpl {
public:
INLINE PipelineCyclerTrivialImpl(CycleData *initial_data, Pipeline *pipeline = NULL);
private:
INLINE PipelineCyclerTrivialImpl(const PipelineCyclerTrivialImpl &copy);
INLINE void operator = (const PipelineCyclerTrivialImpl &copy);
public:
INLINE ~PipelineCyclerTrivialImpl();
INLINE const CycleData *read() const;
INLINE void increment_read(const CycleData *pointer) const;
INLINE void release_read(const CycleData *pointer) const;
INLINE CycleData *write();
INLINE CycleData *elevate_read(const CycleData *pointer);
INLINE void release_write(CycleData *pointer);
INLINE int get_num_stages();
INLINE bool is_stage_unique(int n) const;
INLINE CycleData *write_stage(int n);
INLINE void release_write_stage(int n, CycleData *pointer);
INLINE CycleData *cheat() const;
INLINE int get_read_count() const;
INLINE int get_write_count() const;
// In a trivial implementation, we only need to store the CycleData
// pointer. Actually, we don't even need to do that, if we're lucky
// and the compiler doesn't do anything funny with the struct
// layout.
#ifndef SIMPLE_STRUCT_POINTERS
CycleData *_data;
#endif // SIMPLE_STRUCT_POINTERS
};
#include "pipelineCyclerTrivialImpl.I"
#endif // !DO_PIPELINING
#endif

View File

@ -0,0 +1,196 @@
// Filename: pipelineCyclerTrueImpl.I
// Created by: drose (31Jan06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::read
// Access: Public
// Description: Returns a const CycleData pointer, filled with the
// data for the current stage of the pipeline as seen by
// this thread. This pointer should eventually be
// released by calling release_read().
//
// There should be no outstanding write pointers on the
// data when this function is called.
////////////////////////////////////////////////////////////////////
INLINE const CycleData *PipelineCyclerTrueImpl::
read() const {
int pipeline_stage = Thread::get_current_thread()->get_pipeline_stage();
nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL);
return _data[pipeline_stage]._cycle_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::increment_read
// Access: Public
// Description: Increments the count on a pointer previously
// retrieved by read(); now the pointer will need to be
// released twice.
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerTrueImpl::
increment_read(const CycleData *pointer) const {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::release_read
// Access: Public
// Description: Releases a pointer previously obtained via a call to
// read().
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerTrueImpl::
release_read(const CycleData *pointer) const {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::write
// Access: Public
// Description: Returns a non-const CycleData pointer, filled with a
// unique copy of the data for the current stage of the
// pipeline as seen by this thread. This pointer may
// now be used to write to the data, and that copy of
// the data will be propagated to all later stages of the
// pipeline. This pointer should eventually be released
// by calling release_write().
//
// There may only be one outstanding write pointer on a
// given stage at a time, and if there is a write
// pointer there may be no read pointers on the same
// stage (but see elevate_read).
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerTrueImpl::
write() {
int pipeline_stage = Thread::get_current_thread()->get_pipeline_stage();
nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL);
return _data[pipeline_stage]._cycle_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::elevate_read
// Access: Public
// Description: Elevates a currently-held read pointer into a write
// pointer. This may or may not change the value of the
// pointer. It is only valid to do this if this is the
// only currently-outstanding read pointer on the
// current stage.
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerTrueImpl::
elevate_read(const CycleData *pointer) {
return (CycleData *)pointer;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::release_write
// Access: Public
// Description: Releases a pointer previously obtained via a call to
// write().
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerTrueImpl::
release_write(CycleData *pointer) {
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::get_num_stages
// Access: Public
// Description: Returns the number of stages in the pipeline.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerTrueImpl::
get_num_stages() {
return _num_stages;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::is_stage_unique
// Access: Public
// Description: Returns true if the nth stage is a different pointer
// than the previous stage, or false if its pointer is
// shared with the previous one.
////////////////////////////////////////////////////////////////////
INLINE bool PipelineCyclerTrueImpl::
is_stage_unique(int n) const {
nassertr(n >= 0 && n < _num_stages, false);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::write_stage
// Access: Public
// Description: Returns a pointer suitable for writing to the nth
// stage of the pipeline. This is for special
// applications that need to update the entire pipeline
// at once (for instance, to remove an invalid pointer).
// This pointer should later be released with
// release_write_stage().
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerTrueImpl::
write_stage(int n) {
nassertr(n >= 0 && n < _num_stages, (CycleData *)NULL);
return _data[n]._cycle_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::release_write_stage
// Access: Public
// Description: Releases a pointer previously obtained via a call to
// write_stage().
////////////////////////////////////////////////////////////////////
INLINE void PipelineCyclerTrueImpl::
release_write_stage(int n, CycleData *pointer) {
nassertv(n >= 0 && n < _num_stages);
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::cheat
// Access: Public
// Description: Returns a pointer without counting it. This is only
// intended for use as the return value for certain
// nassertr() functions, so the application can recover
// after a failure to manage the read and write pointers
// correctly. You should never call this function
// directly.
////////////////////////////////////////////////////////////////////
INLINE CycleData *PipelineCyclerTrueImpl::
cheat() const {
int pipeline_stage = Thread::get_current_thread()->get_pipeline_stage();
nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL);
return _data[pipeline_stage]._cycle_data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::get_read_count
// Access: Public
// Description: Returns the number of handles currently outstanding
// to read the current stage of the data. This should
// only be used for debugging purposes.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerTrueImpl::
get_read_count() const {
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::get_write_count
// Access: Public
// Description: Returns the number of handles currently outstanding
// to read the current stage of the data. This will
// normally only be either 0 or 1. This should only be
// used for debugging purposes.
////////////////////////////////////////////////////////////////////
INLINE int PipelineCyclerTrueImpl::
get_write_count() const {
return 0;
}

View File

@ -0,0 +1,140 @@
// Filename: pipelineCyclerTrueImpl.cxx
// Created by: drose (31Jan06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "pipelineCyclerTrueImpl.h"
#if defined(DO_PIPELINING) && defined(HAVE_THREADS)
#include "pipeline.h"
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PipelineCyclerTrueImpl::
PipelineCyclerTrueImpl(CycleData *initial_data, Pipeline *pipeline) :
_pipeline(pipeline)
{
if (_pipeline == (Pipeline *)NULL) {
_pipeline = Pipeline::get_render_pipeline();
}
_pipeline->add_cycler(this);
_num_stages = _pipeline->get_num_stages();
_data = new StageData[_num_stages];
for (int i = 0; i < _num_stages; ++i) {
_data[i]._cycle_data = initial_data->make_copy();
}
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PipelineCyclerTrueImpl::
PipelineCyclerTrueImpl(const PipelineCyclerTrueImpl &copy) :
_pipeline(copy._pipeline)
{
_pipeline->add_cycler(this);
_num_stages = _pipeline->get_num_stages();
nassertv(_num_stages == copy._num_stages);
_data = new StageData[_num_stages];
for (int i = 0; i < _num_stages; ++i) {
_data[i]._cycle_data = copy._data[i]._cycle_data->make_copy();
}
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::Copy Assignment
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void PipelineCyclerTrueImpl::
operator = (const PipelineCyclerTrueImpl &copy) {
nassertv(_num_stages == copy._num_stages);
for (int i = 0; i < _num_stages; ++i) {
_data[i]._cycle_data = copy._data[i]._cycle_data->make_copy();
}
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PipelineCyclerTrueImpl::
~PipelineCyclerTrueImpl() {
_pipeline->remove_cycler(this);
delete[] _data;
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::cycle
// Access: Private
// Description: Cycles the data between frames. This is only called
// from Pipeline::cycle().
////////////////////////////////////////////////////////////////////
void PipelineCyclerTrueImpl::
cycle() {
for (int i = _num_stages - 1; i > 0; --i) {
_data[i] = _data[i - 1];
}
_data[0]._cycle_data = _data[0]._cycle_data->make_copy();
}
////////////////////////////////////////////////////////////////////
// Function: PipelineCyclerTrueImpl::set_num_stages
// Access: Private
// Description: Changes the number of stages in the cycler. This is
// only called from Pipeline::set_num_stages();
////////////////////////////////////////////////////////////////////
void PipelineCyclerTrueImpl::
set_num_stages(int num_stages) {
if (num_stages <= _num_stages) {
// Don't bother to reallocate the array.
for (int i = _num_stages; i < num_stages; ++i) {
_data[i]._cycle_data.clear();
}
_num_stages = num_stages;
} else {
// Increase the array.
StageData *new_data = new StageData[num_stages];
int i;
for (i = 0; i < _num_stages; ++i) {
new_data[i] = _data[i];
}
for (i = _num_stages; i < num_stages; ++i) {
new_data[i]._cycle_data = _data[_num_stages - 1]._cycle_data->make_copy();
}
delete[] _data;
_num_stages = num_stages;
_data = new_data;
}
}
#endif // DO_PIPELINING && HAVE_THREADS

View File

@ -0,0 +1,94 @@
// Filename: pipelineCyclerTrueImpl.h
// Created by: drose (31Jan06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef PIPELINECYCLERTRUEIMPL_H
#define PIPELINECYCLERTRUEIMPL_H
#include "pandabase.h"
#if defined(DO_PIPELINING) && defined(HAVE_THREADS)
#include "cycleData.h"
#include "pointerTo.h"
#include "thread.h"
class Pipeline;
////////////////////////////////////////////////////////////////////
// Class : PipelineCyclerTrueImpl
// Description : This is the true, threaded implementation of
// PipelineCyclerBase. It is only compiled when
// threading is available and DO_PIPELINING is defined.
//
// This implementation is designed to do the actual work
// of cycling the data through a pipeline, and returning
// the actual CycleData appropriate to the current
// thread's pipeline stage.
//
// This is defined as a struct instead of a class,
// mainly to be consistent with
// PipelineCyclerTrivialImpl.
////////////////////////////////////////////////////////////////////
struct EXPCL_PANDA PipelineCyclerTrueImpl {
public:
PipelineCyclerTrueImpl(CycleData *initial_data, Pipeline *pipeline = NULL);
PipelineCyclerTrueImpl(const PipelineCyclerTrueImpl &copy);
void operator = (const PipelineCyclerTrueImpl &copy);
~PipelineCyclerTrueImpl();
INLINE const CycleData *read() const;
INLINE void increment_read(const CycleData *pointer) const;
INLINE void release_read(const CycleData *pointer) const;
INLINE CycleData *write();
INLINE CycleData *elevate_read(const CycleData *pointer);
INLINE void release_write(CycleData *pointer);
INLINE int get_num_stages();
INLINE bool is_stage_unique(int n) const;
INLINE CycleData *write_stage(int n);
INLINE void release_write_stage(int n, CycleData *pointer);
INLINE CycleData *cheat() const;
INLINE int get_read_count() const;
INLINE int get_write_count() const;
private:
void cycle();
void set_num_stages(int num_stages);
private:
Pipeline *_pipeline;
class StageData {
public:
PT(CycleData) _cycle_data;
};
StageData *_data;
int _num_stages;
friend class Pipeline;
};
#include "pipelineCyclerTrueImpl.I"
#endif // DO_PIPELINING && HAVE_THREADS
#endif

View File

@ -6,7 +6,9 @@
#include "nodePointerTo.cxx"
#include "pipeline.cxx"
#include "pipelineCycler.cxx"
#include "pipelineCyclerBase.cxx"
#include "pipelineCyclerDummyImpl.cxx"
#include "pipelineCyclerTrivialImpl.cxx"
#include "pipelineCyclerTrueImpl.cxx"
#include "pta_double.cxx"
#include "pta_float.cxx"
#include "pta_int.cxx"