From: Alberto Luaces <aluaces@udc.es>
Date: Wed, 21 Sep 2016 20:51:59 +0200
Subject: Occlusion Queries Stuttering fix from upstream.

---
 include/osg/OcclusionQueryNode |   4 +-
 src/osg/OcclusionQueryNode.cpp | 105 +++++++++++++++++++++++------------------
 2 files changed, 60 insertions(+), 49 deletions(-)

diff --git a/include/osg/OcclusionQueryNode b/include/osg/OcclusionQueryNode
index 07285f8..2b68e4c 100644
--- a/include/osg/OcclusionQueryNode
+++ b/include/osg/OcclusionQueryNode
@@ -40,7 +40,7 @@ osg::StateSet* initOQDebugState();
 class TestResult : public osg::Referenced
 {
 public:
-    TestResult() : _init( false ), _id( 0 ), _contextID( 0 ), _active( false ), _numPixels( 0 ) {}
+    TestResult() : _init( false ), _id( 0 ), _contextID( 0 ), _active( false ), _numPixels( 0 ) {setThreadSafeRefUnref(true);}
     ~TestResult() {}
 
     bool _init;
@@ -81,7 +81,7 @@ public:
     static void discardDeletedQueryObjects( unsigned int contextID );
 
 protected:
-    typedef std::map< const osg::Camera*, TestResult > ResultMap;
+    typedef std::map< const osg::Camera*, osg::ref_ptr<osg::TestResult> > ResultMap;
     mutable ResultMap _results;
     mutable OpenThreads::Mutex _mapMutex;
 
diff --git a/src/osg/OcclusionQueryNode.cpp b/src/osg/OcclusionQueryNode.cpp
index 1deaf8c..b95f86a 100644
--- a/src/osg/OcclusionQueryNode.cpp
+++ b/src/osg/OcclusionQueryNode.cpp
@@ -97,7 +97,7 @@ StateSet* initOQDebugState()
 
 struct RetrieveQueriesCallback : public osg::Camera::DrawCallback
 {
-    typedef std::vector<osg::TestResult*> ResultsVector;
+    typedef std::vector<osg::ref_ptr<osg::TestResult> > ResultsVector;
     ResultsVector _results;
 
     RetrieveQueriesCallback( osg::GLExtensions* ext=NULL )
@@ -143,7 +143,7 @@ struct RetrieveQueriesCallback : public osg::Camera::DrawCallback
         ResultsVector::const_iterator it = _results.begin();
         while (it != _results.end())
         {
-            osg::TestResult* tr = const_cast<osg::TestResult*>( *it );
+            osg::TestResult* tr = const_cast<osg::TestResult*>( (*it).get() );
 
             if (!tr->_active || !tr->_init)
             {
@@ -159,31 +159,20 @@ struct RetrieveQueriesCallback : public osg::Camera::DrawCallback
             OSG_DEBUG <<
                 "osgOQ: RQCB: Retrieving..." << std::endl;
 
-#ifdef FORCE_QUERY_RESULT_AVAILABLE_BEFORE_RETRIEVAL
-
-            // Should not need to do this, but is required on some platforms to
-            // work aroung issues in the device driver. For example, without this
-            // code, we've seen crashes on 64-bit Mac/Linux NVIDIA systems doing
-            // multithreaded, multipipe rendering (as in a CAVE).
-            // Tried with ATI and verified this workaround is not needed; the
-            //   problem is specific to NVIDIA.
-            GLint ready( 0 );
-            while( !ready )
+            GLint ready = 0;
+            ext->glGetQueryObjectiv( tr->_id, GL_QUERY_RESULT_AVAILABLE, &ready );
+            if (ready)
             {
-                // Apparently, must actually sleep here to avoid issues w/ NVIDIA Quadro.
-                OpenThreads::Thread::microSleep( 5 );
-                ext->glGetQueryObjectiv( tr->_id, GL_QUERY_RESULT_AVAILABLE, &ready );
-            };
-#endif
-
-            ext->glGetQueryObjectiv( tr->_id, GL_QUERY_RESULT, &(tr->_numPixels) );
-            if (tr->_numPixels < 0)
-                OSG_WARN << "osgOQ: RQCB: " <<
-                "glGetQueryObjectiv returned negative value (" << tr->_numPixels << ")." << std::endl;
-
-            // Either retrieve last frame's results, or ignore it because the
-            //   camera is inside the view. In either case, _active is now false.
-            tr->_active = false;
+                ext->glGetQueryObjectiv( tr->_id, GL_QUERY_RESULT, &(tr->_numPixels) );
+                if (tr->_numPixels < 0)
+                    OSG_WARN << "osgOQ: RQCB: " <<
+                    "glGetQueryObjectiv returned negative value (" << tr->_numPixels << ")." << std::endl;
+
+                // Either retrieve last frame's results, or ignore it because the
+                //   camera is inside the view. In either case, _active is now false.
+                tr->_active = false;
+            }
+            // else: query result not available yet, try again next frame
 
             it++;
             count++;
@@ -196,7 +185,13 @@ struct RetrieveQueriesCallback : public osg::Camera::DrawCallback
 
     void reset()
     {
-        _results.clear();
+        for (ResultsVector::iterator it = _results.begin(); it != _results.end();)
+        {
+            if (!(*it)->_active || !(*it)->_init) // remove results that have already been retrieved or their query objects deleted.
+                it = _results.erase(it);
+            else
+                ++it;
+        }
     }
 
     void add( osg::TestResult* tr )
@@ -264,9 +259,9 @@ QueryGeometry::reset()
     ResultMap::iterator it = _results.begin();
     while (it != _results.end())
     {
-        TestResult& tr = it->second;
-        if (tr._init)
-            QueryGeometry::deleteQueryObject( tr._contextID, tr._id );
+        osg::ref_ptr<TestResult> tr = it->second;
+        if (tr->_init)
+            QueryGeometry::deleteQueryObject( tr->_contextID, tr->_id );
         it++;
     }
     _results.clear();
@@ -294,10 +289,30 @@ QueryGeometry::drawImplementation( osg::RenderInfo& renderInfo ) const
     }
 
     // Get TestResult from Camera map
-    TestResult* tr;
+    osg::ref_ptr<osg::TestResult> tr;
     {
         OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _mapMutex );
-        tr = &( _results[ cam ] );
+        tr = ( _results[ cam ] );
+        if (!tr.valid())
+        {
+            tr = new osg::TestResult;
+            _results[ cam ] = tr;
+        }
+    }
+
+
+    // Issue query
+    if (!tr->_init)
+    {
+        ext->glGenQueries( 1, &(tr->_id) );
+        tr->_contextID = contextID;
+        tr->_init = true;
+    }
+
+    if (tr->_active)
+    {
+        // last query hasn't been retrieved yet
+        return;
     }
 
     // Add TestResult to RQCB.
@@ -310,15 +325,6 @@ QueryGeometry::drawImplementation( osg::RenderInfo& renderInfo ) const
     }
     rqcb->add( tr );
 
-
-    // Issue query
-    if (!tr->_init)
-    {
-        ext->glGenQueries( 1, &(tr->_id) );
-        tr->_contextID = contextID;
-        tr->_init = true;
-    }
-
     OSG_DEBUG <<
         "osgOQ: QG: Querying for: " << _oqnName << std::endl;
 
@@ -349,12 +355,17 @@ QueryGeometry::drawImplementation( osg::RenderInfo& renderInfo ) const
 unsigned int
 QueryGeometry::getNumPixels( const osg::Camera* cam )
 {
-    TestResult tr;
+    osg::ref_ptr<osg::TestResult> tr;
     {
         OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _mapMutex );
         tr =  _results[ cam ];
+        if (!tr.valid())
+        {
+            tr = new osg::TestResult;
+            _results[ cam ] = tr;
+        }
     }
-    return tr._numPixels;
+    return tr->_numPixels;
 }
 
 
@@ -375,11 +386,11 @@ QueryGeometry::releaseGLObjects( osg::State* state ) const
         ResultMap::iterator it = _results.begin();
         while (it != _results.end())
         {
-            TestResult& tr = it->second;
-            if (tr._contextID == contextID)
+            osg::ref_ptr<osg::TestResult> tr = it->second;
+            if (tr->_contextID == contextID)
             {
-                QueryGeometry::deleteQueryObject( contextID, tr._id );
-                tr._init = false;
+                QueryGeometry::deleteQueryObject( contextID, tr->_id );
+                tr->_init = false;
             }
             it++;
         }
