/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include using namespace osgViewer; //#define DEBUG_MESSAGE OSG_NOTICE #define DEBUG_MESSAGE OSG_DEBUG OpenGLQuerySupport::OpenGLQuerySupport(): _extensions(0) { } class OSGVIEWER_EXPORT EXTQuerySupport : public OpenGLQuerySupport { public: EXTQuerySupport(); void checkQuery(osg::Stats* stats, osg::State* state, osg::Timer_t startTick); virtual void beginQuery(unsigned int frameNumber, osg::State* state); virtual void endQuery(osg::State* state); virtual void initialize(osg::State* state, osg::Timer_t startTick); protected: GLuint createQueryObject(); typedef std::pair QueryFrameNumberPair; typedef std::list QueryFrameNumberList; typedef std::vector QueryList; QueryFrameNumberList _queryFrameNumberList; QueryList _availableQueryObjects; double _previousQueryTime; }; EXTQuerySupport::EXTQuerySupport(): _previousQueryTime(0.0) { } void EXTQuerySupport::checkQuery(osg::Stats* stats, osg::State* state, osg::Timer_t startTick) { 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()); } GLuint EXTQuerySupport::createQueryObject() { if (_availableQueryObjects.empty()) { GLuint query; _extensions->glGenQueries(1, &query); return query; } else { GLuint query = _availableQueryObjects.back(); _availableQueryObjects.pop_back(); return query; } } void EXTQuerySupport::beginQuery(unsigned int frameNumber, osg::State* state) { GLuint query = createQueryObject(); _extensions->glBeginQuery(GL_TIME_ELAPSED, query); _queryFrameNumberList.push_back(QueryFrameNumberPair(query, frameNumber)); } void EXTQuerySupport::endQuery(osg::State* state) { _extensions->glEndQuery(GL_TIME_ELAPSED); } void OpenGLQuerySupport::initialize(osg::State* state, osg::Timer_t startTick) { _extensions = osg::Drawable::getExtensions(state->getContextID(),true); } void EXTQuerySupport::initialize(osg::State* state, osg::Timer_t startTick) { OpenGLQuerySupport::initialize(state, startTick); _previousQueryTime = osg::Timer::instance()->delta_s(startTick, osg::Timer::instance()->tick()); } class ARBQuerySupport : public OpenGLQuerySupport { public: virtual void checkQuery(osg::Stats* stats, osg::State* state, osg::Timer_t startTick); virtual void beginQuery(unsigned int frameNumber, osg::State* state); virtual void endQuery(osg::State* state); virtual void initialize(osg::State* state, osg::Timer_t startTick); protected: typedef std::pair QueryPair; struct ActiveQuery { ActiveQuery() : queries(0, 0), frameNumber(0) {} ActiveQuery(GLuint start_, GLuint end_, int frameNumber_) : queries(start_, end_), frameNumber(frameNumber_) { } ActiveQuery(const QueryPair& queries_, unsigned int frameNumber_) : queries(queries_), frameNumber(frameNumber_) { } QueryPair queries; unsigned int frameNumber; }; typedef std::list QueryFrameList; typedef std::vector QueryList; QueryFrameList _queryFrameList; QueryList _availableQueryObjects; }; void ARBQuerySupport::initialize(osg::State* state, osg::Timer_t startTick) { OpenGLQuerySupport::initialize(state, startTick); } void ARBQuerySupport::beginQuery(unsigned int frameNumber, osg::State* state) { QueryPair query; if (_availableQueryObjects.empty()) { _extensions->glGenQueries(1, &query.first); _extensions->glGenQueries(1, &query.second); } else { query = _availableQueryObjects.back(); _availableQueryObjects.pop_back(); } _extensions->glQueryCounter(query.first, GL_TIMESTAMP); _queryFrameList.push_back(ActiveQuery(query, frameNumber)); } void ARBQuerySupport::endQuery(osg::State* state) { _extensions->glQueryCounter(_queryFrameList.back().queries.second, GL_TIMESTAMP); } void ARBQuerySupport::checkQuery(osg::Stats* stats, osg::State* state, osg::Timer_t startTick) { for(QueryFrameList::iterator itr = _queryFrameList.begin(); itr != _queryFrameList.end(); ) { GLint available = 0; // If the end query is available, the begin query must be too. _extensions->glGetQueryObjectiv(itr->queries.second, GL_QUERY_RESULT_AVAILABLE, &available); if (available) { QueryPair queries = itr->queries; GLuint64EXT beginTimestamp = 0; GLuint64EXT endTimestamp = 0; _extensions->glGetQueryObjectui64v(queries.first, GL_QUERY_RESULT, &beginTimestamp); _extensions->glGetQueryObjectui64v(queries.second, GL_QUERY_RESULT, &endTimestamp); GLuint64EXT gpuTimestamp = state->getGpuTimestamp(); // Have any of the timestamps wrapped around? int tbits = state->getTimestampBits(); if (tbits < 64) { // If the high bits on any of the timestamp bits are // different then the counters may have wrapped. const int hiShift = (tbits - 1); const GLuint64EXT hiMask = 1 << hiShift; const GLuint64EXT sum = (beginTimestamp >> hiShift) + (endTimestamp >> hiShift) + (gpuTimestamp >> hiShift); if (sum == 1 || sum == 2) { const GLuint64EXT wrapAdd = 1 << tbits; // Counter wrapped between begin and end? if (beginTimestamp > endTimestamp) { endTimestamp += wrapAdd; } else if (gpuTimestamp < beginTimestamp && beginTimestamp - gpuTimestamp > (hiMask >> 1)) { gpuTimestamp += wrapAdd; } else if (endTimestamp < gpuTimestamp && gpuTimestamp - endTimestamp > (hiMask >> 1)) { beginTimestamp += wrapAdd; endTimestamp += wrapAdd; } } } GLuint64EXT timeElapsed = endTimestamp - beginTimestamp; double timeElapsedSeconds = double(timeElapsed)*1e-9; double gpuTick = state->getGpuTime(); double beginTime = 0.0; double endTime = 0.0; if (beginTimestamp > gpuTimestamp) beginTime = gpuTick + double(beginTimestamp - gpuTimestamp) * 1e-9; else beginTime = gpuTick - double(gpuTimestamp - beginTimestamp) * 1e-9; if (endTimestamp > gpuTimestamp) endTime = gpuTick + double(endTimestamp - gpuTimestamp) * 1e-9; else endTime = gpuTick - double(gpuTimestamp - endTimestamp) * 1e-9; stats->setAttribute(itr->frameNumber, "GPU draw begin time", beginTime); stats->setAttribute(itr->frameNumber, "GPU draw end time", endTime); stats->setAttribute(itr->frameNumber, "GPU draw time taken", timeElapsedSeconds); itr = _queryFrameList.erase(itr); _availableQueryObjects.push_back(queries); } else { ++itr; } } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // // ThreadSafeQueue Renderer::ThreadSafeQueue::ThreadSafeQueue() : _isReleased(false) { } Renderer::ThreadSafeQueue::~ThreadSafeQueue() { } void Renderer::ThreadSafeQueue::release() { OpenThreads::ScopedLock lock(_mutex); _isReleased = true; _cond.broadcast(); } osgUtil::SceneView* Renderer::ThreadSafeQueue::takeFront() { OpenThreads::ScopedLock lock(_mutex); // Loop in case there are spurious wakeups from the condition wait. while (true) { // If the queue has been released but nothing is enqueued, // just return. This prevents a deadlock when threading is // restarted. if (_isReleased) { if (!_queue.empty()) { osgUtil::SceneView* front = _queue.front(); _queue.pop_front(); if (_queue.empty()) _isReleased = false; return front; } return 0; } _cond.wait(&_mutex); } return 0; // Can't happen } void Renderer::ThreadSafeQueue::add(osgUtil::SceneView* sv) { OpenThreads::ScopedLock lock(_mutex); _queue.push_back(sv); _isReleased = true; _cond.broadcast(); } static OpenThreads::Mutex s_drawSerializerMutex; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // // Renderer Renderer::Renderer(osg::Camera* camera): osg::GraphicsOperation("Renderer",true), _camera(camera), _done(false), _graphicsThreadDoesCull(true), _compileOnNextDraw(true), _initialized(false), _startTick(0) { DEBUG_MESSAGE<<"Render::Render() "<getView() ? _camera->getView()->getCamera() : camera; osg::StateSet* global_stateset = 0; osg::StateSet* secondary_stateset = 0; if (_camera != masterCamera) { global_stateset = masterCamera->getOrCreateStateSet(); secondary_stateset = _camera->getStateSet(); } else { global_stateset = _camera->getOrCreateStateSet(); } osgViewer::View* view = dynamic_cast(_camera->getView()); osgViewer::ViewerBase* viewer = view ? view->getViewerBase() : 0; osgUtil::IncrementalCompileOperation* ico = viewer ? viewer->getIncrementalCompileOperation() : 0; bool automaticFlush = (ico==NULL); osg::DisplaySettings* ds = _camera->getDisplaySettings() ? _camera->getDisplaySettings() : ((view && view->getDisplaySettings()) ? view->getDisplaySettings() : osg::DisplaySettings::instance().get()); unsigned int sceneViewOptions = osgUtil::SceneView::HEADLIGHT; if (view) { switch(view->getLightingMode()) { case(osg::View::NO_LIGHT): sceneViewOptions = 0; break; case(osg::View::SKY_LIGHT): sceneViewOptions = osgUtil::SceneView::SKY_LIGHT; break; case(osg::View::HEADLIGHT): sceneViewOptions = osgUtil::SceneView::HEADLIGHT; break; } } _sceneView[0]->setAutomaticFlush(automaticFlush); _sceneView[0]->setGlobalStateSet(global_stateset); _sceneView[0]->setSecondaryStateSet(secondary_stateset); _sceneView[1]->setAutomaticFlush(automaticFlush); _sceneView[1]->setGlobalStateSet(global_stateset); _sceneView[1]->setSecondaryStateSet(secondary_stateset); _sceneView[0]->setDefaults(sceneViewOptions); _sceneView[1]->setDefaults(sceneViewOptions); _sceneView[0]->setDisplaySettings(ds); _sceneView[1]->setDisplaySettings(ds); _sceneView[0]->setCamera(_camera.get(), false); _sceneView[1]->setCamera(_camera.get(), false); // lock the mutex for the current cull SceneView to // prevent the draw traversal from reading from it before the cull traversal has been completed. _availableQueue.add(_sceneView[0].get()); _availableQueue.add(_sceneView[1].get()); DEBUG_MESSAGE<<"_availableQueue.size()="<<_availableQueue._queue.size()<getContextID(), true); if (ext->isARBTimerQuerySupported() && state->getTimestampBits() > 0) _querySupport = new ARBQuerySupport(); else if (ext->isTimerQuerySupported()) _querySupport = new EXTQuerySupport(); if (_querySupport.valid()) _querySupport->initialize(state, _startTick); } } void Renderer::setGraphicsThreadDoesCull(bool flag) { if (_graphicsThreadDoesCull==flag) return; _graphicsThreadDoesCull = flag; } void Renderer::updateSceneView(osgUtil::SceneView* sceneView) { osg::Camera* masterCamera = _camera->getView() ? _camera->getView()->getCamera() : _camera.get(); osg::StateSet* global_stateset = 0; osg::StateSet* secondary_stateset = 0; if (_camera != masterCamera) { global_stateset = masterCamera->getOrCreateStateSet(); secondary_stateset = _camera->getStateSet(); } else { global_stateset = _camera->getOrCreateStateSet(); } if (sceneView->getGlobalStateSet()!=global_stateset) { sceneView->setGlobalStateSet(global_stateset); } if (sceneView->getSecondaryStateSet()!=secondary_stateset) { sceneView->setSecondaryStateSet(secondary_stateset); } osg::GraphicsContext* context = _camera->getGraphicsContext(); osg::State* state = context ? context->getState() : 0; if (sceneView->getState()!=state) { sceneView->setState(state); } osgViewer::View* view = dynamic_cast(_camera->getView()); osgViewer::ViewerBase* viewer = view ? view->getViewerBase() : 0; osgUtil::IncrementalCompileOperation* ico = viewer ? viewer->getIncrementalCompileOperation() : 0; bool automaticFlush = (ico==NULL); sceneView->setAutomaticFlush(automaticFlush); osgDB::DatabasePager* databasePager = view ? view->getDatabasePager() : 0; sceneView->getCullVisitor()->setDatabaseRequestHandler(databasePager); osgDB::ImagePager* imagePager = view ? view->getImagePager() : 0; sceneView->getCullVisitor()->setImageRequestHandler(imagePager); sceneView->setFrameStamp(view ? view->getFrameStamp() : state->getFrameStamp()); osg::DisplaySettings* ds = _camera->getDisplaySettings() ? _camera->getDisplaySettings() : ((view &&view->getDisplaySettings()) ? view->getDisplaySettings() : osg::DisplaySettings::instance().get()); sceneView->setDisplaySettings(ds); if (view) { _startTick = view->getStartTick(); if (state) state->setStartTick(_startTick); } } void Renderer::compile() { DEBUG_MESSAGE<<"Renderer::compile()"<getState()->checkGLErrors("Before Renderer::compile"); if (sceneView->getSceneData()) { osgUtil::GLObjectsVisitor glov; glov.setState(sceneView->getState()); sceneView->getSceneData()->accept(glov); } sceneView->getState()->checkGLErrors("After Renderer::compile"); } void Renderer::cull() { DEBUG_MESSAGE<<"cull()"<(sceneView->getCamera()->getView()); if (view) sceneView->setFusionDistance(view->getFusionDistanceMode(), view->getFusionDistanceValue()); osg::Stats* stats = sceneView->getCamera()->getStats(); osg::State* state = sceneView->getState(); const osg::FrameStamp* fs = state->getFrameStamp(); unsigned int frameNumber = fs ? fs->getFrameNumber() : 0; // do cull traversal osg::Timer_t beforeCullTick = osg::Timer::instance()->tick(); sceneView->inheritCullSettings(*(sceneView->getCamera())); sceneView->cull(); osg::Timer_t afterCullTick = osg::Timer::instance()->tick(); #if 0 if (sceneView->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback()) { // OSG_NOTICE<<"Completed in cull"<getDynamicObjectRenderingCompletedCallback()->completed(state); } #endif if (stats && stats->collectStats("rendering")) { DEBUG_MESSAGE<<"Collecting 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)); } if (stats && stats->collectStats("scene")) { osgUtil::Statistics sceneStats; sceneView->getStats(sceneStats); stats->setAttribute(frameNumber, "Visible vertex count", static_cast(sceneStats._vertexCount)); stats->setAttribute(frameNumber, "Visible number of drawables", static_cast(sceneStats.numDrawables)); stats->setAttribute(frameNumber, "Visible number of fast drawables", static_cast(sceneStats.numFastDrawables)); stats->setAttribute(frameNumber, "Visible number of lights", static_cast(sceneStats.nlights)); stats->setAttribute(frameNumber, "Visible number of render bins", static_cast(sceneStats.nbins)); stats->setAttribute(frameNumber, "Visible depth", static_cast(sceneStats.depth)); stats->setAttribute(frameNumber, "Number of StateGraphs", static_cast(sceneStats.numStateGraphs)); stats->setAttribute(frameNumber, "Visible number of impostors", static_cast(sceneStats.nimpostor)); stats->setAttribute(frameNumber, "Number of ordered leaves", static_cast(sceneStats.numOrderedLeaves)); unsigned int totalNumPrimitiveSets = 0; const osgUtil::Statistics::PrimitiveValueMap& pvm = sceneStats.getPrimitiveValueMap(); for(osgUtil::Statistics::PrimitiveValueMap::const_iterator pvm_itr = pvm.begin(); pvm_itr != pvm.end(); ++pvm_itr) { totalNumPrimitiveSets += pvm_itr->second.first; } stats->setAttribute(frameNumber, "Visible number of PrimitiveSets", static_cast(totalNumPrimitiveSets)); osgUtil::Statistics::PrimitiveCountMap& pcm = sceneStats.getPrimitiveCountMap(); stats->setAttribute(frameNumber, "Visible number of GL_POINTS", static_cast(pcm[GL_POINTS])); stats->setAttribute(frameNumber, "Visible number of GL_LINES", static_cast(pcm[GL_LINES])); stats->setAttribute(frameNumber, "Visible number of GL_LINE_STRIP", static_cast(pcm[GL_LINE_STRIP])); stats->setAttribute(frameNumber, "Visible number of GL_LINE_LOOP", static_cast(pcm[GL_LINE_LOOP])); stats->setAttribute(frameNumber, "Visible number of GL_TRIANGLES", static_cast(pcm[GL_TRIANGLES])); stats->setAttribute(frameNumber, "Visible number of GL_TRIANGLE_STRIP", static_cast(pcm[GL_TRIANGLE_STRIP])); stats->setAttribute(frameNumber, "Visible number of GL_TRIANGLE_FAN", static_cast(pcm[GL_TRIANGLE_FAN])); stats->setAttribute(frameNumber, "Visible number of GL_QUADS", static_cast(pcm[GL_QUADS])); stats->setAttribute(frameNumber, "Visible number of GL_QUAD_STRIP", static_cast(pcm[GL_QUAD_STRIP])); stats->setAttribute(frameNumber, "Visible number of GL_POLYGON", static_cast(pcm[GL_POLYGON])); } _drawQueue.add(sceneView); } DEBUG_MESSAGE<<"end cull() "<tick(); osgUtil::SceneView* sceneView = _drawQueue.takeFront(); DEBUG_MESSAGE<<"draw() got SceneView "<collateReferencesToDependentCameras(); if (_compileOnNextDraw) { compile(); } // OSG_NOTICE<<"Drawing buffer "<<_currentDraw<getCamera()->getStats(); osg::State* state = sceneView->getState(); unsigned int frameNumber = state->getFrameStamp()->getFrameNumber(); if (!_initialized) { initialize(state); } state->setDynamicObjectCount(sceneView->getDynamicObjectCount()); if (sceneView->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback()) { // OSG_NOTICE<<"Completed in cull"<getDynamicObjectRenderingCompletedCallback()->completed(state); } bool acquireGPUStats = stats && _querySupport && stats->collectStats("gpu"); if (acquireGPUStats) { _querySupport->checkQuery(stats, state, _startTick); } // do draw traversal if (acquireGPUStats) { _querySupport->checkQuery(stats, state, _startTick); _querySupport->beginQuery(frameNumber, state); } osg::Timer_t beforeDrawTick; bool serializeDraw = sceneView->getDisplaySettings()->getSerializeDrawDispatch(); if (serializeDraw) { OpenThreads::ScopedLock lock(s_drawSerializerMutex); beforeDrawTick = osg::Timer::instance()->tick(); sceneView->draw(); } else { beforeDrawTick = osg::Timer::instance()->tick(); sceneView->draw(); } _availableQueue.add(sceneView); if (acquireGPUStats) { _querySupport->endQuery(state); _querySupport->checkQuery(stats, state, _startTick); } //glFlush(); osg::Timer_t afterDrawTick = osg::Timer::instance()->tick(); // OSG_NOTICE<<"Time wait for draw = "<delta_m(startDrawTick, beforeDrawTick)<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)); } sceneView->clearReferencesToDependentCameras(); } DEBUG_MESSAGE<<"end draw() "<(_camera->getView()); // OSG_NOTICE<<"RenderingOperation"<setFusionDistance(view->getFusionDistanceMode(), view->getFusionDistanceValue()); osg::Stats* stats = sceneView->getCamera()->getStats(); osg::State* state = sceneView->getState(); const osg::FrameStamp* fs = state->getFrameStamp(); unsigned int frameNumber = fs ? fs->getFrameNumber() : 0; if (!_initialized) { initialize(state); } bool acquireGPUStats = stats && _querySupport && stats->collectStats("gpu"); if (acquireGPUStats) { _querySupport->checkQuery(stats, state, _startTick); } // do cull traversal osg::Timer_t beforeCullTick = osg::Timer::instance()->tick(); sceneView->inheritCullSettings(*(sceneView->getCamera())); sceneView->cull(); osg::Timer_t afterCullTick = osg::Timer::instance()->tick(); if (stats && stats->collectStats("scene")) { osgUtil::Statistics sceneStats; sceneView->getStats(sceneStats); stats->setAttribute(frameNumber, "Visible vertex count", static_cast(sceneStats._vertexCount)); stats->setAttribute(frameNumber, "Visible number of drawables", static_cast(sceneStats.numDrawables)); stats->setAttribute(frameNumber, "Visible number of lights", static_cast(sceneStats.nlights)); stats->setAttribute(frameNumber, "Visible number of render bins", static_cast(sceneStats.nbins)); stats->setAttribute(frameNumber, "Visible depth", static_cast(sceneStats.depth)); stats->setAttribute(frameNumber, "Number of StateGraphs", static_cast(sceneStats.numStateGraphs)); stats->setAttribute(frameNumber, "Visible number of impostors", static_cast(sceneStats.nimpostor)); stats->setAttribute(frameNumber, "Number of ordered leaves", static_cast(sceneStats.numOrderedLeaves)); } #if 0 if (state->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback()) { state->getDynamicObjectRenderingCompletedCallback()->completed(state); } #endif // do draw traversal if (acquireGPUStats) { _querySupport->checkQuery(stats, state, _startTick); _querySupport->beginQuery(frameNumber, state); } osg::Timer_t beforeDrawTick; bool serializeDraw = sceneView->getDisplaySettings()->getSerializeDrawDispatch(); if (serializeDraw) { OpenThreads::ScopedLock lock(s_drawSerializerMutex); beforeDrawTick = osg::Timer::instance()->tick(); sceneView->draw(); } else { beforeDrawTick = osg::Timer::instance()->tick(); sceneView->draw(); } if (acquireGPUStats) { _querySupport->endQuery(state); _querySupport->checkQuery(stats, state, _startTick); } osg::Timer_t afterDrawTick = osg::Timer::instance()->tick(); if (stats && stats->collectStats("rendering")) { DEBUG_MESSAGE<<"Collecting 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, 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)); } DEBUG_MESSAGE<<"end cull_draw() "<(object); if (context) operator()(context); osg::Camera* camera = dynamic_cast(object); if (camera) cull(); } void Renderer::operator () (osg::GraphicsContext* context) { if (_graphicsThreadDoesCull) { cull_draw(); } else { draw(); } } void Renderer::release() { OSG_INFO<<"Renderer::release()"<getRenderStage() : 0; if (rs) rs->setCameraRequiresSetUp(flag); } } bool Renderer::getCameraRequiresSetUp() const { bool result = false; for (int i = 0; i < 2; ++i) { const osgUtil::SceneView* sv = getSceneView(i); const osgUtil::RenderStage* rs = sv ? sv->getRenderStage() : 0; if (rs) result = result || rs->getCameraRequiresSetUp(); } return result; }