19 Pipeline *Pipeline::_render_pipeline =
nullptr;
25 Pipeline(
const std::string &name,
int num_stages) :
27 #ifdef THREADED_PIPELINE
28 _num_stages(num_stages),
29 _cycle_lock(
"Pipeline cycle"),
36 #ifdef THREADED_PIPELINE
53 _num_dirty_cyclers = 0;
59 if (num_stages != 1) {
60 pipeline_cat.warning()
61 <<
"Requested " << num_stages
62 <<
" pipeline stages but multithreaded render pipelines not enabled in build.\n";
64 #endif // THREADED_PIPELINE
66 nassertv(num_stages >= 1);
74 #ifdef THREADED_PIPELINE
75 nassertv(_num_cyclers == 0);
76 nassertv(_num_dirty_cyclers == 0);
80 #endif // THREADED_PIPELINE
88 #ifdef THREADED_PIPELINE
89 if (pipeline_cat.is_debug()) {
91 <<
"Beginning the pipeline cycle\n";
97 unsigned int prev_seq, next_seq;
103 if (_num_stages == 1) {
105 nassertv(_dirty._next == &_dirty);
114 prev_seq = next_seq = _next_cycle_seq;
115 if (++next_seq == 0) {
119 _next_cycle_seq = next_seq;
122 prev_dirty.make_head();
123 prev_dirty.take_list(_dirty);
125 saved_cdatas.reserve(_num_dirty_cyclers);
126 _num_dirty_cyclers = 0;
130 switch (_num_stages) {
132 while (prev_dirty._next != &prev_dirty) {
134 while (link != &prev_dirty) {
135 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)link;
137 if (!cycler->_lock.try_lock()) {
141 if (link->_prev != &prev_dirty || link->_next != &prev_dirty) {
142 link = cycler->_next;
147 cycler->_lock.lock();
152 cycler->remove_from_list();
157 saved_cdatas.push_back(cycler->cycle_2());
160 nassertd(!cycler->_dirty)
break;
161 cycler->insert_before(&_clean);
163 inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1);
165 cycler->_lock.unlock();
172 while (prev_dirty._next != &prev_dirty) {
174 while (link != &prev_dirty) {
175 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)link;
177 if (!cycler->_lock.try_lock()) {
181 if (link->_prev != &prev_dirty || link->_next != &prev_dirty) {
182 link = cycler->_next;
187 cycler->_lock.lock();
192 cycler->remove_from_list();
194 saved_cdatas.push_back(cycler->cycle_3());
196 if (cycler->_dirty) {
198 nassertd(cycler->_dirty == prev_seq)
break;
199 cycler->insert_before(&_dirty);
200 cycler->_dirty = next_seq;
201 ++_num_dirty_cyclers;
204 cycler->insert_before(&_clean);
206 inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1);
209 cycler->_lock.unlock();
216 while (prev_dirty._next != &prev_dirty) {
218 while (link != &prev_dirty) {
219 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)link;
221 if (!cycler->_lock.try_lock()) {
225 if (link->_prev != &prev_dirty || link->_next != &prev_dirty) {
226 link = cycler->_next;
231 cycler->_lock.lock();
236 cycler->remove_from_list();
238 saved_cdatas.push_back(cycler->cycle());
240 if (cycler->_dirty) {
242 nassertd(cycler->_dirty == prev_seq)
break;
243 cycler->insert_before(&_dirty);
244 cycler->_dirty = next_seq;
245 ++_num_dirty_cyclers;
248 cycler->insert_before(&_clean);
250 inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1);
253 cycler->_lock.unlock();
261 prev_dirty.clear_head();
269 saved_cdatas.clear();
271 if (pipeline_cat.is_debug()) {
273 <<
"Finished the pipeline cycle\n";
276 #endif // THREADED_PIPELINE
284 nassertv(num_stages >= 1);
285 #ifdef THREADED_PIPELINE
289 if (num_stages != _num_stages) {
294 for (links = _clean._next; links != &_clean; links = links->_next) {
295 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links;
296 cycler->_lock.lock();
298 for (links = _dirty._next; links != &_dirty; links = links->_next) {
299 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links;
300 cycler->_lock.lock();
303 _num_stages = num_stages;
305 for (links = _clean._next; links != &_clean; links = links->_next) {
306 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links;
307 cycler->set_num_stages(num_stages);
309 for (links = _dirty._next; links != &_dirty; links = links->_next) {
310 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links;
311 cycler->set_num_stages(num_stages);
316 for (links = _clean._next; links != &_clean; links = links->_next) {
317 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links;
318 cycler->_lock.unlock();
321 for (links = _dirty._next; links != &_dirty; links = links->_next) {
322 PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links;
323 cycler->_lock.unlock();
326 nassertv(count == _num_cyclers);
329 #else // THREADED_PIPELINE
330 if (num_stages != 1) {
331 pipeline_cat.warning()
332 <<
"Requested " << num_stages
333 <<
" pipeline stages but multithreaded render pipelines not enabled in build.\n";
336 #endif // THREADED_PIPELINE
339 #ifdef THREADED_PIPELINE
345 add_cycler(PipelineCyclerTrueImpl *cycler) {
349 nassertv(!cycler->_dirty);
351 cycler->insert_before(&_clean);
355 inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), 1);
358 #endif // THREADED_PIPELINE
360 #ifdef THREADED_PIPELINE
368 add_dirty_cycler(PipelineCyclerTrueImpl *cycler) {
369 nassertv(cycler->_lock.debug_is_locked());
374 nassertv(!cycler->_dirty);
375 nassertv(_num_stages != 1);
378 cycler->remove_from_list();
379 cycler->insert_before(&_dirty);
380 cycler->_dirty = _next_cycle_seq;
381 ++_num_dirty_cyclers;
384 inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), 1);
387 #endif // THREADED_PIPELINE
389 #ifdef THREADED_PIPELINE
395 remove_cycler(PipelineCyclerTrueImpl *cycler) {
396 nassertv(cycler->_lock.debug_is_locked());
404 while (cycler->_dirty != 0 && cycler->_dirty != _next_cycle_seq) {
405 if (_cycle_lock.try_lock()) {
410 cycler->remove_from_list();
412 cycler->_dirty =
false;
413 --_num_dirty_cyclers;
416 inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), -1);
417 inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1);
420 _cycle_lock.unlock();
426 cycler->_lock.unlock();
428 cycler->_lock.lock();
435 cycler->remove_from_list();
438 inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), -1);
441 if (cycler->_dirty) {
443 --_num_dirty_cyclers;
445 inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1);
449 #endif // THREADED_PIPELINE
451 #if defined(THREADED_PIPELINE) && defined(DEBUG_THREADS)
460 iterate_all_cycler_types(CallbackFunc *func,
void *data)
const {
464 TypeCount::const_iterator ci;
465 for (ci = _all_cycler_types.begin(); ci != _all_cycler_types.end(); ++ci) {
466 func((*ci).first, (*ci).second, data);
469 #endif // THREADED_PIPELINE && DEBUG_THREADS
471 #if defined(THREADED_PIPELINE) && defined(DEBUG_THREADS)
477 iterate_dirty_cycler_types(CallbackFunc *func,
void *data)
const {
481 TypeCount::const_iterator ci;
482 for (ci = _dirty_cycler_types.begin(); ci != _dirty_cycler_types.end(); ++ci) {
483 func((*ci).first, (*ci).second, data);
486 #endif // THREADED_PIPELINE && DEBUG_THREADS
492 make_render_pipeline() {
494 (
"pipeline-stages", 1,
495 PRC_DESC(
"The initial number of stages in the render pipeline. This is "
496 "only meaningful if threaded pipelining is compiled into "
497 "Panda. In most cases, you should not set this at all anyway, "
498 "since the pipeline can automatically grow stages as needed, "
499 "but it will not remove stages automatically, and having more "
500 "pipeline stages than your application requires will incur "
501 "additional runtime overhead."));
503 nassertv(_render_pipeline ==
nullptr);
504 _render_pipeline =
new Pipeline(
"render", pipeline_stages);
507 #if defined(THREADED_PIPELINE) && defined(DEBUG_THREADS)
517 inc_cycler_type(TypeCount &count,
TypeHandle type,
int addend) {
518 TypeCount::iterator ci = count.find(type);
519 if (ci == count.end()) {
520 ci = count.insert(TypeCount::value_type(type, 0)).first;
522 (*ci).second += addend;
523 nassertv((*ci).second >= 0);
525 #endif // THREADED_PIPELINE && DEBUG_THREADS