From Tim Moore, "This patch fixes a race condition in Renderer::ThreadSafeQueue that was causing some notifications of available SceneView objects to be missed. I saw a very noticeable performance problem (60 fps -> 8 fps) in DrawThreadPerContext mode in an osgEarth application before this patch. I had high hopes that this change might fix the much-discussed multiple GPU problem; no such luck, but I think the root cause of that is probably a similar threading issue."
This commit is contained in:
parent
88987d194a
commit
e4b1b6228d
@ -14,6 +14,7 @@
|
|||||||
#ifndef OSGVIEWER_RENDERER
|
#ifndef OSGVIEWER_RENDERER
|
||||||
#define OSGVIEWER_RENDERER 1
|
#define OSGVIEWER_RENDERER 1
|
||||||
|
|
||||||
|
#include <OpenThreads/Condition>
|
||||||
#include <osg/Timer>
|
#include <osg/Timer>
|
||||||
#include <osgDB/DatabasePager>
|
#include <osgDB/DatabasePager>
|
||||||
#include <osgUtil/SceneView>
|
#include <osgUtil/SceneView>
|
||||||
@ -89,20 +90,21 @@ class OSGVIEWER_EXPORT Renderer : public osg::GraphicsOperation
|
|||||||
struct OSGVIEWER_EXPORT ThreadSafeQueue
|
struct OSGVIEWER_EXPORT ThreadSafeQueue
|
||||||
{
|
{
|
||||||
OpenThreads::Mutex _mutex;
|
OpenThreads::Mutex _mutex;
|
||||||
OpenThreads::Block _block;
|
OpenThreads::Condition _cond;
|
||||||
typedef std::list<osgUtil::SceneView*> SceneViewList;
|
typedef std::list<osgUtil::SceneView*> SceneViewList;
|
||||||
SceneViewList _queue;
|
SceneViewList _queue;
|
||||||
|
bool _isReleased;
|
||||||
|
|
||||||
ThreadSafeQueue();
|
ThreadSafeQueue();
|
||||||
~ThreadSafeQueue();
|
~ThreadSafeQueue();
|
||||||
|
|
||||||
void release()
|
/** Release any thread waiting on the queue, even if the queue is empty. */
|
||||||
{
|
void release();
|
||||||
_block.release();
|
|
||||||
}
|
/** Take a SceneView from the queue. Can return 0 if release() is called when the queue is empty. */
|
||||||
|
|
||||||
osgUtil::SceneView* takeFront();
|
osgUtil::SceneView* takeFront();
|
||||||
|
|
||||||
|
/** Add a SceneView object to the back of the queue. */
|
||||||
void add(osgUtil::SceneView* sv);
|
void add(osgUtil::SceneView* sv);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -289,34 +289,53 @@ void ARBQuerySupport::checkQuery(osg::Stats* stats, osg::State* state,
|
|||||||
// ThreadSafeQueue
|
// ThreadSafeQueue
|
||||||
|
|
||||||
Renderer::ThreadSafeQueue::ThreadSafeQueue()
|
Renderer::ThreadSafeQueue::ThreadSafeQueue()
|
||||||
|
: _isReleased(false)
|
||||||
{
|
{
|
||||||
_block.set(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer::ThreadSafeQueue::~ThreadSafeQueue()
|
Renderer::ThreadSafeQueue::~ThreadSafeQueue()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::ThreadSafeQueue::release()
|
||||||
|
{
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||||
|
_isReleased = true;
|
||||||
|
_cond.broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
osgUtil::SceneView* Renderer::ThreadSafeQueue::takeFront()
|
osgUtil::SceneView* Renderer::ThreadSafeQueue::takeFront()
|
||||||
{
|
{
|
||||||
if (_queue.empty()) _block.block();
|
|
||||||
|
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||||
if (_queue.empty()) return 0;
|
// Loop in case there are spurious wakeups from the condition wait.
|
||||||
|
while (true)
|
||||||
osgUtil::SceneView* front = _queue.front();
|
{
|
||||||
_queue.pop_front();
|
// If the queue has been released but nothing is enqueued,
|
||||||
|
// just return. This prevents a deadlock when threading is
|
||||||
if (_queue.empty()) _block.set(false);
|
// restarted.
|
||||||
|
if (_isReleased)
|
||||||
return front;
|
{
|
||||||
|
if (!_queue.empty())
|
||||||
|
{
|
||||||
|
osgUtil::SceneView* front = _queue.front();
|
||||||
|
_queue.pop_front();
|
||||||
|
if (_queue.empty())
|
||||||
|
_isReleased = false;
|
||||||
|
return front;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_cond.wait(&_mutex);
|
||||||
|
}
|
||||||
|
return 0; // Can't happen
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::ThreadSafeQueue::add(osgUtil::SceneView* sv)
|
void Renderer::ThreadSafeQueue::add(osgUtil::SceneView* sv)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||||
_queue.push_back(sv);
|
_queue.push_back(sv);
|
||||||
_block.set(true);
|
_isReleased = true;
|
||||||
|
_cond.broadcast();
|
||||||
}
|
}
|
||||||
|
|
||||||
static OpenThreads::Mutex s_drawSerializerMutex;
|
static OpenThreads::Mutex s_drawSerializerMutex;
|
||||||
|
Loading…
Reference in New Issue
Block a user