Added support for starting and stopping osgViewer::Viewer threading and
automatic handling of windows being closed.
This commit is contained in:
@@ -72,15 +72,19 @@ class OSGVIEWER_EXPORT Viewer : public osgViewer::View
|
||||
const osg::Camera* getCameraWithFocus() const { return _cameraWithFocus.get(); }
|
||||
|
||||
typedef std::vector<osg::GraphicsContext*> Contexts;
|
||||
void getContexts(Contexts& contexts);
|
||||
void getContexts(Contexts& contexts, bool onlyValid=true);
|
||||
|
||||
typedef std::vector<osgViewer::GraphicsWindow*> 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<osg::BarrierOperation> _startRenderingBarrier;
|
||||
osg::ref_ptr<osg::BarrierOperation> _endRenderingDispatchBarrier;
|
||||
|
||||
unsigned int computeNumberOfThreadsIncludingMainRequired();
|
||||
|
||||
unsigned int _numThreadsOnBarrier;
|
||||
|
||||
osg::observer_ptr<osg::Camera> _cameraWithFocus;
|
||||
|
||||
|
||||
@@ -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<Atom>(ev.xclient.data.l[0]) == _deleteWindow)
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"DeleteWindow"<<std::endl;
|
||||
osg::notify(osg::INFO)<<"DeleteWindow event recieved"<<std::endl;
|
||||
close();
|
||||
}
|
||||
}
|
||||
case Expose :
|
||||
@@ -644,20 +646,21 @@ void GraphicsWindowX11::checkEvents()
|
||||
break;
|
||||
|
||||
case GravityNotify :
|
||||
osg::notify(osg::INFO)<<"GravityNotify"<<std::endl;
|
||||
osg::notify(osg::INFO)<<"GravityNotify event recieved"<<std::endl;
|
||||
break;
|
||||
|
||||
case UnmapNotify :
|
||||
osg::notify(osg::INFO)<<"UnmapNotify"<<std::endl;
|
||||
osg::notify(osg::INFO)<<"UnmapNotify event recieved"<<std::endl;
|
||||
break;
|
||||
|
||||
case ReparentNotify:
|
||||
osg::notify(osg::INFO)<<"ReparentNotify"<<std::endl;
|
||||
osg::notify(osg::INFO)<<"ReparentNotify event recieved"<<std::endl;
|
||||
break;
|
||||
|
||||
case DestroyNotify :
|
||||
osg::notify(osg::NOTICE)<<"DestroyNotify"<<std::endl;
|
||||
osg::notify(osg::INFO)<<"DestroyNotify event recieved"<<std::endl;
|
||||
_realized = false;
|
||||
_valid = false;
|
||||
break;
|
||||
|
||||
case ConfigureNotify :
|
||||
@@ -936,7 +939,8 @@ void GraphicsWindowX11::requestWarpPointer(float x,float y)
|
||||
|
||||
int X11ErrorHandling(Display* display, XErrorEvent* event)
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"Got an X11ErrorHandling call"<<std::endl;
|
||||
osg::notify(osg::NOTICE)<<"Got an X11ErrorHandling call display="<<display<<" event="<<event<<std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,7 +25,8 @@ using namespace osgViewer;
|
||||
Viewer::Viewer():
|
||||
_firstFrame(true),
|
||||
_done(false),
|
||||
_threadingModel(ThreadPerContext)
|
||||
_threadingModel(ThreadPerContext),
|
||||
_numThreadsOnBarrier(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -33,17 +34,7 @@ Viewer::~Viewer()
|
||||
{
|
||||
//osg::notify(osg::NOTICE)<<"Viewer::~Viewer()"<<std::endl;
|
||||
|
||||
Contexts contexts;
|
||||
getContexts(contexts);
|
||||
|
||||
// cancel any graphics threads.
|
||||
for(Contexts::iterator citr = contexts.begin();
|
||||
citr != contexts.end();
|
||||
++citr)
|
||||
{
|
||||
osg::GraphicsContext* gc = (*citr);
|
||||
gc->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()"<<std::endl;
|
||||
|
||||
osg::ref_ptr<osgGA::GUIEventAdapter> 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<osg::GraphicsContext*> ContextSet;
|
||||
ContextSet contextSet;
|
||||
osg::notify(osg::INFO)<<"Viewer::stopThreading() - stopping threading"<<std::endl;
|
||||
|
||||
if (_camera.valid() && _camera->getGraphicsContext())
|
||||
{
|
||||
contextSet.insert(_camera->getGraphicsContext());
|
||||
}
|
||||
|
||||
for(unsigned int i=0; i<getNumSlaves(); ++i)
|
||||
{
|
||||
Slave& slave = getSlave(i);
|
||||
if (slave._camera.valid() && slave._camera->getGraphicsContext())
|
||||
{
|
||||
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<osg::GraphicsContext*>(*itr));
|
||||
(*itr)->setGraphicsThread(0);
|
||||
}
|
||||
|
||||
_startRenderingBarrier = 0;
|
||||
_endRenderingDispatchBarrier = 0;
|
||||
_numThreadsOnBarrier = 0;
|
||||
}
|
||||
|
||||
void Viewer::getWindows(Windows& windows)
|
||||
{
|
||||
typedef std::set<osgViewer::GraphicsWindow*> WindowSet;
|
||||
WindowSet windowSet;
|
||||
|
||||
if (_camera.valid() && _camera->getGraphicsContext())
|
||||
{
|
||||
osgViewer::GraphicsWindow* gw = dynamic_cast<osgViewer::GraphicsWindow*>(_camera->getGraphicsContext());
|
||||
if (gw) windowSet.insert(gw);
|
||||
}
|
||||
|
||||
for(unsigned int i=0; i<getNumSlaves(); ++i)
|
||||
{
|
||||
Slave& slave = getSlave(i);
|
||||
if (slave._camera.valid() && slave._camera->getGraphicsContext())
|
||||
{
|
||||
osgViewer::GraphicsWindow* gw = dynamic_cast<osgViewer::GraphicsWindow*>(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<osgViewer::GraphicsWindow*>(*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"<<std::endl;
|
||||
|
||||
Contexts contexts;
|
||||
getContexts(contexts);
|
||||
|
||||
int numProcessors = OpenThreads::GetNumberOfProcessors();
|
||||
bool affinity = true;
|
||||
|
||||
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)
|
||||
{
|
||||
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() "<<gc->getGraphicsThread()<<std::endl;
|
||||
gc->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()"<<std::endl;
|
||||
|
||||
osg::ref_ptr<osgGA::GUIEventAdapter> 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<osg::GraphicsContext*> ContextSet;
|
||||
ContextSet contextSet;
|
||||
|
||||
if (_camera.valid() &&
|
||||
_camera->getGraphicsContext() &&
|
||||
(_camera->getGraphicsContext()->valid() || !onlyValid))
|
||||
{
|
||||
contextSet.insert(_camera->getGraphicsContext());
|
||||
}
|
||||
|
||||
for(unsigned int i=0; i<getNumSlaves(); ++i)
|
||||
{
|
||||
Slave& slave = getSlave(i);
|
||||
if (slave._camera.valid() &&
|
||||
slave._camera->getGraphicsContext() &&
|
||||
(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<osg::GraphicsContext*>(*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<osgViewer::GraphicsWindow*>(*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=="<<numThreadsIncludingMainThread<<std::endl;
|
||||
|
||||
_startRenderingBarrier = new osg::BarrierOperation(numThreadsIncludingMainThread, osg::BarrierOperation::NO_OPERATION);
|
||||
_endRenderingDispatchBarrier = new osg::BarrierOperation(numThreadsIncludingMainThread, osg::BarrierOperation::NO_OPERATION);
|
||||
osg::ref_ptr<osg::SwapBuffersOperation> 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"<<std::endl;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
//osg::notify(osg::NOTICE)<<"Started threads"<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -594,6 +642,9 @@ void Viewer::frameUpdateTraversal()
|
||||
|
||||
void Viewer::frameRenderingTraversals()
|
||||
{
|
||||
// check to see if windows are still valid
|
||||
checkWindowStatus();
|
||||
|
||||
if (_done) return;
|
||||
|
||||
osgDB::DatabasePager* dp = _scene->getDatabasePager();
|
||||
@@ -603,6 +654,7 @@ void Viewer::frameRenderingTraversals()
|
||||
}
|
||||
|
||||
// osg::notify(osg::NOTICE)<<std::endl<<"Joing _startRenderingBarrier block"<<std::endl;
|
||||
|
||||
|
||||
Contexts contexts;
|
||||
getContexts(contexts);
|
||||
@@ -633,6 +685,7 @@ void Viewer::frameRenderingTraversals()
|
||||
++itr)
|
||||
{
|
||||
if (_done) return;
|
||||
|
||||
if (!((*itr)->getGraphicsThread()))
|
||||
{
|
||||
(*itr)->makeCurrent();
|
||||
|
||||
Reference in New Issue
Block a user