diff --git a/include/osg/GraphicsContext b/include/osg/GraphicsContext index c1968a1a7..1870a54b1 100644 --- a/include/osg/GraphicsContext +++ b/include/osg/GraphicsContext @@ -176,6 +176,21 @@ class OSG_EXPORT GraphicsContext : public Referenced /** Run the operations. */ void runOperations(); + typedef std::list< ref_ptr > OperationQueue; + + /** Get the operations queue, not you must use the OperationsMutex when accessing the queue.*/ + OperationQueue& getOperationsQueue() { return _operations; } + + /** Get the operations queue mutex.*/ + OpenThreads::Mutex& getOperationsMutex() { return _operationsMutex; } + + /** Get the operations queue block used to mark an empty queue, if you end items into the empty queu you must release this block.*/ + osg::Block* getOperationsBlock() { return _operationsBlock.get(); } + + /** Get the current operations that is being run.*/ + GraphicsOperation* getCurrentOperation() { return _currentOperation.get(); } + + public: /** Get the traits of the GraphicsContext.*/ @@ -354,8 +369,6 @@ class OSG_EXPORT GraphicsContext : public Referenced OpenThreads::Thread* _threadOfLastMakeCurrent; - typedef std::list< ref_ptr > OperationQueue; - OpenThreads::Mutex _operationsMutex; osg::ref_ptr _operationsBlock; OperationQueue _operations; diff --git a/include/osgUtil/SceneView b/include/osgUtil/SceneView index a9ca660cc..d2bbbc3e9 100644 --- a/include/osgUtil/SceneView +++ b/include/osgUtil/SceneView @@ -443,6 +443,9 @@ class OSGUTIL_EXPORT SceneView : public osg::Object, public osg::CullSettings /** Do draw traversal of draw bins generated by cull traversal.*/ virtual void draw(); + /** Compute the number of dynamic objects that will be held in the rendering backend */ + unsigned int getDynamicObjectCount() const { return _dynamicObjectCount; } + /** Release all OpenGL objects from the scene graph, such as texture objects, display lists etc. * These released scene graphs placed in the respective delete GLObjects cache, which * then need to be deleted in OpenGL by SceneView::flushAllDeleteGLObjects(). */ @@ -515,7 +518,7 @@ class OSGUTIL_EXPORT SceneView : public osg::Object, public osg::CullSettings int _interlacedStereoStencilWidth; int _interlacedStereoStencilHeight; - + unsigned int _dynamicObjectCount; }; } diff --git a/include/osgViewer/View b/include/osgViewer/View index 176f506b8..73b78a878 100644 --- a/include/osgViewer/View +++ b/include/osgViewer/View @@ -29,15 +29,17 @@ class OSGVIEWER_EXPORT EndOfDynamicDrawBlock : public osg::State::DynamicObjectR { public: - EndOfDynamicDrawBlock(); + EndOfDynamicDrawBlock(unsigned int); void completed(osg::State* state); void block(); + + void reset(); void release(); - void set(unsigned int blockCount); + void setNumOfBlocks(unsigned int blockCount); protected: @@ -45,6 +47,7 @@ class OSGVIEWER_EXPORT EndOfDynamicDrawBlock : public osg::State::DynamicObjectR OpenThreads::Mutex _mut; OpenThreads::Condition _cond; + unsigned int _numberOfBlocks; unsigned int _blockCount; }; diff --git a/include/osgViewer/Viewer b/include/osgViewer/Viewer index b656eb73c..b8e12a150 100644 --- a/include/osgViewer/Viewer +++ b/include/osgViewer/Viewer @@ -170,8 +170,8 @@ class OSGVIEWER_EXPORT Viewer : public osgViewer::View unsigned int _numThreadsOnBarrier; - typedef std::map, osg::ref_ptr > CameraSceneViewMap; - CameraSceneViewMap _cameraSceneViewMap; + typedef std::list< osg::ref_ptr > SceneViews; + SceneViews _sceneViews; osg::Timer_t _startTick; osg::ref_ptr _frameStamp; diff --git a/src/osgUtil/SceneView.cpp b/src/osgUtil/SceneView.cpp index 82fe96f56..d42817502 100644 --- a/src/osgUtil/SceneView.cpp +++ b/src/osgUtil/SceneView.cpp @@ -116,6 +116,8 @@ SceneView::SceneView(DisplaySettings* ds) _redrawInterlacedStereoStencilMask = true; _interlacedStereoStencilWidth = 0; _interlacedStereoStencilHeight = 0; + + _dynamicObjectCount = 0; } SceneView::SceneView(const SceneView& rhs, const osg::CopyOp& copyop): @@ -145,6 +147,8 @@ SceneView::SceneView(const SceneView& rhs, const osg::CopyOp& copyop): _redrawInterlacedStereoStencilMask = rhs._redrawInterlacedStereoStencilMask; _interlacedStereoStencilWidth = rhs._interlacedStereoStencilWidth; _interlacedStereoStencilHeight = rhs._interlacedStereoStencilHeight; + + _dynamicObjectCount = 0; } SceneView::~SceneView() @@ -254,7 +258,6 @@ void SceneView::setSceneData(osg::Node* node) void SceneView::init() { - _initCalled = true; // force the initialization of the OpenGL extension string @@ -494,6 +497,8 @@ osg::Matrixd SceneView::computeRightEyeViewImplementation(const osg::Matrixd& vi void SceneView::cull() { + _dynamicObjectCount = 0; + if (_camera->getNodeMask()==0) return; _renderInfo.setView(_camera->getView()); @@ -779,9 +784,7 @@ void SceneView::cullStage(const osg::Matrixd& projection,const osg::Matrixd& mod rendergraph->prune(); // set the number of dynamic objects in the scene. - getState()->setDynamicObjectCount( getState()->getDynamicObjectCount() + renderStage->computeNumberOfDynamicRenderLeaves()); - - // osg::notify(osg::NOTICE)<<"SceneView cull() DynamicObjectCount"<getDynamicObjectCount()<computeNumberOfDynamicRenderLeaves(); } void SceneView::releaseAllGLObjects() diff --git a/src/osgViewer/View.cpp b/src/osgViewer/View.cpp index 2731dac3e..0b641a3e6 100644 --- a/src/osgViewer/View.cpp +++ b/src/osgViewer/View.cpp @@ -504,7 +504,8 @@ bool View::computeIntersections(float x,float y, osg::NodePath& nodePath, osgUti // // EndOfDynamicDrawBlock // -EndOfDynamicDrawBlock::EndOfDynamicDrawBlock(): +EndOfDynamicDrawBlock::EndOfDynamicDrawBlock(unsigned int numberOfBlocks): + _numberOfBlocks(numberOfBlocks), _blockCount(0) { } @@ -541,17 +542,23 @@ void EndOfDynamicDrawBlock::release() } } -void EndOfDynamicDrawBlock::set(unsigned int blockCount) +void EndOfDynamicDrawBlock::reset() { OpenThreads::ScopedLock mutlock(_mut); - if (blockCount!=_blockCount) + if (_numberOfBlocks!=_blockCount) { - if (blockCount==0) _cond.broadcast(); - _blockCount = blockCount; + if (_numberOfBlocks==0) _cond.broadcast(); + _blockCount = _numberOfBlocks; } } +void EndOfDynamicDrawBlock::setNumOfBlocks(unsigned int blockCount) +{ + _numberOfBlocks = blockCount; +} + EndOfDynamicDrawBlock::~EndOfDynamicDrawBlock() { + _blockCount = 0; release(); } diff --git a/src/osgViewer/Viewer.cpp b/src/osgViewer/Viewer.cpp index 9a8815993..d363f3c78 100644 --- a/src/osgViewer/Viewer.cpp +++ b/src/osgViewer/Viewer.cpp @@ -20,6 +20,508 @@ using namespace osgViewer; +class ViewerQuerySupport +{ +public: + ViewerQuerySupport(osg::Timer_t startTick): + _startTick(startTick), + _initialized(false), + _timerQuerySupported(false), + _extensions(0), + _previousQueryTime(0.0) + { + } + + typedef std::pair QueryFrameNumberPair; + typedef std::list QueryFrameNumberList; + typedef std::vector QueryList; + + inline void checkQuery(osg::Stats* stats) + { + for(QueryFrameNumberList::iterator itr = _queryFrameNumberList.begin(); + itr != _queryFrameNumberList.end(); + ) + { + GLuint query = itr->first; + GLint available = 0; + _extensions->glGetQueryObjectiv(query, GL_QUERY_RESULT_AVAILABLE, &available); + if (available) + { + GLuint64EXT timeElapsed = 0; + _extensions->glGetQueryObjectui64v(query, GL_QUERY_RESULT, &timeElapsed); + + double timeElapsedSeconds = double(timeElapsed)*1e-9; + double currentTime = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); + double estimatedEndTime = (_previousQueryTime + currentTime) * 0.5; + double estimatedBeginTime = estimatedEndTime - timeElapsedSeconds; + + stats->setAttribute(itr->second, "GPU draw begin time", estimatedBeginTime); + stats->setAttribute(itr->second, "GPU draw end time", estimatedEndTime); + stats->setAttribute(itr->second, "GPU draw time taken", timeElapsedSeconds); + + + itr = _queryFrameNumberList.erase(itr); + _availableQueryObjects.push_back(query); + } + else + { + ++itr; + } + + } + _previousQueryTime = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); + } + + inline GLuint createQueryObject() + { + if (_availableQueryObjects.empty()) + { + GLuint query; + _extensions->glGenQueries(1, &query); + return query; + } + else + { + GLuint query = _availableQueryObjects.back(); + _availableQueryObjects.pop_back(); + return query; + } + } + + inline void beginQuery(int frameNumber) + { + GLuint query = createQueryObject(); + _extensions->glBeginQuery(GL_TIME_ELAPSED, query); + _queryFrameNumberList.push_back(QueryFrameNumberPair(query, frameNumber)); + } + + inline void endQuery() + { + _extensions->glEndQuery(GL_TIME_ELAPSED); + } + + void initialize(osg::State* state) + { + if (_initialized) return; + + _initialized = true; + _extensions = osg::Drawable::getExtensions(state->getContextID(),true); + _timerQuerySupported = _extensions && _extensions->isTimerQuerySupported(); + _previousQueryTime = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); + } + + osg::Timer_t _startTick; + bool _initialized; + bool _timerQuerySupported; + const osg::Drawable::Extensions* _extensions; + QueryFrameNumberList _queryFrameNumberList; + QueryList _availableQueryObjects; + double _previousQueryTime; + +}; + + +// Draw operation, that does a draw on the scene graph. +struct ViewerRenderingOperation : public osg::GraphicsOperation, public ViewerQuerySupport +{ + ViewerRenderingOperation(osgUtil::SceneView* sceneView, osgDB::DatabasePager* databasePager, osg::Timer_t startTick): + osg::GraphicsOperation("Render",true), + ViewerQuerySupport(startTick), + _sceneView(sceneView), + _databasePager(databasePager) + { + _sceneView->getCullVisitor()->setDatabaseRequestHandler(_databasePager.get()); + } + + virtual void operator () (osg::GraphicsContext*) + { + if (!_sceneView) return; + + // osg::notify(osg::NOTICE)<<"RenderingOperation"<getCamera()->getStats(); + osg::State* state = _sceneView->getState(); + const osg::FrameStamp* fs = state->getFrameStamp(); + int frameNumber = fs ? fs->getFrameNumber() : 0; + + if (!_initialized) + { + initialize(state); + } + + bool aquireGPUStats = stats && _timerQuerySupported && stats->collectStats("gpu"); + + if (aquireGPUStats) + { + checkQuery(stats); + } + + // do cull taversal + osg::Timer_t beforeCullTick = osg::Timer::instance()->tick(); + _sceneView->cull(); + osg::Timer_t afterCullTick = osg::Timer::instance()->tick(); + +#if 0 + if (_sceneView->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback()) + { + osg::notify(osg::NOTICE)<<"Completed in ViewerRenderingOperation"<getDynamicObjectRenderingCompletedCallback()->completed(state); + } +#endif + + state->setDynamicObjectCount(_sceneView->getDynamicObjectCount()); + + // do draw traveral + if (aquireGPUStats) + { + checkQuery(stats); + beginQuery(frameNumber); + } + + _sceneView->draw(); + + double availableTime = 0.004; // 4 ms + if (_databasePager.valid()) + { + _databasePager->compileGLObjects(*(_sceneView->getState()), availableTime); + } + _sceneView->flushDeletedGLObjects(availableTime); + + if (aquireGPUStats) + { + endQuery(); + checkQuery(stats); + } + + osg::Timer_t afterDrawTick = osg::Timer::instance()->tick(); + + if (stats && stats->collectStats("rendering")) + { + stats->setAttribute(frameNumber, "Cull traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeCullTick)); + stats->setAttribute(frameNumber, "Cull traversal end time", osg::Timer::instance()->delta_s(_startTick, afterCullTick)); + stats->setAttribute(frameNumber, "Cull traversal time taken", osg::Timer::instance()->delta_s(beforeCullTick, afterCullTick)); + + stats->setAttribute(frameNumber, "Draw traversal begin time", osg::Timer::instance()->delta_s(_startTick, afterCullTick)); + stats->setAttribute(frameNumber, "Draw traversal end time", osg::Timer::instance()->delta_s(_startTick, afterDrawTick)); + stats->setAttribute(frameNumber, "Draw traversal time taken", osg::Timer::instance()->delta_s(afterCullTick, afterDrawTick)); + } + + } + + osg::observer_ptr _sceneView; + osg::observer_ptr _databasePager; + +}; + + +// Draw operation, that does a draw on the scene graph. +struct ViewerDoubleBufferedRenderingOperation : public osg::GraphicsOperation, public ViewerQuerySupport +{ + ViewerDoubleBufferedRenderingOperation(bool graphicsThreadDoesCull, osgUtil::SceneView* sv0, osgUtil::SceneView* sv1, osgDB::DatabasePager* databasePager, osg::Timer_t startTick): + osg::GraphicsOperation("Render",true), + ViewerQuerySupport(startTick), + _graphicsThreadDoesCull(graphicsThreadDoesCull), + _done(false), + _databasePager(databasePager) + { + _sceneView[0] = sv0; + _sceneView[0]->getCullVisitor()->setDatabaseRequestHandler(_databasePager.get()); + + _sceneView[1] = sv1; + _sceneView[1]->getCullVisitor()->setDatabaseRequestHandler(_databasePager.get()); + + _currentCull = 0; + _currentDraw = 0; + + // lock the mutex for the current cull SceneView to + // prevent the draw traversal from reading from it before the cull traversal has been completed. + if (!_graphicsThreadDoesCull) _mutex[_currentCull].lock(); + + osg::notify(osg::NOTICE)<<"constructed)"<getCamera()->getStats(); + osg::State* state = sceneView->getState(); + const osg::FrameStamp* fs = state->getFrameStamp(); + int frameNumber = fs ? fs->getFrameNumber() : 0; + + _frameNumber[_currentCull] = frameNumber; + + // do cull taversal + osg::Timer_t beforeCullTick = osg::Timer::instance()->tick(); + sceneView->cull(); + osg::Timer_t afterCullTick = osg::Timer::instance()->tick(); + +#if 0 + if (sceneView->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback()) + { + // osg::notify(osg::NOTICE)<<"Completed in cull"<getDynamicObjectRenderingCompletedCallback()->completed(state); + } +#endif + if (stats && stats->collectStats("rendering")) + { + stats->setAttribute(frameNumber, "Cull traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeCullTick)); + stats->setAttribute(frameNumber, "Cull traversal end time", osg::Timer::instance()->delta_s(_startTick, afterCullTick)); + stats->setAttribute(frameNumber, "Cull traversal time taken", osg::Timer::instance()->delta_s(beforeCullTick, afterCullTick)); + } + } + + + // relase the mutex associated with this cull traversal, let the draw commense. + _mutex[_currentCull].unlock(); + + // swap which SceneView we need to do cull traversal on next. + _currentCull = 1 - _currentCull; + + // aquire the lock for it for the new cull traversal + _mutex[_currentCull].lock(); + } + + void draw() + { + // osg::notify(osg::NOTICE)<<"draw()"< lock(_mutex[_currentDraw]); + + // osg::notify(osg::NOTICE)<<"Drawing buffer "<<_currentDraw<getCamera()->getStats(); + osg::State* state = sceneView->getState(); + int frameNumber = _frameNumber[_currentDraw]; + + if (!_initialized) + { + initialize(state); + } + + state->setDynamicObjectCount(sceneView->getDynamicObjectCount()); + + if (sceneView->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback()) + { + // osg::notify(osg::NOTICE)<<"Completed in cull"<getDynamicObjectRenderingCompletedCallback()->completed(state); + } + + osg::Timer_t beforeDrawTick = osg::Timer::instance()->tick(); + + bool aquireGPUStats = stats && _timerQuerySupported && stats->collectStats("gpu"); + + if (aquireGPUStats) + { + checkQuery(stats); + } + + // do draw traveral + if (aquireGPUStats) + { + checkQuery(stats); + beginQuery(frameNumber); + } + + sceneView->draw(); + + double availableTime = 0.004; // 4 ms + if (_databasePager.valid()) + { + _databasePager->compileGLObjects(*(sceneView->getState()), availableTime); + } + + sceneView->flushDeletedGLObjects(availableTime); + + if (aquireGPUStats) + { + endQuery(); + checkQuery(stats); + } + + glFlush(); + + + osg::Timer_t afterDrawTick = osg::Timer::instance()->tick(); + + if (stats && stats->collectStats("rendering")) + { + stats->setAttribute(frameNumber, "Draw traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeDrawTick)); + stats->setAttribute(frameNumber, "Draw traversal end time", osg::Timer::instance()->delta_s(_startTick, afterDrawTick)); + stats->setAttribute(frameNumber, "Draw traversal time taken", osg::Timer::instance()->delta_s(beforeDrawTick, afterDrawTick)); + } + } + + _currentDraw = 1-_currentDraw; + + } + + void cull_draw() + { + osgUtil::SceneView* sceneView = _sceneView[_currentDraw].get(); + if (!sceneView || _done) return; + + OpenThreads::ScopedLock lock(_mutex[_currentDraw]); + + if (_done) + { + osg::notify(osg::INFO)<<"ViewerDoubleBufferedRenderingOperation::release() causing cull_draw to exit"<getCamera()->getStats(); + osg::State* state = sceneView->getState(); + const osg::FrameStamp* fs = state->getFrameStamp(); + int frameNumber = fs ? fs->getFrameNumber() : 0; + + if (!_initialized) + { + initialize(state); + } + + bool aquireGPUStats = stats && _timerQuerySupported && stats->collectStats("gpu"); + + if (aquireGPUStats) + { + checkQuery(stats); + } + + // do cull taversal + osg::Timer_t beforeCullTick = osg::Timer::instance()->tick(); + sceneView->cull(); + osg::Timer_t afterCullTick = osg::Timer::instance()->tick(); + + if (state->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback()) + { + state->getDynamicObjectRenderingCompletedCallback()->completed(state); + } + + // do draw traveral + if (aquireGPUStats) + { + checkQuery(stats); + beginQuery(frameNumber); + } + + sceneView->draw(); + + double availableTime = 0.004; // 4 ms + if (_databasePager.valid()) + { + _databasePager->compileGLObjects(*(sceneView->getState()), availableTime); + } + sceneView->flushDeletedGLObjects(availableTime); + + if (aquireGPUStats) + { + endQuery(); + checkQuery(stats); + } + + osg::Timer_t afterDrawTick = osg::Timer::instance()->tick(); + + if (stats && stats->collectStats("rendering")) + { + stats->setAttribute(frameNumber, "Cull traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeCullTick)); + stats->setAttribute(frameNumber, "Cull traversal end time", osg::Timer::instance()->delta_s(_startTick, afterCullTick)); + stats->setAttribute(frameNumber, "Cull traversal time taken", osg::Timer::instance()->delta_s(beforeCullTick, afterCullTick)); + + stats->setAttribute(frameNumber, "Draw traversal begin time", osg::Timer::instance()->delta_s(_startTick, afterCullTick)); + stats->setAttribute(frameNumber, "Draw traversal end time", osg::Timer::instance()->delta_s(_startTick, afterDrawTick)); + stats->setAttribute(frameNumber, "Draw traversal time taken", osg::Timer::instance()->delta_s(afterCullTick, afterDrawTick)); + } + } + + virtual void operator () (osg::GraphicsContext*) + { + //osg::notify(osg::NOTICE)<<"GraphicsCall "< _sceneView[2]; + int _frameNumber[2]; + osg::observer_ptr _databasePager; + + +}; + + Viewer::Viewer(): _firstFrame(true), _done(false), @@ -202,6 +704,30 @@ void Viewer::stopThreading() Contexts contexts; getContexts(contexts); + Contexts::iterator citr; + + // reset any double buffer graphics objects + for(citr = contexts.begin(); + citr != contexts.end(); + ++citr) + { + osg::GraphicsContext* gc = (*citr); + + OpenThreads::ScopedLock lock( gc->getOperationsMutex() ); + osg::GraphicsContext::OperationQueue& operations = gc->getOperationsQueue(); + for(osg::GraphicsContext::OperationQueue::iterator oitr = operations.begin(); + oitr != operations.end(); + ++oitr) + { + ViewerDoubleBufferedRenderingOperation* vdbro = dynamic_cast(oitr->get()); + if (vdbro) + { + vdbro->release(); + } + } + + } + // delete all the graphics threads. for(Contexts::iterator itr = contexts.begin(); itr != contexts.end(); @@ -210,9 +736,34 @@ void Viewer::stopThreading() (*itr)->setGraphicsThread(0); } + // reset any double buffer graphics objects + for(citr = contexts.begin(); + citr != contexts.end(); + ++citr) + { + osg::GraphicsContext* gc = (*citr); + + OpenThreads::ScopedLock lock( gc->getOperationsMutex() ); + osg::GraphicsContext::OperationQueue& operations = gc->getOperationsQueue(); + for(osg::GraphicsContext::OperationQueue::iterator oitr = operations.begin(); + oitr != operations.end(); + ++oitr) + { + ViewerDoubleBufferedRenderingOperation* vdbro = dynamic_cast(oitr->get()); + if (vdbro) + { + vdbro->setGraphicsThreadDoesCull( true ); + vdbro->_done = false; + } + } + + } + _startRenderingBarrier = 0; _endRenderingDispatchBarrier = 0; _numThreadsOnBarrier = 0; + _endDynamicDrawBlock = 0; + osg::notify(osg::INFO)<<"Viewer::stopThreading() - stopped threading :-)"< lock( gc->getOperationsMutex() ); + osg::GraphicsContext::OperationQueue& operations = gc->getOperationsQueue(); + for(osg::GraphicsContext::OperationQueue::iterator oitr = operations.begin(); + oitr != operations.end(); + ++oitr) + { + ViewerDoubleBufferedRenderingOperation* vdbro = dynamic_cast(oitr->get()); + if (vdbro) + { + vdbro->setGraphicsThreadDoesCull( _threadingModel != ThreadPerCamera ); + vdbro->_done = false; + ++numViewerDoubleBufferedRenderingOperation; + } + } + + } if (_threadingModel==ThreadPerContext) { + _startRenderingBarrier = new osg::BarrierOperation(_numThreadsOnBarrier, osg::BarrierOperation::NO_OPERATION); + #if 1 _endRenderingDispatchBarrier = new osg::BarrierOperation(_numThreadsOnBarrier, osg::BarrierOperation::NO_OPERATION); #else _endRenderingDispatchBarrier = new osg::BarrierOperation(_numThreadsOnBarrier, osg::BarrierOperation::GL_FINISH); #endif + _endDynamicDrawBlock = 0; } - else + else if (_threadingModel==ThreadPerCamera) { - _endDynamicDrawBlock = new EndOfDynamicDrawBlock; + _startRenderingBarrier = 0; + _endRenderingDispatchBarrier = 0; + _endDynamicDrawBlock = new EndOfDynamicDrawBlock(numViewerDoubleBufferedRenderingOperation); } osg::ref_ptr swapOp = new osg::SwapBuffersOperation(); - Contexts::iterator citr = contexts.begin(); + citr = contexts.begin(); unsigned int processNum = 0; if (firstContextAsMainThread) @@ -344,7 +935,6 @@ void Viewer::startThreading() ++citr; } - for(; citr != contexts.end(); ++citr, @@ -362,7 +952,7 @@ void Viewer::startThreading() gc->getGraphicsThread()->add(new ViewerCompileOperation(getSceneData())); // add the startRenderingBarrier - gc->getGraphicsThread()->add(_startRenderingBarrier.get()); + if (_startRenderingBarrier.valid()) gc->getGraphicsThread()->add(_startRenderingBarrier.get()); // add the rendering operation itself. gc->getGraphicsThread()->add(new ViewerRunOperations()); @@ -396,11 +986,14 @@ void Viewer::startThreading() osg::GraphicsContext* gc = (*citr); if (gc->getGraphicsThread() && !gc->getGraphicsThread()->isRunning()) { - //osg::notify(osg::NOTICE)<<" gc->getGraphicsThread()->startThread() "<getGraphicsThread()<getGraphicsThread()->startThread() "<getGraphicsThread()<getGraphicsThread()->startThread(); // OpenThreads::Thread::YieldCurrentThread(); } } + + osg::notify(osg::INFO)<<"Set up threading"< QueryFrameNumberPair; - typedef std::list QueryFrameNumberList; - typedef std::vector QueryList; - - inline void checkQuery(osg::Stats* stats) - { - for(QueryFrameNumberList::iterator itr = _queryFrameNumberList.begin(); - itr != _queryFrameNumberList.end(); - ) - { - GLuint query = itr->first; - GLint available = 0; - _extensions->glGetQueryObjectiv(query, GL_QUERY_RESULT_AVAILABLE, &available); - if (available) - { - GLuint64EXT timeElapsed = 0; - _extensions->glGetQueryObjectui64v(query, GL_QUERY_RESULT, &timeElapsed); - - double timeElapsedSeconds = double(timeElapsed)*1e-9; - double currentTime = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); - double estimatedEndTime = (_previousQueryTime + currentTime) * 0.5; - double estimatedBeginTime = estimatedEndTime - timeElapsedSeconds; - - stats->setAttribute(itr->second, "GPU draw begin time", estimatedBeginTime); - stats->setAttribute(itr->second, "GPU draw end time", estimatedEndTime); - stats->setAttribute(itr->second, "GPU draw time taken", timeElapsedSeconds); - - - itr = _queryFrameNumberList.erase(itr); - _availableQueryObjects.push_back(query); - } - else - { - ++itr; - } - - } - _previousQueryTime = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); - } - - inline GLuint createQueryObject() - { - if (_availableQueryObjects.empty()) - { - GLuint query; - _extensions->glGenQueries(1, &query); - return query; - } - else - { - GLuint query = _availableQueryObjects.back(); - _availableQueryObjects.pop_back(); - return query; - } - } - - inline void beginQuery(int frameNumber) - { - GLuint query = createQueryObject(); - _extensions->glBeginQuery(GL_TIME_ELAPSED, query); - _queryFrameNumberList.push_back(QueryFrameNumberPair(query, frameNumber)); - } - - inline void endQuery() - { - _extensions->glEndQuery(GL_TIME_ELAPSED); - } - - void initialize(osg::State* state) - { - if (_initialized) return; - - _initialized = true; - _extensions = osg::Drawable::getExtensions(state->getContextID(),true); - _timerQuerySupported = _extensions && _extensions->isTimerQuerySupported(); - _previousQueryTime = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); - } - - osg::Timer_t _startTick; - bool _initialized; - bool _timerQuerySupported; - const osg::Drawable::Extensions* _extensions; - QueryFrameNumberList _queryFrameNumberList; - QueryList _availableQueryObjects; - double _previousQueryTime; - -}; - - -// Draw operation, that does a draw on the scene graph. -struct ViewerRenderingOperation : public osg::GraphicsOperation, public ViewerQuerySupport -{ - ViewerRenderingOperation(osgUtil::SceneView* sceneView, osgDB::DatabasePager* databasePager, osg::Timer_t startTick): - osg::GraphicsOperation("Render",true), - ViewerQuerySupport(startTick), - _sceneView(sceneView), - _databasePager(databasePager) - { - _sceneView->getCullVisitor()->setDatabaseRequestHandler(_databasePager.get()); - } - - virtual void operator () (osg::GraphicsContext*) - { - if (!_sceneView) return; - - // osg::notify(osg::NOTICE)<<"RenderingOperation"<getCamera()->getStats(); - osg::State* state = _sceneView->getState(); - const osg::FrameStamp* fs = state->getFrameStamp(); - int frameNumber = fs ? fs->getFrameNumber() : 0; - - if (!_initialized) - { - initialize(state); - } - - bool aquireGPUStats = stats && _timerQuerySupported && stats->collectStats("gpu"); - - if (aquireGPUStats) - { - checkQuery(stats); - } - - // do cull taversal - osg::Timer_t beforeCullTick = osg::Timer::instance()->tick(); - _sceneView->cull(); - osg::Timer_t afterCullTick = osg::Timer::instance()->tick(); - - if (state->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback()) - { - state->getDynamicObjectRenderingCompletedCallback()->completed(state); - } - - // do draw traveral - if (aquireGPUStats) - { - checkQuery(stats); - beginQuery(frameNumber); - } - - _sceneView->draw(); - - double availableTime = 0.004; // 4 ms - if (_databasePager.valid()) - { - _databasePager->compileGLObjects(*(_sceneView->getState()), availableTime); - } - _sceneView->flushDeletedGLObjects(availableTime); - - if (aquireGPUStats) - { - endQuery(); - checkQuery(stats); - } - - osg::Timer_t afterDrawTick = osg::Timer::instance()->tick(); - - if (stats && stats->collectStats("rendering")) - { - stats->setAttribute(frameNumber, "Cull traversal begin time", osg::Timer::instance()->delta_s(_startTick, beforeCullTick)); - stats->setAttribute(frameNumber, "Cull traversal end time", osg::Timer::instance()->delta_s(_startTick, afterCullTick)); - stats->setAttribute(frameNumber, "Cull traversal time taken", osg::Timer::instance()->delta_s(beforeCullTick, afterCullTick)); - - stats->setAttribute(frameNumber, "Draw traversal begin time", osg::Timer::instance()->delta_s(_startTick, afterCullTick)); - stats->setAttribute(frameNumber, "Draw traversal end time", osg::Timer::instance()->delta_s(_startTick, afterDrawTick)); - stats->setAttribute(frameNumber, "Draw traversal time taken", osg::Timer::instance()->delta_s(afterCullTick, afterDrawTick)); - } - - } - - osg::observer_ptr _sceneView; - osg::observer_ptr _databasePager; - -}; - void Viewer::setUpRenderingSupport() { - _cameraSceneViewMap.clear(); + _sceneViews.clear(); Contexts contexts; getContexts(contexts); @@ -681,40 +1086,124 @@ void Viewer::setUpRenderingSupport() osg::DisplaySettings* ds = _displaySettings.valid() ? _displaySettings.get() : osg::DisplaySettings::instance(); osgDB::DatabasePager* dp = _scene.valid() ? _scene->getDatabasePager() : 0; - for(Contexts::iterator gcitr = contexts.begin(); - gcitr != contexts.end(); - ++gcitr) + bool graphicsThreadDoesCull = _threadingModel!=ThreadPerCamera; + unsigned int numViewerDoubleBufferedRenderingOperation = 0; + + Cameras localCameras; + getCameras(localCameras); + + if (true)//(_threadingModel==ThreadPerCamera) { - (*gcitr)->removeAllOperations(); - - osg::GraphicsContext* gc = *gcitr; - osg::GraphicsContext::Cameras& cameras = gc->getCameras(); - osg::State* state = gc->getState(); - - for(osg::GraphicsContext::Cameras::iterator citr = cameras.begin(); - citr != cameras.end(); - ++citr) + for(Contexts::iterator gcitr = contexts.begin(); + gcitr != contexts.end(); + ++gcitr) { - osg::Camera* camera = *citr; - - camera->setStats(new osg::Stats("Camera")); - - osgUtil::SceneView* sceneView = new osgUtil::SceneView; - _cameraSceneViewMap[camera] = sceneView; - - sceneView->setGlobalStateSet(_camera->getStateSet()); - sceneView->setDefaults(); - sceneView->setDisplaySettings(ds); - sceneView->setCamera(camera); - sceneView->setState(state); - sceneView->setFrameStamp(frameStamp); + (*gcitr)->removeAllOperations(); + osg::GraphicsContext* gc = *gcitr; + osg::GraphicsContext::Cameras& cameras = gc->getCameras(); + osg::State* state = gc->getState(); if (dp) dp->setCompileGLObjectsForContextID(state->getContextID(), true); - gc->add(new ViewerRenderingOperation(sceneView, dp, _startTick)); - + for(osg::GraphicsContext::Cameras::iterator citr = cameras.begin(); + citr != cameras.end(); + ++citr) + { + osg::Camera* camera = *citr; + camera->setStats(new osg::Stats("Camera")); + + bool localCamera = std::find(localCameras.begin(),localCameras.end(),camera) != localCameras.end(); + if (localCamera) + { + osgUtil::SceneView* sceneViewList[2]; + + for(int i=0; i<2; ++i) + { + osgUtil::SceneView* sceneView = new osgUtil::SceneView; + + _sceneViews.push_back(sceneView); + sceneViewList[i] = sceneView; + + sceneView->setGlobalStateSet(_camera->getStateSet()); + sceneView->setDefaults(); + sceneView->setDisplaySettings(ds); + sceneView->setCamera(camera); + sceneView->setState(state); + sceneView->setFrameStamp(frameStamp); + } + + + osg::notify(osg::NOTICE)<<"localCamera"<add(vdbro); + ++numViewerDoubleBufferedRenderingOperation; + } + else + { + osg::notify(osg::NOTICE)<<"non local Camera"<setGlobalStateSet(_camera->getStateSet()); + sceneView->setDefaults(); + sceneView->setDisplaySettings(ds); + sceneView->setCamera(camera); + sceneView->setState(state); + sceneView->setFrameStamp(frameStamp); + + ViewerRenderingOperation* vro = new ViewerRenderingOperation(sceneView, dp, _startTick); + gc->add(vro); + } + + } } } + else + { + for(Contexts::iterator gcitr = contexts.begin(); + gcitr != contexts.end(); + ++gcitr) + { + (*gcitr)->removeAllOperations(); + + osg::GraphicsContext* gc = *gcitr; + osg::GraphicsContext::Cameras& cameras = gc->getCameras(); + osg::State* state = gc->getState(); + + for(osg::GraphicsContext::Cameras::iterator citr = cameras.begin(); + citr != cameras.end(); + ++citr) + { + osg::Camera* camera = *citr; + + camera->setStats(new osg::Stats("Camera")); + + osgUtil::SceneView* sceneView = new osgUtil::SceneView; + _sceneViews.push_back(sceneView); + + sceneView->setGlobalStateSet(_camera->getStateSet()); + sceneView->setDefaults(); + sceneView->setDisplaySettings(ds); + sceneView->setCamera(camera); + sceneView->setState(state); + sceneView->setFrameStamp(frameStamp); + + if (dp) dp->setCompileGLObjectsForContextID(state->getContextID(), true); + + gc->add(new ViewerRenderingOperation(sceneView, dp, _startTick)); + + ++numViewerDoubleBufferedRenderingOperation; + } + } + } + + if (_endDynamicDrawBlock.valid()) + { + _endDynamicDrawBlock->setNumOfBlocks(numViewerDoubleBufferedRenderingOperation); + } + } @@ -732,7 +1221,12 @@ void Viewer::realize() osg::notify(osg::INFO)<<"Viewer::realize() - No valid contexts found, setting up view across all screens."<getGraphicsThread())) ++numToBlock; - } - - _endDynamicDrawBlock->set(numToBlock); - } // dispatch the the rendering threads if (_startRenderingBarrier.valid()) _startRenderingBarrier->block(); + if (_endDynamicDrawBlock.valid()) + { + _endDynamicDrawBlock->reset(); + } + + // reset any double buffer graphics objects + for(itr = contexts.begin(); + itr != contexts.end(); + ++itr) + { + osg::GraphicsContext* gc = (*itr); + + OpenThreads::ScopedLock lock( gc->getOperationsMutex() ); + osg::GraphicsContext::OperationQueue& operations = gc->getOperationsQueue(); + for(osg::GraphicsContext::OperationQueue::iterator oitr = operations.begin(); + oitr != operations.end(); + ++oitr) + { + ViewerDoubleBufferedRenderingOperation* vdbro = dynamic_cast(oitr->get()); + if (vdbro) + { + if (!vdbro->getGraphicsThreadDoesCull()) + { + vdbro->cull(); + } + } + } + + } + for(itr = contexts.begin(); itr != contexts.end(); ++itr)