From bf965cae203c11e6ecac6b7f1591f3f67e526efa Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 16 Feb 2006 18:12:47 +0000 Subject: [PATCH] restore automatic pipeline expansion --- panda/src/display/graphicsEngine.cxx | 1 + panda/src/putil/Sources.pp | 2 + panda/src/putil/pipeline.I | 11 +++ panda/src/putil/pipeline.cxx | 79 +++++++++++++++++--- panda/src/putil/pipeline.h | 5 +- panda/src/putil/pipelineCyclerLinks.I | 83 ++++++++++++++++++++++ panda/src/putil/pipelineCyclerLinks.h | 54 ++++++++++++++ panda/src/putil/pipelineCyclerTrueImpl.cxx | 6 +- panda/src/putil/pipelineCyclerTrueImpl.h | 11 +-- 9 files changed, 235 insertions(+), 17 deletions(-) create mode 100644 panda/src/putil/pipelineCyclerLinks.I create mode 100644 panda/src/putil/pipelineCyclerLinks.h diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 9174d6a1b8..38a2aabd51 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -1605,6 +1605,7 @@ get_window_renderer(const string &name, int pipeline_stage) { PT(RenderThread) thread = new RenderThread(name, this); thread->set_min_pipeline_stage(pipeline_stage); + _pipeline->set_min_stages(pipeline_stage + 1); thread->start(TP_normal, true, true); _threads[name] = thread; diff --git a/panda/src/putil/Sources.pp b/panda/src/putil/Sources.pp index a9c824e142..afb82cd524 100644 --- a/panda/src/putil/Sources.pp +++ b/panda/src/putil/Sources.pp @@ -51,6 +51,7 @@ nodePointerTo.h nodePointerTo.I \ pipeline.h pipeline.I \ pipelineCycler.h pipelineCycler.I \ + pipelineCyclerLinks.h pipelineCyclerLinks.I \ pipelineCyclerBase.h \ pipelineCyclerDummyImpl.h pipelineCyclerDummyImpl.I \ pipelineCyclerTrivialImpl.h pipelineCyclerTrivialImpl.I \ @@ -152,6 +153,7 @@ nodePointerTo.h nodePointerTo.I \ pipeline.h pipeline.I \ pipelineCycler.h pipelineCycler.I \ + pipelineCyclerLinks.h pipelineCyclerLinks.I \ pipelineCyclerBase.h \ pipelineCyclerDummyImpl.h pipelineCyclerDummyImpl.I \ pipelineCyclerTrivialImpl.h pipelineCyclerTrivialImpl.I \ diff --git a/panda/src/putil/pipeline.I b/panda/src/putil/pipeline.I index 1bff17f440..da4c28dfef 100644 --- a/panda/src/putil/pipeline.I +++ b/panda/src/putil/pipeline.I @@ -30,6 +30,17 @@ get_render_pipeline() { return _render_pipeline; } +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::set_min_stages +// Access: Public +// Description: Ensures that at least the indicated number of stages +// are in the pipeline. +//////////////////////////////////////////////////////////////////// +INLINE void Pipeline:: +set_min_stages(int min_stages) { + set_num_stages(max(min_stages, get_num_stages())); +} + //////////////////////////////////////////////////////////////////// // Function: Pipeline::get_num_stages // Access: Public diff --git a/panda/src/putil/pipeline.cxx b/panda/src/putil/pipeline.cxx index 7485f14723..4dc0bf4190 100644 --- a/panda/src/putil/pipeline.cxx +++ b/panda/src/putil/pipeline.cxx @@ -30,13 +30,20 @@ Pipeline *Pipeline::_render_pipeline = (Pipeline *)NULL; //////////////////////////////////////////////////////////////////// Pipeline:: Pipeline(const string &name, int num_stages) : - Namable(name), - _num_stages(num_stages) + Namable(name) { #ifdef THREADED_PIPELINE + // Set up the linked list of cyclers to be a circular list that + // begins with this object. + _prev = this; + _next = this; + _num_cyclers = 0; _cycling = false; + #endif // THREADED_PIPELINE + + set_num_stages(num_stages); } //////////////////////////////////////////////////////////////////// @@ -48,6 +55,9 @@ Pipeline:: ~Pipeline() { #ifdef THREADED_PIPELINE nassertv(_num_cyclers == 0); + nassertv(_prev == this && _next == this); + _prev = NULL; + _next = NULL; nassertv(!_cycling); #endif // THREADED_PIPELINE } @@ -148,6 +158,54 @@ cycle() { #endif // THREADED_PIPELINE } +//////////////////////////////////////////////////////////////////// +// Function: Pipeline::set_num_stages +// Access: Public +// Description: Specifies the number of stages required for the +// pipeline. +//////////////////////////////////////////////////////////////////// +void Pipeline:: +set_num_stages(int num_stages) { + nassertv(num_stages >= 1); +#ifdef THREADED_PIPELINE + ReMutexHolder holder(_lock); + if (num_stages != _num_stages) { + + // We need to lock every PipelineCycler object attached to this + // pipeline before we can adjust the number of stages. + PipelineCyclerLinks *links; + for (links = this->_next; links != this; links = links->_next) { + PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links; + cycler->_lock.lock(); + } + + _num_stages = num_stages; + + for (links = this->_next; links != this; links = links->_next) { + PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links; + cycler->set_num_stages(num_stages); + } + + // Now release them all. + int count = 0; + for (links = this->_next; links != this; links = links->_next) { + PipelineCyclerTrueImpl *cycler = (PipelineCyclerTrueImpl *)links; + cycler->_lock.release(); + ++count; + } + nassertv(count == _num_cyclers); + } + +#else // THREADED_PIPELINE + if (_num_stages != 1) { + display_cat.warning() + << "Requested " << pipeline_stages + << " pipeline stages but multithreaded render pipelines not enabled in build.\n"; + } + _num_stages = 1; +#endif // THREADED_PIPELINE +} + #ifdef THREADED_PIPELINE //////////////////////////////////////////////////////////////////// // Function: Pipeline::add_cycler @@ -162,7 +220,8 @@ add_cycler(PipelineCyclerTrueImpl *cycler) { nassertv(!cycler->_dirty); nassertv(!_cycling); ++_num_cyclers; - + cycler->insert_before(this); + #ifdef DEBUG_THREADS inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), 1); #endif @@ -213,6 +272,7 @@ remove_cycler(PipelineCyclerTrueImpl *cycler) { nassertv(!_cycling); --_num_cyclers; + cycler->remove_from_list(); #ifdef DEBUG_THREADS inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), -1); @@ -280,12 +340,13 @@ void Pipeline:: make_render_pipeline() { ConfigVariableInt pipeline_stages ("pipeline-stages", 1, - PRC_DESC("The number of stages in the render pipeline. This is only " - "meaningful if threaded pipelining is compiled into Panda, in " - "which case you should set this to 1, 2, or 3, according to " - "your application's threading model. You may set it larger " - "than your application requires, but this will incur additional " - "overhead.")); + PRC_DESC("The initial number of stages in the render pipeline. This is " + "only meaningful if threaded pipelining is compiled into " + "Panda. In most cases, you should not set this at all anyway, " + "since the pipeline can automatically grow stages as needed, " + "but it will not remove stages automatically, and having more " + "pipeline stages than your application requires will incur " + "additional runtime overhead.")); nassertv(_render_pipeline == (Pipeline *)NULL); _render_pipeline = new Pipeline("render", pipeline_stages); diff --git a/panda/src/putil/pipeline.h b/panda/src/putil/pipeline.h index 2271c1b0a8..9b769b0aa6 100644 --- a/panda/src/putil/pipeline.h +++ b/panda/src/putil/pipeline.h @@ -20,6 +20,7 @@ #define PIPELINE_H #include "pandabase.h" +#include "pipelineCyclerLinks.h" #include "namable.h" #include "pset.h" #include "reMutex.h" @@ -40,7 +41,7 @@ struct PipelineCyclerTrueImpl; // pipeline. Other specialty pipelines may be created // as needed. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA Pipeline : public Namable { +class EXPCL_PANDA Pipeline : public PipelineCyclerLinks, public Namable { public: Pipeline(const string &name, int num_stages); ~Pipeline(); @@ -49,6 +50,8 @@ public: void cycle(); + void set_num_stages(int num_stages); + INLINE void set_min_stages(int min_stages); INLINE int get_num_stages() const; #ifdef THREADED_PIPELINE diff --git a/panda/src/putil/pipelineCyclerLinks.I b/panda/src/putil/pipelineCyclerLinks.I new file mode 100644 index 0000000000..07d2337c6c --- /dev/null +++ b/panda/src/putil/pipelineCyclerLinks.I @@ -0,0 +1,83 @@ +// Filename: pipelineCyclerLinks.I +// Created by: drose (16Feb06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +#ifdef THREADED_PIPELINE +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerLinks::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PipelineCyclerLinks:: +PipelineCyclerLinks() { +#ifndef NDEBUG + _next = NULL; + _prev = NULL; +#endif +} +#endif // THREADED_PIPELINE + +#ifdef THREADED_PIPELINE +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerLinks::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PipelineCyclerLinks:: +~PipelineCyclerLinks() { + nassertv(_next == NULL && _prev == NULL); +} +#endif // THREADED_PIPELINE + +#ifdef THREADED_PIPELINE +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerLinks::remove_from_list +// Access: Private +// Description: Removes a PipelineCyclerLinks record from the +// doubly-linked list. +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerLinks:: +remove_from_list() { + nassertv(_prev->_next == this && _next->_prev == this); + _prev->_next = _next; + _next->_prev = _prev; +#ifndef NDEBUG + _next = NULL; + _prev = NULL; +#endif +} +#endif // THREADED_PIPELINE + +#ifdef THREADED_PIPELINE +//////////////////////////////////////////////////////////////////// +// Function: PipelineCyclerLinks::insert_before +// Access: Private +// Description: Adds a PipelineCyclerLinks record before the indicated +// node in the doubly-linked list. +//////////////////////////////////////////////////////////////////// +INLINE void PipelineCyclerLinks:: +insert_before(PipelineCyclerLinks *node) { + nassertv(node->_prev->_next == node && node->_next->_prev == node); + nassertv(_prev == (PipelineCyclerLinks *)NULL && + _next == (PipelineCyclerLinks *)NULL); + _prev = node->_prev; + _next = node; + _prev->_next = this; + node->_prev = this; +} +#endif // THREADED_PIPELINE diff --git a/panda/src/putil/pipelineCyclerLinks.h b/panda/src/putil/pipelineCyclerLinks.h new file mode 100644 index 0000000000..e09085854d --- /dev/null +++ b/panda/src/putil/pipelineCyclerLinks.h @@ -0,0 +1,54 @@ +// Filename: pipelineCyclerLinks.h +// Created by: drose (16Feb06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef PIPELINECYCLERLINKS_H +#define PIPELINECYCLERLINKS_H + +#include "pandabase.h" +#include "selectThreadImpl.h" // for THREADED_PIPELINE definition + +//////////////////////////////////////////////////////////////////// +// Class : PipelineCyclerLinks +// Description : This just stores the pointers to implement a +// doubly-linked list of PipelineCyclers for a +// particular Pipeline object. We use a hand-rolled +// linked list rather than any STL container, because we +// want PipelineCyclers to be able to add and remove +// themselves from this list very quickly. +// +// These pointers are inherited from this separate class +// so the Pipeline object itself can be the root of the +// linked list. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA PipelineCyclerLinks { +protected: +#ifdef THREADED_PIPELINE + INLINE PipelineCyclerLinks(); + INLINE ~PipelineCyclerLinks(); + + INLINE void remove_from_list(); + INLINE void insert_before(PipelineCyclerLinks *node); + + PipelineCyclerLinks *_prev, *_next; +#endif + friend class Pipeline; +}; + +#include "pipelineCyclerLinks.I" + +#endif diff --git a/panda/src/putil/pipelineCyclerTrueImpl.cxx b/panda/src/putil/pipelineCyclerTrueImpl.cxx index 7353a8da26..dfe0cbe5d7 100644 --- a/panda/src/putil/pipelineCyclerTrueImpl.cxx +++ b/panda/src/putil/pipelineCyclerTrueImpl.cxx @@ -18,7 +18,7 @@ #include "pipelineCyclerTrueImpl.h" -#if defined(DO_PIPELINING) && defined(HAVE_THREADS) +#ifdef THREADED_PIPELINE #include "config_util.h" #include "pipeline.h" @@ -343,8 +343,8 @@ void PipelineCyclerTrueImpl::CyclerMutex:: output(ostream &out) const { _cycler->cheat()->output(out); } -#endif +#endif // DEBUG_THREADS -#endif // DO_PIPELINING && HAVE_THREADS +#endif // THREADED_PIPELINE diff --git a/panda/src/putil/pipelineCyclerTrueImpl.h b/panda/src/putil/pipelineCyclerTrueImpl.h index 11911ea538..dfe60b3174 100644 --- a/panda/src/putil/pipelineCyclerTrueImpl.h +++ b/panda/src/putil/pipelineCyclerTrueImpl.h @@ -21,8 +21,9 @@ #include "pandabase.h" -#if defined(DO_PIPELINING) && defined(HAVE_THREADS) +#ifdef THREADED_PIPELINE +#include "pipelineCyclerLinks.h" #include "cycleData.h" #include "pointerTo.h" #include "thread.h" @@ -46,7 +47,9 @@ class Pipeline; // mainly to be consistent with // PipelineCyclerTrivialImpl. //////////////////////////////////////////////////////////////////// -struct EXPCL_PANDA PipelineCyclerTrueImpl { +struct EXPCL_PANDA PipelineCyclerTrueImpl : public PipelineCyclerLinks { +private: + PipelineCyclerTrueImpl(); public: PipelineCyclerTrueImpl(CycleData *initial_data, Pipeline *pipeline = NULL); PipelineCyclerTrueImpl(const PipelineCyclerTrueImpl ©); @@ -91,7 +94,7 @@ public: #ifdef DEBUG_THREADS virtual void output(ostream &out) const; PipelineCyclerTrueImpl *_cycler; -#endif +#endif // DEBUG_THREADS }; private: @@ -115,7 +118,7 @@ private: #include "pipelineCyclerTrueImpl.I" -#endif // DO_PIPELINING && HAVE_THREADS +#endif // THREADED_PIPELINE #endif