Merged the threading set up and rendering code from Viewer and CompositeViewer

into ViewerBase to allow CompositeViewer to inherit the same theading models
previously just supported by osgViewer::Viewer
This commit is contained in:
Robert Osfield
2007-10-02 21:23:58 +00:00
parent 43a243c161
commit caeed02f52
6 changed files with 820 additions and 1180 deletions

View File

@@ -61,33 +61,15 @@ class OSGVIEWER_EXPORT CompositeViewer : public ViewerBase, public virtual osg::
osg::FrameStamp* getFrameStamp() { return _frameStamp.get(); }
const osg::FrameStamp* getFrameStamp() const { return _frameStamp.get(); }
/** Set the threading model the rendering traversals will use.*/
virtual void setThreadingModel(ThreadingModel threadingModel);
virtual double elapsedTime();
virtual osg::FrameStamp* getViewerFrameStamp() { return getFrameStamp(); }
void setEventQueue(osgGA::EventQueue* eventQueue) { _eventQueue = eventQueue; }
osgGA::EventQueue* getEventQueue() { return _eventQueue.get(); }
const osgGA::EventQueue* getEventQueue() const { return _eventQueue.get(); }
enum BarrierPosition
{
BeforeSwapBuffers,
AfterSwapBuffers
};
/** Set the position of the end barrier.
* AfterSwapBuffers will may result is slightly higher framerates, by may
* lead to inconcistent swapping between different windows.
* BeforeSwapBuffers may lead to slightly lower framerate, but improve consistency in timing of swap buffers,
* especially important if you are likely to consistently break frame.*/
void setEndBarrierPosition(BarrierPosition bp);
/** Get the end barrier position.*/
BarrierPosition getEndBarrierPosition() const { return _endBarrierPosition; }
/** Execute a main frame loop.
* Equivialant to while (!viewer.done()) viewer.frame();
* Also calls realize() if the viewer is not already realized,
@@ -95,18 +77,12 @@ class OSGVIEWER_EXPORT CompositeViewer : public ViewerBase, public virtual osg::
*/
virtual int run();
/** Render a complete new frame.
* Calls advance(), eventTraversal(), updateTraversal(), renderingTraversals(). */
virtual void frame(double simulationTime=USE_REFERENCE_TIME);
virtual void advance(double simulationTime=USE_REFERENCE_TIME);
virtual void eventTraversal();
virtual void updateTraversal();
virtual void renderingTraversals();
void setCameraWithFocus(osg::Camera* camera);
osg::Camera* getCameraWithFocus() { return _cameraWithFocus.get(); }
@@ -130,15 +106,6 @@ class OSGVIEWER_EXPORT CompositeViewer : public ViewerBase, public virtual osg::
virtual void getViews(Views& views, bool onlyValid=true);
/** Set up the threading and processor affinity as per the viewers threading model.*/
virtual void setUpThreading();
/** Stop any threads begin run by viewer.*/
virtual void stopThreading();
/** Start any threads required by the viewer, as per viewers ThreadingModel.*/
virtual void startThreading();
/** Get the keyboard and mouse usage of this viewer.*/
virtual void getUsage(osg::ApplicationUsage& usage) const;
@@ -146,24 +113,13 @@ class OSGVIEWER_EXPORT CompositeViewer : public ViewerBase, public virtual osg::
void constructorInit();
void init();
void checkWindowStatus();
virtual void viewerInit();
typedef std::vector< osg::ref_ptr<osgViewer::View> > RefViews;
RefViews _views;
bool _firstFrame;
BarrierPosition _endBarrierPosition;
osg::ref_ptr<osg::BarrierOperation> _startRenderingBarrier;
osg::ref_ptr<osg::BarrierOperation> _endRenderingDispatchBarrier;
unsigned int computeNumberOfThreadsIncludingMainRequired();
unsigned int _numThreadsOnBarrier;
osg::Timer_t _startTick;
osg::ref_ptr<osg::FrameStamp> _frameStamp;

View File

@@ -61,28 +61,10 @@ class OSGVIEWER_EXPORT Viewer : public ViewerBase, public osgViewer::View
* Returns the GraphicsWindowEmbedded that can be used by applications to pass in events to the viewer. */
virtual GraphicsWindowEmbedded* setUpViewerAsEmbeddedInWindow(int x, int y, int width, int height);
/** Set the threading model the rendering traversals will use.*/
virtual void setThreadingModel(ThreadingModel threadingModel);
virtual double elapsedTime();
/** Let the viewer suggest the best threading model for the viewers camera/window setup and the hardware available.*/
ThreadingModel suggestBestThreadingModel();
enum BarrierPosition
{
BeforeSwapBuffers,
AfterSwapBuffers
};
/** Set the position of the end barrier.
* AfterSwapBuffers will may result is slightly higher framerates, by may
* lead to inconcistent swapping between different windows.
* BeforeSwapBuffers may lead to slightly lower framerate, but improve consistency in timing of swap buffers,
* especially important if you are likely to consistently break frame.*/
void setEndBarrierPosition(BarrierPosition bp);
/** Get the end barrier position.*/
BarrierPosition getEndBarrierPosition() const { return _endBarrierPosition; }
virtual osg::FrameStamp* getViewerFrameStamp() { return getFrameStamp(); }
/** Execute a main frame loop.
@@ -92,18 +74,12 @@ class OSGVIEWER_EXPORT Viewer : public ViewerBase, public osgViewer::View
*/
virtual int run();
/** Render a complete new frame.
* Calls advance(), eventTraversal(), updateTraversal(), renderingTraversals(). */
virtual void frame(double simulationTime=USE_REFERENCE_TIME);
virtual void advance(double simulationTime=USE_REFERENCE_TIME);
virtual void eventTraversal();
virtual void updateTraversal();
virtual void renderingTraversals();
void setCameraWithFocus(osg::Camera* camera) { _cameraWithFocus = camera; }
osg::Camera* getCameraWithFocus() { return _cameraWithFocus.get(); }
const osg::Camera* getCameraWithFocus() const { return _cameraWithFocus.get(); }
@@ -122,60 +98,19 @@ class OSGVIEWER_EXPORT Viewer : public ViewerBase, public osgViewer::View
virtual void getViews(Views& views, bool onlyValid=true);
/** Set up the threading and processor affinity as per the viewers threading model.*/
virtual void setUpThreading();
/** Stop any threads begin run by viewer.*/
virtual void stopThreading();
/** Start any threads required by the viewer.*/
virtual void startThreading();
/** Get the keyboard and mouse usage of this viewer.*/
virtual void getUsage(osg::ApplicationUsage& usage) const;
protected:
void constructorInit();
void checkWindowStatus();
inline void makeCurrent(osg::GraphicsContext* gc)
{
if (_currentContext==gc) return;
releaseContext();
if (gc && gc->valid() && gc->makeCurrent()) _currentContext = gc;
}
inline void releaseContext()
{
if (_currentContext.valid() && _currentContext->valid())
{
_currentContext->releaseContext();
}
_currentContext = 0;
}
bool _firstFrame;
BarrierPosition _endBarrierPosition;
virtual void viewerInit() { init(); }
osg::ref_ptr<osg::BarrierOperation> _startRenderingBarrier;
osg::ref_ptr<osg::BarrierOperation> _endRenderingDispatchBarrier;
osg::ref_ptr<osg::EndOfDynamicDrawBlock> _endDynamicDrawBlock;
unsigned int _numWindowsOpenAtLastSetUpThreading;
osg::observer_ptr<osg::Camera> _cameraWithFocus;
osg::observer_ptr<osg::GraphicsContext> _currentContext;
};

View File

@@ -71,11 +71,43 @@ class OSGVIEWER_EXPORT ViewerBase : public virtual osg::Object
};
/** Set the threading model the rendering traversals will use.*/
virtual void setThreadingModel(ThreadingModel threadingModel) = 0;
virtual void setThreadingModel(ThreadingModel threadingModel);
/** Get the threading model the rendering traversals will use.*/
ThreadingModel getThreadingModel() const { return _threadingModel; }
/** Let the viewer suggest the best threading model for the viewers camera/window setup and the hardware available.*/
virtual ThreadingModel suggestBestThreadingModel();
/** Set up the threading and processor affinity as per the viewers threading model.*/
virtual void setUpThreading();
/** Return true if viewer threads are running. */
bool areThreadsRunning() const { return _threadsRunning; }
/** Stop any threads begin run by viewer.*/
virtual void stopThreading();
/** Start any threads required by the viewer.*/
virtual void startThreading();
enum BarrierPosition
{
BeforeSwapBuffers,
AfterSwapBuffers
};
/** Set the position of the end barrier.
* AfterSwapBuffers will may result is slightly higher framerates, by may
* lead to inconcistent swapping between different windows.
* BeforeSwapBuffers may lead to slightly lower framerate, but improve consistency in timing of swap buffers,
* especially important if you are likely to consistently break frame.*/
void setEndBarrierPosition(BarrierPosition bp);
/** Get the end barrier position.*/
BarrierPosition getEndBarrierPosition() const { return _endBarrierPosition; }
/** Set the done flag to singnal the viewer's work is done and should exit the frame loop.*/
void setDone(bool done) { _done = done; }
@@ -135,6 +167,18 @@ class OSGVIEWER_EXPORT ViewerBase : public virtual osg::Object
void removeUpdateOperation(osg::Operation* operation);
/** Set the graphics operation to call on realization of the viewers graphics windows.*/
void setRealizeOperation(osg::Operation* op) { _realizeOperation = op; }
/** Get the graphics operation to call on realization of the viewers graphics windows.*/
osg::Operation* getRealizeOperation() { return _realizeOperation.get(); }
/** Check to see if windows are still open, if not set viewer done to true. */
void checkWindowStatus();
/** Execute a main frame loop.
* Equivialant to while (!viewer.done()) viewer.frame();
* Also calls realize() if the viewer is not already realized,
@@ -144,7 +188,7 @@ class OSGVIEWER_EXPORT ViewerBase : public virtual osg::Object
/** Render a complete new frame.
* Calls advance(), eventTraversal(), updateTraversal(), renderingTraversals(). */
virtual void frame(double simulationTime=USE_REFERENCE_TIME) = 0;
virtual void frame(double simulationTime=USE_REFERENCE_TIME);
virtual void advance(double simulationTime=USE_REFERENCE_TIME) = 0;
@@ -152,7 +196,7 @@ class OSGVIEWER_EXPORT ViewerBase : public virtual osg::Object
virtual void updateTraversal() = 0;
virtual void renderingTraversals() = 0;
virtual void renderingTraversals();
typedef std::vector<osg::Camera*> Cameras;
virtual void getCameras(Cameras& cameras, bool onlyActive=true) = 0;
@@ -175,38 +219,51 @@ class OSGVIEWER_EXPORT ViewerBase : public virtual osg::Object
typedef std::vector<osgViewer::View*> Views;
virtual void getViews(Views& views, bool onlyValid=true) = 0;
virtual double elapsedTime() = 0;
/** Set the graphics operation to call on realization of the viewers graphics windows.*/
void setRealizeOperation(osg::Operation* op) { _realizeOperation = op; }
/** Get the graphics operation to call on realization of the viewers graphics windows.*/
osg::Operation* getRealizeOperation() { return _realizeOperation.get(); }
/** Set up the threading and processor affinity as per the viewers threading model.*/
virtual void setUpThreading() = 0;
/** Return true if viewer threads are running. */
bool areThreadsRunning() const { return _threadsRunning; }
/** Stop any threads begin run by viewer.*/
virtual void stopThreading() = 0;
/** Start any threads required by the viewer.*/
virtual void startThreading() = 0;
virtual osg::FrameStamp* getViewerFrameStamp() = 0;
/** Get the keyboard and mouse usage of this viewer.*/
virtual void getUsage(osg::ApplicationUsage& usage) const = 0;
protected:
inline void makeCurrent(osg::GraphicsContext* gc)
{
if (_currentContext==gc) return;
releaseContext();
if (gc && gc->valid() && gc->makeCurrent()) _currentContext = gc;
}
inline void releaseContext()
{
if (_currentContext.valid() && _currentContext->valid())
{
_currentContext->releaseContext();
}
_currentContext = 0;
}
virtual void viewerInit() = 0;
osg::ref_ptr<osg::Stats> _stats;
bool _firstFrame;
bool _done;
int _keyEventSetsDone;
bool _quitEventSetsDone;
ThreadingModel _threadingModel;
bool _threadsRunning;
BarrierPosition _endBarrierPosition;
osg::ref_ptr<osg::BarrierOperation> _startRenderingBarrier;
osg::ref_ptr<osg::BarrierOperation> _endRenderingDispatchBarrier;
osg::ref_ptr<osg::EndOfDynamicDrawBlock> _endDynamicDrawBlock;
osg::ref_ptr<osgGA::EventVisitor> _eventVisitor;
@@ -215,7 +272,9 @@ class OSGVIEWER_EXPORT ViewerBase : public virtual osg::Object
osg::ref_ptr<osg::Operation> _realizeOperation;
osg::observer_ptr<osg::GraphicsContext> _currentContext;
};
}
#endif

View File

@@ -45,7 +45,9 @@ CompositeViewer::CompositeViewer(osg::ArgumentParser& arguments)
}
while (arguments.read("--SingleThreaded")) setThreadingModel(SingleThreaded);
while (arguments.read("--ThreadPerContext")) setThreadingModel(ThreadPerContext);
while (arguments.read("--CullDrawThreadPerContext")) setThreadingModel(CullDrawThreadPerContext);
while (arguments.read("--DrawThreadPerContext")) setThreadingModel(DrawThreadPerContext);
while (arguments.read("--CullThreadPerCameraDrawThreadPerContext")) setThreadingModel(CullThreadPerCameraDrawThreadPerContext);
osg::DisplaySettings::instance()->readCommandLine(arguments);
osgDB::readCommandLine(arguments);
@@ -54,7 +56,6 @@ CompositeViewer::CompositeViewer(osg::ArgumentParser& arguments)
void CompositeViewer::constructorInit()
{
_endBarrierPosition = AfterSwapBuffers;
_numThreadsOnBarrier = 0;
_startTick = 0;
// make sure View is safe to reference multi-threaded.
@@ -183,17 +184,7 @@ int CompositeViewer::run()
}
}
if (!isRealized())
{
realize();
}
while (!done())
{
frame();
}
return 0;
return ViewerBase::run();
}
void CompositeViewer::setStartTick(osg::Timer_t tick)
@@ -236,228 +227,8 @@ void CompositeViewer::setReferenceTime(double time)
}
void CompositeViewer::setThreadingModel(ThreadingModel threadingModel)
{
if (_threadingModel == threadingModel) return;
if (_threadingModel!=SingleThreaded) stopThreading();
_threadingModel = threadingModel;
if (isRealized() && _threadingModel!=SingleThreaded) startThreading();
}
void CompositeViewer::setEndBarrierPosition(BarrierPosition bp)
{
if (_endBarrierPosition == bp) return;
if (_threadingModel!=SingleThreaded) stopThreading();
_endBarrierPosition = bp;
if (_threadingModel!=SingleThreaded) startThreading();
}
void CompositeViewer::stopThreading()
{
if (!_threadsRunning) return;
if (_numThreadsOnBarrier==0) return;
osg::notify(osg::INFO)<<"CompositeViewer::stopThreading() - stopping threading"<<std::endl;
Contexts contexts;
getContexts(contexts);
// delete all the graphics threads.
for(Contexts::iterator itr = contexts.begin();
itr != contexts.end();
++itr)
{
(*itr)->setGraphicsThread(0);
}
_startRenderingBarrier = 0;
_endRenderingDispatchBarrier = 0;
_numThreadsOnBarrier = 0;
}
unsigned int CompositeViewer::computeNumberOfThreadsIncludingMainRequired()
{
Contexts contexts;
getContexts(contexts);
if (contexts.empty()) return 0;
if (contexts.size()==1 || _threadingModel==SingleThreaded)
{
return 1;
}
bool firstContextAsMainThread = _threadingModel == ThreadPerContext;
return firstContextAsMainThread ? contexts.size() : contexts.size()+1;
}
void CompositeViewer::setUpThreading()
{
Contexts contexts;
getContexts(contexts);
if (_threadingModel==SingleThreaded)
{
if (_threadsRunning) stopThreading();
}
else
{
if (!_threadsRunning) startThreading();
}
}
void CompositeViewer::startThreading()
{
if (_threadsRunning) return;
unsigned int numThreadsIncludingMainThread = computeNumberOfThreadsIncludingMainRequired();
// return if we don't need multiple threads.
if (numThreadsIncludingMainThread <= 1) return;
// return if threading is already up and running
if (numThreadsIncludingMainThread == _numThreadsOnBarrier) return;
if (_numThreadsOnBarrier!=0)
{
// we already have threads running but not the right number, so stop them and then create new threads.
stopThreading();
}
osg::notify(osg::INFO)<<"CompositeViewer::startThreading() - starting threading"<<std::endl;
// using multi-threading so make sure that new objects are allocated with thread safe ref/unref
osg::Referenced::setThreadSafeReferenceCounting(true);
Scenes scenes;
getScenes(scenes);
for(Scenes::iterator sitr = scenes.begin();
sitr != scenes.end();
++sitr)
{
osg::Node* sceneData = (*sitr)->getSceneData();
if (sceneData)
{
osg::notify(osg::INFO)<<"Making scene thread safe"<<std::endl;
// make sure that existing scene graph objects are allocated with thread safe ref/unref
sceneData->setThreadSafeRefUnref(true);
// update the scene graph so that it has enough GL object buffer memory for the graphics contexts that will be using it.
sceneData->resizeGLObjectBuffers(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts());
}
}
Contexts contexts;
getContexts(contexts);
int numProcessors = OpenThreads::GetNumberOfProcessors();
bool affinity = false;
bool firstContextAsMainThread = numThreadsIncludingMainThread==contexts.size();
// osg::notify(osg::NOTICE)<<"numThreadsIncludingMainThread=="<<numThreadsIncludingMainThread<<std::endl;
_numThreadsOnBarrier = numThreadsIncludingMainThread;
_startRenderingBarrier = new osg::BarrierOperation(_numThreadsOnBarrier, osg::BarrierOperation::NO_OPERATION);
_endRenderingDispatchBarrier = new osg::BarrierOperation(_numThreadsOnBarrier, osg::BarrierOperation::NO_OPERATION);
osg::ref_ptr<osg::SwapBuffersOperation> swapOp = new osg::SwapBuffersOperation();
Contexts::iterator citr = contexts.begin();
unsigned int processNum = 0;
if (firstContextAsMainThread)
{
++processNum;
++citr;
}
for(;
citr != contexts.end();
++citr,
++processNum)
{
osg::GraphicsContext* gc = (*citr);
// create the a graphics thread for this context
gc->createGraphicsThread();
if (affinity) gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors);
gc->getGraphicsThread()->add(new osgUtil::GLObjectsOperation());
// add the startRenderingBarrier
gc->getGraphicsThread()->add(_startRenderingBarrier.get());
// add the rendering operation itself.
gc->getGraphicsThread()->add(new osg::RunOperations());
if (_endBarrierPosition==BeforeSwapBuffers)
{
// add the endRenderingDispatchBarrier
gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
}
// add the swap buffers
gc->getGraphicsThread()->add(swapOp.get());
if (_endBarrierPosition==AfterSwapBuffers)
{
// add the endRenderingDispatchBarrier
gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
}
}
if (firstContextAsMainThread)
{
if (affinity) OpenThreads::SetProcessorAffinityOfCurrentThread(0);
}
for(citr = contexts.begin();
citr != contexts.end();
++citr)
{
osg::GraphicsContext* gc = (*citr);
if (gc->getGraphicsThread() && !gc->getGraphicsThread()->isRunning())
{
//osg::notify(osg::NOTICE)<<" gc->getGraphicsThread()->startThread() "<<gc->getGraphicsThread()<<std::endl;
gc->getGraphicsThread()->startThread();
// OpenThreads::Thread::YieldCurrentThread();
}
}
_threadsRunning = true;
}
void CompositeViewer::checkWindowStatus()
{
Contexts contexts;
getContexts(contexts);
// osg::notify(osg::INFO)<<"Viewer::checkWindowStatus() - "<<contexts.size()<<std::endl;
if (contexts.size()==0)
{
_done = true;
if (areThreadsRunning()) stopThreading();
}
}
void CompositeViewer::init()
void CompositeViewer::viewerInit()
{
osg::notify(osg::INFO)<<"CompositeViewer::init()"<<std::endl;
@@ -741,31 +512,6 @@ void CompositeViewer::realize()
}
void CompositeViewer::frame(double simulationTime)
{
if (_done) return;
// osg::notify(osg::NOTICE)<<std::endl<<"CompositeViewer::frame()"<<std::endl<<std::endl;
if (_firstFrame)
{
init();
if (!isRealized())
{
realize();
}
_firstFrame = false;
}
advance(simulationTime);
eventTraversal();
updateTraversal();
renderingTraversals();
}
void CompositeViewer::advance(double simulationTime)
{
if (_done) return;
@@ -1236,93 +982,9 @@ void CompositeViewer::updateTraversal()
}
void CompositeViewer::renderingTraversals()
double CompositeViewer::elapsedTime()
{
// check to see if windows are still valid
checkWindowStatus();
if (_done) return;
double beginRenderingTraversals = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
Scenes scenes;
getScenes(scenes);
for(Scenes::iterator sitr = scenes.begin();
sitr != scenes.end();
++sitr)
{
Scene* scene = *sitr;
osgDB::DatabasePager* dp = scene ? scene->getDatabasePager() : 0;
if (dp)
{
dp->signalBeginFrame(getFrameStamp());
}
}
// osg::notify(osg::NOTICE)<<std::endl<<"Joing _startRenderingBarrier block"<<std::endl;
Contexts contexts;
getContexts(contexts);
// dispatch the the rendering threads
if (_startRenderingBarrier.valid()) _startRenderingBarrier->block();
Contexts::iterator itr;
for(itr = contexts.begin();
itr != contexts.end();
++itr)
{
if (_done) return;
if (!((*itr)->getGraphicsThread()) && (*itr)->valid())
{
(*itr)->makeCurrent();
(*itr)->runOperations();
(*itr)->releaseContext();
}
}
// osg::notify(osg::NOTICE)<<"Joing _endRenderingDispatchBarrier block"<<std::endl;
// wait till the rendering dispatch is done.
if (_endRenderingDispatchBarrier.valid()) _endRenderingDispatchBarrier->block();
for(itr = contexts.begin();
itr != contexts.end();
++itr)
{
if (_done) return;
if (!((*itr)->getGraphicsThread()) && (*itr)->valid())
{
(*itr)->makeCurrent();
(*itr)->swapBuffers();
(*itr)->releaseContext();
}
}
for(Scenes::iterator sitr = scenes.begin();
sitr != scenes.end();
++sitr)
{
Scene* scene = *sitr;
osgDB::DatabasePager* dp = scene ? scene->getDatabasePager() : 0;
if (dp)
{
dp->signalEndFrame();
}
}
if (getStats() && getStats()->collectStats("update"))
{
double endRenderingTraversals = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
// update current frames stats
getStats()->setAttribute(_frameStamp->getFrameNumber(), "Rendering traversals begin time ", beginRenderingTraversals);
getStats()->setAttribute(_frameStamp->getFrameNumber(), "Rendering traversals end time ", endRenderingTraversals);
getStats()->setAttribute(_frameStamp->getFrameNumber(), "Rendering traversals time taken", endRenderingTraversals-beginRenderingTraversals);
}
return osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
}
void CompositeViewer::getUsage(osg::ApplicationUsage& usage) const

View File

@@ -30,11 +30,6 @@
using namespace osgViewer;
static osg::ApplicationUsageProxy Viewer_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_CONFIG_FILE <filename>","Specify a viewer configuration file to load by default.");
static osg::ApplicationUsageProxy Viewer_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_THREADING <value>","Set the threading model using by Viewer, <value> can be SingleThreaded, CullDrawThreadPerContext, DrawThreadPerContext or CullThreadPerCameraDrawThreadPerContext.");
static osg::ApplicationUsageProxy Viewer_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_SCREEN <value>","Set the default screen that windows should open up on.");
static osg::ApplicationUsageProxy Viewer_e3(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_WINDOW x y width height","Set the default window dimensions that windows should open up on.");
Viewer::Viewer()
{
@@ -128,10 +123,6 @@ Viewer::Viewer(const osgViewer::Viewer& viewer, const osg::CopyOp& copyop):
void Viewer::constructorInit()
{
_firstFrame = true;
_endBarrierPosition = AfterSwapBuffers;
_numWindowsOpenAtLastSetUpThreading = 0;
_eventVisitor = new osgGA::EventVisitor;
_eventVisitor->setActionAdapter(this);
_eventVisitor->setFrameStamp(_frameStamp.get());
@@ -189,7 +180,6 @@ void Viewer::take(View& rhs)
if (rhs_viewer)
{
// variables left to take.
_firstFrame = rhs_viewer->_firstFrame;
_done = rhs_viewer->_done;
_keyEventSetsDone = rhs_viewer->_keyEventSetsDone;
_quitEventSetsDone = rhs_viewer->_quitEventSetsDone;
@@ -199,7 +189,6 @@ void Viewer::take(View& rhs)
_startRenderingBarrier = rhs_viewer->_startRenderingBarrier;
_endRenderingDispatchBarrier = rhs_viewer->_endRenderingDispatchBarrier;
_endDynamicDrawBlock = rhs_viewer->_endDynamicDrawBlock;
_numWindowsOpenAtLastSetUpThreading = rhs_viewer->_numWindowsOpenAtLastSetUpThreading;
_cameraWithFocus = rhs_viewer->_cameraWithFocus;
_eventVisitor = rhs_viewer->_eventVisitor;
_updateOperations = rhs_viewer->_updateOperations;
@@ -213,7 +202,6 @@ void Viewer::take(View& rhs)
rhs_viewer->_startRenderingBarrier = 0;
rhs_viewer->_endRenderingDispatchBarrier = 0;
rhs_viewer->_endDynamicDrawBlock = 0;
rhs_viewer->_numWindowsOpenAtLastSetUpThreading = 0;
rhs_viewer->_cameraWithFocus = 0;
rhs_viewer->_eventVisitor = 0;
rhs_viewer->_updateOperations = 0;
@@ -278,49 +266,12 @@ bool Viewer::isRealized() const
int Viewer::run()
{
// if we don't have any scene graph assigned then just return
if (!getSceneData())
{
osg::notify(osg::NOTICE)<<"Warning: Viewer::run() called without a scene graph being assigned to the viewer, cannot run."<<std::endl;
return 1;
}
if (!getCameraManipulator() && getCamera()->getAllowEventFocus())
{
setCameraManipulator(new osgGA::TrackballManipulator());
}
if (!isRealized())
{
realize();
}
#if 0
while (!done())
{
frame();
}
#else
const char* str = getenv("OSG_RUN_FRAME_COUNT");
if (str)
{
int runTillFrameNumber = atoi(str);
while (!done() && getFrameStamp()->getFrameNumber()<runTillFrameNumber)
{
frame();
}
}
else
{
while (!done())
{
frame();
}
}
#endif
return 0;
return ViewerBase::run();
}
void Viewer::setStartTick(osg::Timer_t tick)
@@ -383,522 +334,6 @@ GraphicsWindowEmbedded* Viewer::setUpViewerAsEmbeddedInWindow(int x, int y, int
return gw;
}
void Viewer::setThreadingModel(ThreadingModel threadingModel)
{
if (_threadingModel == threadingModel) return;
if (_threadsRunning) stopThreading();
_threadingModel = threadingModel;
if (isRealized() && _threadingModel!=SingleThreaded) startThreading();
}
void Viewer::setUpThreading()
{
Contexts contexts;
getContexts(contexts);
_numWindowsOpenAtLastSetUpThreading = contexts.size();
if (_threadingModel==SingleThreaded)
{
if (_threadsRunning) stopThreading();
else
{
// we'll set processor affinity here to help single threaded apps
// with multiple processor cores, and using the database pager.
int numProcessors = OpenThreads::GetNumberOfProcessors();
bool affinity = numProcessors>1;
if (affinity)
{
OpenThreads::SetProcessorAffinityOfCurrentThread(0);
if (_scene.valid() && _scene->getDatabasePager())
{
_scene->getDatabasePager()->setProcessorAffinity(1);
}
}
}
}
else
{
if (!_threadsRunning) startThreading();
}
}
void Viewer::setEndBarrierPosition(BarrierPosition bp)
{
if (_endBarrierPosition == bp) return;
if (_threadsRunning) stopThreading();
_endBarrierPosition = bp;
if (_threadingModel!=SingleThreaded) startThreading();
}
void Viewer::stopThreading()
{
if (!_threadsRunning) return;
osg::notify(osg::INFO)<<"Viewer::stopThreading() - stopping threading"<<std::endl;
Contexts contexts;
getContexts(contexts);
Cameras cameras;
getCameras(cameras);
Contexts::iterator gcitr;
Cameras::iterator citr;
for(Cameras::iterator camItr = cameras.begin();
camItr != cameras.end();
++camItr)
{
osg::Camera* camera = *camItr;
Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
if (renderer) renderer->release();
}
// delete all the graphics threads.
for(gcitr = contexts.begin();
gcitr != contexts.end();
++gcitr)
{
(*gcitr)->setGraphicsThread(0);
}
// delete all the camera threads.
for(citr = cameras.begin();
citr != cameras.end();
++citr)
{
(*citr)->setCameraThread(0);
}
for(Cameras::iterator camItr = cameras.begin();
camItr != cameras.end();
++camItr)
{
osg::Camera* camera = *camItr;
Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
if (renderer)
{
renderer->setGraphicsThreadDoesCull( true );
renderer->setDone(false);
}
}
int numProcessors = OpenThreads::GetNumberOfProcessors();
bool affinity = numProcessors>1;
if (affinity)
{
OpenThreads::SetProcessorAffinityOfCurrentThread(0);
if (_scene.valid() && _scene->getDatabasePager())
{
_scene->getDatabasePager()->setProcessorAffinity(1);
}
}
_threadsRunning = false;
_startRenderingBarrier = 0;
_endRenderingDispatchBarrier = 0;
_endDynamicDrawBlock = 0;
_numWindowsOpenAtLastSetUpThreading = contexts.size();
osg::notify(osg::INFO)<<"Viewer::stopThreading() - stopped threading."<<std::endl;
}
Viewer::ThreadingModel Viewer::suggestBestThreadingModel()
{
const char* str = getenv("OSG_THREADING");
if (str)
{
if (strcmp(str,"SingleThreaded")==0) return SingleThreaded;
else if (strcmp(str,"CullDrawThreadPerContext")==0) return CullDrawThreadPerContext;
else if (strcmp(str,"DrawThreadPerContext")==0) return DrawThreadPerContext;
else if (strcmp(str,"CullThreadPerCameraDrawThreadPerContext")==0) return CullThreadPerCameraDrawThreadPerContext;
}
Contexts contexts;
getContexts(contexts);
if (contexts.empty()) return SingleThreaded;
#if 0
// temporary hack to disable multi-threading under Windows till we find good solutions for
// crashes that users are seeing.
return SingleThreaded;
#endif
Cameras cameras;
getCameras(cameras);
if (cameras.empty()) return SingleThreaded;
int numProcessors = OpenThreads::GetNumberOfProcessors();
if (contexts.size()==1)
{
if (numProcessors==1) return SingleThreaded;
else return DrawThreadPerContext;
}
#if 1
if (numProcessors >= static_cast<int>(cameras.size()+contexts.size()))
{
return CullThreadPerCameraDrawThreadPerContext;
}
#endif
return DrawThreadPerContext;
}
void Viewer::startThreading()
{
if (_threadsRunning) return;
osg::notify(osg::INFO)<<"Viewer::startThreading() - starting threading"<<std::endl;
// release any context held by the main thread.
releaseContext();
_threadingModel = _threadingModel==AutomaticSelection ? suggestBestThreadingModel() : _threadingModel;
Contexts contexts;
getContexts(contexts);
osg::notify(osg::INFO)<<"Viewer::startThreading() - contexts.size()="<<contexts.size()<<std::endl;
Cameras cameras;
getCameras(cameras);
unsigned int numThreadsOnStartBarrier = 0;
unsigned int numThreadsOnEndBarrier = 0;
switch(_threadingModel)
{
case(SingleThreaded):
numThreadsOnStartBarrier = 1;
numThreadsOnEndBarrier = 1;
return;
case(CullDrawThreadPerContext):
numThreadsOnStartBarrier = contexts.size()+1;
numThreadsOnEndBarrier = contexts.size()+1;
break;
case(DrawThreadPerContext):
numThreadsOnStartBarrier = 1;
numThreadsOnEndBarrier = 1;
break;
case(CullThreadPerCameraDrawThreadPerContext):
numThreadsOnStartBarrier = cameras.size()+1;
numThreadsOnEndBarrier = 1;
break;
default:
osg::notify(osg::NOTICE)<<"Error: Threading model not selected"<<std::endl;
return;
}
// using multi-threading so make sure that new objects are allocated with thread safe ref/unref
osg::Referenced::setThreadSafeReferenceCounting(true);
if (getSceneData())
{
osg::notify(osg::INFO)<<"Making scene thread safe"<<std::endl;
// make sure that existing scene graph objects are allocated with thread safe ref/unref
getSceneData()->setThreadSafeRefUnref(true);
// update the scene graph so that it has enough GL object buffer memory for the graphics contexts that will be using it.
getSceneData()->resizeGLObjectBuffers(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts());
}
int numProcessors = OpenThreads::GetNumberOfProcessors();
bool affinity = numProcessors>1;
Contexts::iterator citr;
unsigned int numViewerDoubleBufferedRenderingOperation = 0;
bool graphicsThreadsDoesCull = _threadingModel == CullDrawThreadPerContext || _threadingModel==SingleThreaded;
for(Cameras::iterator camItr = cameras.begin();
camItr != cameras.end();
++camItr)
{
osg::Camera* camera = *camItr;
Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
if (renderer)
{
renderer->setGraphicsThreadDoesCull(graphicsThreadsDoesCull);
renderer->setDone(false);
++numViewerDoubleBufferedRenderingOperation;
}
}
if (_threadingModel==CullDrawThreadPerContext)
{
_startRenderingBarrier = 0;
_endRenderingDispatchBarrier = 0;
_endDynamicDrawBlock = 0;
}
else if (_threadingModel==DrawThreadPerContext ||
_threadingModel==CullThreadPerCameraDrawThreadPerContext)
{
_startRenderingBarrier = 0;
_endRenderingDispatchBarrier = 0;
_endDynamicDrawBlock = new osg::EndOfDynamicDrawBlock(numViewerDoubleBufferedRenderingOperation);
#ifndef OSGUTIL_RENDERBACKEND_USE_REF_PTR
if (!osg::Referenced::getDeleteHandler()) osg::Referenced::setDeleteHandler(new osg::DeleteHandler(2));
else osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(2);
#endif
}
if (numThreadsOnStartBarrier>1)
{
_startRenderingBarrier = new osg::BarrierOperation(numThreadsOnStartBarrier, osg::BarrierOperation::NO_OPERATION);
}
if (numThreadsOnEndBarrier>1)
{
_endRenderingDispatchBarrier = new osg::BarrierOperation(numThreadsOnEndBarrier, osg::BarrierOperation::NO_OPERATION);
}
osg::ref_ptr<osg::BarrierOperation> swapReadyBarrier = contexts.empty() ? 0 : new osg::BarrierOperation(contexts.size(), osg::BarrierOperation::NO_OPERATION);
osg::ref_ptr<osg::SwapBuffersOperation> swapOp = new osg::SwapBuffersOperation();
typedef std::map<OpenThreads::Thread*, int> ThreadAffinityMap;
ThreadAffinityMap threadAffinityMap;
unsigned int processNum = 1;
for(citr = contexts.begin();
citr != contexts.end();
++citr, ++processNum)
{
osg::GraphicsContext* gc = (*citr);
gc->getState()->setDynamicObjectRenderingCompletedCallback(_endDynamicDrawBlock.get());
// create the a graphics thread for this context
gc->createGraphicsThread();
if (affinity) gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors);
threadAffinityMap[gc->getGraphicsThread()] = processNum % numProcessors;
gc->getGraphicsThread()->add(new osgUtil::GLObjectsOperation());
// add the startRenderingBarrier
if (_threadingModel==CullDrawThreadPerContext && _startRenderingBarrier.valid()) gc->getGraphicsThread()->add(_startRenderingBarrier.get());
// add the rendering operation itself.
gc->getGraphicsThread()->add(new osg::RunOperations());
if (_threadingModel==CullDrawThreadPerContext && _endBarrierPosition==BeforeSwapBuffers && _endRenderingDispatchBarrier.valid())
{
// add the endRenderingDispatchBarrier
gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
}
if (swapReadyBarrier.valid()) gc->getGraphicsThread()->add(swapReadyBarrier.get());
// add the swap buffers
gc->getGraphicsThread()->add(swapOp.get());
if (_threadingModel==CullDrawThreadPerContext && _endBarrierPosition==AfterSwapBuffers && _endRenderingDispatchBarrier.valid())
{
// add the endRenderingDispatchBarrier
gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
}
}
if (_threadingModel==CullThreadPerCameraDrawThreadPerContext && numThreadsOnStartBarrier>1)
{
Cameras::iterator camItr;
for(camItr = cameras.begin();
camItr != cameras.end();
++camItr, ++processNum)
{
osg::Camera* camera = *camItr;
camera->createCameraThread();
if (affinity) camera->getCameraThread()->setProcessorAffinity(processNum % numProcessors);
threadAffinityMap[camera->getCameraThread()] = processNum % numProcessors;
osg::GraphicsContext* gc = camera->getGraphicsContext();
// add the startRenderingBarrier
if (_startRenderingBarrier.valid()) camera->getCameraThread()->add(_startRenderingBarrier.get());
Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
renderer->setGraphicsThreadDoesCull(false);
camera->getCameraThread()->add(renderer);
if (_endRenderingDispatchBarrier.valid())
{
// add the endRenderingDispatchBarrier
gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
}
}
for(camItr = cameras.begin();
camItr != cameras.end();
++camItr)
{
osg::Camera* camera = *camItr;
if (camera->getCameraThread() && !camera->getCameraThread()->isRunning())
{
osg::notify(osg::INFO)<<" camera->getCameraThread()-> "<<camera->getCameraThread()<<std::endl;
camera->getCameraThread()->startThread();
}
}
}
if (affinity)
{
OpenThreads::SetProcessorAffinityOfCurrentThread(0);
if (_scene.valid() && _scene->getDatabasePager())
{
#if 0
_scene->getDatabasePager()->setProcessorAffinity(1);
#else
_scene->getDatabasePager()->setProcessorAffinity(0);
#endif
}
}
#if 0
if (affinity)
{
for(ThreadAffinityMap::iterator titr = threadAffinityMap.begin();
titr != threadAffinityMap.end();
++titr)
{
titr->first->setProcessorAffinity(titr->second);
}
}
#endif
for(citr = contexts.begin();
citr != contexts.end();
++citr)
{
osg::GraphicsContext* gc = (*citr);
if (gc->getGraphicsThread() && !gc->getGraphicsThread()->isRunning())
{
osg::notify(osg::INFO)<<" gc->getGraphicsThread()->startThread() "<<gc->getGraphicsThread()<<std::endl;
gc->getGraphicsThread()->startThread();
// OpenThreads::Thread::YieldCurrentThread();
}
}
_threadsRunning = true;
_numWindowsOpenAtLastSetUpThreading = contexts.size();
osg::notify(osg::INFO)<<"Set up threading"<<std::endl;
}
void Viewer::checkWindowStatus()
{
Contexts contexts;
getContexts(contexts);
// osg::notify(osg::NOTICE)<<"Viewer::checkWindowStatus() - "<<contexts.size()<<std::endl;
if (contexts.size()==0)
{
_done = true;
if (areThreadsRunning()) stopThreading();
}
}
void Viewer::getWindows(Windows& windows, bool onlyValid)
{
windows.clear();
Contexts contexts;
getContexts(contexts, onlyValid);
for(Contexts::iterator itr = contexts.begin();
itr != contexts.end();
++itr)
{
osgViewer::GraphicsWindow* gw = dynamic_cast<osgViewer::GraphicsWindow*>(*itr);
if (gw) windows.push_back(gw);
}
}
void Viewer::getAllThreads(Threads& threads, bool onlyActive)
{
OperationThreads operationThreads;
getOperationThreads(operationThreads);
for(OperationThreads::iterator itr = operationThreads.begin();
itr != operationThreads.end();
++itr)
{
threads.push_back(*itr);
}
if (_scene.valid() &&
_scene->getDatabasePager() &&
(!onlyActive || _scene->getDatabasePager()->isRunning()))
{
threads.push_back(_scene->getDatabasePager());
}
}
void Viewer::getOperationThreads(OperationThreads& threads, bool onlyActive)
{
threads.clear();
Contexts contexts;
getContexts(contexts);
for(Contexts::iterator gcitr = contexts.begin();
gcitr != contexts.end();
++gcitr)
{
osg::GraphicsContext* gc = *gcitr;
if (gc->getGraphicsThread() &&
(!onlyActive || gc->getGraphicsThread()->isRunning()) )
{
threads.push_back(gc->getGraphicsThread());
}
}
Cameras cameras;
getCameras(cameras);
for(Cameras::iterator citr = cameras.begin();
citr != cameras.end();
++citr)
{
osg::Camera* camera = *citr;
if (camera->getCameraThread() &&
(!onlyActive || camera->getCameraThread()->isRunning()) )
{
threads.push_back(camera->getCameraThread());
}
}
}
void Viewer::realize()
{
//osg::notify(osg::INFO)<<"Viewer::realize()"<<std::endl;
@@ -1023,29 +458,6 @@ void Viewer::realize()
}
void Viewer::frame(double simulationTime)
{
if (_done) return;
// osg::notify(osg::NOTICE)<<std::endl<<"Viewer::frame()"<<std::endl<<std::endl;
if (_firstFrame)
{
init();
if (!isRealized())
{
realize();
}
_firstFrame = false;
}
advance(simulationTime);
eventTraversal();
updateTraversal();
renderingTraversals();
}
void Viewer::advance(double simulationTime)
{
@@ -1474,111 +886,6 @@ void Viewer::updateTraversal()
}
}
void Viewer::renderingTraversals()
{
// check to see if windows are still valid
checkWindowStatus();
if (_done) return;
double beginRenderingTraversals = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
osgDB::DatabasePager* dp = _scene.valid() ? _scene->getDatabasePager() : 0;
if (dp)
{
dp->signalBeginFrame(getFrameStamp());
}
// osg::notify(osg::NOTICE)<<std::endl<<"Start frame"<<std::endl;
Contexts contexts;
getContexts(contexts);
Cameras cameras;
getCameras(cameras);
Contexts::iterator itr;
// dispatch the the rendering threads
if (_startRenderingBarrier.valid()) _startRenderingBarrier->block();
if (_endDynamicDrawBlock.valid())
{
_endDynamicDrawBlock->reset();
}
// reset any double buffer graphics objects
for(Cameras::iterator camItr = cameras.begin();
camItr != cameras.end();
++camItr)
{
osg::Camera* camera = *camItr;
Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
if (renderer)
{
if (!renderer->getGraphicsThreadDoesCull() && !(camera->getCameraThread()))
{
renderer->cull();
}
}
}
for(itr = contexts.begin();
itr != contexts.end();
++itr)
{
if (_done) return;
if (!((*itr)->getGraphicsThread()) && (*itr)->valid())
{
makeCurrent(*itr);
(*itr)->runOperations();
}
}
// osg::notify(osg::NOTICE)<<"Joing _endRenderingDispatchBarrier block "<<_endRenderingDispatchBarrier.get()<<std::endl;
// wait till the rendering dispatch is done.
if (_endRenderingDispatchBarrier.valid()) _endRenderingDispatchBarrier->block();
for(itr = contexts.begin();
itr != contexts.end();
++itr)
{
if (_done) return;
if (!((*itr)->getGraphicsThread()) && (*itr)->valid())
{
makeCurrent(*itr);
(*itr)->swapBuffers();
}
}
if (dp)
{
dp->signalEndFrame();
}
// wait till the dynamic draw is complete.
if (_endDynamicDrawBlock.valid())
{
// osg::Timer_t startTick = osg::Timer::instance()->tick();
_endDynamicDrawBlock->block();
// osg::notify(osg::NOTICE)<<"Time waiting "<<osg::Timer::instance()->delta_m(startTick, osg::Timer::instance()->tick())<<std::endl;;
}
if (getStats() && getStats()->collectStats("update"))
{
double endRenderingTraversals = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
// update current frames stats
getStats()->setAttribute(_frameStamp->getFrameNumber(), "Rendering traversals begin time ", beginRenderingTraversals);
getStats()->setAttribute(_frameStamp->getFrameNumber(), "Rendering traversals end time ", endRenderingTraversals);
getStats()->setAttribute(_frameStamp->getFrameNumber(), "Rendering traversals time taken", endRenderingTraversals-beginRenderingTraversals);
}
}
void Viewer::getScenes(Scenes& scenes, bool onlyValid)
{
scenes.push_back(_scene.get());
@@ -1589,6 +896,78 @@ void Viewer::getViews(Views& views, bool onlyValid)
views.push_back(this);
}
void Viewer::getWindows(Windows& windows, bool onlyValid)
{
windows.clear();
Contexts contexts;
getContexts(contexts, onlyValid);
for(Contexts::iterator itr = contexts.begin();
itr != contexts.end();
++itr)
{
osgViewer::GraphicsWindow* gw = dynamic_cast<osgViewer::GraphicsWindow*>(*itr);
if (gw) windows.push_back(gw);
}
}
void Viewer::getAllThreads(Threads& threads, bool onlyActive)
{
OperationThreads operationThreads;
getOperationThreads(operationThreads);
for(OperationThreads::iterator itr = operationThreads.begin();
itr != operationThreads.end();
++itr)
{
threads.push_back(*itr);
}
if (_scene.valid() &&
_scene->getDatabasePager() &&
(!onlyActive || _scene->getDatabasePager()->isRunning()))
{
threads.push_back(_scene->getDatabasePager());
}
}
void Viewer::getOperationThreads(OperationThreads& threads, bool onlyActive)
{
threads.clear();
Contexts contexts;
getContexts(contexts);
for(Contexts::iterator gcitr = contexts.begin();
gcitr != contexts.end();
++gcitr)
{
osg::GraphicsContext* gc = *gcitr;
if (gc->getGraphicsThread() &&
(!onlyActive || gc->getGraphicsThread()->isRunning()) )
{
threads.push_back(gc->getGraphicsThread());
}
}
Cameras cameras;
getCameras(cameras);
for(Cameras::iterator citr = cameras.begin();
citr != cameras.end();
++citr)
{
osg::Camera* camera = *citr;
if (camera->getCameraThread() &&
(!onlyActive || camera->getCameraThread()->isRunning()) )
{
threads.push_back(camera->getCameraThread());
}
}
}
struct LessGraphicsContext
{
bool operator () (const osg::GraphicsContext* lhs, const osg::GraphicsContext* rhs) const
@@ -1670,6 +1049,11 @@ void Viewer::getCameras(Cameras& cameras, bool onlyActive)
}
double Viewer::elapsedTime()
{
return osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
}
void Viewer::getUsage(osg::ApplicationUsage& usage) const
{
@@ -1686,4 +1070,3 @@ void Viewer::getUsage(osg::ApplicationUsage& usage) const
}
}

View File

@@ -12,6 +12,7 @@
*/
#include <osgViewer/ViewerBase>
#include <osgViewer/Renderer>
#include <osg/io_utils>
@@ -21,23 +22,483 @@
#include <osgUtil/Optimizer>
#include <osgUtil/IntersectionVisitor>
#include <osgUtil/GLObjectsVisitor>
static osg::ApplicationUsageProxy ViewerBase_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_CONFIG_FILE <filename>","Specify a viewer configuration file to load by default.");
static osg::ApplicationUsageProxy ViewerBase_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_THREADING <value>","Set the threading model using by Viewer, <value> can be SingleThreaded, CullDrawThreadPerContext, DrawThreadPerContext or CullThreadPerCameraDrawThreadPerContext.");
static osg::ApplicationUsageProxy ViewerBase_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_SCREEN <value>","Set the default screen that windows should open up on.");
static osg::ApplicationUsageProxy ViewerBase_e3(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_WINDOW x y width height","Set the default window dimensions that windows should open up on.");
using namespace osgViewer;
ViewerBase::ViewerBase():
osg::Object(true)
{
_firstFrame = true;
_done = false;
_keyEventSetsDone = osgGA::GUIEventAdapter::KEY_Escape;
_quitEventSetsDone = true;
_threadingModel = AutomaticSelection;
_threadsRunning = false;
_endBarrierPosition = AfterSwapBuffers;
}
ViewerBase::ViewerBase(const ViewerBase& base):
osg::Object(true)
{
_firstFrame = true;
_done = false;
_keyEventSetsDone = osgGA::GUIEventAdapter::KEY_Escape;
_quitEventSetsDone = true;
_threadingModel = AutomaticSelection;
_threadsRunning = false;
_endBarrierPosition = AfterSwapBuffers;
}
void ViewerBase::setThreadingModel(ThreadingModel threadingModel)
{
if (_threadingModel == threadingModel) return;
if (_threadsRunning) stopThreading();
_threadingModel = threadingModel;
if (isRealized() && _threadingModel!=SingleThreaded) startThreading();
}
ViewerBase::ThreadingModel ViewerBase::suggestBestThreadingModel()
{
const char* str = getenv("OSG_THREADING");
if (str)
{
if (strcmp(str,"SingleThreaded")==0) return SingleThreaded;
else if (strcmp(str,"CullDrawThreadPerContext")==0) return CullDrawThreadPerContext;
else if (strcmp(str,"DrawThreadPerContext")==0) return DrawThreadPerContext;
else if (strcmp(str,"CullThreadPerCameraDrawThreadPerContext")==0) return CullThreadPerCameraDrawThreadPerContext;
}
Contexts contexts;
getContexts(contexts);
if (contexts.empty()) return SingleThreaded;
#if 0
// temporary hack to disable multi-threading under Windows till we find good solutions for
// crashes that users are seeing.
return SingleThreaded;
#endif
Cameras cameras;
getCameras(cameras);
if (cameras.empty()) return SingleThreaded;
int numProcessors = OpenThreads::GetNumberOfProcessors();
if (contexts.size()==1)
{
if (numProcessors==1) return SingleThreaded;
else return DrawThreadPerContext;
}
#if 1
if (numProcessors >= static_cast<int>(cameras.size()+contexts.size()))
{
return CullThreadPerCameraDrawThreadPerContext;
}
#endif
return DrawThreadPerContext;
}
void ViewerBase::setUpThreading()
{
Contexts contexts;
getContexts(contexts);
if (_threadingModel==SingleThreaded)
{
if (_threadsRunning) stopThreading();
else
{
// we'll set processor affinity here to help single threaded apps
// with multiple processor cores, and using the database pager.
int numProcessors = OpenThreads::GetNumberOfProcessors();
bool affinity = numProcessors>1;
if (affinity)
{
OpenThreads::SetProcessorAffinityOfCurrentThread(0);
Scenes scenes;
getScenes(scenes);
for(Scenes::iterator itr = scenes.begin();
itr != scenes.end();
++itr)
{
Scene* scene = *itr;
if (scene && scene->getDatabasePager())
{
scene->getDatabasePager()->setProcessorAffinity(1);
}
}
}
}
}
else
{
if (!_threadsRunning) startThreading();
}
}
void ViewerBase::setEndBarrierPosition(BarrierPosition bp)
{
if (_endBarrierPosition == bp) return;
if (_threadsRunning) stopThreading();
_endBarrierPosition = bp;
if (_threadingModel!=SingleThreaded) startThreading();
}
void ViewerBase::stopThreading()
{
if (!_threadsRunning) return;
osg::notify(osg::INFO)<<"ViewerBase::stopThreading() - stopping threading"<<std::endl;
Contexts contexts;
getContexts(contexts);
Cameras cameras;
getCameras(cameras);
Contexts::iterator gcitr;
Cameras::iterator citr;
for(Cameras::iterator camItr = cameras.begin();
camItr != cameras.end();
++camItr)
{
osg::Camera* camera = *camItr;
Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
if (renderer) renderer->release();
}
// delete all the graphics threads.
for(gcitr = contexts.begin();
gcitr != contexts.end();
++gcitr)
{
(*gcitr)->setGraphicsThread(0);
}
// delete all the camera threads.
for(citr = cameras.begin();
citr != cameras.end();
++citr)
{
(*citr)->setCameraThread(0);
}
for(Cameras::iterator camItr = cameras.begin();
camItr != cameras.end();
++camItr)
{
osg::Camera* camera = *camItr;
Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
if (renderer)
{
renderer->setGraphicsThreadDoesCull( true );
renderer->setDone(false);
}
}
_threadsRunning = false;
_startRenderingBarrier = 0;
_endRenderingDispatchBarrier = 0;
_endDynamicDrawBlock = 0;
osg::notify(osg::INFO)<<"Viewer::stopThreading() - stopped threading."<<std::endl;
}
void ViewerBase::startThreading()
{
if (_threadsRunning) return;
osg::notify(osg::INFO)<<"Viewer::startThreading() - starting threading"<<std::endl;
// release any context held by the main thread.
releaseContext();
_threadingModel = _threadingModel==AutomaticSelection ? suggestBestThreadingModel() : _threadingModel;
Contexts contexts;
getContexts(contexts);
osg::notify(osg::INFO)<<"Viewer::startThreading() - contexts.size()="<<contexts.size()<<std::endl;
Cameras cameras;
getCameras(cameras);
unsigned int numThreadsOnStartBarrier = 0;
unsigned int numThreadsOnEndBarrier = 0;
switch(_threadingModel)
{
case(SingleThreaded):
numThreadsOnStartBarrier = 1;
numThreadsOnEndBarrier = 1;
return;
case(CullDrawThreadPerContext):
numThreadsOnStartBarrier = contexts.size()+1;
numThreadsOnEndBarrier = contexts.size()+1;
break;
case(DrawThreadPerContext):
numThreadsOnStartBarrier = 1;
numThreadsOnEndBarrier = 1;
break;
case(CullThreadPerCameraDrawThreadPerContext):
numThreadsOnStartBarrier = cameras.size()+1;
numThreadsOnEndBarrier = 1;
break;
default:
osg::notify(osg::NOTICE)<<"Error: Threading model not selected"<<std::endl;
return;
}
// using multi-threading so make sure that new objects are allocated with thread safe ref/unref
osg::Referenced::setThreadSafeReferenceCounting(true);
Scenes scenes;
getScenes(scenes);
for(Scenes::iterator scitr = scenes.begin();
scitr != scenes.end();
++scitr)
{
if ((*scitr)->getSceneData())
{
osg::notify(osg::INFO)<<"Making scene thread safe"<<std::endl;
// make sure that existing scene graph objects are allocated with thread safe ref/unref
(*scitr)->getSceneData()->setThreadSafeRefUnref(true);
// update the scene graph so that it has enough GL object buffer memory for the graphics contexts that will be using it.
(*scitr)->getSceneData()->resizeGLObjectBuffers(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts());
}
}
int numProcessors = OpenThreads::GetNumberOfProcessors();
bool affinity = numProcessors>1;
Contexts::iterator citr;
unsigned int numViewerDoubleBufferedRenderingOperation = 0;
bool graphicsThreadsDoesCull = _threadingModel == CullDrawThreadPerContext || _threadingModel==SingleThreaded;
for(Cameras::iterator camItr = cameras.begin();
camItr != cameras.end();
++camItr)
{
osg::Camera* camera = *camItr;
Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
if (renderer)
{
renderer->setGraphicsThreadDoesCull(graphicsThreadsDoesCull);
renderer->setDone(false);
++numViewerDoubleBufferedRenderingOperation;
}
}
if (_threadingModel==CullDrawThreadPerContext)
{
_startRenderingBarrier = 0;
_endRenderingDispatchBarrier = 0;
_endDynamicDrawBlock = 0;
}
else if (_threadingModel==DrawThreadPerContext ||
_threadingModel==CullThreadPerCameraDrawThreadPerContext)
{
_startRenderingBarrier = 0;
_endRenderingDispatchBarrier = 0;
_endDynamicDrawBlock = new osg::EndOfDynamicDrawBlock(numViewerDoubleBufferedRenderingOperation);
#ifndef OSGUTIL_RENDERBACKEND_USE_REF_PTR
if (!osg::Referenced::getDeleteHandler()) osg::Referenced::setDeleteHandler(new osg::DeleteHandler(2));
else osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(2);
#endif
}
if (numThreadsOnStartBarrier>1)
{
_startRenderingBarrier = new osg::BarrierOperation(numThreadsOnStartBarrier, osg::BarrierOperation::NO_OPERATION);
}
if (numThreadsOnEndBarrier>1)
{
_endRenderingDispatchBarrier = new osg::BarrierOperation(numThreadsOnEndBarrier, osg::BarrierOperation::NO_OPERATION);
}
osg::ref_ptr<osg::BarrierOperation> swapReadyBarrier = contexts.empty() ? 0 : new osg::BarrierOperation(contexts.size(), osg::BarrierOperation::NO_OPERATION);
osg::ref_ptr<osg::SwapBuffersOperation> swapOp = new osg::SwapBuffersOperation();
typedef std::map<OpenThreads::Thread*, int> ThreadAffinityMap;
ThreadAffinityMap threadAffinityMap;
unsigned int processNum = 1;
for(citr = contexts.begin();
citr != contexts.end();
++citr, ++processNum)
{
osg::GraphicsContext* gc = (*citr);
gc->getState()->setDynamicObjectRenderingCompletedCallback(_endDynamicDrawBlock.get());
// create the a graphics thread for this context
gc->createGraphicsThread();
if (affinity) gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors);
threadAffinityMap[gc->getGraphicsThread()] = processNum % numProcessors;
gc->getGraphicsThread()->add(new osgUtil::GLObjectsOperation());
// add the startRenderingBarrier
if (_threadingModel==CullDrawThreadPerContext && _startRenderingBarrier.valid()) gc->getGraphicsThread()->add(_startRenderingBarrier.get());
// add the rendering operation itself.
gc->getGraphicsThread()->add(new osg::RunOperations());
if (_threadingModel==CullDrawThreadPerContext && _endBarrierPosition==BeforeSwapBuffers && _endRenderingDispatchBarrier.valid())
{
// add the endRenderingDispatchBarrier
gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
}
if (swapReadyBarrier.valid()) gc->getGraphicsThread()->add(swapReadyBarrier.get());
// add the swap buffers
gc->getGraphicsThread()->add(swapOp.get());
if (_threadingModel==CullDrawThreadPerContext && _endBarrierPosition==AfterSwapBuffers && _endRenderingDispatchBarrier.valid())
{
// add the endRenderingDispatchBarrier
gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
}
}
if (_threadingModel==CullThreadPerCameraDrawThreadPerContext && numThreadsOnStartBarrier>1)
{
Cameras::iterator camItr;
for(camItr = cameras.begin();
camItr != cameras.end();
++camItr, ++processNum)
{
osg::Camera* camera = *camItr;
camera->createCameraThread();
if (affinity) camera->getCameraThread()->setProcessorAffinity(processNum % numProcessors);
threadAffinityMap[camera->getCameraThread()] = processNum % numProcessors;
osg::GraphicsContext* gc = camera->getGraphicsContext();
// add the startRenderingBarrier
if (_startRenderingBarrier.valid()) camera->getCameraThread()->add(_startRenderingBarrier.get());
Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
renderer->setGraphicsThreadDoesCull(false);
camera->getCameraThread()->add(renderer);
if (_endRenderingDispatchBarrier.valid())
{
// add the endRenderingDispatchBarrier
gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
}
}
for(camItr = cameras.begin();
camItr != cameras.end();
++camItr)
{
osg::Camera* camera = *camItr;
if (camera->getCameraThread() && !camera->getCameraThread()->isRunning())
{
osg::notify(osg::INFO)<<" camera->getCameraThread()-> "<<camera->getCameraThread()<<std::endl;
camera->getCameraThread()->startThread();
}
}
}
#if 0
if (affinity)
{
OpenThreads::SetProcessorAffinityOfCurrentThread(0);
if (_scene.valid() && _scene->getDatabasePager())
{
#if 0
_scene->getDatabasePager()->setProcessorAffinity(1);
#else
_scene->getDatabasePager()->setProcessorAffinity(0);
#endif
}
}
#endif
#if 0
if (affinity)
{
for(ThreadAffinityMap::iterator titr = threadAffinityMap.begin();
titr != threadAffinityMap.end();
++titr)
{
titr->first->setProcessorAffinity(titr->second);
}
}
#endif
for(citr = contexts.begin();
citr != contexts.end();
++citr)
{
osg::GraphicsContext* gc = (*citr);
if (gc->getGraphicsThread() && !gc->getGraphicsThread()->isRunning())
{
osg::notify(osg::INFO)<<" gc->getGraphicsThread()->startThread() "<<gc->getGraphicsThread()<<std::endl;
gc->getGraphicsThread()->startThread();
// OpenThreads::Thread::YieldCurrentThread();
}
}
_threadsRunning = true;
osg::notify(osg::INFO)<<"Set up threading"<<std::endl;
}
void ViewerBase::checkWindowStatus()
{
Contexts contexts;
getContexts(contexts);
// osg::notify(osg::NOTICE)<<"Viewer::checkWindowStatus() - "<<contexts.size()<<std::endl;
if (contexts.size()==0)
{
_done = true;
if (areThreadsRunning()) stopThreading();
}
}
void ViewerBase::addUpdateOperation(osg::Operation* operation)
@@ -58,3 +519,187 @@ void ViewerBase::removeUpdateOperation(osg::Operation* operation)
_updateOperations->remove(operation);
}
}
int ViewerBase::run()
{
if (!isRealized())
{
realize();
}
#if 0
while (!done())
{
frame();
}
#else
const char* str = getenv("OSG_RUN_FRAME_COUNT");
if (str)
{
int runTillFrameNumber = atoi(str);
while (!done() && getViewerFrameStamp()->getFrameNumber()<runTillFrameNumber)
{
frame();
}
}
else
{
while (!done())
{
frame();
}
}
#endif
}
void ViewerBase::frame(double simulationTime)
{
if (_done) return;
// osg::notify(osg::NOTICE)<<std::endl<<"CompositeViewer::frame()"<<std::endl<<std::endl;
if (_firstFrame)
{
viewerInit();
if (!isRealized())
{
realize();
}
_firstFrame = false;
}
advance(simulationTime);
eventTraversal();
updateTraversal();
renderingTraversals();
}
void ViewerBase::renderingTraversals()
{
// check to see if windows are still valid
checkWindowStatus();
if (_done) return;
double beginRenderingTraversals = elapsedTime();
osg::FrameStamp* frameStamp = getViewerFrameStamp();
Scenes scenes;
getScenes(scenes);
for(Scenes::iterator sitr = scenes.begin();
sitr != scenes.end();
++sitr)
{
Scene* scene = *sitr;
osgDB::DatabasePager* dp = scene ? scene->getDatabasePager() : 0;
if (dp)
{
dp->signalBeginFrame(frameStamp);
}
}
// osg::notify(osg::NOTICE)<<std::endl<<"Start frame"<<std::endl;
Contexts contexts;
getContexts(contexts);
Cameras cameras;
getCameras(cameras);
Contexts::iterator itr;
// dispatch the the rendering threads
if (_startRenderingBarrier.valid()) _startRenderingBarrier->block();
if (_endDynamicDrawBlock.valid())
{
_endDynamicDrawBlock->reset();
}
// reset any double buffer graphics objects
for(Cameras::iterator camItr = cameras.begin();
camItr != cameras.end();
++camItr)
{
osg::Camera* camera = *camItr;
Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
if (renderer)
{
if (!renderer->getGraphicsThreadDoesCull() && !(camera->getCameraThread()))
{
renderer->cull();
}
}
}
for(itr = contexts.begin();
itr != contexts.end();
++itr)
{
if (_done) return;
if (!((*itr)->getGraphicsThread()) && (*itr)->valid())
{
makeCurrent(*itr);
(*itr)->runOperations();
}
}
// osg::notify(osg::NOTICE)<<"Joing _endRenderingDispatchBarrier block "<<_endRenderingDispatchBarrier.get()<<std::endl;
// wait till the rendering dispatch is done.
if (_endRenderingDispatchBarrier.valid()) _endRenderingDispatchBarrier->block();
for(itr = contexts.begin();
itr != contexts.end();
++itr)
{
if (_done) return;
if (!((*itr)->getGraphicsThread()) && (*itr)->valid())
{
makeCurrent(*itr);
(*itr)->swapBuffers();
}
}
for(Scenes::iterator sitr = scenes.begin();
sitr != scenes.end();
++sitr)
{
Scene* scene = *sitr;
osgDB::DatabasePager* dp = scene ? scene->getDatabasePager() : 0;
if (dp)
{
dp->signalEndFrame();
}
}
// wait till the dynamic draw is complete.
if (_endDynamicDrawBlock.valid())
{
// osg::Timer_t startTick = osg::Timer::instance()->tick();
_endDynamicDrawBlock->block();
// osg::notify(osg::NOTICE)<<"Time waiting "<<osg::Timer::instance()->delta_m(startTick, osg::Timer::instance()->tick())<<std::endl;;
}
if (getStats() && getStats()->collectStats("update"))
{
double endRenderingTraversals = elapsedTime();
// update current frames stats
getStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering traversals begin time ", beginRenderingTraversals);
getStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering traversals end time ", endRenderingTraversals);
getStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering traversals time taken", endRenderingTraversals-beginRenderingTraversals);
}
}