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 NPT(CycleData)[_num_stages];
00039   for (int i = 0; i < _num_stages; ++i) {
00040     _data[i] = 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 NPT(CycleData)[_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]];
00073     if (new_pt == NULL) {
00074       new_pt = copy._data[i]->make_copy();
00075     }
00076     _data[i] = 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]];
00101     if (new_pt == NULL) {
00102       new_pt = copy._data[i]->make_copy();
00103     }
00104     _data[i] = 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];
00150 
00151   // Only the node reference count is considered an important count
00152   // for copy-on-write purposes.  A standard reference of other than 1
00153   // just means that some code (other that the PipelineCycler) has a
00154   // pointer, which is safe to modify.
00155   if (old_data->get_node_ref_count() != 1) {
00156     // Copy-on-write.
00157     _data[pipeline_stage] = old_data->make_copy();
00158 
00159     // Now we have differences between some of the data pointers, so
00160     // we're "dirty".  Mark it so.
00161     if (!_dirty && _num_stages != 1) {
00162       _pipeline->add_dirty_cycler(this);
00163     }
00164   }
00165 
00166   return _data[pipeline_stage];
00167 }
00168 
00169 ////////////////////////////////////////////////////////////////////
00170 //     Function: PipelineCyclerTrueImpl::write_stage_upstream
00171 //       Access: Public
00172 //  Description: This special variant on write_stage() will
00173 //               automatically propagate changes back to upstream
00174 //               pipeline stages.  See write_upstream().
00175 ////////////////////////////////////////////////////////////////////
00176 CycleData *PipelineCyclerTrueImpl::
00177 write_stage_upstream(int pipeline_stage, bool force_to_0, Thread *current_thread) {
00178   _lock.acquire(current_thread);
00179 
00180 #ifndef NDEBUG
00181   nassertd(pipeline_stage >= 0 && pipeline_stage < _num_stages) {
00182     _lock.release();
00183     return NULL;
00184   }
00185 #endif  // NDEBUG
00186 
00187   CycleData *old_data = _data[pipeline_stage];
00188 
00189   if (old_data->get_ref_count() != 1 || force_to_0) {
00190     // Count the number of references before the current stage, and
00191     // the number of references remaining other than those.
00192     int external_count = old_data->get_ref_count() - 1;
00193     int k = pipeline_stage - 1;
00194     while (k >= 0 && _data[k] == old_data) {
00195       --k;
00196       --external_count;
00197     }
00198     
00199     if (external_count > 0) {
00200       // There are references other than the ones before this stage in
00201       // the pipeline; perform a copy-on-write.
00202       PT(CycleData) new_data = old_data->make_copy();
00203       
00204       k = pipeline_stage - 1;
00205       while (k >= 0 && (_data[k] == old_data || force_to_0)) {
00206         _data[k] = new_data.p();
00207         --k;
00208       }
00209       
00210       _data[pipeline_stage] = new_data;
00211       
00212       if (k >= 0 || pipeline_stage + 1 < _num_stages) {
00213         // Now we have differences between some of the data pointers,
00214         // which makes us "dirty".
00215         if (!_dirty) {
00216           _pipeline->add_dirty_cycler(this);
00217         }
00218       }
00219 
00220     } else if (k >= 0 && force_to_0) {
00221       // There are no external pointers, so no need to copy-on-write,
00222       // but the current pointer doesn't go all the way back.  Make it
00223       // do so.
00224       while (k >= 0) {
00225         _data[k] = old_data;
00226         --k;
00227       }
00228     }
00229   }
00230 
00231   return _data[pipeline_stage];
00232 }
00233 
00234 ////////////////////////////////////////////////////////////////////
00235 //     Function: PipelineCyclerTrueImpl::cycle
00236 //       Access: Private
00237 //  Description: Cycles the data between frames.  This is only called
00238 //               from Pipeline::cycle(), and presumably it is only
00239 //               called if the cycler is "dirty".
00240 //
00241 //               At the conclusion of this method, the cycler should
00242 //               clear its dirty flag if it is no longer "dirty"--that
00243 //               is, if all of the pipeline pointers are the same.
00244 //
00245 //               The return value is the CycleData pointer which fell
00246 //               off the end of the cycle.  If this is allowed to
00247 //               destruct immediately, there may be side-effects that
00248 //               cascade through the system, so the caller may choose
00249 //               to hold the pointer until it can safely be released
00250 //               later.
00251 ////////////////////////////////////////////////////////////////////
00252 PT(CycleData) PipelineCyclerTrueImpl::
00253 cycle() {
00254   PT(CycleData) last_val = _data[_num_stages - 1].p();
00255   nassertr(_lock.debug_is_locked(), last_val);
00256   nassertr(_dirty, last_val);
00257 
00258   int i;
00259   for (i = _num_stages - 1; i > 0; --i) {
00260     _data[i] = _data[i - 1];
00261   }
00262 
00263   for (i = 1; i < _num_stages; ++i) {
00264     if (_data[i] != _data[i - 1]) {
00265       // Still dirty.
00266       return last_val;
00267     }
00268   }
00269 
00270   // No longer dirty.
00271   _dirty = false;
00272   return last_val;
00273 }
00274 
00275 ////////////////////////////////////////////////////////////////////
00276 //     Function: PipelineCyclerTrueImpl::set_num_stages
00277 //       Access: Private
00278 //  Description: Changes the number of stages in the cycler.  This is
00279 //               only called from Pipeline::set_num_stages();
00280 ////////////////////////////////////////////////////////////////////
00281 void PipelineCyclerTrueImpl::
00282 set_num_stages(int num_stages) {
00283   nassertv(_lock.debug_is_locked());
00284 
00285   if (num_stages <= _num_stages) {
00286     // Don't bother to reallocate the array smaller; we just won't use
00287     // the rest of the array.
00288     for (int i = _num_stages; i < num_stages; ++i) {
00289       _data[i].clear();
00290     }
00291 
00292     _num_stages = num_stages;
00293     
00294 
00295   } else {
00296     // To increase the array, we must reallocate it larger.
00297     NPT(CycleData) *new_data = new NPT(CycleData)[num_stages];
00298     int i;
00299     for (i = 0; i < _num_stages; ++i) {
00300       new_data[i] = _data[i];
00301     }
00302     for (i = _num_stages; i < num_stages; ++i) {
00303       new_data[i] = _data[_num_stages - 1];
00304     }
00305     delete[] _data;
00306 
00307     _num_stages = num_stages;
00308     _data = new_data;
00309   }
00310 }
00311 
00312 #ifdef DEBUG_THREADS
00313 ////////////////////////////////////////////////////////////////////
00314 //     Function: PipelineCyclerTrueImpl::CyclerMutex::output
00315 //       Access: Public, Virtual
00316 //  Description: 
00317 ////////////////////////////////////////////////////////////////////
00318 void PipelineCyclerTrueImpl::CyclerMutex::
00319 output(ostream &out) const {
00320   out << "CyclerMutex ";
00321   _cycler->cheat()->output(out);
00322 }
00323 #endif  // DEBUG_THREADS
00324 
00325 #endif  // THREADED_PIPELINE
00326 
00327 
 All Classes Functions Variables Enumerations