19Pipeline *Pipeline::_render_pipeline =
nullptr;
25Pipeline(
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";
66 nassertv(num_stages >= 1);
74#ifdef THREADED_PIPELINE
75 nassertv(_num_cyclers == 0);
76 nassertv(_num_dirty_cyclers == 0);
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";
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);
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";
339#ifdef THREADED_PIPELINE
345add_cycler(PipelineCyclerTrueImpl *cycler) {
349 nassertv(!cycler->_dirty);
351 cycler->insert_before(&_clean);
355 inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), 1);
360#ifdef THREADED_PIPELINE
369add_cycler(PipelineCyclerTrueImpl *cycler,
bool dirty) {
373 nassertv(!cycler->_dirty);
376 cycler->insert_before(&_clean);
379 nassertv(_num_stages != 1);
380 cycler->insert_before(&_dirty);
381 cycler->_dirty = _next_cycle_seq;
382 ++_num_dirty_cyclers;
385 inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), 1);
391 inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), 1);
396#ifdef THREADED_PIPELINE
404add_dirty_cycler(PipelineCyclerTrueImpl *cycler) {
405 nassertv(cycler->_lock.debug_is_locked());
410 nassertv(!cycler->_dirty);
411 nassertv(_num_stages != 1);
414 cycler->remove_from_list();
415 cycler->insert_before(&_dirty);
416 cycler->_dirty = _next_cycle_seq;
417 ++_num_dirty_cyclers;
420 inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), 1);
425#ifdef THREADED_PIPELINE
431remove_cycler(PipelineCyclerTrueImpl *cycler) {
432 nassertv(cycler->_lock.debug_is_locked());
440 while (cycler->_dirty != 0 && cycler->_dirty != _next_cycle_seq) {
441 if (_cycle_lock.try_lock()) {
446 cycler->remove_from_list();
448 cycler->_dirty =
false;
449 --_num_dirty_cyclers;
452 inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), -1);
453 inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1);
456 _cycle_lock.unlock();
462 cycler->_lock.unlock();
464 cycler->_lock.lock();
471 cycler->remove_from_list();
474 inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), -1);
477 if (cycler->_dirty) {
479 --_num_dirty_cyclers;
481 inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1);
487#if defined(THREADED_PIPELINE) && defined(DEBUG_THREADS)
496iterate_all_cycler_types(CallbackFunc *func,
void *data)
const {
500 TypeCount::const_iterator ci;
501 for (ci = _all_cycler_types.begin(); ci != _all_cycler_types.end(); ++ci) {
502 func((*ci).first, (*ci).second, data);
507#if defined(THREADED_PIPELINE) && defined(DEBUG_THREADS)
513iterate_dirty_cycler_types(CallbackFunc *func,
void *data)
const {
517 TypeCount::const_iterator ci;
518 for (ci = _dirty_cycler_types.begin(); ci != _dirty_cycler_types.end(); ++ci) {
519 func((*ci).first, (*ci).second, data);
528make_render_pipeline() {
530 (
"pipeline-stages", 1,
531 PRC_DESC(
"The initial number of stages in the render pipeline. This is "
532 "only meaningful if threaded pipelining is compiled into "
533 "Panda. In most cases, you should not set this at all anyway, "
534 "since the pipeline can automatically grow stages as needed, "
535 "but it will not remove stages automatically, and having more "
536 "pipeline stages than your application requires will incur "
537 "additional runtime overhead."));
539 nassertv(_render_pipeline ==
nullptr);
540 _render_pipeline =
new Pipeline(
"render", pipeline_stages);
543#if defined(THREADED_PIPELINE) && defined(DEBUG_THREADS)
553inc_cycler_type(TypeCount &count,
TypeHandle type,
int addend) {
554 TypeCount::iterator ci = count.find(type);
555 if (ci == count.end()) {
556 ci = count.insert(TypeCount::value_type(type, 0)).first;
558 (*ci).second += addend;
559 nassertv((*ci).second >= 0);
This is a convenience class to specialize ConfigVariable as an integer type.
A single page of data maintained by a PipelineCycler.
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
A base class for all things which can have a name.
This just stores the pointers to implement a doubly-linked list of PipelineCyclers for a particular P...
This class manages a staged pipeline of data, for instance the render pipeline, so that each stage of...
void cycle()
Flows all the pipeline data down to the next stage.
void set_num_stages(int num_stages)
Specifies the number of stages required for the pipeline.
Similar to MutexHolder, but for a reentrant mutex.
static void force_yield()
Suspends the current thread for the rest of the current epoch.
TypeHandle is the identifier used to differentiate C++ class types.
This is our own Panda specialization on the default STL vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.