Panda3D
|
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 00037 // We maintain all of the cyclers in the world on one of two linked 00038 // lists. Cyclers that are "clean", which is to say, they have the 00039 // same value across all pipeline stages, are stored on the _clean 00040 // list. Cyclers that are "dirty", which have different values 00041 // across some pipeline stages, are stored instead on the _dirty 00042 // list. Cyclers can move themselves from clean to dirty by calling 00043 // add_dirty_cycler(), and cyclers get moved from dirty to clean 00044 // during cycle(). 00045 00046 // To visit each cycler once requires traversing both lists. 00047 _clean.make_head(); 00048 _dirty.make_head(); 00049 00050 // We also store the total count of all cyclers, clean and dirty, in 00051 // _num_cyclers; and the count of only dirty cyclers in 00052 // _num_dirty_cyclers. 00053 _num_cyclers = 0; 00054 _num_dirty_cyclers = 0; 00055 00056 // This flag is true only during the call to cycle(). 00057 _cycling = false; 00058 00059 #endif // THREADED_PIPELINE 00060 00061 set_num_stages(num_stages); 00062 } 00063 00064 //////////////////////////////////////////////////////////////////// 00065 // Function: Pipeline::Destructor 00066 // Access: Public 00067 // Description: 00068 //////////////////////////////////////////////////////////////////// 00069 Pipeline:: 00070 ~Pipeline() { 00071 #ifdef THREADED_PIPELINE 00072 nassertv(_num_cyclers == 0); 00073 nassertv(_num_dirty_cyclers == 0); 00074 _clean.clear_head(); 00075 _dirty.clear_head(); 00076 nassertv(!_cycling); 00077 #endif // THREADED_PIPELINE 00078 } 00079 00080 //////////////////////////////////////////////////////////////////// 00081 // Function: Pipeline::cycle 00082 // Access: Public 00083 // Description: Flows all the pipeline data down to the next stage. 00084 //////////////////////////////////////////////////////////////////// 00085 void Pipeline:: 00086 cycle() { 00087 #ifdef THREADED_PIPELINE 00088 if (pipeline_cat.is_debug()) { 00089 pipeline_cat.debug() 00090 << "Beginning the pipeline cycle\n"; 00091 } 00092 00093 pvector< PT(CycleData) > saved_cdatas; 00094 saved_cdatas.reserve(_num_dirty_cyclers); 00095 { 00096 ReMutexHolder holder(_lock); 00097 if (_num_stages == 1) { 00098 // No need to cycle if there's only one stage. 00099 nassertv(_dirty._next == &_dirty); 00100 return; 00101 } 00102 00103 nassertv(!_cycling); 00104 _cycling = true; 00105 00106 // Move the dirty list to prev_dirty, for processing. 00107 PipelineCyclerLinks prev_dirty; 00108 prev_dirty.make_head(); 00109 prev_dirty.take_list(_dirty); 00110 _num_dirty_cyclers = 0; 00111 00112 switch (_num_stages) { 00113 case 2: 00114 while (prev_dirty._next != &prev_dirty) { 00115 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)prev_dirty._next; 00116 cycler->remove_from_list(); 00117 ReMutexHolder holder2(cycler->_lock); 00118 00119 // We save the result of cycle(), so that we can defer the 00120 // side-effects that might occur when CycleDatas destruct, at 00121 // least until the end of this loop. 00122 saved_cdatas.push_back(cycler->cycle_2()); 00123 00124 if (cycler->_dirty) { 00125 // The cycler is still dirty after cycling. Keep it on the 00126 // dirty list for next time. 00127 cycler->insert_before(&_dirty); 00128 ++_num_dirty_cyclers; 00129 } else { 00130 // The cycler is now clean. Add it back to the clean list. 00131 cycler->insert_before(&_clean); 00132 #ifdef DEBUG_THREADS 00133 inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1); 00134 #endif 00135 } 00136 } 00137 break; 00138 00139 case 3: 00140 while (prev_dirty._next != &prev_dirty) { 00141 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)prev_dirty._next; 00142 cycler->remove_from_list(); 00143 ReMutexHolder holder2(cycler->_lock); 00144 00145 saved_cdatas.push_back(cycler->cycle_3()); 00146 00147 if (cycler->_dirty) { 00148 cycler->insert_before(&_dirty); 00149 ++_num_dirty_cyclers; 00150 } else { 00151 cycler->insert_before(&_clean); 00152 #ifdef DEBUG_THREADS 00153 inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1); 00154 #endif 00155 } 00156 } 00157 break; 00158 00159 default: 00160 while (prev_dirty._next != &prev_dirty) { 00161 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)prev_dirty._next; 00162 cycler->remove_from_list(); 00163 ReMutexHolder holder2(cycler->_lock); 00164 00165 saved_cdatas.push_back(cycler->cycle()); 00166 00167 if (cycler->_dirty) { 00168 cycler->insert_before(&_dirty); 00169 ++_num_dirty_cyclers; 00170 } else { 00171 cycler->insert_before(&_clean); 00172 #ifdef DEBUG_THREADS 00173 inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1); 00174 #endif 00175 } 00176 } 00177 break; 00178 } 00179 00180 // Now we're ready for the next frame. 00181 prev_dirty.clear_head(); 00182 _cycling = false; 00183 } 00184 00185 // And now it's safe to let the CycleData pointers in saved_cdatas 00186 // destruct, which may cause cascading deletes, and which will in 00187 // turn cause PipelineCyclers to remove themselves from (or add 00188 // themselves to) the _dirty list. 00189 saved_cdatas.clear(); 00190 00191 if (pipeline_cat.is_debug()) { 00192 pipeline_cat.debug() 00193 << "Finished the pipeline cycle\n"; 00194 } 00195 00196 #endif // THREADED_PIPELINE 00197 } 00198 00199 //////////////////////////////////////////////////////////////////// 00200 // Function: Pipeline::set_num_stages 00201 // Access: Public 00202 // Description: Specifies the number of stages required for the 00203 // pipeline. 00204 //////////////////////////////////////////////////////////////////// 00205 void Pipeline:: 00206 set_num_stages(int num_stages) { 00207 nassertv(num_stages >= 1); 00208 #ifdef THREADED_PIPELINE 00209 ReMutexHolder holder(_lock); 00210 if (num_stages != _num_stages) { 00211 00212 // We need to lock every PipelineCycler object attached to this 00213 // pipeline before we can adjust the number of stages. 00214 PipelineCyclerLinks *links; 00215 for (links = _clean._next; links != &_clean; links = links->_next) { 00216 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links; 00217 cycler->_lock.acquire(); 00218 } 00219 for (links = _dirty._next; links != &_dirty; links = links->_next) { 00220 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links; 00221 cycler->_lock.acquire(); 00222 } 00223 00224 _num_stages = num_stages; 00225 00226 for (links = _clean._next; links != &_clean; links = links->_next) { 00227 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links; 00228 cycler->set_num_stages(num_stages); 00229 } 00230 for (links = _dirty._next; links != &_dirty; links = links->_next) { 00231 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links; 00232 cycler->set_num_stages(num_stages); 00233 } 00234 00235 // Now release them all. 00236 int count = 0; 00237 for (links = _clean._next; links != &_clean; links = links->_next) { 00238 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links; 00239 cycler->_lock.release(); 00240 ++count; 00241 } 00242 for (links = _dirty._next; links != &_dirty; links = links->_next) { 00243 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links; 00244 cycler->_lock.release(); 00245 ++count; 00246 } 00247 nassertv(count == _num_cyclers); 00248 } 00249 00250 #else // THREADED_PIPELINE 00251 if (num_stages != 1) { 00252 pipeline_cat.warning() 00253 << "Requested " << num_stages 00254 << " pipeline stages but multithreaded render pipelines not enabled in build.\n"; 00255 } 00256 _num_stages = 1; 00257 #endif // THREADED_PIPELINE 00258 } 00259 00260 #ifdef THREADED_PIPELINE 00261 //////////////////////////////////////////////////////////////////// 00262 // Function: Pipeline::add_cycler 00263 // Access: Public 00264 // Description: Adds the indicated cycler to 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 add_cycler(PipelineCyclerTrueImpl *cycler) { 00270 ReMutexHolder holder(_lock); 00271 nassertv(!cycler->_dirty); 00272 nassertv(!_cycling); 00273 00274 cycler->insert_before(&_clean); 00275 ++_num_cyclers; 00276 00277 #ifdef DEBUG_THREADS 00278 inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), 1); 00279 #endif 00280 } 00281 #endif // THREADED_PIPELINE 00282 00283 #ifdef THREADED_PIPELINE 00284 //////////////////////////////////////////////////////////////////// 00285 // Function: Pipeline::add_dirty_cycler 00286 // Access: Public 00287 // Description: Marks the indicated cycler as "dirty", meaning it 00288 // will need to be cycled next frame. This both adds it 00289 // to the "dirty" set and also sets the "dirty" flag 00290 // within the cycler. This method only exists when true 00291 // pipelining is configured on. 00292 //////////////////////////////////////////////////////////////////// 00293 void Pipeline:: 00294 add_dirty_cycler(PipelineCyclerTrueImpl *cycler) { 00295 nassertv(cycler->_lock.debug_is_locked()); 00296 00297 ReMutexHolder holder(_lock); 00298 nassertv(_num_stages != 1); 00299 nassertv(!_cycling); 00300 nassertv(!cycler->_dirty); 00301 00302 // Remove it from the "clean" list and add it to the "dirty" list. 00303 cycler->remove_from_list(); 00304 cycler->insert_before(&_dirty); 00305 cycler->_dirty = true; 00306 ++_num_dirty_cyclers; 00307 00308 #ifdef DEBUG_THREADS 00309 inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), 1); 00310 #endif 00311 } 00312 #endif // THREADED_PIPELINE 00313 00314 #ifdef THREADED_PIPELINE 00315 //////////////////////////////////////////////////////////////////// 00316 // Function: Pipeline::remove_cycler 00317 // Access: Public 00318 // Description: Removes the indicated cycler from the list of cyclers 00319 // associated with the pipeline. This method only 00320 // exists when true pipelining is configured on. 00321 //////////////////////////////////////////////////////////////////// 00322 void Pipeline:: 00323 remove_cycler(PipelineCyclerTrueImpl *cycler) { 00324 nassertv(cycler->_lock.debug_is_locked()); 00325 00326 ReMutexHolder holder(_lock); 00327 nassertv(!_cycling); 00328 00329 --_num_cyclers; 00330 cycler->remove_from_list(); 00331 00332 #ifdef DEBUG_THREADS 00333 inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), -1); 00334 #endif 00335 00336 if (cycler->_dirty) { 00337 cycler->_dirty = false; 00338 --_num_dirty_cyclers; 00339 #ifdef DEBUG_THREADS 00340 inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1); 00341 #endif 00342 } 00343 } 00344 #endif // THREADED_PIPELINE 00345 00346 #if defined(THREADED_PIPELINE) && defined(DEBUG_THREADS) 00347 //////////////////////////////////////////////////////////////////// 00348 // Function: Pipeline::iterate_all_cycler_types 00349 // Access: Public 00350 // Description: Walks through the list of all the different 00351 // PipelineCycler types in the universe. For each one, 00352 // calls the indicated callback function with the 00353 // TypeHandle of the respective type (actually, the 00354 // result of cycler::get_parent_type()) and the count of 00355 // pipeline cyclers of that type. Mainly used for 00356 // PStats reporting. 00357 //////////////////////////////////////////////////////////////////// 00358 void Pipeline:: 00359 iterate_all_cycler_types(CallbackFunc *func, void *data) const { 00360 ReMutexHolder holder(_lock); 00361 TypeCount::const_iterator ci; 00362 for (ci = _all_cycler_types.begin(); ci != _all_cycler_types.end(); ++ci) { 00363 func((*ci).first, (*ci).second, data); 00364 } 00365 } 00366 #endif // THREADED_PIPELINE && DEBUG_THREADS 00367 00368 #if defined(THREADED_PIPELINE) && defined(DEBUG_THREADS) 00369 //////////////////////////////////////////////////////////////////// 00370 // Function: Pipeline::iterate_dirty_cycler_types 00371 // Access: Public 00372 // Description: Walks through the list of all the different 00373 // PipelineCycler types, for only the dirty 00374 // PipelineCyclers. See also 00375 // iterate_all_cycler_types(). 00376 //////////////////////////////////////////////////////////////////// 00377 void Pipeline:: 00378 iterate_dirty_cycler_types(CallbackFunc *func, void *data) const { 00379 ReMutexHolder holder(_lock); 00380 TypeCount::const_iterator ci; 00381 for (ci = _dirty_cycler_types.begin(); ci != _dirty_cycler_types.end(); ++ci) { 00382 func((*ci).first, (*ci).second, data); 00383 } 00384 } 00385 #endif // THREADED_PIPELINE && DEBUG_THREADS 00386 00387 //////////////////////////////////////////////////////////////////// 00388 // Function: Pipeline::make_render_pipeline 00389 // Access: Private, Static 00390 // Description: 00391 //////////////////////////////////////////////////////////////////// 00392 void Pipeline:: 00393 make_render_pipeline() { 00394 ConfigVariableInt pipeline_stages 00395 ("pipeline-stages", 1, 00396 PRC_DESC("The initial number of stages in the render pipeline. This is " 00397 "only meaningful if threaded pipelining is compiled into " 00398 "Panda. In most cases, you should not set this at all anyway, " 00399 "since the pipeline can automatically grow stages as needed, " 00400 "but it will not remove stages automatically, and having more " 00401 "pipeline stages than your application requires will incur " 00402 "additional runtime overhead.")); 00403 00404 nassertv(_render_pipeline == (Pipeline *)NULL); 00405 _render_pipeline = new Pipeline("render", pipeline_stages); 00406 } 00407 00408 #if defined(THREADED_PIPELINE) && defined(DEBUG_THREADS) 00409 //////////////////////////////////////////////////////////////////// 00410 // Function: Pipeline::inc_cycler_type 00411 // Access: Private, Static 00412 // Description: Increments (or decrements, according to added) the 00413 // value for TypeHandle in the indicated TypeCount map. 00414 // This is used in DEBUG_THREADS mode to track the types 00415 // of PipelineCyclers that are coming and going, mainly 00416 // for PStats reporting. 00417 // 00418 // It is assumed the lock is held during this call. 00419 //////////////////////////////////////////////////////////////////// 00420 void Pipeline:: 00421 inc_cycler_type(TypeCount &count, TypeHandle type, int addend) { 00422 TypeCount::iterator ci = count.find(type); 00423 if (ci == count.end()) { 00424 ci = count.insert(TypeCount::value_type(type, 0)).first; 00425 } 00426 (*ci).second += addend; 00427 nassertv((*ci).second >= 0); 00428 } 00429 #endif // THREADED_PIPELINE && DEBUG_THREADS