/* -*-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 using namespace osgViewer; //#define DEBUG_MESSAGE osg::notify(osg::NOTICE) #define DEBUG_MESSAGE osg::notify(osg::DEBUG_FP) OpenGLQuerySupport::OpenGLQuerySupport(): _startTick(0), _initialized(false), _timerQuerySupported(false), _extensions(0), _previousQueryTime(0.0) { } void OpenGLQuerySupport::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()); } GLuint OpenGLQuerySupport::createQueryObject() { if (_availableQueryObjects.empty()) { GLuint query; _extensions->glGenQueries(1, &query); return query; } else { GLuint query = _availableQueryObjects.back(); _availableQueryObjects.pop_back(); return query; } } void OpenGLQuerySupport::beginQuery(int frameNumber) { GLuint query = createQueryObject(); _extensions->glBeginQuery(GL_TIME_ELAPSED, query); _queryFrameNumberList.push_back(QueryFrameNumberPair(query, frameNumber)); } void OpenGLQuerySupport::endQuery() { _extensions->glEndQuery(GL_TIME_ELAPSED); } void OpenGLQuerySupport::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()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // // TheadSafeQueue Renderer::TheadSafeQueue::TheadSafeQueue() { _block.set(false); } Renderer::TheadSafeQueue::~TheadSafeQueue() { } osgUtil::SceneView* Renderer::TheadSafeQueue::takeFront() { if (_queue.empty()) _block.block(); OpenThreads::ScopedLock lock(_mutex); if (_queue.empty()) return 0; osgUtil::SceneView* front = _queue.front(); _queue.pop_front(); if (_queue.empty()) _block.set(false); return front; } void Renderer::TheadSafeQueue::add(osgUtil::SceneView* sv) { OpenThreads::ScopedLock lock(_mutex); _queue.push_back(sv); _block.set(true); } static OpenThreads::Mutex s_drawSerializerMutex; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // // Renderer Renderer::Renderer(osg::Camera* camera): osg::GraphicsOperation("Renderer",true), OpenGLQuerySupport(), _camera(camera), _done(false), _graphicsThreadDoesCull(true) { DEBUG_MESSAGE<<"Render::Render() "<getView() ? _camera->getView()->getCamera() : camera; osg::StateSet* stateset = masterCamera->getOrCreateStateSet(); osgViewer::View* view = dynamic_cast(_camera->getView()); osg::DisplaySettings* ds = _camera->getDisplaySettings() ? _camera->getDisplaySettings() : ((view && view->getDisplaySettings()) ? view->getDisplaySettings() : osg::DisplaySettings::instance()); _sceneView[0]->setGlobalStateSet(stateset); _sceneView[1]->setGlobalStateSet(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()<getView() ? _camera->getView()->getCamera() : _camera.get(); osg::StateSet* stateset = masterCamera->getOrCreateStateSet(); if (sceneView->getGlobalStateSet()!=stateset) { sceneView->setGlobalStateSet(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()); osgDB::DatabasePager* databasePager = view ? view->getDatabasePager() : 0; sceneView->getCullVisitor()->setDatabaseRequestHandler(databasePager); sceneView->setFrameStamp(view ? view->getFrameStamp() : state->getFrameStamp()); if (databasePager) databasePager->setCompileGLObjectsForContextID(state->getContextID(), true); osg::DisplaySettings* ds = _camera->getDisplaySettings() ? _camera->getDisplaySettings() : ((view &&view->getDisplaySettings()) ? view->getDisplaySettings() : osg::DisplaySettings::instance()); sceneView->setDisplaySettings(ds); if (view) _startTick = view->getStartTick(); } 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(); 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::notify(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)); } _drawQueue.add(sceneView); } DEBUG_MESSAGE<<"end cull() "<tick(); osgUtil::SceneView* sceneView = _drawQueue.takeFront(); DEBUG_MESSAGE<<"draw() got SceneView "<getState()->getContextID()) : 0; osg::GraphicsThread* compileThread = compileContext ? compileContext->getGraphicsThread() : 0; if (sceneView || _done) { osgViewer::View* view = dynamic_cast(_camera->getView()); osgDB::DatabasePager* databasePager = view ? view->getDatabasePager() : 0; // osg::notify(osg::NOTICE)<<"Drawing buffer "<<_currentDraw<getCamera()->getStats(); osg::State* state = sceneView->getState(); int frameNumber = state->getFrameStamp()->getFrameNumber(); if (!_initialized) { initialize(state); } state->setDynamicObjectCount(sceneView->getDynamicObjectCount()); if (sceneView->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback()) { // osg::notify(osg::NOTICE)<<"Completed in cull"<getDynamicObjectRenderingCompletedCallback()->completed(state); } bool acquireGPUStats = stats && _timerQuerySupported && stats->collectStats("gpu"); if (acquireGPUStats) { checkQuery(stats); } // do draw traversal if (acquireGPUStats) { checkQuery(stats); beginQuery(frameNumber); } 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); double availableTime = 0.004; // 4 ms if (databasePager && databasePager->requiresExternalCompileGLObjects(sceneView->getState()->getContextID())) { databasePager->compileGLObjects(*(sceneView->getState()), availableTime); } if (compileThread) { compileThread->add(_flushOperation.get()); } else { sceneView->flushDeletedGLObjects(availableTime); } if (acquireGPUStats) { endQuery(); checkQuery(stats); } //glFlush(); osg::Timer_t afterDrawTick = osg::Timer::instance()->tick(); // osg::notify(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)); } } DEBUG_MESSAGE<<"end draw() "<(_camera->getView()); osgDB::DatabasePager* databasePager = view ? view->getDatabasePager() : 0; osg::GraphicsContext* compileContext = osg::GraphicsContext::getCompileContext(sceneView->getState()->getContextID()); osg::GraphicsThread* compileThread = compileContext ? compileContext->getGraphicsThread() : 0; if (_done) { osg::notify(osg::INFO)<<"Render::release() causing cull_draw to exit"<setFusionDistance(view->getFusionDistanceMode(), view->getFusionDistanceValue()); osg::Stats* stats = sceneView->getCamera()->getStats(); osg::State* state = sceneView->getState(); const osg::FrameStamp* fs = state->getFrameStamp(); int frameNumber = fs ? fs->getFrameNumber() : 0; if (!_initialized) { initialize(state); } bool acquireGPUStats = stats && _timerQuerySupported && stats->collectStats("gpu"); if (acquireGPUStats) { checkQuery(stats); } // 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 (state->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback()) { state->getDynamicObjectRenderingCompletedCallback()->completed(state); } #endif // do draw traversal if (acquireGPUStats) { checkQuery(stats); beginQuery(frameNumber); } 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(); } double availableTime = 0.004; // 4 ms if (databasePager && databasePager->requiresExternalCompileGLObjects(sceneView->getState()->getContextID())) { databasePager->compileGLObjects(*(sceneView->getState()), availableTime); } if (compileThread) { compileThread->add(_flushOperation.get()); } else { sceneView->flushDeletedGLObjects(availableTime); } if (acquireGPUStats) { endQuery(); checkQuery(stats); } 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::notify(osg::INFO)<<"Renderer::release()"<