Panda3D

pipeline.cxx

00001 // Filename: pipeline.cxx
00002 // Created by:  drose (21Feb02)
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 "pipeline.h"
00016 #include "pipelineCyclerTrueImpl.h"
00017 #include "reMutexHolder.h"
00018 #include "configVariableInt.h"
00019 #include "config_pipeline.h"
00020 
00021 Pipeline *Pipeline::_render_pipeline = (Pipeline *)NULL;
00022 
00023 ////////////////////////////////////////////////////////////////////
00024 //     Function: Pipeline::Constructor
00025 //       Access: Public
00026 //  Description: 
00027 ////////////////////////////////////////////////////////////////////
00028 Pipeline::
00029 Pipeline(const string &name, int num_stages) :
00030   Namable(name)
00031 #ifdef THREADED_PIPELINE
00032   , _lock("Pipeline")
00033 #endif
00034 {
00035 #ifdef THREADED_PIPELINE
00036   // Set up the linked list of cyclers to be a circular list that
00037   // begins with this object.
00038   _prev = this;
00039   _next = this;
00040 
00041   _num_cyclers = 0;
00042   _cycling = false;
00043 
00044 #endif  // THREADED_PIPELINE
00045 
00046   set_num_stages(num_stages);
00047 }
00048 
00049 ////////////////////////////////////////////////////////////////////
00050 //     Function: Pipeline::Destructor
00051 //       Access: Public
00052 //  Description: 
00053 ////////////////////////////////////////////////////////////////////
00054 Pipeline::
00055 ~Pipeline() {
00056 #ifdef THREADED_PIPELINE
00057   nassertv(_num_cyclers == 0);
00058   nassertv(_prev == this && _next == this);
00059   _prev = NULL;
00060   _next = NULL;
00061   nassertv(!_cycling);
00062 #endif  // THREADED_PIPELINE
00063 }
00064 
00065 ////////////////////////////////////////////////////////////////////
00066 //     Function: Pipeline::cycle
00067 //       Access: Public
00068 //  Description: Flows all the pipeline data down to the next stage.
00069 ////////////////////////////////////////////////////////////////////
00070 void Pipeline::
00071 cycle() {
00072 #ifdef THREADED_PIPELINE
00073   pvector< PT(CycleData) > saved_cdatas;
00074   saved_cdatas.reserve(_dirty_cyclers.size());
00075   {
00076     ReMutexHolder holder(_lock);
00077     if (_num_stages == 1) {
00078       // No need to cycle if there's only one stage.
00079       nassertv(_dirty_cyclers.empty());
00080       return;
00081     }
00082     
00083     nassertv(!_cycling);
00084     _cycling = true;
00085     
00086     Cyclers next_dirty_cyclers;
00087 
00088     Cyclers::iterator ci;
00089     switch (_num_stages) {
00090     case 2:
00091       for (ci = _dirty_cyclers.begin(); ci != _dirty_cyclers.end(); ++ci) {
00092         PipelineCyclerTrueImpl *cycler = (*ci);
00093         ReMutexHolder holder2(cycler->_lock);
00094         
00095         // We save the result of cycle(), so that we can defer the
00096         // side-effects that might occur when CycleDatas destruct, at
00097         // least until the end of this loop.
00098         saved_cdatas.push_back(cycler->cycle_2());
00099         
00100         if (cycler->_dirty) {
00101           // The cycler is still dirty after cycling.  Preserve it in the
00102           // set for next time.
00103           bool inserted = next_dirty_cyclers.insert(cycler).second;
00104           nassertv(inserted);
00105         } else {
00106 #ifdef DEBUG_THREADS
00107           inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1);
00108 #endif
00109         }
00110       }
00111       break;
00112 
00113     case 3:
00114       for (ci = _dirty_cyclers.begin(); ci != _dirty_cyclers.end(); ++ci) {
00115         PipelineCyclerTrueImpl *cycler = (*ci);
00116         ReMutexHolder holder2(cycler->_lock);
00117         
00118         saved_cdatas.push_back(cycler->cycle_3());
00119         if (cycler->_dirty) {
00120           bool inserted = next_dirty_cyclers.insert(cycler).second;
00121           nassertv(inserted);
00122         } else {
00123 #ifdef DEBUG_THREADS
00124           inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1);
00125 #endif
00126         }
00127       }
00128       break;
00129 
00130     default:
00131       for (ci = _dirty_cyclers.begin(); ci != _dirty_cyclers.end(); ++ci) {
00132         PipelineCyclerTrueImpl *cycler = (*ci);
00133         ReMutexHolder holder2(cycler->_lock);
00134         
00135         saved_cdatas.push_back(cycler->cycle());
00136         if (cycler->_dirty) {
00137           bool inserted = next_dirty_cyclers.insert(cycler).second;
00138           nassertv(inserted);
00139         } else {
00140 #ifdef DEBUG_THREADS
00141           inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1);
00142 #endif
00143         }
00144       }
00145       break;
00146     }
00147       
00148     // Finally, we're ready for the next frame.
00149     _dirty_cyclers.swap(next_dirty_cyclers);
00150     _cycling = false;
00151   }
00152 
00153   // And now it's safe to let the CycleData pointers in saved_cdatas
00154   // destruct, which may cause cascading deletes, and which will in
00155   // turn case PipelineCyclers to remove themselves from (or add
00156   // themselves to) the _dirty_cyclers list.
00157 
00158 #endif  // THREADED_PIPELINE
00159 }
00160 
00161 ////////////////////////////////////////////////////////////////////
00162 //     Function: Pipeline::set_num_stages
00163 //       Access: Public
00164 //  Description: Specifies the number of stages required for the
00165 //               pipeline.
00166 ////////////////////////////////////////////////////////////////////
00167 void Pipeline::
00168 set_num_stages(int num_stages) {
00169   nassertv(num_stages >= 1);
00170 #ifdef THREADED_PIPELINE
00171   ReMutexHolder holder(_lock);
00172   if (num_stages != _num_stages) {
00173 
00174     // We need to lock every PipelineCycler object attached to this
00175     // pipeline before we can adjust the number of stages.
00176     PipelineCyclerLinks *links;
00177     for (links = this->_next; links != this; links = links->_next) {
00178       PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links;
00179       cycler->_lock.acquire();
00180     }
00181 
00182     _num_stages = num_stages;
00183 
00184     for (links = this->_next; links != this; links = links->_next) {
00185       PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links;
00186       cycler->set_num_stages(num_stages);
00187     }
00188 
00189     // Now release them all.
00190     int count = 0;
00191     for (links = this->_next; links != this; links = links->_next) {
00192       PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links;
00193       cycler->_lock.release();
00194       ++count;
00195     }
00196     nassertv(count == _num_cyclers);
00197   }
00198 
00199 #else  // THREADED_PIPELINE
00200   if (num_stages != 1) {
00201     pipeline_cat.warning()
00202       << "Requested " << num_stages
00203       << " pipeline stages but multithreaded render pipelines not enabled in build.\n";
00204   }
00205   _num_stages = 1;
00206 #endif  // THREADED_PIPELINE
00207 }
00208 
00209 #ifdef THREADED_PIPELINE
00210 ////////////////////////////////////////////////////////////////////
00211 //     Function: Pipeline::add_cycler
00212 //       Access: Public
00213 //  Description: Adds the indicated cycler to the list of cyclers
00214 //               associated with the pipeline.  This method only
00215 //               exists when true pipelining is configured on.
00216 ////////////////////////////////////////////////////////////////////
00217 void Pipeline::
00218 add_cycler(PipelineCyclerTrueImpl *cycler) {
00219   ReMutexHolder holder(_lock);
00220   nassertv(!cycler->_dirty);
00221   nassertv(!_cycling);
00222   ++_num_cyclers;
00223   cycler->insert_before(this);
00224   
00225 #ifdef DEBUG_THREADS
00226   inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), 1);
00227 #endif
00228 }
00229 #endif  // THREADED_PIPELINE
00230 
00231 #ifdef THREADED_PIPELINE
00232 ////////////////////////////////////////////////////////////////////
00233 //     Function: Pipeline::add_dirty_cycler
00234 //       Access: Public
00235 //  Description: Marks the indicated cycler as "dirty", meaning it
00236 //               will need to be cycled next frame.  This both adds it
00237 //               to the "dirty" set and also sets the "dirty" flag
00238 //               within the cycler.  This method only exists when true
00239 //               pipelining is configured on.
00240 ////////////////////////////////////////////////////////////////////
00241 void Pipeline::
00242 add_dirty_cycler(PipelineCyclerTrueImpl *cycler) {
00243   nassertv(cycler->_lock.debug_is_locked());
00244 
00245   ReMutexHolder holder(_lock);
00246   nassertv(_num_stages != 1);
00247   nassertv(!_cycling);
00248   nassertv(!cycler->_dirty);
00249   cycler->_dirty = true;
00250 
00251   bool inserted = _dirty_cyclers.insert(cycler).second;
00252   nassertv(inserted);
00253 
00254 #ifdef DEBUG_THREADS
00255   inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), 1);
00256 #endif
00257 }
00258 #endif  // THREADED_PIPELINE
00259 
00260 #ifdef THREADED_PIPELINE
00261 ////////////////////////////////////////////////////////////////////
00262 //     Function: Pipeline::remove_cycler
00263 //       Access: Public
00264 //  Description: Removes the indicated cycler from the list of cyclers
00265 //               associated with the pipeline.  This method only
00266 //               exists when true pipelining is configured on.
00267 ////////////////////////////////////////////////////////////////////
00268 void Pipeline::
00269 remove_cycler(PipelineCyclerTrueImpl *cycler) {
00270   nassertv(cycler->_lock.debug_is_locked());
00271 
00272   ReMutexHolder holder(_lock);
00273   nassertv(!_cycling);
00274 
00275   --_num_cyclers;
00276   cycler->remove_from_list();
00277 
00278 #ifdef DEBUG_THREADS
00279   inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), -1);
00280 #endif
00281 
00282   if (cycler->_dirty) {
00283     cycler->_dirty = false;
00284     Cyclers::iterator ci = _dirty_cyclers.find(cycler);
00285     nassertv(ci != _dirty_cyclers.end());
00286     _dirty_cyclers.erase(ci);
00287 #ifdef DEBUG_THREADS
00288     inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1);
00289 #endif
00290   }
00291 }
00292 #endif  // THREADED_PIPELINE
00293 
00294 #if defined(THREADED_PIPELINE) && defined(DEBUG_THREADS) 
00295 ////////////////////////////////////////////////////////////////////
00296 //     Function: Pipeline::iterate_all_cycler_types
00297 //       Access: Public
00298 //  Description: Walks through the list of all the different
00299 //               PipelineCycler types in the universe.  For each one,
00300 //               calls the indicated callback function with the
00301 //               TypeHandle of the respective type (actually, the
00302 //               result of cycler::get_parent_type()) and the count of
00303 //               pipeline cyclers of that type.  Mainly used for
00304 //               PStats reporting.
00305 ////////////////////////////////////////////////////////////////////
00306 void Pipeline::
00307 iterate_all_cycler_types(CallbackFunc *func, void *data) const {
00308   ReMutexHolder holder(_lock);
00309   TypeCount::const_iterator ci;
00310   for (ci = _all_cycler_types.begin(); ci != _all_cycler_types.end(); ++ci) {
00311     func((*ci).first, (*ci).second, data);
00312   }
00313 }
00314 #endif  // THREADED_PIPELINE && DEBUG_THREADS
00315 
00316 #if defined(THREADED_PIPELINE) && defined(DEBUG_THREADS) 
00317 ////////////////////////////////////////////////////////////////////
00318 //     Function: Pipeline::iterate_dirty_cycler_types
00319 //       Access: Public
00320 //  Description: Walks through the list of all the different
00321 //               PipelineCycler types, for only the dirty
00322 //               PipelineCyclers.  See also
00323 //               iterate_all_cycler_types().
00324 ////////////////////////////////////////////////////////////////////
00325 void Pipeline::
00326 iterate_dirty_cycler_types(CallbackFunc *func, void *data) const {
00327   ReMutexHolder holder(_lock);
00328   TypeCount::const_iterator ci;
00329   for (ci = _dirty_cycler_types.begin(); ci != _dirty_cycler_types.end(); ++ci) {
00330     func((*ci).first, (*ci).second, data);
00331   }
00332 }
00333 #endif  // THREADED_PIPELINE && DEBUG_THREADS
00334 
00335 ////////////////////////////////////////////////////////////////////
00336 //     Function: Pipeline::make_render_pipeline
00337 //       Access: Private, Static
00338 //  Description: 
00339 ////////////////////////////////////////////////////////////////////
00340 void Pipeline::
00341 make_render_pipeline() {
00342   ConfigVariableInt pipeline_stages
00343     ("pipeline-stages", 1,
00344      PRC_DESC("The initial number of stages in the render pipeline.  This is "
00345               "only meaningful if threaded pipelining is compiled into "
00346               "Panda.  In most cases, you should not set this at all anyway, "
00347               "since the pipeline can automatically grow stages as needed, "
00348               "but it will not remove stages automatically, and having more "
00349               "pipeline stages than your application requires will incur "
00350               "additional runtime overhead."));
00351 
00352   nassertv(_render_pipeline == (Pipeline *)NULL);
00353   _render_pipeline = new Pipeline("render", pipeline_stages);
00354 }
00355 
00356 #if defined(THREADED_PIPELINE) && defined(DEBUG_THREADS) 
00357 ////////////////////////////////////////////////////////////////////
00358 //     Function: Pipeline::inc_cycler_type
00359 //       Access: Private, Static
00360 //  Description: Increments (or decrements, according to added) the
00361 //               value for TypeHandle in the indicated TypeCount map.
00362 //               This is used in DEBUG_THREADS mode to track the types
00363 //               of PipelineCyclers that are coming and going, mainly
00364 //               for PStats reporting.
00365 //
00366 //               It is assumed the lock is held during this call.
00367 ////////////////////////////////////////////////////////////////////
00368 void Pipeline::
00369 inc_cycler_type(TypeCount &count, TypeHandle type, int addend) {
00370   TypeCount::iterator ci = count.find(type);
00371   if (ci == count.end()) {
00372     ci = count.insert(TypeCount::value_type(type, 0)).first;
00373   }
00374   (*ci).second += addend;
00375   nassertv((*ci).second >= 0);
00376 }
00377 #endif  // THREADED_PIPELINE && DEBUG_THREADS
 All Classes Functions Variables Enumerations