From 0ec854a3659f30fe813f93e0ed3005ab4d3ffbae Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 4 Jan 2007 11:49:15 +0000 Subject: [PATCH] Added support for starting and stopping osgViewer::Viewer threading and automatic handling of windows being closed. --- include/osgViewer/Viewer | 14 +- src/osgViewer/GraphicsWindowX11.cpp | 18 +- src/osgViewer/Viewer.cpp | 373 ++++++++++++++++------------ 3 files changed, 235 insertions(+), 170 deletions(-) diff --git a/include/osgViewer/Viewer b/include/osgViewer/Viewer index 448982bd1..5af75418f 100644 --- a/include/osgViewer/Viewer +++ b/include/osgViewer/Viewer @@ -72,15 +72,19 @@ class OSGVIEWER_EXPORT Viewer : public osgViewer::View const osg::Camera* getCameraWithFocus() const { return _cameraWithFocus.get(); } typedef std::vector Contexts; - void getContexts(Contexts& contexts); + void getContexts(Contexts& contexts, bool onlyValid=true); typedef std::vector Windows; - void getWindows(Windows& windows); + void getWindows(Windows& windows, bool onlyValid=true); - public: + protected: void init(); + void stopThreading(); + void startThreading(); + void checkWindowStatus(); + bool _firstFrame; bool _done; @@ -88,6 +92,10 @@ class OSGVIEWER_EXPORT Viewer : public osgViewer::View osg::ref_ptr _startRenderingBarrier; osg::ref_ptr _endRenderingDispatchBarrier; + + unsigned int computeNumberOfThreadsIncludingMainRequired(); + + unsigned int _numThreadsOnBarrier; osg::observer_ptr _cameraWithFocus; diff --git a/src/osgViewer/GraphicsWindowX11.cpp b/src/osgViewer/GraphicsWindowX11.cpp index fba3dc1e0..6182e43cc 100644 --- a/src/osgViewer/GraphicsWindowX11.cpp +++ b/src/osgViewer/GraphicsWindowX11.cpp @@ -597,6 +597,7 @@ void GraphicsWindowX11::closeImplementation() _initialized = false; _realized = false; + _valid = false; } void GraphicsWindowX11::swapBuffersImplementation() @@ -634,9 +635,10 @@ void GraphicsWindowX11::checkEvents() { case ClientMessage: { - if (ev.xclient.data.l[0] == _deleteWindow) + if (static_cast(ev.xclient.data.l[0]) == _deleteWindow) { - osg::notify(osg::NOTICE)<<"DeleteWindow"<setGraphicsThread(0); - } + stopThreading(); if (_scene.valid() && _scene->getDatabasePager()) { @@ -56,87 +47,37 @@ Viewer::~Viewer() void Viewer::setThreadingModel(ThreadingModel threadingModel) { + if (_threadingModel == threadingModel) return; + + if (_threadingModel!=SingleThreaded) stopThreading(); + _threadingModel = threadingModel; + + if (_threadingModel!=SingleThreaded) startThreading(); } -void Viewer::init() +void Viewer::stopThreading() { - osg::notify(osg::INFO)<<"Viewer::init()"< initEvent = _eventQueue->createEvent(); - initEvent->setEventType(osgGA::GUIEventAdapter::FRAME); - - if (_cameraManipulator.valid()) - { - _cameraManipulator->init(*initEvent, *this); - } -} + if (_numThreadsOnBarrier==0) return; -void Viewer::getContexts(Contexts& contexts) -{ - typedef std::set ContextSet; - ContextSet contextSet; + osg::notify(osg::INFO)<<"Viewer::stopThreading() - stopping threading"<getGraphicsContext()) - { - contextSet.insert(_camera->getGraphicsContext()); - } - - for(unsigned int i=0; igetGraphicsContext()) - { - contextSet.insert(slave._camera->getGraphicsContext()); - } - } + Contexts contexts; + getContexts(contexts); - contexts.clear(); - contexts.reserve(contextSet.size()); - - for(ContextSet::iterator itr = contextSet.begin(); - itr != contextSet.end(); + // delete all the graphics threads. + for(Contexts::iterator itr = contexts.begin(); + itr != contexts.end(); ++itr) { - contexts.push_back(const_cast(*itr)); + (*itr)->setGraphicsThread(0); } + + _startRenderingBarrier = 0; + _endRenderingDispatchBarrier = 0; + _numThreadsOnBarrier = 0; } -void Viewer::getWindows(Windows& windows) -{ - typedef std::set WindowSet; - WindowSet windowSet; - - if (_camera.valid() && _camera->getGraphicsContext()) - { - osgViewer::GraphicsWindow* gw = dynamic_cast(_camera->getGraphicsContext()); - if (gw) windowSet.insert(gw); - } - - for(unsigned int i=0; igetGraphicsContext()) - { - osgViewer::GraphicsWindow* gw = dynamic_cast(slave._camera->getGraphicsContext()); - if (gw) windowSet.insert(gw); - } - } - - windows.clear(); - windows.reserve(windowSet.size()); - - for(WindowSet::iterator itr = windowSet.begin(); - itr != windowSet.end(); - ++itr) - { - windows.push_back(const_cast(*itr)); - } -} - - -OpenThreads::Mutex mutex; - // Compile operation, that compile OpenGL objects. struct CompileOperation : public osg::GraphicsOperation { @@ -183,6 +124,187 @@ struct RunOperations : public osg::GraphicsOperation osg::GraphicsContext* _originalContext; }; +unsigned int Viewer::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 Viewer::startThreading() +{ + 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)<<"Viewer::startThreading() - starting threading"< swapOp = new osg::SwapBuffersOperation(); + + Contexts::iterator citr = contexts.begin(); + unsigned int processNum = 0; + + if (firstContextAsMainThread) + { + if (affinity) OpenThreads::SetProcessorAffinityOfCurrentThread(processNum % numProcessors); + ++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 CompileOperation(getSceneData())); + + // add the startRenderingBarrier + gc->getGraphicsThread()->add(_startRenderingBarrier.get()); + + // add the rendering operation itself. + gc->getGraphicsThread()->add(new RunOperations(gc)); + + // add the endRenderingDispatchBarrier + gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get()); + + // add the swap buffers + gc->getGraphicsThread()->add(swapOp.get()); + + } + + + 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() "<getGraphicsThread()<getGraphicsThread()->startThread(); + // OpenThreads::Thread::YieldCurrentThread(); + } + } +} + +void Viewer::checkWindowStatus() +{ + unsigned int numThreadsIncludingMainThread = computeNumberOfThreadsIncludingMainRequired(); + if (numThreadsIncludingMainThread != _numThreadsOnBarrier) + { + stopThreading(); + + if (numThreadsIncludingMainThread > 1) startThreading(); + } + + if (numThreadsIncludingMainThread==0) _done = true; +} + + + +void Viewer::init() +{ + osg::notify(osg::INFO)<<"Viewer::init()"< initEvent = _eventQueue->createEvent(); + initEvent->setEventType(osgGA::GUIEventAdapter::FRAME); + + if (_cameraManipulator.valid()) + { + _cameraManipulator->init(*initEvent, *this); + } +} + +void Viewer::getContexts(Contexts& contexts, bool onlyValid) +{ + typedef std::set ContextSet; + ContextSet contextSet; + + if (_camera.valid() && + _camera->getGraphicsContext() && + (_camera->getGraphicsContext()->valid() || !onlyValid)) + { + contextSet.insert(_camera->getGraphicsContext()); + } + + for(unsigned int i=0; igetGraphicsContext() && + (slave._camera->getGraphicsContext()->valid() || !onlyValid)) + { + contextSet.insert(slave._camera->getGraphicsContext()); + } + } + + contexts.clear(); + contexts.reserve(contextSet.size()); + + for(ContextSet::iterator itr = contextSet.begin(); + itr != contextSet.end(); + ++itr) + { + contexts.push_back(const_cast(*itr)); + } +} + +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(*itr); + if (gw) windows.push_back(gw); + } +} void Viewer::realize() { @@ -190,78 +312,21 @@ void Viewer::realize() setCameraWithFocus(0); - Contexts::iterator citr; - Contexts contexts; getContexts(contexts); - int numProcessors = OpenThreads::GetNumberOfProcessors(); - bool multiThreaded = contexts.size() > 1 && _threadingModel>=ThreadPerContext; - bool affinity = true; - - if (multiThreaded) - { - bool firstContextAsMainThread = _threadingModel==ThreadPerContext; - unsigned int numThreadsIncludingMainThread = firstContextAsMainThread ? contexts.size() : contexts.size()+1; - - // osg::notify(osg::NOTICE)<<"numThreadsIncludingMainThread=="< swapOp = new osg::SwapBuffersOperation(); - - citr = contexts.begin(); - unsigned int processNum = 0; - - if (firstContextAsMainThread) - { - if (affinity) OpenThreads::SetProcessorAffinityOfCurrentThread(processNum % numProcessors); - ++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 CompileOperation(getSceneData())); - - // add the startRenderingBarrier - gc->getGraphicsThread()->add(_startRenderingBarrier.get()); - - // add the rendering operation itself. - gc->getGraphicsThread()->add(new RunOperations(gc)); - - // add the endRenderingDispatchBarrier - gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get()); - - // add the swap buffers - gc->getGraphicsThread()->add(swapOp.get()); - - } - - } - - for(citr = contexts.begin(); + for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { (*citr)->realize(); - OpenThreads::Thread::YieldCurrentThread(); +// OpenThreads::Thread::YieldCurrentThread(); } bool grabFocus = true; if (grabFocus) { - for(citr = contexts.begin(); + for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { @@ -273,28 +338,11 @@ void Viewer::realize() } } + startThreading(); + // initialize the global timer to be relative to the current time. osg::Timer::instance()->setStartTick(); - if (multiThreaded) - { - //osg::notify(osg::NOTICE)<<"Ready to start threads"<getGraphicsThread() && !gc->getGraphicsThread()->isRunning()) - { - //osg::notify(osg::NOTICE)<<" gc->getGraphicsThread()->startThread() "<getGraphicsThread()<getGraphicsThread()->startThread(); - OpenThreads::Thread::YieldCurrentThread(); - } - } - - //osg::notify(osg::NOTICE)<<"Started threads"<getDatabasePager(); @@ -603,6 +654,7 @@ void Viewer::frameRenderingTraversals() } // osg::notify(osg::NOTICE)<getGraphicsThread())) { (*itr)->makeCurrent();