From 7b7b4037a08a88ceaf3fbaf6da522684eab25853 Mon Sep 17 00:00:00 2001 From: Daniel Trstenjak Date: Mon, 28 Jan 2019 15:02:19 +0100 Subject: [PATCH 1/3] OcclusionQueryNode: add more debug output --- src/osg/OcclusionQueryNode.cpp | 45 ++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/osg/OcclusionQueryNode.cpp b/src/osg/OcclusionQueryNode.cpp index 65a3e206a37..cf263a67b51 100644 --- a/src/osg/OcclusionQueryNode.cpp +++ b/src/osg/OcclusionQueryNode.cpp @@ -173,11 +173,17 @@ struct RetrieveQueriesCallback : public osg::Camera::DrawCallback OSG_WARN << "osgOQ: RQCB: " << "glGetQueryObjectiv returned negative value (" << tr->_numPixels << ")." << std::endl; + OSG_DEBUG << "osgOQ: query result: numPixels=" << 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 + // query result not available yet, try again next frame + else + { + OSG_DEBUG << "osgOQ: query result not available yet" << std::endl; + } it++; count++; @@ -263,6 +269,8 @@ QueryGeometry::~QueryGeometry() void QueryGeometry::reset() { + OSG_DEBUG << "osgOQ: QueryGeometry::reset()" << std::endl; + OpenThreads::ScopedLock lock( _mapMutex ); ResultMap::iterator it = _results.begin(); @@ -282,6 +290,8 @@ QueryGeometry::reset() void QueryGeometry::drawImplementation( osg::RenderInfo& renderInfo ) const { + OSG_DEBUG << "osgOQ: QueryGeometry::drawImplementation(...)" << std::endl; + unsigned int contextID = renderInfo.getState()->getContextID(); osg::GLExtensions* ext = renderInfo.getState()->get(); @@ -477,6 +487,7 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv ) { // Queries are not enabled. The caller should be osgUtil::CullVisitor, // return true to traverse the subgraphs. + OSG_DEBUG << "osgOQ: passed because queries are disabled" << std::endl; _passed = true; return _passed; } @@ -491,6 +502,12 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv ) if( ( lastQueryFrame == 0 ) || ( (nv.getTraversalNumber() - lastQueryFrame) > (_queryFrameCount + 1) ) ) { + OSG_DEBUG << "osgOQ: passed because" + << " lastQueryFrame=" << lastQueryFrame + << ", traversalNumber=" << nv.getTraversalNumber() + << ", _queryFrameCount=" << _queryFrameCount + << std::endl; + _passed = true; return _passed; } @@ -528,11 +545,20 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv ) { // The query hasn't finished yet and the result still // isn't available, return true to traverse the subgraphs. + OSG_DEBUG << "osgOQ: passed because query result is still not available" << std::endl; _passed = true; return _passed; } _passed = ( result.numPixels > _visThreshold ); + + OSG_DEBUG << "osgOQ: passed=" << _passed << " because" + << " numPixels=" << result.numPixels + << ", _visThreshold=" << _visThreshold + << std::endl; + } + else { + OSG_DEBUG << "osgOQ: passed because distance=" << distance << std::endl; } return _passed; @@ -548,8 +574,17 @@ void OcclusionQueryNode::traverseQuery( const Camera* camera, NodeVisitor& nv ) unsigned int& lastQueryFrame = _frameCountMap[ camera ]; issueQuery = (curFrame - lastQueryFrame >= _queryFrameCount); if (issueQuery) + { + OSG_DEBUG << "osgOQ: traverse query because:" + << " curFrame=" << curFrame + << ", lastQueryFrame=" << lastQueryFrame + << ", _queryFrameCount=" << _queryFrameCount + << std::endl; + lastQueryFrame = curFrame; + } } + if (issueQuery) _queryGeode->accept( nv ); } @@ -573,11 +608,15 @@ BoundingSphere OcclusionQueryNode::computeBound() const // away constness to compute the bounding box and modify the query geometry. osg::OcclusionQueryNode* nonConstThis = const_cast( this ); - ComputeBoundsVisitor cbv; nonConstThis->accept( cbv ); BoundingBox bb = cbv.getBoundingBox(); + OSG_DEBUG << "osgOQ: compute query bound:" + << " min=(" << bb._min.x() << "," << bb._min.y() << "," << bb._min.z() << ")" + << ", max=(" << bb._max.x() << "," << bb._max.y() << "," << bb._max.z() << ")" + << std::endl; + osg::ref_ptr v = new Vec3Array; v->resize( 8 ); (*v)[0] = Vec3( bb._min.x(), bb._min.y(), bb._min.z() ); @@ -608,6 +647,8 @@ void OcclusionQueryNode::setQueriesEnabled( bool enable ) void OcclusionQueryNode::resetQueries() { + OSG_DEBUG << "osgOQ: OcclusionQueryNode::resetQueries()" << std::endl; + OpenThreads::ScopedLock lock( _frameCountMutex ); _frameCountMap.clear(); } From 8b7cdf19961c4a2efbfdb61f7999352aebfae5df Mon Sep 17 00:00:00 2001 From: Daniel Trstenjak Date: Tue, 29 Jan 2019 11:37:28 +0100 Subject: [PATCH 2/3] OcclusionQueryNode: ensure a valid query geometry In the case of an invalid geometry there're two ways to react on it, traverse the subgraph or not traversing it. In the case of an invalid query box from e.g. a geometry with a cleared DrawElements list, not traversing the subgraph would be the right thing. But if the geometry only consists of e.g. one point, then the query box would be always invalid and the subgraph never traversed. So it seems safer to always traverse the subgraph, which is done in this patch. --- include/osg/OcclusionQueryNode | 3 +++ src/osg/OcclusionQueryNode.cpp | 41 +++++++++++++++++++++++++++------- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/include/osg/OcclusionQueryNode b/include/osg/OcclusionQueryNode index a2c09cabe75..afd19f167b1 100644 --- a/include/osg/OcclusionQueryNode +++ b/include/osg/OcclusionQueryNode @@ -198,6 +198,9 @@ protected: bool _enabled; + // If the box of the query geometry is valid. + bool _validQueryGeometry; + // Tracks the last frame number that we performed a query. // User can set how many times (See setQueryFrameCount). typedef std::map< const osg::Camera*, unsigned int > FrameCountMap; diff --git a/src/osg/OcclusionQueryNode.cpp b/src/osg/OcclusionQueryNode.cpp index cf263a67b51..43a1e4f2cea 100644 --- a/src/osg/OcclusionQueryNode.cpp +++ b/src/osg/OcclusionQueryNode.cpp @@ -452,6 +452,7 @@ QueryGeometry::discardDeletedQueryObjects( unsigned int contextID ) OcclusionQueryNode::OcclusionQueryNode() : _enabled( true ), + _validQueryGeometry( false ), _passed(false), _visThreshold( 500 ), _queryFrameCount( 5 ), @@ -469,6 +470,7 @@ OcclusionQueryNode::~OcclusionQueryNode() OcclusionQueryNode::OcclusionQueryNode( const OcclusionQueryNode& oqn, const CopyOp& copyop ) : Group( oqn, copyop ), + _validQueryGeometry( false ), _passed( false ) { _enabled = oqn._enabled; @@ -492,6 +494,14 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv ) return _passed; } + if ( !_validQueryGeometry ) + { + // The box of the query geometry is invalid, return true to traverse + // the subgraphs. + _passed = true; + return _passed; + } + { // Two situations where we want to simply do a regular traversal: // 1) it's the first frame for this camera @@ -566,6 +576,9 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv ) void OcclusionQueryNode::traverseQuery( const Camera* camera, NodeVisitor& nv ) { + if (!_validQueryGeometry) + return; + bool issueQuery; { const int curFrame = nv.getTraversalNumber(); @@ -617,16 +630,28 @@ BoundingSphere OcclusionQueryNode::computeBound() const << ", max=(" << bb._max.x() << "," << bb._max.y() << "," << bb._max.z() << ")" << std::endl; + nonConstThis->_validQueryGeometry = bb.valid(); + OSG_DEBUG << "osgOQ: _validQueryGeometry=" << nonConstThis->_validQueryGeometry << std::endl; + osg::ref_ptr v = new Vec3Array; v->resize( 8 ); - (*v)[0] = Vec3( bb._min.x(), bb._min.y(), bb._min.z() ); - (*v)[1] = Vec3( bb._max.x(), bb._min.y(), bb._min.z() ); - (*v)[2] = Vec3( bb._max.x(), bb._min.y(), bb._max.z() ); - (*v)[3] = Vec3( bb._min.x(), bb._min.y(), bb._max.z() ); - (*v)[4] = Vec3( bb._max.x(), bb._max.y(), bb._min.z() ); - (*v)[5] = Vec3( bb._min.x(), bb._max.y(), bb._min.z() ); - (*v)[6] = Vec3( bb._min.x(), bb._max.y(), bb._max.z() ); - (*v)[7] = Vec3( bb._max.x(), bb._max.y(), bb._max.z() ); + + // Having (0,0,0) as vertices for the case of the invalid query geometry + // still isn't quite the right thing. But the query geometry is public + // accessible and therefore a user might expect eight vertices, so + // it seems safer to keep eight vertices in the geometry. + + if (nonConstThis->_validQueryGeometry) + { + (*v)[0] = Vec3( bb._min.x(), bb._min.y(), bb._min.z() ); + (*v)[1] = Vec3( bb._max.x(), bb._min.y(), bb._min.z() ); + (*v)[2] = Vec3( bb._max.x(), bb._min.y(), bb._max.z() ); + (*v)[3] = Vec3( bb._min.x(), bb._min.y(), bb._max.z() ); + (*v)[4] = Vec3( bb._max.x(), bb._max.y(), bb._min.z() ); + (*v)[5] = Vec3( bb._min.x(), bb._max.y(), bb._min.z() ); + (*v)[6] = Vec3( bb._min.x(), bb._max.y(), bb._max.z() ); + (*v)[7] = Vec3( bb._max.x(), bb._max.y(), bb._max.z() ); + } Geometry* geom = static_cast< Geometry* >( nonConstThis->_queryGeode->getDrawable( 0 ) ); geom->setVertexArray( v.get() ); From d7472d9c0b8b0c3a7a06b3477eb2af871c2af072 Mon Sep 17 00:00:00 2001 From: Daniel Trstenjak Date: Tue, 29 Jan 2019 14:40:16 +0100 Subject: [PATCH 3/3] OcclusionQueryNode: reset the test result of the invalid geometry There're cases that the occlusion test result has been retrieved after the query geometry has been changed, it's the result of the geometry before the change. --- src/osg/OcclusionQueryNode.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/osg/OcclusionQueryNode.cpp b/src/osg/OcclusionQueryNode.cpp index 43a1e4f2cea..a6bebc5efe5 100644 --- a/src/osg/OcclusionQueryNode.cpp +++ b/src/osg/OcclusionQueryNode.cpp @@ -494,8 +494,15 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv ) return _passed; } + QueryGeometry* qg = static_cast< QueryGeometry* >( _queryGeode->getDrawable( 0 ) ); + if ( !_validQueryGeometry ) { + // There're cases that the occlusion test result has been retrieved + // after the query geometry has been changed, it's the result of the + // geometry before the change. + qg->reset(); + // The box of the query geometry is invalid, return true to traverse // the subgraphs. _passed = true; @@ -530,7 +537,6 @@ bool OcclusionQueryNode::getPassed( const Camera* camera, NodeVisitor& nv ) _passed = true; return _passed; } - QueryGeometry* qg = static_cast< QueryGeometry* >( _queryGeode->getDrawable( 0 ) ); // Get the near plane for the upcoming distance calculation. osg::Matrix::value_type nearPlane;