Began work on providing support for threading camera cull traversals in parallel with

the previous frames draw traversal.  Changes range from osg::State, through osgUtil::RenderBin, through to osgViewer
This commit is contained in:
Robert Osfield 2007-01-29 22:44:29 +00:00
parent 6835996c21
commit fd0ea388c2
18 changed files with 387 additions and 26 deletions

View File

@ -753,6 +753,47 @@ class OSG_EXPORT State : public Referenced
* if true steps should be taken to complete rendering early.*/ * if true steps should be taken to complete rendering early.*/
bool getAbortRendering() const { return _abortRenderingPtr!=0?(*_abortRenderingPtr):false; } bool getAbortRendering() const { return _abortRenderingPtr!=0?(*_abortRenderingPtr):false; }
struct DynamicObjectRenderingCompletedCallback : public osg::Referenced
{
virtual void completed(osg::State*) = 0;
};
/** Set the callback to be called when the dynamic object count hits 0.*/
void setDynamicObjectRenderingCompletedCallback(DynamicObjectRenderingCompletedCallback* cb){ _completeDynamicObjectRenderingCallback = cb; }
/** Get the callback to be called when the dynamic object count hits 0.*/
DynamicObjectRenderingCompletedCallback* getDynamicObjectRenderingCompletedCallback() { return _completeDynamicObjectRenderingCallback.get(); }
/** Set the number of dynamic objects that will be rendered in this graphics context this frame.*/
void setDynamicObjectCount(unsigned int count, bool callCallbackOnZero = false)
{
if (_dynamicObjectCount != count)
{
_dynamicObjectCount = count;
if (_dynamicObjectCount==0 && callCallbackOnZero && _completeDynamicObjectRenderingCallback.valid())
{
_completeDynamicObjectRenderingCallback->completed(this);
}
}
}
/** Get the number of dynamic objects that will be rendered in this graphics context this frame.*/
unsigned int getDynamicObjectCount() const { return _dynamicObjectCount; }
/** Decrement the number of dynamic objects left to render this frame, and once the count goes to zero call the
* DynamicObjectRenderingCompletedCallback to inform of completion.*/
inline void decrementDynamicObjectCount()
{
--_dynamicObjectCount;
if (_dynamicObjectCount==0 && _completeDynamicObjectRenderingCallback.valid())
{
_completeDynamicObjectRenderingCallback->completed(this);
}
}
enum CheckForGLErrors enum CheckForGLErrors
{ {
/** NEVER_CHECK_GL_ERRORS hints that OpenGL need not be checked for, this /** NEVER_CHECK_GL_ERRORS hints that OpenGL need not be checked for, this
@ -1028,6 +1069,9 @@ class OSG_EXPORT State : public Referenced
DisableVertexAttribProc _glDisableVertexAttribArray; DisableVertexAttribProc _glDisableVertexAttribArray;
void initializeExtensionProcs(); void initializeExtensionProcs();
unsigned int _dynamicObjectCount;
osg::ref_ptr<DynamicObjectRenderingCompletedCallback> _completeDynamicObjectRenderingCallback;
}; };
inline void State::pushModeList(ModeMap& modeMap,const StateSet::ModeList& modeList) inline void State::pushModeList(ModeMap& modeMap,const StateSet::ModeList& modeList)

View File

@ -82,6 +82,7 @@ class OSGUTIL_EXPORT Optimizer
MERGE_GEODES = 0x1000, MERGE_GEODES = 0x1000,
FLATTEN_BILLBOARDS = 0x2000, FLATTEN_BILLBOARDS = 0x2000,
TEXTURE_ATLAS_BUILDER = 0x4000, TEXTURE_ATLAS_BUILDER = 0x4000,
STATIC_OBJECT_DETECTION = 0x8000,
DEFAULT_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS | DEFAULT_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS |
REMOVE_REDUNDANT_NODES | REMOVE_REDUNDANT_NODES |
REMOVE_LOADED_PROXY_NODES | REMOVE_LOADED_PROXY_NODES |
@ -89,7 +90,8 @@ class OSGUTIL_EXPORT Optimizer
SHARE_DUPLICATE_STATE | SHARE_DUPLICATE_STATE |
MERGE_GEOMETRY | MERGE_GEOMETRY |
CHECK_GEOMETRY | CHECK_GEOMETRY |
OPTIMIZE_TEXTURE_SETTINGS, OPTIMIZE_TEXTURE_SETTINGS |
STATIC_OBJECT_DETECTION,
ALL_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS | ALL_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS |
REMOVE_REDUNDANT_NODES | REMOVE_REDUNDANT_NODES |
REMOVE_LOADED_PROXY_NODES | REMOVE_LOADED_PROXY_NODES |
@ -102,7 +104,8 @@ class OSGUTIL_EXPORT Optimizer
COPY_SHARED_NODES | COPY_SHARED_NODES |
TRISTRIP_GEOMETRY | TRISTRIP_GEOMETRY |
OPTIMIZE_TEXTURE_SETTINGS | OPTIMIZE_TEXTURE_SETTINGS |
TEXTURE_ATLAS_BUILDER TEXTURE_ATLAS_BUILDER |
STATIC_OBJECT_DETECTION
}; };
/** Reset internal data to initial state - the getPermissibleOptionsMap is cleared.*/ /** Reset internal data to initial state - the getPermissibleOptionsMap is cleared.*/
@ -740,6 +743,27 @@ class OSGUTIL_EXPORT Optimizer
}; };
/** Optimize the setting of StateSet and Geometry objects in scene so that they have a STATIC DataVariance
* when they don't have any callbacks associated with them. */
class OSGUTIL_EXPORT StaticObjectDetectionVisitor : public BaseOptimizerVisitor
{
public:
/// default to traversing all children.
StaticObjectDetectionVisitor(Optimizer* optimizer=0):
BaseOptimizerVisitor(optimizer, STATIC_OBJECT_DETECTION) {}
virtual void apply(osg::Node& node);
virtual void apply(osg::Geode& geode);
protected:
void applyStateSet(osg::StateSet& stateset);
void applyDrawable(osg::Drawable& drawable);
};
}; };
inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::StateSet* object) const inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::StateSet* object) const

View File

@ -140,6 +140,9 @@ class OSGUTIL_EXPORT RenderBin : public osg::Object
/** Extract stats for current draw list. */ /** Extract stats for current draw list. */
bool getStats(Statistics& primStats) const; bool getStats(Statistics& primStats) const;
/** Compute the number of dynamic RenderLeaves.*/
virtual unsigned int computeNumberOfDynamicRenderLeaves() const;
void copyLeavesFromStateGraphListToRenderLeafList(); void copyLeavesFromStateGraphListToRenderLeafList();

View File

@ -39,16 +39,20 @@ class OSGUTIL_EXPORT RenderLeaf : public osg::Referenced
_drawable(drawable), _drawable(drawable),
_projection(projection), _projection(projection),
_modelview(modelview), _modelview(modelview),
_depth(depth) {} _depth(depth)
{
_dynamic = (drawable->getDataVariance()==osg::Object::DYNAMIC);
}
inline void set(osg::Drawable* drawable,osg::RefMatrix* projection,osg::RefMatrix* modelview, float depth=0.0f) inline void set(osg::Drawable* drawable,osg::RefMatrix* projection,osg::RefMatrix* modelview, float depth=0.0f)
{ {
_parent = 0; _parent = 0;
_drawable = drawable; _drawable = drawable;
_projection = projection, _projection = projection,
_modelview = modelview, _modelview = modelview,
_depth = depth; _depth = depth;
_dynamic = (drawable->getDataVariance()==osg::Object::DYNAMIC);
} }
inline void reset() inline void reset()
@ -58,6 +62,7 @@ class OSGUTIL_EXPORT RenderLeaf : public osg::Referenced
_projection = 0; _projection = 0;
_modelview = 0; _modelview = 0;
_depth = 0.0f; _depth = 0.0f;
_dynamic = false;
} }
virtual void render(osg::RenderInfo& renderInfo,RenderLeaf* previous); virtual void render(osg::RenderInfo& renderInfo,RenderLeaf* previous);
@ -72,6 +77,7 @@ class OSGUTIL_EXPORT RenderLeaf : public osg::Referenced
osg::ref_ptr<osg::RefMatrix> _projection; osg::ref_ptr<osg::RefMatrix> _projection;
osg::ref_ptr<osg::RefMatrix> _modelview; osg::ref_ptr<osg::RefMatrix> _modelview;
float _depth; float _depth;
bool _dynamic;
private: private:

View File

@ -201,9 +201,10 @@ class OSGUTIL_EXPORT RenderStage : public RenderBin
/** Extract stats for current draw list. */ /** Extract stats for current draw list. */
bool getStats(Statistics& stats) const; bool getStats(Statistics& stats) const;
/** Compute the number of dynamic RenderLeaves.*/
virtual unsigned int computeNumberOfDynamicRenderLeaves() const;
struct Attachment
struct Attachment
{ {
osg::ref_ptr<osg::Image> _image; osg::ref_ptr<osg::Image> _image;
GLenum _imageReadPixelFormat; GLenum _imageReadPixelFormat;

View File

@ -58,6 +58,7 @@ class OSGUTIL_EXPORT StateGraph : public osg::Referenced
osg::ref_ptr<osg::Referenced> _userData; osg::ref_ptr<osg::Referenced> _userData;
bool _dynamic;
StateGraph(): StateGraph():
osg::Referenced(false), osg::Referenced(false),
@ -66,7 +67,8 @@ class OSGUTIL_EXPORT StateGraph : public osg::Referenced
_depth(0), _depth(0),
_averageDistance(0), _averageDistance(0),
_minimumDistance(0), _minimumDistance(0),
_userData(NULL) _userData(NULL),
_dynamic(false)
{ {
} }
@ -77,9 +79,13 @@ class OSGUTIL_EXPORT StateGraph : public osg::Referenced
_depth(0), _depth(0),
_averageDistance(0), _averageDistance(0),
_minimumDistance(0), _minimumDistance(0),
_userData(NULL) _userData(NULL),
_dynamic(false)
{ {
if (_parent) _depth = _parent->_depth + 1; if (_parent) _depth = _parent->_depth + 1;
if (_parent && _parent->_dynamic) _dynamic = true;
else _dynamic = stateset->getDataVariance()==osg::Object::DYNAMIC;
} }
~StateGraph() {} ~StateGraph() {}
@ -176,6 +182,7 @@ class OSGUTIL_EXPORT StateGraph : public osg::Referenced
_minimumDistance = FLT_MAX; // signify dirty. _minimumDistance = FLT_MAX; // signify dirty.
_leaves.push_back(leaf); _leaves.push_back(leaf);
leaf->_parent = this; leaf->_parent = this;
if (_dynamic) leaf->_dynamic = true;
} }
} }

View File

@ -25,6 +25,30 @@
namespace osgViewer { namespace osgViewer {
class OSGVIEWER_EXPORT EndOfDynamicDrawBlock : public osg::State::DynamicObjectRenderingCompletedCallback
{
public:
EndOfDynamicDrawBlock();
void completed(osg::State* state);
void block();
void release();
void set(unsigned int blockCount);
protected:
~EndOfDynamicDrawBlock();
OpenThreads::Mutex _mut;
OpenThreads::Condition _cond;
unsigned int _blockCount;
};
/** View holds a single view on a scene, this view may be composed of one or more slave cameras.*/ /** View holds a single view on a scene, this view may be composed of one or more slave cameras.*/
class OSGVIEWER_EXPORT View : public osg::View, public osgGA::GUIActionAdapter class OSGVIEWER_EXPORT View : public osg::View, public osgGA::GUIActionAdapter
{ {

View File

@ -63,6 +63,13 @@ class OSGVIEWER_EXPORT Viewer : public osgViewer::View
/** Get the threading model the rendering traversals will use.*/ /** Get the threading model the rendering traversals will use.*/
ThreadingModel getThreadingModel() const { return _threadingModel; } ThreadingModel getThreadingModel() const { return _threadingModel; }
/** Set whether the main thread, calling frame(), should be used for the rendering traversals.*/
void setUseMainThreadForRenderingTraversals(bool flag);
/** Get whether the main thread, calling frame(), should be used for the rendering traversals.*/
bool getUseMainThreadForRenderingTraversals() const { return _useMainThreadForRenderingTraversal; }
enum BarrierPosition enum BarrierPosition
{ {
BeforeSwapBuffers, BeforeSwapBuffers,
@ -148,11 +155,13 @@ class OSGVIEWER_EXPORT Viewer : public osgViewer::View
int _keyEventSetsDone; int _keyEventSetsDone;
bool _quitEventSetsDone; bool _quitEventSetsDone;
ThreadingModel _threadingModel; ThreadingModel _threadingModel;
bool _useMainThreadForRenderingTraversal;
BarrierPosition _endBarrierPosition; BarrierPosition _endBarrierPosition;
osg::ref_ptr<osg::BarrierOperation> _startRenderingBarrier; osg::ref_ptr<osg::BarrierOperation> _startRenderingBarrier;
osg::ref_ptr<osg::BarrierOperation> _endRenderingDispatchBarrier; osg::ref_ptr<osg::BarrierOperation> _endRenderingDispatchBarrier;
osg::ref_ptr<EndOfDynamicDrawBlock> _endDynamicDrawBlock;
unsigned int computeNumberOfThreadsIncludingMainRequired(); unsigned int computeNumberOfThreadsIncludingMainRequired();

View File

@ -246,6 +246,8 @@ void Drawable::flushDeletedVertexBufferObjects(unsigned int contextID,double /*c
Drawable::Drawable() Drawable::Drawable()
{ {
setDataVariance(osg::Object::STATIC);
_boundingBoxComputed = false; _boundingBoxComputed = false;
// Note, if your are defining a subclass from drawable which is // Note, if your are defining a subclass from drawable which is

View File

@ -53,6 +53,8 @@ State::State()
_glVertexAttribPointer = 0; _glVertexAttribPointer = 0;
_glEnableVertexAttribArray = 0; _glEnableVertexAttribArray = 0;
_glDisableVertexAttribArray = 0; _glDisableVertexAttribArray = 0;
_dynamicObjectCount = 0;
} }
State::~State() State::~State()

View File

@ -80,7 +80,7 @@ bool osg::isTextureMode(StateAttribute::GLMode mode)
StateSet::StateSet() StateSet::StateSet()
{ {
setDataVariance(osg::StateAttribute::STATIC); setDataVariance(osg::Object::STATIC);
_renderingHint = DEFAULT_BIN; _renderingHint = DEFAULT_BIN;

View File

@ -47,7 +47,7 @@ void Optimizer::reset()
{ {
} }
static osg::ApplicationUsageProxy Optimizer_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_OPTIMIZER \"<type> [<type>]\"","OFF | DEFAULT | FLATTEN_STATIC_TRANSFORMS | REMOVE_REDUNDANT_NODES | COMBINE_ADJACENT_LODS | SHARE_DUPLICATE_STATE | MERGE_GEOMETRY | MERGE_GEODES | SPATIALIZE_GROUPS | COPY_SHARED_NODES | TRISTRIP_GEOMETRY | OPTIMIZE_TEXTURE_SETTINGS | REMOVE_LOADED_PROXY_NODES | TESSELLATE_GEOMETRY | CHECK_GEOMETRY | FLATTEN_BILLBOARDS | TEXTURE_ATLAS_BUILDER"); static osg::ApplicationUsageProxy Optimizer_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_OPTIMIZER \"<type> [<type>]\"","OFF | DEFAULT | FLATTEN_STATIC_TRANSFORMS | REMOVE_REDUNDANT_NODES | COMBINE_ADJACENT_LODS | SHARE_DUPLICATE_STATE | MERGE_GEOMETRY | MERGE_GEODES | SPATIALIZE_GROUPS | COPY_SHARED_NODES | TRISTRIP_GEOMETRY | OPTIMIZE_TEXTURE_SETTINGS | REMOVE_LOADED_PROXY_NODES | TESSELLATE_GEOMETRY | CHECK_GEOMETRY | FLATTEN_BILLBOARDS | TEXTURE_ATLAS_BUILDER | STATIC_OBJECT_DETECTION");
void Optimizer::optimize(osg::Node* node) void Optimizer::optimize(osg::Node* node)
{ {
@ -108,6 +108,9 @@ void Optimizer::optimize(osg::Node* node)
if(str.find("~TEXTURE_ATLAS_BUILDER")!=std::string::npos) options ^= TEXTURE_ATLAS_BUILDER; if(str.find("~TEXTURE_ATLAS_BUILDER")!=std::string::npos) options ^= TEXTURE_ATLAS_BUILDER;
else if(str.find("TEXTURE_ATLAS_BUILDER")!=std::string::npos) options |= TEXTURE_ATLAS_BUILDER; else if(str.find("TEXTURE_ATLAS_BUILDER")!=std::string::npos) options |= TEXTURE_ATLAS_BUILDER;
if(str.find("~STATIC_OBJECT_DETECTION")!=std::string::npos) options ^= STATIC_OBJECT_DETECTION;
else if(str.find("STATIC_OBJECT_DETECTION")!=std::string::npos) options |= STATIC_OBJECT_DETECTION;
} }
else else
@ -299,7 +302,13 @@ void Optimizer::optimize(osg::Node* node, unsigned int options)
node->accept(sv); node->accept(sv);
sv.divide(); sv.divide();
} }
if (options & STATIC_OBJECT_DETECTION)
{
StaticObjectDetectionVisitor sodv;
node->accept(sodv);
}
if (osg::getNotifyLevel()>=osg::INFO) if (osg::getNotifyLevel()>=osg::INFO)
{ {
stats.reset(); stats.reset();
@ -4104,3 +4113,45 @@ void Optimizer::TextureAtlasVisitor::optimize()
} }
} }
////////////////////////////////////////////////////////////////////////////
// StaticObjectDectionVisitor
////////////////////////////////////////////////////////////////////////////
void Optimizer::StaticObjectDetectionVisitor::apply(osg::Node& node)
{
if (node.getStateSet()) applyStateSet(*node.getStateSet());
traverse(node);
}
void Optimizer::StaticObjectDetectionVisitor::apply(osg::Geode& geode)
{
if (geode.getStateSet()) applyStateSet(*geode.getStateSet());
for(unsigned int i=0; i<geode.getNumDrawables(); ++i)
{
applyDrawable(*geode.getDrawable(i));
}
}
void Optimizer::StaticObjectDetectionVisitor::applyStateSet(osg::StateSet& stateset)
{
stateset.setDataVariance(osg::Object::STATIC);
}
void Optimizer::StaticObjectDetectionVisitor::applyDrawable(osg::Drawable& drawable)
{
if (drawable.getStateSet()) applyStateSet(*drawable.getStateSet());
osg::Object::DataVariance dataVariance = osg::Object::STATIC;
if (drawable.getDrawCallback()) dataVariance = osg::Object::DYNAMIC;
if (drawable.getCullCallback()) dataVariance = osg::Object::DYNAMIC;
if (drawable.getDrawCallback()) dataVariance = osg::Object::DYNAMIC;
drawable.setDataVariance(dataVariance);
}

View File

@ -301,7 +301,7 @@ void RenderBin::sortBackToFront()
void RenderBin::copyLeavesFromStateGraphListToRenderLeafList() void RenderBin::copyLeavesFromStateGraphListToRenderLeafList()
{ {
// _renderLeafList.clear(); _renderLeafList.clear();
int totalsize=0; int totalsize=0;
StateGraphList::iterator itr; StateGraphList::iterator itr;
@ -509,3 +509,52 @@ bool RenderBin::getStats(Statistics& stats) const
return statsCollected; return statsCollected;
} }
unsigned int RenderBin::computeNumberOfDynamicRenderLeaves() const
{
unsigned int count = 0;
// draw first set of draw bins.
RenderBinList::const_iterator rbitr;
for(rbitr = _bins.begin();
rbitr!=_bins.end() && rbitr->first<0;
++rbitr)
{
count += rbitr->second->computeNumberOfDynamicRenderLeaves();
}
// draw fine grained ordering.
for(RenderLeafList::const_iterator rlitr= _renderLeafList.begin();
rlitr!= _renderLeafList.end();
++rlitr)
{
RenderLeaf* rl = *rlitr;
if (rl->_dynamic) ++count;
}
// draw coarse grained ordering.
for(StateGraphList::const_iterator oitr=_stateGraphList.begin();
oitr!=_stateGraphList.end();
++oitr)
{
for(StateGraph::LeafList::const_iterator dw_itr = (*oitr)->_leaves.begin();
dw_itr != (*oitr)->_leaves.end();
++dw_itr)
{
RenderLeaf* rl = dw_itr->get();
if (rl->_dynamic) ++count;
}
}
// draw post bins.
for(;
rbitr!=_bins.end();
++rbitr)
{
count += rbitr->second->computeNumberOfDynamicRenderLeaves();
}
return count;
}

View File

@ -74,5 +74,10 @@ void RenderLeaf::render(osg::RenderInfo& renderInfo,RenderLeaf* previous)
_drawable->draw(renderInfo); _drawable->draw(renderInfo);
} }
if (_dynamic)
{
state.decrementDynamicObjectCount();
}
// osg::notify(osg::NOTICE)<<"RenderLeaf "<<_drawable->getName()<<" "<<_depth<<std::endl; // osg::notify(osg::NOTICE)<<"RenderLeaf "<<_drawable->getName()<<" "<<_depth<<std::endl;
} }

View File

@ -1031,3 +1031,27 @@ void RenderStage::attach(osg::Camera::BufferComponent buffer, osg::Image* image)
{ {
_bufferAttachmentMap[buffer]._image = image; _bufferAttachmentMap[buffer]._image = image;
} }
unsigned int RenderStage::computeNumberOfDynamicRenderLeaves() const
{
unsigned int count = 0;
for(RenderStageList::const_iterator pre_itr = _preRenderList.begin();
pre_itr != _preRenderList.end();
++pre_itr)
{
count += pre_itr->second->computeNumberOfDynamicRenderLeaves();
}
count += RenderBin::computeNumberOfDynamicRenderLeaves();
for(RenderStageList::const_iterator post_itr = _postRenderList.begin();
post_itr != _postRenderList.end();
++post_itr)
{
count += post_itr->second->computeNumberOfDynamicRenderLeaves();
}
return count;
}

View File

@ -777,6 +777,11 @@ void SceneView::cullStage(const osg::Matrixd& projection,const osg::Matrixd& mod
// a clean has been used instead to try to minimize the amount of // a clean has been used instead to try to minimize the amount of
// allocation and deleteing of the StateGraph nodes. // allocation and deleteing of the StateGraph nodes.
rendergraph->prune(); rendergraph->prune();
// set the number of dynamic objects in the scene.
getState()->setDynamicObjectCount( getState()->getDynamicObjectCount() + renderStage->computeNumberOfDynamicRenderLeaves());
// osg::notify(osg::NOTICE)<<"SceneView cull() DynamicObjectCount"<<getState()->getDynamicObjectCount()<<std::endl;
} }
void SceneView::releaseAllGLObjects() void SceneView::releaseAllGLObjects()
@ -1319,6 +1324,9 @@ void SceneView::draw()
state->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE); state->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE);
} }
} }
// osg::notify(osg::NOTICE)<<"SceneView draw() DynamicObjectCount"<<getState()->getDynamicObjectCount()<<std::endl;
} }
/** Calculate, via glUnProject, the object coordinates of a window point. /** Calculate, via glUnProject, the object coordinates of a window point.

View File

@ -522,3 +522,60 @@ bool View::computeIntersections(float x,float y, osg::NodePath& nodePath, osgUti
return false; return false;
} }
} }
/////////////////////////////////////////////////////////////////////////////
//
// EndOfDynamicDrawBlock
//
EndOfDynamicDrawBlock::EndOfDynamicDrawBlock():
_blockCount(0)
{
}
void EndOfDynamicDrawBlock::completed(osg::State* state)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> mutlock(_mut);
if (_blockCount>0)
{
--_blockCount;
if (_blockCount==0)
{
// osg::notify(osg::NOTICE)<<"Released"<<std::endl;
_cond.broadcast();
}
}
}
void EndOfDynamicDrawBlock::block()
{
OpenThreads::ScopedLock<OpenThreads::Mutex> mutlock(_mut);
if (_blockCount)
_cond.wait(&_mut);
}
void EndOfDynamicDrawBlock::release()
{
OpenThreads::ScopedLock<OpenThreads::Mutex> mutlock(_mut);
if (_blockCount)
{
_blockCount = 0;
_cond.broadcast();
}
}
void EndOfDynamicDrawBlock::set(unsigned int blockCount)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> mutlock(_mut);
if (blockCount!=_blockCount)
{
if (blockCount==0) _cond.broadcast();
_blockCount = blockCount;
}
}
EndOfDynamicDrawBlock::~EndOfDynamicDrawBlock()
{
release();
}

View File

@ -170,6 +170,16 @@ void Viewer::setThreadingModel(ThreadingModel threadingModel)
if (_threadingModel!=SingleThreaded) startThreading(); if (_threadingModel!=SingleThreaded) startThreading();
} }
void Viewer::setUseMainThreadForRenderingTraversals(bool flag)
{
if (_useMainThreadForRenderingTraversal==flag) return;
if (_threadingModel!=SingleThreaded) stopThreading();
_useMainThreadForRenderingTraversal = flag;
if (_threadingModel!=SingleThreaded) startThreading();
}
void Viewer::setEndBarrierPosition(BarrierPosition bp) void Viewer::setEndBarrierPosition(BarrierPosition bp)
{ {
@ -259,12 +269,9 @@ unsigned int Viewer::computeNumberOfThreadsIncludingMainRequired()
return 1; return 1;
} }
bool firstContextAsMainThread = _threadingModel == ThreadPerContext; return _useMainThreadForRenderingTraversal ? contexts.size() : contexts.size()+1;
return firstContextAsMainThread ? contexts.size() : contexts.size()+1;
} }
void Viewer::startThreading() void Viewer::startThreading()
{ {
unsigned int numThreadsIncludingMainThread = computeNumberOfThreadsIncludingMainRequired(); unsigned int numThreadsIncludingMainThread = computeNumberOfThreadsIncludingMainRequired();
@ -310,11 +317,21 @@ void Viewer::startThreading()
_numThreadsOnBarrier = numThreadsIncludingMainThread; _numThreadsOnBarrier = numThreadsIncludingMainThread;
_startRenderingBarrier = new osg::BarrierOperation(_numThreadsOnBarrier, osg::BarrierOperation::NO_OPERATION); _startRenderingBarrier = new osg::BarrierOperation(_numThreadsOnBarrier, osg::BarrierOperation::NO_OPERATION);
#if 1
_endRenderingDispatchBarrier = new osg::BarrierOperation(_numThreadsOnBarrier, osg::BarrierOperation::NO_OPERATION);
#else if (_threadingModel==ThreadPerContext)
_endRenderingDispatchBarrier = new osg::BarrierOperation(_numThreadsOnBarrier, osg::BarrierOperation::GL_FINISH); {
#endif #if 1
_endRenderingDispatchBarrier = new osg::BarrierOperation(_numThreadsOnBarrier, osg::BarrierOperation::NO_OPERATION);
#else
_endRenderingDispatchBarrier = new osg::BarrierOperation(_numThreadsOnBarrier, osg::BarrierOperation::GL_FINISH);
#endif
}
else
{
_endDynamicDrawBlock = new EndOfDynamicDrawBlock;
}
osg::ref_ptr<osg::SwapBuffersOperation> swapOp = new osg::SwapBuffersOperation(); osg::ref_ptr<osg::SwapBuffersOperation> swapOp = new osg::SwapBuffersOperation();
Contexts::iterator citr = contexts.begin(); Contexts::iterator citr = contexts.begin();
@ -326,12 +343,15 @@ void Viewer::startThreading()
++citr; ++citr;
} }
for(; for(;
citr != contexts.end(); citr != contexts.end();
++citr, ++citr,
++processNum) ++processNum)
{ {
osg::GraphicsContext* gc = (*citr); osg::GraphicsContext* gc = (*citr);
gc->getState()->setDynamicObjectRenderingCompletedCallback(_endDynamicDrawBlock.get());
// create the a graphics thread for this context // create the a graphics thread for this context
gc->createGraphicsThread(); gc->createGraphicsThread();
@ -346,7 +366,7 @@ void Viewer::startThreading()
// add the rendering operation itself. // add the rendering operation itself.
gc->getGraphicsThread()->add(new ViewerRunOperations()); gc->getGraphicsThread()->add(new ViewerRunOperations());
if (_endBarrierPosition==BeforeSwapBuffers) if (_endBarrierPosition==BeforeSwapBuffers && _endRenderingDispatchBarrier.valid())
{ {
// add the endRenderingDispatchBarrier // add the endRenderingDispatchBarrier
gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get()); gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
@ -355,7 +375,7 @@ void Viewer::startThreading()
// add the swap buffers // add the swap buffers
gc->getGraphicsThread()->add(swapOp.get()); gc->getGraphicsThread()->add(swapOp.get());
if (_endBarrierPosition==AfterSwapBuffers) if (_endBarrierPosition==AfterSwapBuffers && _endRenderingDispatchBarrier.valid())
{ {
// add the endRenderingDispatchBarrier // add the endRenderingDispatchBarrier
gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get()); gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get());
@ -561,6 +581,10 @@ struct ViewerRenderingOperation : public osg::GraphicsOperation
_sceneView->cull(); _sceneView->cull();
osg::Timer_t afterCullTick = osg::Timer::instance()->tick(); osg::Timer_t afterCullTick = osg::Timer::instance()->tick();
if (state->getDynamicObjectCount()==0 && state->getDynamicObjectRenderingCompletedCallback())
{
state->getDynamicObjectRenderingCompletedCallback()->completed(state);
}
// do draw traveral // do draw traveral
if (_aquireGPUStats) if (_aquireGPUStats)
@ -1187,11 +1211,24 @@ void Viewer::renderingTraversals()
Contexts contexts; Contexts contexts;
getContexts(contexts); getContexts(contexts);
Contexts::iterator itr;
if (_endDynamicDrawBlock.valid())
{
unsigned int numToBlock = 0;
for(itr = contexts.begin();
itr != contexts.end();
++itr)
{
if (((*itr)->getGraphicsThread())) ++numToBlock;
}
_endDynamicDrawBlock->set(numToBlock);
}
// dispatch the the rendering threads // dispatch the the rendering threads
if (_startRenderingBarrier.valid()) _startRenderingBarrier->block(); if (_startRenderingBarrier.valid()) _startRenderingBarrier->block();
Contexts::iterator itr;
for(itr = contexts.begin(); for(itr = contexts.begin();
itr != contexts.end(); itr != contexts.end();
++itr) ++itr)
@ -1207,6 +1244,14 @@ void Viewer::renderingTraversals()
// osg::notify(osg::NOTICE)<<"Joing _endRenderingDispatchBarrier block"<<std::endl; // osg::notify(osg::NOTICE)<<"Joing _endRenderingDispatchBarrier block"<<std::endl;
// 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;;
}
// wait till the rendering dispatch is done. // wait till the rendering dispatch is done.
if (_endRenderingDispatchBarrier.valid()) _endRenderingDispatchBarrier->block(); if (_endRenderingDispatchBarrier.valid()) _endRenderingDispatchBarrier->block();