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 void set_num_stages(int num_stages)
Specifies the number of stages required for the pipeline.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A single page of data maintained by a PipelineCycler.
This just stores the pointers to implement a doubly-linked list of PipelineCyclers for a particular P...
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
static void force_yield()
Suspends the current thread for the rest of the current epoch.
This is our own Panda specialization on the default STL vector.
void cycle()
Flows all the pipeline data down to the next stage.
A base class for all things which can have a name.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Similar to MutexHolder, but for a reentrant mutex.
This class manages a staged pipeline of data, for instance the render pipeline, so that each stage of...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a convenience class to specialize ConfigVariable as an integer type.
TypeHandle is the identifier used to differentiate C++ class types.