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 // 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