OpenSceneGraph/src/osgViewer/ViewerBase.cpp
Robert Osfield bada884342 From Pjotr Svetachov, "when you restart threading
with startThreading/stopThreading the _drawQueue and _availableQueue
are not reset properly. This can lead to a deadlock when threading is
started again. So before threading is started again the queues must be
reset. This deadlock is also reported earlier by someone else in here:
http://forum.openscenegraph.org/viewtopic.php?p=43415#43415"
2013-01-23 17:38:28 +00:00

878 lines
28 KiB
C++

/* -*-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 <stdlib.h>
#include <string.h>
#include <osgViewer/ViewerBase>
#include <osgViewer/View>
#include <osgViewer/Renderer>
#include <osg/io_utils>
#include <osg/TextureCubeMap>
#include <osg/TextureRectangle>
#include <osg/TexMat>
#include <osg/DeleteHandler>
#include <osgUtil/Optimizer>
#include <osgUtil/IntersectionVisitor>
#include <osgUtil/Statistics>
static osg::ApplicationUsageProxy ViewerBase_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_CONFIG_FILE <filename>","Specify a viewer configuration file to load by default.");
static osg::ApplicationUsageProxy ViewerBase_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_THREADING <value>","Set the threading model using by Viewer, <value> can be SingleThreaded, CullDrawThreadPerContext, DrawThreadPerContext or CullThreadPerCameraDrawThreadPerContext.");
static osg::ApplicationUsageProxy ViewerBase_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_SCREEN <value>","Set the default screen that windows should open up on.");
static osg::ApplicationUsageProxy ViewerBase_e3(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_WINDOW x y width height","Set the default window dimensions that windows should open up on.");
static osg::ApplicationUsageProxy ViewerBase_e4(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_RUN_FRAME_SCHEME","Frame rate manage scheme that viewer run should use, ON_DEMAND or CONTINUOUS (default).");
static osg::ApplicationUsageProxy ViewerBase_e5(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_RUN_MAX_FRAME_RATE","Set the maximum number of frame as second that viewer run. 0.0 is default and disables an frame rate capping.");
using namespace osgViewer;
ViewerBase::ViewerBase():
osg::Object(true)
{
viewerBaseInit();
}
ViewerBase::ViewerBase(const ViewerBase&):
osg::Object(true)
{
viewerBaseInit();
}
void ViewerBase::viewerBaseInit()
{
_firstFrame = true;
_done = false;
_keyEventSetsDone = osgGA::GUIEventAdapter::KEY_Escape;
_quitEventSetsDone = true;
_releaseContextAtEndOfFrameHint = true;
_threadingModel = AutomaticSelection;
_threadsRunning = false;
_endBarrierPosition = AfterSwapBuffers;
_endBarrierOperation = osg::BarrierOperation::NO_OPERATION;
_requestRedraw = true;
_requestContinousUpdate = false;
_runFrameScheme = CONTINUOUS;
_runMaxFrameRate = 0.0f;
const char* str = getenv("OSG_RUN_FRAME_SCHEME");
if (str)
{
if (strcmp(str, "ON_DEMAND")==0) _runFrameScheme = ON_DEMAND;
else if (strcmp(str, "CONTINUOUS")==0) _runFrameScheme = CONTINUOUS;
}
str = getenv("OSG_RUN_MAX_FRAME_RATE");
if (str)
{
_runMaxFrameRate = osg::asciiToDouble(str);
}
}
void ViewerBase::setThreadingModel(ThreadingModel threadingModel)
{
if (_threadingModel == threadingModel) return;
if (_threadsRunning) stopThreading();
_threadingModel = threadingModel;
if (isRealized() && _threadingModel!=SingleThreaded) startThreading();
}
ViewerBase::ThreadingModel ViewerBase::suggestBestThreadingModel()
{
const char* str = getenv("OSG_THREADING");
if (str)
{
if (strcmp(str,"SingleThreaded")==0) return SingleThreaded;
else if (strcmp(str,"CullDrawThreadPerContext")==0) return CullDrawThreadPerContext;
else if (strcmp(str,"DrawThreadPerContext")==0) return DrawThreadPerContext;
else if (strcmp(str,"CullThreadPerCameraDrawThreadPerContext")==0) return CullThreadPerCameraDrawThreadPerContext;
}
Contexts contexts;
getContexts(contexts);
if (contexts.empty()) return SingleThreaded;
#if 0
// temporary hack to disable multi-threading under Windows till we find good solutions for
// crashes that users are seeing.
return SingleThreaded;
#endif
Cameras cameras;
getCameras(cameras);
if (cameras.empty()) return SingleThreaded;
int numProcessors = OpenThreads::GetNumberOfProcessors();
if (contexts.size()==1)
{
if (numProcessors==1) return SingleThreaded;
else return DrawThreadPerContext;
}
#if 1
if (numProcessors >= static_cast<int>(cameras.size()+contexts.size()))
{
return CullThreadPerCameraDrawThreadPerContext;
}
#endif
return DrawThreadPerContext;
}
void ViewerBase::setUpThreading()
{
Contexts contexts;
getContexts(contexts);
if (_threadingModel==SingleThreaded)
{
if (_threadsRunning) stopThreading();
else
{
// we'll set processor affinity here to help single threaded apps
// with multiple processor cores, and using the database pager.
int numProcessors = OpenThreads::GetNumberOfProcessors();
bool affinity = numProcessors>1;
if (affinity)
{
OpenThreads::SetProcessorAffinityOfCurrentThread(0);
Scenes scenes;
getScenes(scenes);
}
}
}
else
{
if (!_threadsRunning) startThreading();
}
}
void ViewerBase::setEndBarrierPosition(BarrierPosition bp)
{
if (_endBarrierPosition == bp) return;
if (_threadsRunning) stopThreading();
_endBarrierPosition = bp;
if (_threadingModel!=SingleThreaded) startThreading();
}
void ViewerBase::setEndBarrierOperation(osg::BarrierOperation::PreBlockOp op)
{
if (_endBarrierOperation == op) return;
if (_threadsRunning) stopThreading();
_endBarrierOperation = op;
if (_threadingModel!=SingleThreaded) startThreading();
}
void ViewerBase::stopThreading()
{
if (!_threadsRunning) return;
OSG_INFO<<"ViewerBase::stopThreading() - stopping threading"<<std::endl;
Contexts contexts;
getContexts(contexts);
Cameras cameras;
getCameras(cameras);
Contexts::iterator gcitr;
Cameras::iterator citr;
for(Cameras::iterator camItr = cameras.begin();
camItr != cameras.end();
++camItr)
{
osg::Camera* camera = *camItr;
Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
if (renderer) renderer->release();
}
// delete all the graphics threads.
for(gcitr = contexts.begin();
gcitr != contexts.end();
++gcitr)
{
(*gcitr)->setGraphicsThread(0);
}
// delete all the camera threads.
for(citr = cameras.begin();
citr != cameras.end();
++citr)
{
(*citr)->setCameraThread(0);
}
for(Cameras::iterator camItr = cameras.begin();
camItr != cameras.end();
++camItr)
{
osg::Camera* camera = *camItr;
Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
if (renderer)
{
renderer->setGraphicsThreadDoesCull( true );
renderer->setDone(false);
}
}
_threadsRunning = false;
_startRenderingBarrier = 0;
_endRenderingDispatchBarrier = 0;
_endDynamicDrawBlock = 0;
OSG_INFO<<"Viewer::stopThreading() - stopped threading."<<std::endl;
}
void ViewerBase::startThreading()
{
if (_threadsRunning) return;
OSG_INFO<<"Viewer::startThreading() - starting threading"<<std::endl;
// release any context held by the main thread.
releaseContext();
_threadingModel = _threadingModel==AutomaticSelection ? suggestBestThreadingModel() : _threadingModel;
Contexts contexts;
getContexts(contexts);
OSG_INFO<<"Viewer::startThreading() - contexts.size()="<<contexts.size()<<std::endl;
Cameras cameras;
getCameras(cameras);
unsigned int numThreadsOnStartBarrier = 0;
unsigned int numThreadsOnEndBarrier = 0;
switch(_threadingModel)
{
case(SingleThreaded):
numThreadsOnStartBarrier = 1;
numThreadsOnEndBarrier = 1;
return;
case(CullDrawThreadPerContext):
numThreadsOnStartBarrier = contexts.size()+1;
numThreadsOnEndBarrier = contexts.size()+1;
break;
case(DrawThreadPerContext):
numThreadsOnStartBarrier = 1;
numThreadsOnEndBarrier = 1;
break;
case(CullThreadPerCameraDrawThreadPerContext):
numThreadsOnStartBarrier = cameras.size()+1;
numThreadsOnEndBarrier = 1;
break;
default:
OSG_NOTICE<<"Error: Threading model not selected"<<std::endl;
return;
}
// using multi-threading so make sure that new objects are allocated with thread safe ref/unref
osg::Referenced::setThreadSafeReferenceCounting(true);
Scenes scenes;
getScenes(scenes);
for(Scenes::iterator scitr = scenes.begin();
scitr != scenes.end();
++scitr)
{
if ((*scitr)->getSceneData())
{
OSG_INFO<<"Making scene thread safe"<<std::endl;
// make sure that existing scene graph objects are allocated with thread safe ref/unref
(*scitr)->getSceneData()->setThreadSafeRefUnref(true);
// update the scene graph so that it has enough GL object buffer memory for the graphics contexts that will be using it.
(*scitr)->getSceneData()->resizeGLObjectBuffers(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts());
}
}
int numProcessors = OpenThreads::GetNumberOfProcessors();
bool affinity = numProcessors>1;
Contexts::iterator citr;
unsigned int numViewerDoubleBufferedRenderingOperation = 0;
bool graphicsThreadsDoesCull = _threadingModel == CullDrawThreadPerContext || _threadingModel==SingleThreaded;
for(Cameras::iterator camItr = cameras.begin();
camItr != cameras.end();
++camItr)
{
osg::Camera* camera = *camItr;
Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
if (renderer)
{
renderer->setGraphicsThreadDoesCull(graphicsThreadsDoesCull);
renderer->setDone(false);
renderer->reset();
++numViewerDoubleBufferedRenderingOperation;
}
}
if (_threadingModel==CullDrawThreadPerContext)
{
_startRenderingBarrier = 0;
_endRenderingDispatchBarrier = 0;
_endDynamicDrawBlock = 0;
}
else if (_threadingModel==DrawThreadPerContext ||
_threadingModel==CullThreadPerCameraDrawThreadPerContext)
{
_startRenderingBarrier = 0;
_endRenderingDispatchBarrier = 0;
_endDynamicDrawBlock = new osg::EndOfDynamicDrawBlock(numViewerDoubleBufferedRenderingOperation);
#ifndef OSGUTIL_RENDERBACKEND_USE_REF_PTR
if (!osg::Referenced::getDeleteHandler()) osg::Referenced::setDeleteHandler(new osg::DeleteHandler(2));
else osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(2);
#endif
}
if (numThreadsOnStartBarrier>1)
{
_startRenderingBarrier = new osg::BarrierOperation(numThreadsOnStartBarrier, osg::BarrierOperation::NO_OPERATION);
}
if (numThreadsOnEndBarrier>1)
{
_endRenderingDispatchBarrier = new osg::BarrierOperation(numThreadsOnEndBarrier, _endBarrierOperation);
}
osg::ref_ptr<osg::BarrierOperation> swapReadyBarrier = contexts.empty() ? 0 : new osg::BarrierOperation(contexts.size(), osg::BarrierOperation::NO_OPERATION);
osg::ref_ptr<osg::SwapBuffersOperation> swapOp = new osg::SwapBuffersOperation();
typedef std::map<OpenThreads::Thread*, int> ThreadAffinityMap;
ThreadAffinityMap threadAffinityMap;
unsigned int processNum = 1;
for(citr = contexts.begin();
citr != contexts.end();
++citr, ++processNum)
{
osg::GraphicsContext* gc = (*citr);
if (!gc->isRealized())
{
OSG_INFO<<"ViewerBase::startThreading() : Realizng window "<<gc<<std::endl;
gc->realize();
}
gc->getState()->setDynamicObjectRenderingCompletedCallback(_endDynamicDrawBlock.get());
// create the a graphics thread for this context
gc->createGraphicsThread();
if (affinity) gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors);
threadAffinityMap[gc->getGraphicsThread()] = processNum % numProcessors;
// add the startRenderingBarrier
if (_threadingModel==CullDrawThreadPerContext && _startRenderingBarrier.valid()) gc->getGraphicsThread()->add(_startRenderingBarrier.get());
// add the rendering operation itself.
gc->getGraphicsThread()->add(new osg::RunOperations());
if (_threadingModel==CullDrawThreadPerContext && _endBarrierPosition==BeforeSwapBuffers && _endRenderingDispatchBarrier.valid())
{
// add the endRenderingDispatchBarrier
gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
}
if (swapReadyBarrier.valid()) gc->getGraphicsThread()->add(swapReadyBarrier.get());
// add the swap buffers
gc->getGraphicsThread()->add(swapOp.get());
if (_threadingModel==CullDrawThreadPerContext && _endBarrierPosition==AfterSwapBuffers && _endRenderingDispatchBarrier.valid())
{
// add the endRenderingDispatchBarrier
gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
}
}
if (_threadingModel==CullThreadPerCameraDrawThreadPerContext && numThreadsOnStartBarrier>1)
{
Cameras::iterator camItr;
for(camItr = cameras.begin();
camItr != cameras.end();
++camItr, ++processNum)
{
osg::Camera* camera = *camItr;
camera->createCameraThread();
if (affinity) camera->getCameraThread()->setProcessorAffinity(processNum % numProcessors);
threadAffinityMap[camera->getCameraThread()] = processNum % numProcessors;
osg::GraphicsContext* gc = camera->getGraphicsContext();
// add the startRenderingBarrier
if (_startRenderingBarrier.valid()) camera->getCameraThread()->add(_startRenderingBarrier.get());
Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
renderer->setGraphicsThreadDoesCull(false);
camera->getCameraThread()->add(renderer);
if (_endRenderingDispatchBarrier.valid())
{
// add the endRenderingDispatchBarrier
gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
}
}
for(camItr = cameras.begin();
camItr != cameras.end();
++camItr)
{
osg::Camera* camera = *camItr;
if (camera->getCameraThread() && !camera->getCameraThread()->isRunning())
{
OSG_INFO<<" camera->getCameraThread()-> "<<camera->getCameraThread()<<std::endl;
camera->getCameraThread()->startThread();
}
}
}
#if 0
if (affinity)
{
OpenThreads::SetProcessorAffinityOfCurrentThread(0);
if (_scene.valid() && _scene->getDatabasePager())
{
#if 0
_scene->getDatabasePager()->setProcessorAffinity(1);
#else
_scene->getDatabasePager()->setProcessorAffinity(0);
#endif
}
}
#endif
#if 0
if (affinity)
{
for(ThreadAffinityMap::iterator titr = threadAffinityMap.begin();
titr != threadAffinityMap.end();
++titr)
{
titr->first->setProcessorAffinity(titr->second);
}
}
#endif
for(citr = contexts.begin();
citr != contexts.end();
++citr)
{
osg::GraphicsContext* gc = (*citr);
if (gc->getGraphicsThread() && !gc->getGraphicsThread()->isRunning())
{
OSG_INFO<<" gc->getGraphicsThread()->startThread() "<<gc->getGraphicsThread()<<std::endl;
gc->getGraphicsThread()->startThread();
// OpenThreads::Thread::YieldCurrentThread();
}
}
_threadsRunning = true;
OSG_INFO<<"Set up threading"<<std::endl;
}
void ViewerBase::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 ViewerBase::checkWindowStatus()
{
Contexts contexts;
getContexts(contexts);
checkWindowStatus(contexts);
}
void ViewerBase::checkWindowStatus(const Contexts& contexts)
{
if (contexts.size()==0)
{
_done = true;
if (areThreadsRunning()) stopThreading();
}
}
void ViewerBase::addUpdateOperation(osg::Operation* operation)
{
if (!operation) return;
if (!_updateOperations) _updateOperations = new osg::OperationQueue;
_updateOperations->add(operation);
}
void ViewerBase::removeUpdateOperation(osg::Operation* operation)
{
if (!operation) return;
if (_updateOperations.valid())
{
_updateOperations->remove(operation);
}
}
void ViewerBase::setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico)
{
if (_incrementalCompileOperation == ico) return;
Contexts contexts;
getContexts(contexts, false);
if (_incrementalCompileOperation.valid()) _incrementalCompileOperation->removeContexts(contexts);
// assign new operation
_incrementalCompileOperation = ico;
Scenes scenes;
getScenes(scenes,false);
for(Scenes::iterator itr = scenes.begin();
itr != scenes.end();
++itr)
{
osgDB::DatabasePager* dp = (*itr)->getDatabasePager();
dp->setIncrementalCompileOperation(ico);
}
if (_incrementalCompileOperation) _incrementalCompileOperation->assignContexts(contexts);
}
int ViewerBase::run()
{
if (!isRealized())
{
realize();
}
const char* run_frame_count_str = getenv("OSG_RUN_FRAME_COUNT");
unsigned int runTillFrameNumber = run_frame_count_str==0 ? osg::UNINITIALIZED_FRAME_NUMBER : atoi(run_frame_count_str);
while(!done() && (run_frame_count_str==0 || getViewerFrameStamp()->getFrameNumber()<runTillFrameNumber))
{
double minFrameTime = _runMaxFrameRate>0.0 ? 1.0/_runMaxFrameRate : 0.0;
osg::Timer_t startFrameTick = osg::Timer::instance()->tick();
if (_runFrameScheme==ON_DEMAND)
{
if (checkNeedToDoFrame())
{
frame();
}
else
{
// we don't need to render a frame but we don't want to spin the run loop so make sure the minimum
// loop time is 1/100th of second, if not otherwise set, so enabling the frame microSleep below to
// avoid consume excessive CPU resources.
if (minFrameTime==0.0) minFrameTime=0.01;
}
}
else
{
frame();
}
// work out if we need to force a sleep to hold back the frame rate
osg::Timer_t endFrameTick = osg::Timer::instance()->tick();
double frameTime = osg::Timer::instance()->delta_s(startFrameTick, endFrameTick);
if (frameTime < minFrameTime) OpenThreads::Thread::microSleep(static_cast<unsigned int>(1000000.0*(minFrameTime-frameTime)));
}
return 0;
}
void ViewerBase::frame(double simulationTime)
{
if (_done) return;
// OSG_NOTICE<<std::endl<<"CompositeViewer::frame()"<<std::endl<<std::endl;
if (_firstFrame)
{
viewerInit();
if (!isRealized())
{
realize();
}
_firstFrame = false;
}
advance(simulationTime);
eventTraversal();
updateTraversal();
renderingTraversals();
}
void ViewerBase::renderingTraversals()
{
bool _outputMasterCameraLocation = false;
if (_outputMasterCameraLocation)
{
Views views;
getViews(views);
for(Views::iterator itr = views.begin();
itr != views.end();
++itr)
{
osgViewer::View* view = *itr;
if (view)
{
const osg::Matrixd& m = view->getCamera()->getInverseViewMatrix();
OSG_NOTICE<<"View "<<view<<", Master Camera position("<<m.getTrans()<<"), rotation("<<m.getRotate()<<")"<<std::endl;
}
}
}
Contexts contexts;
getContexts(contexts);
// check to see if windows are still valid
checkWindowStatus(contexts);
if (_done) return;
double beginRenderingTraversals = elapsedTime();
osg::FrameStamp* frameStamp = getViewerFrameStamp();
if (getViewerStats() && getViewerStats()->collectStats("scene"))
{
unsigned int frameNumber = frameStamp ? frameStamp->getFrameNumber() : 0;
Views views;
getViews(views);
for(Views::iterator vitr = views.begin();
vitr != views.end();
++vitr)
{
View* view = *vitr;
osg::Stats* stats = view->getStats();
osg::Node* sceneRoot = view->getSceneData();
if (sceneRoot && stats)
{
osgUtil::StatsVisitor statsVisitor;
sceneRoot->accept(statsVisitor);
statsVisitor.totalUpStats();
unsigned int unique_primitives = 0;
osgUtil::Statistics::PrimitiveCountMap::iterator pcmitr;
for(pcmitr = statsVisitor._uniqueStats.GetPrimitivesBegin();
pcmitr != statsVisitor._uniqueStats.GetPrimitivesEnd();
++pcmitr)
{
unique_primitives += pcmitr->second;
}
stats->setAttribute(frameNumber, "Number of unique StateSet", static_cast<double>(statsVisitor._statesetSet.size()));
stats->setAttribute(frameNumber, "Number of unique Group", static_cast<double>(statsVisitor._groupSet.size()));
stats->setAttribute(frameNumber, "Number of unique Transform", static_cast<double>(statsVisitor._transformSet.size()));
stats->setAttribute(frameNumber, "Number of unique LOD", static_cast<double>(statsVisitor._lodSet.size()));
stats->setAttribute(frameNumber, "Number of unique Switch", static_cast<double>(statsVisitor._switchSet.size()));
stats->setAttribute(frameNumber, "Number of unique Geode", static_cast<double>(statsVisitor._geodeSet.size()));
stats->setAttribute(frameNumber, "Number of unique Drawable", static_cast<double>(statsVisitor._drawableSet.size()));
stats->setAttribute(frameNumber, "Number of unique Geometry", static_cast<double>(statsVisitor._geometrySet.size()));
stats->setAttribute(frameNumber, "Number of unique Vertices", static_cast<double>(statsVisitor._uniqueStats._vertexCount));
stats->setAttribute(frameNumber, "Number of unique Primitives", static_cast<double>(unique_primitives));
unsigned int instanced_primitives = 0;
for(pcmitr = statsVisitor._instancedStats.GetPrimitivesBegin();
pcmitr != statsVisitor._instancedStats.GetPrimitivesEnd();
++pcmitr)
{
instanced_primitives += pcmitr->second;
}
stats->setAttribute(frameNumber, "Number of instanced Stateset", static_cast<double>(statsVisitor._numInstancedStateSet));
stats->setAttribute(frameNumber, "Number of instanced Group", static_cast<double>(statsVisitor._numInstancedGroup));
stats->setAttribute(frameNumber, "Number of instanced Transform", static_cast<double>(statsVisitor._numInstancedTransform));
stats->setAttribute(frameNumber, "Number of instanced LOD", static_cast<double>(statsVisitor._numInstancedLOD));
stats->setAttribute(frameNumber, "Number of instanced Switch", static_cast<double>(statsVisitor._numInstancedSwitch));
stats->setAttribute(frameNumber, "Number of instanced Geode", static_cast<double>(statsVisitor._numInstancedGeode));
stats->setAttribute(frameNumber, "Number of instanced Drawable", static_cast<double>(statsVisitor._numInstancedDrawable));
stats->setAttribute(frameNumber, "Number of instanced Geometry", static_cast<double>(statsVisitor._numInstancedGeometry));
stats->setAttribute(frameNumber, "Number of instanced Vertices", static_cast<double>(statsVisitor._instancedStats._vertexCount));
stats->setAttribute(frameNumber, "Number of instanced Primitives", static_cast<double>(instanced_primitives));
}
}
}
Scenes scenes;
getScenes(scenes);
for(Scenes::iterator sitr = scenes.begin();
sitr != scenes.end();
++sitr)
{
Scene* scene = *sitr;
osgDB::DatabasePager* dp = scene ? scene->getDatabasePager() : 0;
if (dp) dp->signalBeginFrame(frameStamp);
osgDB::ImagePager* ip = scene ? scene->getImagePager() : 0;
if (ip) ip->signalBeginFrame(frameStamp);
if (scene->getSceneData())
{
// fire off a build of the bounding volumes while we
// are still running single threaded.
scene->getSceneData()->getBound();
}
}
// OSG_NOTICE<<std::endl<<"Start frame"<<std::endl;
Cameras cameras;
getCameras(cameras);
Contexts::iterator itr;
bool doneMakeCurrentInThisThread = false;
if (_endDynamicDrawBlock.valid())
{
_endDynamicDrawBlock->reset();
}
// dispatch the rendering threads
if (_startRenderingBarrier.valid()) _startRenderingBarrier->block();
// reset any double buffer graphics objects
for(Cameras::iterator camItr = cameras.begin();
camItr != cameras.end();
++camItr)
{
osg::Camera* camera = *camItr;
Renderer* renderer = dynamic_cast<Renderer*>(camera->getRenderer());
if (renderer)
{
if (!renderer->getGraphicsThreadDoesCull() && !(camera->getCameraThread()))
{
renderer->cull();
}
}
}
for(itr = contexts.begin();
itr != contexts.end() && !_done;
++itr)
{
if (!((*itr)->getGraphicsThread()) && (*itr)->valid())
{
doneMakeCurrentInThisThread = true;
makeCurrent(*itr);
(*itr)->runOperations();
}
}
// OSG_NOTICE<<"Joing _endRenderingDispatchBarrier block "<<_endRenderingDispatchBarrier.get()<<std::endl;
// wait till the rendering dispatch is done.
if (_endRenderingDispatchBarrier.valid()) _endRenderingDispatchBarrier->block();
for(itr = contexts.begin();
itr != contexts.end() && !_done;
++itr)
{
if (!((*itr)->getGraphicsThread()) && (*itr)->valid())
{
doneMakeCurrentInThisThread = true;
makeCurrent(*itr);
(*itr)->swapBuffers();
}
}
for(Scenes::iterator sitr = scenes.begin();
sitr != scenes.end();
++sitr)
{
Scene* scene = *sitr;
osgDB::DatabasePager* dp = scene ? scene->getDatabasePager() : 0;
if (dp) dp->signalEndFrame();
osgDB::ImagePager* ip = scene ? scene->getImagePager() : 0;
if (ip) ip->signalEndFrame();
}
// wait till the dynamic draw is complete.
if (_endDynamicDrawBlock.valid())
{
// osg::Timer_t startTick = osg::Timer::instance()->tick();
_endDynamicDrawBlock->block();
// OSG_NOTICE<<"Time waiting "<<osg::Timer::instance()->delta_m(startTick, osg::Timer::instance()->tick())<<std::endl;;
}
if (_releaseContextAtEndOfFrameHint && doneMakeCurrentInThisThread)
{
//OSG_NOTICE<<"Doing release context"<<std::endl;
releaseContext();
}
if (getViewerStats() && getViewerStats()->collectStats("update"))
{
double endRenderingTraversals = elapsedTime();
// update current frames stats
getViewerStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering traversals begin time ", beginRenderingTraversals);
getViewerStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering traversals end time ", endRenderingTraversals);
getViewerStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering traversals time taken", endRenderingTraversals-beginRenderingTraversals);
}
_requestRedraw = false;
}