Panda3D

pipelineCyclerTrueImpl.cxx

00001 // Filename: pipelineCyclerTrueImpl.cxx
00002 // Created by:  drose (31Jan06)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "pipelineCyclerTrueImpl.h"
00016 
00017 #ifdef THREADED_PIPELINE
00018 
00019 #include "config_pipeline.h"
00020 #include "pipeline.h"
00021 
00022 ////////////////////////////////////////////////////////////////////
00023 //     Function: PipelineCyclerTrueImpl::Constructor
00024 //       Access: Public
00025 //  Description: 
00026 ////////////////////////////////////////////////////////////////////
00027 PipelineCyclerTrueImpl::
00028 PipelineCyclerTrueImpl(CycleData *initial_data, Pipeline *pipeline) :
00029   _pipeline(pipeline),
00030   _dirty(false),
00031   _lock(this)
00032 {
00033   if (_pipeline == (Pipeline *)NULL) {
00034     _pipeline = Pipeline::get_render_pipeline();
00035   }
00036 
00037   _num_stages = _pipeline->get_num_stages();
00038   _data = new CycleDataNode[_num_stages];
00039   for (int i = 0; i < _num_stages; ++i) {
00040     _data[i]._cdata = initial_data;
00041   }
00042 
00043   _pipeline->add_cycler(this);
00044 }
00045 
00046 ////////////////////////////////////////////////////////////////////
00047 //     Function: PipelineCyclerTrueImpl::Copy Constructor
00048 //       Access: Public
00049 //  Description: 
00050 ////////////////////////////////////////////////////////////////////
00051 PipelineCyclerTrueImpl::
00052 PipelineCyclerTrueImpl(const PipelineCyclerTrueImpl &copy) :
00053   _pipeline(copy._pipeline),
00054   _dirty(false),
00055   _lock(this)
00056 {
00057   ReMutexHolder holder(_lock);
00058   ReMutexHolder holder2(copy._lock);
00059   
00060   _num_stages = _pipeline->get_num_stages();
00061   nassertv(_num_stages == copy._num_stages);
00062   _data = new CycleDataNode[_num_stages];
00063   
00064   // It's no longer critically important that we preserve pointerwise
00065   // equivalence between different stages in the copy, but it doesn't
00066   // cost much and might be a little more efficient, so we do it
00067   // anyway.
00068   typedef pmap<CycleData *, PT(CycleData) > Pointers;
00069   Pointers pointers;
00070   
00071   for (int i = 0; i < _num_stages; ++i) {
00072     PT(CycleData) &new_pt = pointers[copy._data[i]._cdata];
00073     if (new_pt == NULL) {
00074       new_pt = copy._data[i]._cdata->make_copy();
00075     }
00076     _data[i]._cdata = new_pt.p();
00077   }
00078 
00079   _pipeline->add_cycler(this);
00080   if (copy._dirty) {
00081     _pipeline->add_dirty_cycler(this);
00082   }
00083 }
00084 
00085 ////////////////////////////////////////////////////////////////////
00086 //     Function: PipelineCyclerTrueImpl::Copy Assignment
00087 //       Access: Public
00088 //  Description: 
00089 ////////////////////////////////////////////////////////////////////
00090 void PipelineCyclerTrueImpl::
00091 operator = (const PipelineCyclerTrueImpl &copy) {
00092   ReMutexHolder holder1(_lock);
00093   ReMutexHolder holder2(copy._lock);
00094   nassertv(get_parent_type() == copy.get_parent_type());
00095 
00096   typedef pmap<CycleData *, PT(CycleData) > Pointers;
00097   Pointers pointers;
00098 
00099   for (int i = 0; i < _num_stages; ++i) {
00100     PT(CycleData) &new_pt = pointers[copy._data[i]._cdata];
00101     if (new_pt == NULL) {
00102       new_pt = copy._data[i]._cdata->make_copy();
00103     }
00104     _data[i]._cdata = new_pt.p();
00105   }
00106 
00107   if (copy._dirty && !_dirty) {
00108     _pipeline->add_dirty_cycler(this);
00109   }
00110 }
00111 
00112 ////////////////////////////////////////////////////////////////////
00113 //     Function: PipelineCyclerTrueImpl::Destructor
00114 //       Access: Public
00115 //  Description: 
00116 ////////////////////////////////////////////////////////////////////
00117 PipelineCyclerTrueImpl::
00118 ~PipelineCyclerTrueImpl() {
00119   ReMutexHolder holder(_lock);
00120 
00121   _pipeline->remove_cycler(this);
00122 
00123   delete[] _data;
00124   _data = NULL;
00125   _num_stages = 0;
00126 }
00127 
00128 ////////////////////////////////////////////////////////////////////
00129 //     Function: PipelineCyclerTrueImpl::write_stage
00130 //       Access: Public
00131 //  Description: Returns a pointer suitable for writing to the nth
00132 //               stage of the pipeline.  This is for special
00133 //               applications that need to update the entire pipeline
00134 //               at once (for instance, to remove an invalid pointer).
00135 //               This pointer should later be released with
00136 //               release_write_stage().
00137 ////////////////////////////////////////////////////////////////////
00138 CycleData *PipelineCyclerTrueImpl::
00139 write_stage(int pipeline_stage, Thread *current_thread) {
00140   _lock.acquire(current_thread);
00141 
00142 #ifndef NDEBUG
00143   nassertd(pipeline_stage >= 0 && pipeline_stage < _num_stages) {
00144     _lock.release();
00145     return NULL;
00146   }
00147 #endif  // NDEBUG
00148 
00149   CycleData *old_data = _data[pipeline_stage]._cdata;
00150 
00151   // We only perform copy-on-write if this is the first CycleData
00152   // requested for write mode from this thread.  (We will never have
00153   // outstanding writes for multiple threads, because we hold the
00154   // CyclerMutex during the entire lifetime of write() .. release()).
00155   if (_data[pipeline_stage]._writes_outstanding == 0) {
00156     // Only the node reference count is considered an important count
00157     // for copy-on-write purposes.  A standard reference of other than 1
00158     // just means that some code (other that the PipelineCycler) has a
00159     // pointer, which is safe to modify.
00160     if (old_data->get_node_ref_count() != 1) {
00161       // Copy-on-write.
00162       _data[pipeline_stage]._cdata = old_data->make_copy();
00163       if (pipeline_cat.is_debug()) {
00164         pipeline_cat.debug()
00165           << "Copy-on-write a: " << old_data << " becomes " 
00166           << _data[pipeline_stage]._cdata << "\n";
00167         //nassertr(false, NULL);
00168       }
00169       
00170       // Now we have differences between some of the data pointers, so
00171       // we're "dirty".  Mark it so.
00172       if (!_dirty && _num_stages != 1) {
00173         _pipeline->add_dirty_cycler(this);
00174       }
00175     }
00176   }
00177 
00178   ++(_data[pipeline_stage]._writes_outstanding);
00179   return _data[pipeline_stage]._cdata;
00180 }
00181 
00182 ////////////////////////////////////////////////////////////////////
00183 //     Function: PipelineCyclerTrueImpl::write_stage_upstream
00184 //       Access: Public
00185 //  Description: This special variant on write_stage() will
00186 //               automatically propagate changes back to upstream
00187 //               pipeline stages.  See write_upstream().
00188 ////////////////////////////////////////////////////////////////////
00189 CycleData *PipelineCyclerTrueImpl::
00190 write_stage_upstream(int pipeline_stage, bool force_to_0, Thread *current_thread) {
00191   _lock.acquire(current_thread);
00192 
00193 #ifndef NDEBUG
00194   nassertd(pipeline_stage >= 0 && pipeline_stage < _num_stages) {
00195     _lock.release();
00196     return NULL;
00197   }
00198 #endif  // NDEBUG
00199 
00200   CycleData *old_data = _data[pipeline_stage]._cdata;
00201 
00202   if (old_data->get_ref_count() != 1 || force_to_0) {
00203     // Count the number of references before the current stage, and
00204     // the number of references remaining other than those.
00205     int external_count = old_data->get_ref_count() - 1;
00206     int k = pipeline_stage - 1;
00207     while (k >= 0 && _data[k]._cdata == old_data) {
00208       --k;
00209       --external_count;
00210     }
00211     
00212     // We only perform copy-on-write if this is the first CycleData
00213     // requested for write mode from this thread.  (We will never have
00214     // outstanding writes for multiple threads, because we hold the
00215     // CyclerMutex during the entire lifetime of write()
00216     // .. release()).
00217     if (external_count > 0 && _data[pipeline_stage]._writes_outstanding == 0) {
00218       // There are references other than the ones before this stage in
00219       // the pipeline; perform a copy-on-write.
00220       PT(CycleData) new_data = old_data->make_copy();
00221       if (pipeline_cat.is_debug()) {
00222         pipeline_cat.debug()
00223           << "Copy-on-write b: " << old_data << " becomes " 
00224           << new_data << "\n";
00225         //nassertr(false, NULL);
00226       }
00227       
00228       k = pipeline_stage - 1;
00229       while (k >= 0 && (_data[k]._cdata == old_data || force_to_0)) {
00230         nassertr(_data[k]._writes_outstanding == 0, NULL);
00231         _data[k]._cdata = new_data.p();
00232         --k;
00233       }
00234       
00235       _data[pipeline_stage]._cdata = new_data;
00236       
00237       if (k >= 0 || pipeline_stage + 1 < _num_stages) {
00238         // Now we have differences between some of the data pointers,
00239         // which makes us "dirty".
00240         if (!_dirty) {
00241           _pipeline->add_dirty_cycler(this);
00242         }
00243       }
00244       
00245     } else if (k >= 0 && force_to_0) {
00246       // There are no external pointers, so no need to copy-on-write,
00247       // but the current pointer doesn't go all the way back.  Make it
00248       // do so.
00249       while (k >= 0) {
00250         nassertr(_data[k]._writes_outstanding == 0, NULL);
00251         _data[k]._cdata = old_data;
00252         --k;
00253       }
00254     }
00255   }
00256     
00257   ++(_data[pipeline_stage]._writes_outstanding);
00258   return _data[pipeline_stage]._cdata;
00259 }
00260   
00261 ////////////////////////////////////////////////////////////////////
00262 //     Function: PipelineCyclerTrueImpl::cycle
00263 //       Access: Private
00264 //  Description: Cycles the data between frames.  This is only called
00265 //               from Pipeline::cycle(), and presumably it is only
00266 //               called if the cycler is "dirty".
00267 //
00268 //               At the conclusion of this method, the cycler should
00269 //               clear its dirty flag if it is no longer "dirty"--that
00270 //               is, if all of the pipeline pointers are the same.
00271 //
00272 //               The return value is the CycleData pointer which fell
00273 //               off the end of the cycle.  If this is allowed to
00274 //               destruct immediately, there may be side-effects that
00275 //               cascade through the system, so the caller may choose
00276 //               to hold the pointer until it can safely be released
00277 //               later.
00278 ////////////////////////////////////////////////////////////////////
00279 PT(CycleData) PipelineCyclerTrueImpl::
00280 cycle() {
00281   PT(CycleData) last_val = _data[_num_stages - 1]._cdata.p();
00282   nassertr(_lock.debug_is_locked(), last_val);
00283   nassertr(_dirty, last_val);
00284 
00285   int i;
00286   for (i = _num_stages - 1; i > 0; --i) {
00287     nassertr(_data[i]._writes_outstanding == 0, last_val);
00288     _data[i]._cdata = _data[i - 1]._cdata;
00289   }
00290 
00291   for (i = 1; i < _num_stages; ++i) {
00292     if (_data[i]._cdata != _data[i - 1]._cdata) {
00293       // Still dirty.
00294       return last_val;
00295     }
00296   }
00297 
00298   // No longer dirty.
00299   _dirty = false;
00300   return last_val;
00301 }
00302 
00303 ////////////////////////////////////////////////////////////////////
00304 //     Function: PipelineCyclerTrueImpl::set_num_stages
00305 //       Access: Private
00306 //  Description: Changes the number of stages in the cycler.  This is
00307 //               only called from Pipeline::set_num_stages();
00308 ////////////////////////////////////////////////////////////////////
00309 void PipelineCyclerTrueImpl::
00310 set_num_stages(int num_stages) {
00311   nassertv(_lock.debug_is_locked());
00312 
00313   if (num_stages <= _num_stages) {
00314     // Don't bother to reallocate the array smaller; we just won't use
00315     // the rest of the array.
00316     for (int i = _num_stages; i < num_stages; ++i) {
00317       nassertv(_data[i]._writes_outstanding == 0);
00318       _data[i]._cdata.clear();
00319     }
00320 
00321     _num_stages = num_stages;
00322     
00323 
00324   } else {
00325     // To increase the array, we must reallocate it larger.
00326     CycleDataNode *new_data = new CycleDataNode[num_stages];
00327     int i;
00328     for (i = 0; i < _num_stages; ++i) {
00329       nassertv(_data[i]._writes_outstanding == 0);
00330       new_data[i]._cdata = _data[i]._cdata;
00331     }
00332     for (i = _num_stages; i < num_stages; ++i) {
00333       new_data[i]._cdata = _data[_num_stages - 1]._cdata;
00334     }
00335     delete[] _data;
00336 
00337     _num_stages = num_stages;
00338     _data = new_data;
00339   }
00340 }
00341 
00342 #ifdef DEBUG_THREADS
00343 ////////////////////////////////////////////////////////////////////
00344 //     Function: PipelineCyclerTrueImpl::CyclerMutex::output
00345 //       Access: Public, Virtual
00346 //  Description: 
00347 ////////////////////////////////////////////////////////////////////
00348 void PipelineCyclerTrueImpl::CyclerMutex::
00349 output(ostream &out) const {
00350   out << "CyclerMutex ";
00351   _cycler->cheat()->output(out);
00352 }
00353 #endif  // DEBUG_THREADS
00354 
00355 #endif  // THREADED_PIPELINE
00356 
00357 
 All Classes Functions Variables Enumerations