In the attached sourcefiles, I propose two changes. First, in
include/osgViewer/ViewerBase, the function releaseContext() calls
_currentContext.valid() twice in the same if-statement. It should only do so
once.
Second, and this one is a bit questionable (although it works just fine on my
systems...), in src/osgViewer/ViewerBase.cpp, in the renderingTraversals()
function, I have found that for multithreaded execution, the for-loops
containing the calls to GraphicsContext::makeCurrent() and
GraphicsContext::swapBuffers() are unnecessary. So I wrapped that entire
section of code in an if-statement that checks _threadsRunning. If I'm right,
it should provide somewhat more efficient execution.
Lastly, my submission is against the 2.6.1 Release.
Thanks,
Kyle
/* -*-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.
*/
#ifndef OSGVIEWER_VIEWERBASE
#define OSGVIEWER_VIEWERBASE 1
#include <osg/Stats>
#include <osgUtil/UpdateVisitor>
#include <osgGA/MatrixManipulator>
#include <osgGA/EventVisitor>
#include <osgGA/EventQueue>
#include <osgViewer/Scene>
#include <osgViewer/GraphicsWindow>
namespace osgViewer {
#define USE_REFERENCE_TIME DBL_MAX
class View;
/** ViewerBase is the view base class that is inherited by both Viewer and
CompositeViewer.*/
class OSGVIEWER_EXPORT ViewerBase : public virtual osg::Object
{
public:
ViewerBase();
ViewerBase(const ViewerBase& vb);
/** Set the Stats object used for collect various frame related timing
and scene graph stats.*/
void setStats(osg::Stats* stats) { _stats = stats; }
/** Get the Viewers Stats object.*/
osg::Stats* getStats() { return _stats.get(); }
/** Get the Viewers Stats object.*/
const osg::Stats* getStats() const { return _stats.get(); }
/** read the viewer configuration from a configuration file.*/
virtual bool readConfiguration(const std::string& filename) = 0;
/** Get whether at least of one of this viewers windows are realized.*/
virtual bool isRealized() const = 0;
/** set up windows and associated threads.*/
virtual void realize() = 0;
enum ThreadingModel
{
SingleThreaded,
CullDrawThreadPerContext,
ThreadPerContext = CullDrawThreadPerContext,
DrawThreadPerContext,
CullThreadPerCameraDrawThreadPerContext,
ThreadPerCamera = CullThreadPerCameraDrawThreadPerContext,
AutomaticSelection
};
/** Set the threading model the rendering traversals will use.*/
virtual void setThreadingModel(ThreadingModel threadingModel);
/** Get the threading model the rendering traversals will use.*/
ThreadingModel getThreadingModel() const { return _threadingModel; }
/** Let the viewer suggest the best threading model for the viewers
camera/window setup and the hardware available.*/
virtual ThreadingModel suggestBestThreadingModel();
/** Set up the threading and processor affinity as per the viewers
threading model.*/
virtual void setUpThreading();
/** Return true if viewer threads are running. */
bool areThreadsRunning() const { return _threadsRunning; }
/** Stop any threads begin run by viewer.*/
virtual void stopThreading();
/** Start any threads required by the viewer.*/
virtual void startThreading();
enum BarrierPosition
{
BeforeSwapBuffers,
AfterSwapBuffers
};
/** Set the position of the end barrier.
* AfterSwapBuffers may result in slightly higher framerates, but may
* lead to inconsistent swapping between different windows.
* BeforeSwapBuffers may lead to slightly lower framerate, but improve
consistency in timing of swap buffers,
* especially important if you are likely to consistently break
frame.*/
void setEndBarrierPosition(BarrierPosition bp);
/** Get the end barrier position.*/
BarrierPosition getEndBarrierPosition() const { return
_endBarrierPosition; }
/** Set the done flag to signal the viewer's work is done and should
exit the frame loop.*/
void setDone(bool done) { _done = done; }
/** Return true if viewer's work is done and should exit the frame
loop.*/
bool done() const { return _done; }
/** Set the EventVisitor. */
void setEventVisitor(osgGA::EventVisitor* eventVisitor) { _eventVisitor
= eventVisitor; }
/** Get the EventVisitor. */
osgGA::EventVisitor* getEventVisitor() { return _eventVisitor.get(); }
/** Get the const EventVisitor. */
const osgGA::EventVisitor* getEventVisitor() const { return
_eventVisitor.get(); }
/** Set the key event that the viewer checks on each frame to see if
the viewer's done flag should be set to
* signal end of viewers main loop.
* Default value is Escape (osgGA::GUIEVentAdapter::KEY_Escape).
* Setting to 0 switches off the feature.*/
void setKeyEventSetsDone(int key) { _keyEventSetsDone = key; }
/** get the key event that the viewer checks on each frame to see if
the viewer's done flag.*/
int getKeyEventSetsDone() const { return _keyEventSetsDone; }
/** if the flag is true, the viewer set its done flag when a
QUIT_APPLICATION is received, false disables this feature */
void setQuitEventSetsDone(bool flag) { _quitEventSetsDone = flag; }
/** @return true if the viewer respond to the QUIT_APPLICATION-event */
bool getQuitEventSetsDone() const { return _quitEventSetsDone; }
/** Hint to tell the renderingTraversals() method whether to call
relaseContext() on the last
* context that was made current by the thread calling
renderingTraverals(). Note, when
* running multi-threaded viewer no threads will be made current or
release current.
* Setting this hint to false can enable the frame loop to be lazy
about calling makeCurrent
* and releaseContext on each new frame, helping performance.
However, if you frame loop
* is managing multiple graphics context all from the main frame
thread then this hint must
* be left on, otherwise the wrong context could be left active,
introducing errors in rendering.*/
void setReleaseContextAtEndOfFrameHint(bool hint) {
_releaseContextAtEndOfFrameHint = hint; }
/** Hint to tell the renderingTraversals() method whether to call
relaseContext().*/
bool getReleaseContextAtEndOfFrameHint() const { return
_releaseContextAtEndOfFrameHint; }
/** Set the UpdateVisitor. */
void setUpdateVisitor(osgUtil::UpdateVisitor* updateVisitor) {
_updateVisitor = updateVisitor; }
/** Get the UpdateVisitor. */
osgUtil::UpdateVisitor* getUpdateVisitor() { return
_updateVisitor.get(); }
/** Get the const UpdateVisitor. */
const osgUtil::UpdateVisitor* getUpdateVisitor() const { return
_updateVisitor.get(); }
/** Set the Update OperationQueue. */
void setUpdateOperations(osg::OperationQueue* operations) {
_updateOperations = operations; }
/** Get the Update OperationQueue. */
osg::OperationQueue* getUpdateOperations() { return
_updateOperations.get(); }
/** Get the const Update OperationQueue. */
const osg::OperationQueue* getUpdateOperations() const { return
_updateOperations.get(); }
/** Add an update operation.*/
void addUpdateOperation(osg::Operation* operation);
/** Remove an update operation.*/
void removeUpdateOperation(osg::Operation* operation);
/** Set the graphics operation to call on realization of the viewers
graphics windows.*/
void setRealizeOperation(osg::Operation* op) { _realizeOperation = op; }
/** Get the graphics operation to call on realization of the viewers
graphics windows.*/
osg::Operation* getRealizeOperation() { return _realizeOperation.get();
}
/** Check to see if windows are still open, if not set viewer done to
true. */
void checkWindowStatus();
/** Execute a main frame loop.
* Equivalent to while (!viewer.done()) viewer.frame();
* Also calls realize() if the viewer is not already realized,
* and installs trackball manipulator if one is not already assigned.
*/
virtual int run() = 0;
/** Render a complete new frame.
* Calls advance(), eventTraversal(), updateTraversal(),
renderingTraversals(). */
virtual void frame(double simulationTime=USE_REFERENCE_TIME);
virtual void advance(double simulationTime=USE_REFERENCE_TIME) = 0;
virtual void eventTraversal() = 0;
virtual void updateTraversal() = 0;
virtual void renderingTraversals();
typedef std::vector<osg::Camera*> Cameras;
virtual void getCameras(Cameras& cameras, bool onlyActive=true) = 0;
typedef std::vector<osg::GraphicsContext*> Contexts;
virtual void getContexts(Contexts& contexts, bool onlyValid=true) = 0;
typedef std::vector<osgViewer::GraphicsWindow*> Windows;
virtual void getWindows(Windows& windows, bool onlyValid=true) = 0;
typedef std::vector<OpenThreads::Thread*> Threads;
virtual void getAllThreads(Threads& threads, bool onlyActive=true) = 0;
typedef std::vector<osg::OperationThread*> OperationThreads;
virtual void getOperationThreads(OperationThreads& threads, bool
onlyActive=true) = 0;
typedef std::vector<osgViewer::Scene*> Scenes;
virtual void getScenes(Scenes& scenes, bool onlyValid=true) = 0;
typedef std::vector<osgViewer::View*> Views;
virtual void getViews(Views& views, bool onlyValid=true) = 0;
virtual double elapsedTime() = 0;
virtual osg::FrameStamp* getViewerFrameStamp() = 0;
/** Get the keyboard and mouse usage of this viewer.*/
virtual void getUsage(osg::ApplicationUsage& usage) const = 0;
protected:
inline void makeCurrent(osg::GraphicsContext* gc)
{
if (_currentContext==gc) return;
releaseContext();
if (gc && gc->valid() && gc->makeCurrent()) _currentContext = gc;
}
inline void releaseContext()
{
if (_currentContext.valid())
{
_currentContext->releaseContext();
}
_currentContext = 0;
}
virtual void viewerInit() = 0;
osg::ref_ptr<osg::Stats> _stats;
bool _firstFrame;
bool _done;
int _keyEventSetsDone;
bool _quitEventSetsDone;
bool
_releaseContextAtEndOfFrameHint;
ThreadingModel _threadingModel;
bool _threadsRunning;
BarrierPosition _endBarrierPosition;
osg::ref_ptr<osg::BarrierOperation> _startRenderingBarrier;
osg::ref_ptr<osg::BarrierOperation>
_endRenderingDispatchBarrier;
osg::ref_ptr<osg::EndOfDynamicDrawBlock> _endDynamicDrawBlock;
osg::ref_ptr<osgGA::EventVisitor> _eventVisitor;
osg::ref_ptr<osg::OperationQueue> _updateOperations;
osg::ref_ptr<osgUtil::UpdateVisitor> _updateVisitor;
osg::ref_ptr<osg::Operation> _realizeOperation;
osg::observer_ptr<osg::GraphicsContext> _currentContext;
};
}
#endif
/* -*-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>
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.");
using namespace osgViewer;
ViewerBase::ViewerBase():
osg::Object(true)
{
_firstFrame = true;
_done = false;
_keyEventSetsDone = osgGA::GUIEventAdapter::KEY_Escape;
_quitEventSetsDone = true;
_releaseContextAtEndOfFrameHint = true;
_threadingModel = AutomaticSelection;
_threadsRunning = false;
_endBarrierPosition = AfterSwapBuffers;
}
ViewerBase::ViewerBase(const ViewerBase& base):
osg::Object(true)
{
_firstFrame = true;
_done = false;
_keyEventSetsDone = osgGA::GUIEventAdapter::KEY_Escape;
_quitEventSetsDone = true;
_releaseContextAtEndOfFrameHint = true;
_threadingModel = AutomaticSelection;
_threadsRunning = false;
_endBarrierPosition = AfterSwapBuffers;
}
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);
for(Scenes::iterator itr = scenes.begin();
itr != scenes.end();
++itr)
{
Scene* scene = *itr;
osgDB::DatabasePager* dp = scene->getDatabasePager();
if (dp)
{
for(unsigned int i=0; i<dp->getNumDatabaseThreads();
++i)
{
osgDB::DatabasePager::DatabaseThread* dt =
dp->getDatabaseThread(i);
dt->setProcessorAffinity(1);
}
}
}
}
}
}
else
{
if (!_threadsRunning) startThreading();
}
}
void ViewerBase::setEndBarrierPosition(BarrierPosition bp)
{
if (_endBarrierPosition == bp) return;
if (_threadsRunning) stopThreading();
_endBarrierPosition = bp;
if (_threadingModel!=SingleThreaded) startThreading();
}
void ViewerBase::stopThreading()
{
if (!_threadsRunning) return;
osg::notify(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::notify(osg::INFO)<<"Viewer::stopThreading() - stopped
threading."<<std::endl;
}
void ViewerBase::startThreading()
{
if (_threadsRunning) return;
osg::notify(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::notify(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::notify(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::notify(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);
++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,
osg::BarrierOperation::NO_OPERATION);
}
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::notify(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::notify(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::notify(osg::INFO)<<" gc->getGraphicsThread()->startThread()
"<<gc->getGraphicsThread()<<std::endl;
gc->getGraphicsThread()->startThread();
// OpenThreads::Thread::YieldCurrentThread();
}
}
_threadsRunning = true;
osg::notify(osg::INFO)<<"Set up threading"<<std::endl;
}
void ViewerBase::checkWindowStatus()
{
Contexts contexts;
getContexts(contexts);
// osg::notify(osg::NOTICE)<<"Viewer::checkWindowStatus() -
"<<contexts.size()<<std::endl;
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);
}
}
int ViewerBase::run()
{
if (!isRealized())
{
realize();
}
#if 0
while (!done())
{
frame();
}
#else
const char* str = getenv("OSG_RUN_FRAME_COUNT");
if (str)
{
int runTillFrameNumber = atoi(str);
while (!done() &&
getViewerFrameStamp()->getFrameNumber()<runTillFrameNumber)
{
frame();
}
}
else
{
while (!done())
{
frame();
}
}
#endif
return 0;
}
void ViewerBase::frame(double simulationTime)
{
if (_done) return;
//
osg::notify(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::notify(osg::NOTICE)<<"View "<<view<<", Master Camera
position("<<m.getTrans()<<"), rotation("<<m.getRotate()<<")"<<std::endl;
}
}
}
// check to see if windows are still valid
checkWindowStatus();
if (_done) return;
double beginRenderingTraversals = elapsedTime();
osg::FrameStamp* frameStamp = getViewerFrameStamp();
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);
}
if (scene->getSceneData())
{
// fire off a build of the bounding volumes while we
// are still running single threaded.
scene->getSceneData()->getBound();
}
}
// osg::notify(osg::NOTICE)<<std::endl<<"Start frame"<<std::endl;
Contexts contexts;
getContexts(contexts);
Cameras cameras;
getCameras(cameras);
Contexts::iterator itr;
bool doneMakeCurrentInThisThread = false;
// dispatch the the rendering threads
if (_startRenderingBarrier.valid()) _startRenderingBarrier->block();
if (_endDynamicDrawBlock.valid())
{
_endDynamicDrawBlock->reset();
}
// 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();
}
}
}
if( ! _threadsRunning)
{
for(itr = contexts.begin();
itr != contexts.end();
++itr)
{
if (_done) return;
if (!((*itr)->getGraphicsThread()) && (*itr)->valid())
{
doneMakeCurrentInThisThread = true;
makeCurrent(*itr);
(*itr)->runOperations();
}
}
// osg::notify(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();
++itr)
{
if (_done) return;
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();
}
}
// wait till the dynamic draw is complete.
if (_endDynamicDrawBlock.valid())
{
// osg::Timer_t startTick = osg::Timer::instance()->tick();
_endDynamicDrawBlock->block();
// osg::notify(osg::NOTICE)<<"Time waiting
"<<osg::Timer::instance()->delta_m(startTick,
osg::Timer::instance()->tick())<<std::endl;;
}
if (_releaseContextAtEndOfFrameHint && doneMakeCurrentInThisThread)
{
//osg::notify(osg::NOTICE)<<"Doing release context"<<std::endl;
releaseContext();
}
if (getStats() && getStats()->collectStats("update"))
{
double endRenderingTraversals = elapsedTime();
// update current frames stats
getStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering
traversals begin time ", beginRenderingTraversals);
getStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering
traversals end time ", endRenderingTraversals);
getStats()->setAttribute(frameStamp->getFrameNumber(), "Rendering
traversals time taken", endRenderingTraversals-beginRenderingTraversals);
}
}
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org