00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00025
00026
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
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047 _clean.make_head();
00048 _dirty.make_head();
00049
00050
00051
00052
00053 _num_cyclers = 0;
00054 _num_dirty_cyclers = 0;
00055
00056
00057 _cycling = false;
00058
00059 #endif // THREADED_PIPELINE
00060
00061 set_num_stages(num_stages);
00062 }
00063
00064
00065
00066
00067
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
00082
00083
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
00099 nassertv(_dirty._next == &_dirty);
00100 return;
00101 }
00102
00103 nassertv(!_cycling);
00104 _cycling = true;
00105
00106
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
00120
00121
00122 saved_cdatas.push_back(cycler->cycle_2());
00123
00124 if (cycler->_dirty) {
00125
00126
00127 cycler->insert_before(&_dirty);
00128 ++_num_dirty_cyclers;
00129 } else {
00130
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
00181 prev_dirty.clear_head();
00182 _cycling = false;
00183 }
00184
00185
00186
00187
00188
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
00201
00202
00203
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
00213
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
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
00263
00264
00265
00266
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
00286
00287
00288
00289
00290
00291
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
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
00317
00318
00319
00320
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
00349
00350
00351
00352
00353
00354
00355
00356
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
00371
00372
00373
00374
00375
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
00389
00390
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
00411
00412
00413
00414
00415
00416
00417
00418
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