diff --git a/include/osg/Drawable b/include/osg/Drawable index 0f532aec3..3b6b235f9 100644 --- a/include/osg/Drawable +++ b/include/osg/Drawable @@ -45,6 +45,7 @@ #ifndef GL_TIME_ELAPSED #define GL_TIME_ELAPSED 0x88BF + #define GL_TIMESTAMP 0x8E28 #endif #ifndef GL_QUERY_RESULT @@ -607,7 +608,8 @@ class OSG_EXPORT Drawable : public Object void setTimerQuerySupported(bool flag) { _isTimerQuerySupported = flag; } bool isTimerQuerySupported() const { return _isTimerQuerySupported; } - + void setARBTimerQuerySupported(bool flag) { _isARBTimerQuerySupported = flag; } + bool isARBTimerQuerySupported() { return _isARBTimerQuerySupported; } void glSecondaryColor3ubv(const GLubyte* coord) const; void glSecondaryColor3fv(const GLfloat* coord) const; @@ -661,11 +663,13 @@ class OSG_EXPORT Drawable : public Object void glGenQueries(GLsizei n, GLuint *ids) const; void glBeginQuery(GLenum target, GLuint id) const; void glEndQuery(GLenum target) const; + void glQueryCounter(GLuint id, GLenum target) const; GLboolean glIsQuery(GLuint id) const; void glDeleteQueries(GLsizei n, const GLuint *ids) const; void glGetQueryObjectiv(GLuint id, GLenum pname, GLint *params) const; void glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) const; void glGetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params) const; + void glGetInteger64v(GLenum pname, GLint64EXT *params) const; protected: @@ -715,10 +719,12 @@ class OSG_EXPORT Drawable : public Object typedef GLboolean (GL_APIENTRY *IsQueryProc) (GLuint id); typedef void (GL_APIENTRY *BeginQueryProc) (GLenum target, GLuint id); typedef void (GL_APIENTRY *EndQueryProc) (GLenum target); + typedef void (GL_APIENTRY *QueryCounterProc)(GLuint id, GLenum target); typedef void (GL_APIENTRY *GetQueryivProc) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRY *GetQueryObjectivProc) (GLuint id, GLenum pname, GLint *params); typedef void (GL_APIENTRY *GetQueryObjectuivProc) (GLuint id, GLenum pname, GLuint *params); typedef void (GL_APIENTRY *GetQueryObjectui64vProc) (GLuint id, GLenum pname, GLuint64EXT *params); + typedef void (GL_APIENTRY *GetInteger64vProc) (GLenum pname, GLint64EXT *params); ~Extensions() {} @@ -729,6 +735,7 @@ class OSG_EXPORT Drawable : public Object bool _isOcclusionQuerySupported; bool _isARBOcclusionQuerySupported; bool _isTimerQuerySupported; + bool _isARBTimerQuerySupported; FogCoordProc _glFogCoordfv; @@ -785,10 +792,12 @@ class OSG_EXPORT Drawable : public Object IsQueryProc _gl_is_query_arb; BeginQueryProc _gl_begin_query_arb; EndQueryProc _gl_end_query_arb; + QueryCounterProc _glQueryCounter; GetQueryivProc _gl_get_queryiv_arb; GetQueryObjectivProc _gl_get_query_objectiv_arb; GetQueryObjectuivProc _gl_get_query_objectuiv_arb; GetQueryObjectui64vProc _gl_get_query_objectui64v; + GetInteger64vProc _glGetInteger64v; }; diff --git a/include/osg/GraphicsContext b/include/osg/GraphicsContext index 3f8a2d9aa..040e35b7b 100644 --- a/include/osg/GraphicsContext +++ b/include/osg/GraphicsContext @@ -392,6 +392,34 @@ class OSG_EXPORT GraphicsContext : public Object * Pure virtual - must be implemented by concrete implementations of GraphicsContext. */ virtual void bindPBufferToTextureImplementation(GLenum buffer) = 0; + struct SwapCallback : public osg::Referenced + { + virtual void swapBuffersImplementation(GraphicsContext* gc) = 0; + }; + /** Set the swap callback which overrides the + * GraphicsContext::swapBuffersImplementation(), allowing + * developers to provide custom behavior for swap. + * The callback must call + * GraphicsContext::swapBuffersImplementation() */ + void setSwapCallback(SwapCallback* rc) { _swapCallback = rc; } + + /** Get the swap callback which overrides the GraphicsContext::swapBuffersImplementation().*/ + SwapCallback* getSwapCallback() { return _swapCallback.get(); } + + /** Get the const swap callback which overrides the GraphicsContext::swapBuffersImplementation().*/ + const SwapCallback* getSwapCallback() const { return _swapCallback.get(); } + + /** convinience method for handling whether to call swapbuffers callback or the standard context swapBuffersImplementation. + * swapBuffersCallbackOrImplemenation() is called by swapBuffers() and osg::SwapBuffersOperation, end users should normally + * call swapBuffers() rather than swapBuffersCallbackOrImplemenation(). */ + void swapBuffersCallbackOrImplemenation() + { + if (_state.valid()) _state->frameCompleted(); + + if (_swapCallback.valid()) _swapCallback->swapBuffersImplementation(this); + else swapBuffersImplementation(); + } + /** Swap the front and back buffers implementation. * Pure virtual - must be implemented by concrete implementations of GraphicsContext. */ virtual void swapBuffersImplementation() = 0; @@ -411,14 +439,14 @@ class OSG_EXPORT GraphicsContext : public Object virtual void resizedImplementation(GraphicsContext* gc, int x, int y, int width, int height) = 0; }; - /** Set the resized callback which overrides the GraphicsContext::resizedImplementation(), allow developers to provide custom behavior + /** Set the resized callback which overrides the GraphicsConext::realizedImplementation(), allow developers to provide custom behavior * in response to a window being resized.*/ void setResizedCallback(ResizedCallback* rc) { _resizedCallback = rc; } - /** Get the resized callback which overrides the GraphicsContext::resizedImplementation().*/ + /** Get the resized callback which overrides the GraphicsConext::realizedImplementation().*/ ResizedCallback* getResizedCallback() { return _resizedCallback.get(); } - /** Get the const resized callback which overrides the GraphicsContext::resizedImplementation().*/ + /** Get the const resized callback which overrides the GraphicsConext::realizedImplementation().*/ const ResizedCallback* getResizedCallback() const { return _resizedCallback.get(); } /** resized implementation, by default resizes the viewports and aspect ratios the cameras associated with the graphics Window. */ @@ -479,6 +507,7 @@ class OSG_EXPORT GraphicsContext : public Object ref_ptr _graphicsThread; ref_ptr _resizedCallback; + ref_ptr _swapCallback; Timer_t _lastClearTick; }; diff --git a/include/osg/State b/include/osg/State index ddd8e0a21..f28f5715a 100644 --- a/include/osg/State +++ b/include/osg/State @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -1366,6 +1367,31 @@ class OSG_EXPORT State : public Referenced, public Observer /** get the helper class for dispatching osg::Arrays as OpenGL attribute data.*/ inline ArrayDispatchers& getArrayDispatchers() { return _arrayDispatchers; } + /** Support for synchronizing the system time and the timestamp + * counter available with ARB_timer_query. Note that State + * doesn't update these values itself. + */ + Timer_t getStartTick() const { return _startTick; } + void setStartTick(Timer_t tick) { _startTick = tick; } + Timer_t getGpuTick() const { return _gpuTick; } + + double getGpuTime() const + { + return osg::Timer::instance()->delta_s(_startTick, _gpuTick); + } + GLuint64EXT getGpuTimestamp() const { return _gpuTimestamp; } + + void setGpuTimestamp(Timer_t tick, GLuint64EXT timestamp) + { + _gpuTick = tick; + _gpuTimestamp = timestamp; + } + int getTimestampBits() const { return _timestampBits; } + void setTimestampBits(int bits) { _timestampBits = bits; } + + /** called by the GraphicsContext just before GraphicsContext::swapBuffersImplementation().*/ + virtual void frameCompleted(); + protected: virtual ~State(); @@ -1776,7 +1802,10 @@ class OSG_EXPORT State : public Referenced, public Observer GLBeginEndAdapter _glBeginEndAdapter; ArrayDispatchers _arrayDispatchers; - + Timer_t _startTick; + Timer_t _gpuTick; + GLuint64EXT _gpuTimestamp; + int _timestampBits; }; inline void State::pushModeList(ModeMap& modeMap,const StateSet::ModeList& modeList) diff --git a/include/osgViewer/Renderer b/include/osgViewer/Renderer index 200fb034d..c7a44e031 100644 --- a/include/osgViewer/Renderer +++ b/include/osgViewer/Renderer @@ -21,38 +21,23 @@ namespace osgViewer { -class OSGVIEWER_EXPORT OpenGLQuerySupport +class OSGVIEWER_EXPORT OpenGLQuerySupport : public osg::Referenced { public: OpenGLQuerySupport(); - typedef std::pair QueryFrameNumberPair; - typedef std::list QueryFrameNumberList; - typedef std::vector QueryList; - - void setStartTick(osg::Timer_t startTick) { _startTick = startTick; } - osg::Timer_t getStartTick() const { return _startTick; } - - void checkQuery(osg::Stats* stats); + virtual void checkQuery(osg::Stats* stats, osg::State* state, + osg::Timer_t startTick) = 0; - GLuint createQueryObject(); - void beginQuery(int frameNumber); - void endQuery(); - void initialize(osg::State* state); - + virtual void beginQuery(int frameNumber, osg::State* state) = 0; + virtual void endQuery(osg::State* state) = 0; + virtual void initialize(osg::State* state, osg::Timer_t startTick); protected: - osg::Timer_t _startTick; - bool _initialized; - bool _timerQuerySupported; const osg::Drawable::Extensions* _extensions; - QueryFrameNumberList _queryFrameNumberList; - QueryList _availableQueryObjects; - double _previousQueryTime; - }; -class OSGVIEWER_EXPORT Renderer : public osg::GraphicsOperation, public OpenGLQuerySupport +class OSGVIEWER_EXPORT Renderer : public osg::GraphicsOperation { public: @@ -132,7 +117,7 @@ class OSGVIEWER_EXPORT Renderer : public osg::GraphicsOperation, public OpenGLQu bool getCameraRequiresSetUp() const; protected: - + void initialize(osg::State* state); virtual ~Renderer(); virtual void updateSceneView(osgUtil::SceneView* sceneView); @@ -178,6 +163,9 @@ class OSGVIEWER_EXPORT Renderer : public osg::GraphicsOperation, public OpenGLQu ThreadSafeQueue _availableQueue; ThreadSafeQueue _drawQueue; + bool _initialized; + osg::ref_ptr _querySupport; + osg::Timer_t _startTick; }; } diff --git a/src/osg/Drawable.cpp b/src/osg/Drawable.cpp index e21f15328..0a77f03c0 100644 --- a/src/osg/Drawable.cpp +++ b/src/osg/Drawable.cpp @@ -844,6 +844,7 @@ Drawable::Extensions::Extensions(const Extensions& rhs): _isMultiTexSupported = rhs._isMultiTexSupported; _isOcclusionQuerySupported = rhs._isOcclusionQuerySupported; _isTimerQuerySupported = rhs._isTimerQuerySupported; + _isARBTimerQuerySupported = rhs._isARBTimerQuerySupported; _glFogCoordfv = rhs._glFogCoordfv; _glSecondaryColor3ubv = rhs._glSecondaryColor3ubv; @@ -880,6 +881,7 @@ Drawable::Extensions::Extensions(const Extensions& rhs): _gl_get_query_objectiv_arb = rhs._gl_get_query_objectiv_arb; _gl_get_query_objectuiv_arb = rhs._gl_get_query_objectuiv_arb; _gl_get_query_objectui64v = rhs._gl_get_query_objectui64v; + _glGetInteger64v = rhs._glGetInteger64v; } @@ -893,6 +895,7 @@ void Drawable::Extensions::lowestCommonDenominator(const Extensions& rhs) if (!rhs._isARBOcclusionQuerySupported) _isARBOcclusionQuerySupported = false; if (!rhs._isTimerQuerySupported) _isTimerQuerySupported = false; + if (!rhs._isARBTimerQuerySupported) _isARBTimerQuerySupported = false; if (!rhs._glFogCoordfv) _glFogCoordfv = 0; if (!rhs._glSecondaryColor3ubv) _glSecondaryColor3ubv = 0; @@ -939,6 +942,7 @@ void Drawable::Extensions::lowestCommonDenominator(const Extensions& rhs) if (!rhs._gl_get_query_objectiv_arb) _gl_get_query_objectiv_arb = 0; if (!rhs._gl_get_query_objectuiv_arb) _gl_get_query_objectuiv_arb = 0; if (!rhs._gl_get_query_objectui64v) _gl_get_query_objectui64v = 0; + if (!rhs._glGetInteger64v) _glGetInteger64v = 0; } void Drawable::Extensions::setupGLExtensions(unsigned int contextID) @@ -950,7 +954,8 @@ void Drawable::Extensions::setupGLExtensions(unsigned int contextID) _isOcclusionQuerySupported = osg::isGLExtensionSupported(contextID, "GL_NV_occlusion_query" ); _isARBOcclusionQuerySupported = OSG_GL3_FEATURES || osg::isGLExtensionSupported(contextID, "GL_ARB_occlusion_query" ); - _isTimerQuerySupported = osg::isGLExtensionSupported(contextID, "GL_EXT_timer_query" );; + _isTimerQuerySupported = osg::isGLExtensionSupported(contextID, "GL_EXT_timer_query" ); + _isARBTimerQuerySupported = osg::isGLExtensionSupported(contextID, "GL_ARB_timer_query"); setGLExtensionFuncPtr(_glFogCoordfv, "glFogCoordfv","glFogCoordfvEXT"); @@ -1008,6 +1013,8 @@ void Drawable::Extensions::setupGLExtensions(unsigned int contextID) setGLExtensionFuncPtr(_gl_get_query_objectiv_arb, "glGetQueryObjectiv","glGetQueryObjectivARB"); setGLExtensionFuncPtr(_gl_get_query_objectuiv_arb, "glGetQueryObjectuiv","glGetQueryObjectuivARB"); setGLExtensionFuncPtr(_gl_get_query_objectui64v, "glGetQueryObjectui64v","glGetQueryObjectui64vEXT"); + setGLExtensionFuncPtr(_glQueryCounter, "glQueryCounter"); + setGLExtensionFuncPtr(_glGetInteger64v, "glGetInteger64v"); } void Drawable::Extensions::glFogCoordfv(const GLfloat* coord) const @@ -1471,6 +1478,14 @@ void Drawable::Extensions::glEndQuery(GLenum target) const OSG_WARN << "Error: glEndQuery not supported by OpenGL driver" << std::endl; } +void Drawable::Extensions::glQueryCounter(GLuint id, GLenum target) const +{ + if (_glQueryCounter) + _glQueryCounter(id, target); + else + OSG_WARN << "Error: glQueryCounter not supported by OpenGL driver\n"; +} + GLboolean Drawable::Extensions::glIsQuery(GLuint id) const { if (_gl_is_query_arb) return _gl_is_query_arb(id); @@ -1510,3 +1525,12 @@ void Drawable::Extensions::glGetQueryObjectui64v(GLuint id, GLenum pname, GLuint else OSG_WARN << "Error: glGetQueryObjectui64v not supported by OpenGL driver" << std::endl; } + +void Drawable::Extensions::glGetInteger64v(GLenum pname, GLint64EXT *params) + const +{ + if (_glGetInteger64v) + _glGetInteger64v(pname, params); + else + OSG_WARN << "Error: glGetInteger64v not supported by OpenGL driver\n"; +} diff --git a/src/osg/GraphicsContext.cpp b/src/osg/GraphicsContext.cpp index e12b63bf5..ceba69df6 100644 --- a/src/osg/GraphicsContext.cpp +++ b/src/osg/GraphicsContext.cpp @@ -617,7 +617,7 @@ void GraphicsContext::swapBuffers() { if (isCurrent()) { - swapBuffersImplementation(); + swapBuffersCallbackOrImplemenation(); clear(); } else if (_graphicsThread.valid() && @@ -628,13 +628,11 @@ void GraphicsContext::swapBuffers() else { makeCurrent(); - swapBuffersImplementation(); + swapBuffersCallbackOrImplemenation(); clear(); } } - - void GraphicsContext::createGraphicsThread() { if (!_graphicsThread) diff --git a/src/osg/GraphicsThread.cpp b/src/osg/GraphicsThread.cpp index cac0ea4a8..3ea29aa5b 100644 --- a/src/osg/GraphicsThread.cpp +++ b/src/osg/GraphicsThread.cpp @@ -55,7 +55,7 @@ void GraphicsOperation::operator () (Object* object) void SwapBuffersOperation::operator () (GraphicsContext* context) { - context->swapBuffersImplementation(); + context->swapBuffersCallbackOrImplemenation(); context->clear(); } diff --git a/src/osg/State.cpp b/src/osg/State.cpp index cebcf0d1b..366e59a44 100644 --- a/src/osg/State.cpp +++ b/src/osg/State.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -157,6 +158,11 @@ State::State(): _glBeginEndAdapter.setState(this); _arrayDispatchers.setState(this); + + _startTick = 0; + _gpuTick = 0; + _gpuTimestamp = 0; + _timestampBits = 0; } State::~State() @@ -910,6 +916,16 @@ void State::initializeExtensionProcs() _glMaxTextureCoords = 1; } + osg::Drawable::Extensions* extensions = osg::Drawable::getExtensions(getContextID(), true); + if (extensions && extensions->isARBTimerQuerySupported()) + { + GLint bits = 0; + extensions->glGetQueryiv(GL_TIMESTAMP, GL_QUERY_COUNTER_BITS_ARB, &bits); + OSG_NOTICE << "timestamp query counter bits: " << bits << "\n"; + setTimestampBits(bits); + } + + _extensionProcsInitialized = true; } @@ -1568,60 +1584,17 @@ void State::print(std::ostream& fout) const fout<<(*itr)->getName()<<" "<<*itr< EnabledTexCoordArrayList; - typedef std::vector EnabledVertexAttribArrayList; - - EnabledArrayPair _vertexArray; - EnabledArrayPair _normalArray; - EnabledArrayPair _colorArray; - EnabledArrayPair _secondaryColorArray; - EnabledArrayPair _fogArray; - EnabledTexCoordArrayList _texCoordArrayList; - EnabledVertexAttribArrayList _vertexAttribArrayList; - - unsigned int _currentActiveTextureUnit; - unsigned int _currentClientActiveTextureUnit; - GLBufferObject* _currentVBO; - GLBufferObject* _currentEBO; - GLBufferObject* _currentPBO; - - mutable bool _isSecondaryColorSupportResolved; - mutable bool _isSecondaryColorSupported; - bool computeSecondaryColorSupported() const; - - mutable bool _isFogCoordSupportResolved; - mutable bool _isFogCoordSupported; - bool computeFogCoordSupported() const; - - mutable bool _isVertexBufferObjectSupportResolved; - mutable bool _isVertexBufferObjectSupported; - bool computeVertexBufferObjectSupported() const; -#endif - -#if 0 - unsigned int _dynamicObjectCount; - osg::ref_ptr _completeDynamicObjectRenderingCallback; - - GLBeginEndAdapter _glBeginEndAdapter; - ArrayDispatchers _arrayDispatchers; -#endif } + +void State::frameCompleted() +{ + + osg::Drawable::Extensions* extensions = osg::Drawable::getExtensions(getContextID(), true); + if (extensions && getTimestampBits()) + { + GLint64EXT timestamp; + extensions->glGetInteger64v(GL_TIMESTAMP, ×tamp); + setGpuTimestamp(osg::Timer::instance()->tick(), timestamp); + OSG_NOTICE<<"State::frameCompleted() setting time stamp."< QueryFrameNumberPair; + typedef std::list QueryFrameNumberList; + typedef std::vector QueryList; + + QueryFrameNumberList _queryFrameNumberList; + QueryList _availableQueryObjects; + double _previousQueryTime; +}; + + +EXTQuerySupport::EXTQuerySupport(): _previousQueryTime(0.0) { } -void OpenGLQuerySupport::checkQuery(osg::Stats* stats) +void EXTQuerySupport::checkQuery(osg::Stats* stats, osg::State* state, + osg::Timer_t startTick) { for(QueryFrameNumberList::iterator itr = _queryFrameNumberList.begin(); itr != _queryFrameNumberList.end(); @@ -59,7 +81,7 @@ void OpenGLQuerySupport::checkQuery(osg::Stats* stats) _extensions->glGetQueryObjectui64v(query, GL_QUERY_RESULT, &timeElapsed); double timeElapsedSeconds = double(timeElapsed)*1e-9; - double currentTime = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); + double currentTime = osg::Timer::instance()->delta_s(startTick, osg::Timer::instance()->tick()); double estimatedEndTime = (_previousQueryTime + currentTime) * 0.5; double estimatedBeginTime = estimatedEndTime - timeElapsedSeconds; @@ -77,10 +99,10 @@ void OpenGLQuerySupport::checkQuery(osg::Stats* stats) } } - _previousQueryTime = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); + _previousQueryTime = osg::Timer::instance()->delta_s(startTick, osg::Timer::instance()->tick()); } -GLuint OpenGLQuerySupport::createQueryObject() +GLuint EXTQuerySupport::createQueryObject() { if (_availableQueryObjects.empty()) { @@ -96,26 +118,169 @@ GLuint OpenGLQuerySupport::createQueryObject() } } -void OpenGLQuerySupport::beginQuery(int frameNumber) +void EXTQuerySupport::beginQuery(int frameNumber, osg::State* state) { GLuint query = createQueryObject(); _extensions->glBeginQuery(GL_TIME_ELAPSED, query); _queryFrameNumberList.push_back(QueryFrameNumberPair(query, frameNumber)); } -void OpenGLQuerySupport::endQuery() +void EXTQuerySupport::endQuery(osg::State* state) { _extensions->glEndQuery(GL_TIME_ELAPSED); } -void OpenGLQuerySupport::initialize(osg::State* state) +void OpenGLQuerySupport::initialize(osg::State* state, osg::Timer_t startTick) { - if (_initialized) return; - - _initialized = true; _extensions = osg::Drawable::getExtensions(state->getContextID(),true); - _timerQuerySupported = _extensions && _extensions->isTimerQuerySupported(); - _previousQueryTime = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); +} + +void EXTQuerySupport::initialize(osg::State* state, osg::Timer_t startTick) +{ + OpenGLQuerySupport::initialize(state, startTick); + _previousQueryTime = osg::Timer::instance()->delta_s(startTick, osg::Timer::instance()->tick()); + +} + +class ARBQuerySupport : public OpenGLQuerySupport +{ +public: + virtual void checkQuery(osg::Stats* stats, osg::State* state, + osg::Timer_t startTick); + + virtual void beginQuery(int frameNumber, osg::State* state); + virtual void endQuery(osg::State* state); + virtual void initialize(osg::State* state, osg::Timer_t startTick); +protected: + typedef std::pair QueryPair; + struct ActiveQuery { + ActiveQuery() : queries(0, 0), frameNumber(0) {} + ActiveQuery(GLuint start_, GLuint end_, int frameNumber_) + : queries(start_, end_), frameNumber(frameNumber_) + { + } + ActiveQuery(const QueryPair& queries_, int frameNumber_) + : queries(queries_), frameNumber(frameNumber_) + { + } + QueryPair queries; + int frameNumber; + }; + typedef std::list QueryFrameList; + typedef std::vector QueryList; + QueryFrameList _queryFrameList; + QueryList _availableQueryObjects; +}; + +void ARBQuerySupport::initialize(osg::State* state, osg::Timer_t startTick) +{ + OpenGLQuerySupport::initialize(state, startTick); +} + +void ARBQuerySupport::beginQuery(int frameNumber, osg::State* state) +{ + QueryPair query; + if (_availableQueryObjects.empty()) + { + _extensions->glGenQueries(1, &query.first); + _extensions->glGenQueries(1, &query.second); + } + else + { + query = _availableQueryObjects.back(); + _availableQueryObjects.pop_back(); + } + _extensions->glQueryCounter(query.first, GL_TIMESTAMP); + _queryFrameList.push_back(ActiveQuery(query, frameNumber)); +} + +void ARBQuerySupport::endQuery(osg::State* state) +{ + _extensions->glQueryCounter(_queryFrameList.back().queries.second, + GL_TIMESTAMP); +} + +void ARBQuerySupport::checkQuery(osg::Stats* stats, osg::State* state, + osg::Timer_t startTick) +{ + for(QueryFrameList::iterator itr = _queryFrameList.begin(); + itr != _queryFrameList.end(); + ) + { + GLint available = 0; + // If the end query is available, the begin query must be too. + _extensions->glGetQueryObjectiv(itr->queries.second, + GL_QUERY_RESULT_AVAILABLE, &available); + if (available) + { + QueryPair queries = itr->queries; + GLuint64EXT beginTimestamp = 0; + GLuint64EXT endTimestamp = 0; + _extensions->glGetQueryObjectui64v(queries.first, GL_QUERY_RESULT, + &beginTimestamp); + _extensions->glGetQueryObjectui64v(queries.second, GL_QUERY_RESULT, + &endTimestamp); + GLuint64EXT gpuTimestamp = state->getGpuTimestamp(); + // Have any of the timestamps wrapped around? + int tbits = state->getTimestampBits(); + if (tbits < 64) + { + // If the high bits on any of the timestamp bits are + // different then the counters may have wrapped. + const int hiShift = (tbits - 1); + const GLuint64EXT hiMask = 1 << hiShift; + const GLuint64EXT sum = (beginTimestamp >> hiShift) + + (endTimestamp >> hiShift) + (gpuTimestamp >> hiShift); + if (sum == 1 || sum == 2) { + const GLuint64EXT wrapAdd = 1 << tbits; + // Counter wrapped between begin and end? + if (beginTimestamp > endTimestamp) + { + endTimestamp += wrapAdd; + } + else if (gpuTimestamp < beginTimestamp + && beginTimestamp - gpuTimestamp > (hiMask >> 1)) + { + gpuTimestamp += wrapAdd; + } + else if (endTimestamp < gpuTimestamp + && gpuTimestamp - endTimestamp > (hiMask >> 1)) + { + beginTimestamp += wrapAdd; + endTimestamp += wrapAdd; + } + } + } + GLuint64EXT timeElapsed = endTimestamp - beginTimestamp; + double timeElapsedSeconds = double(timeElapsed)*1e-9; + double gpuTick = state->getGpuTime(); + double beginTime = 0.0; + double endTime = 0.0; + if (beginTimestamp > gpuTimestamp) + beginTime = gpuTick + + double(beginTimestamp - gpuTimestamp) * 1e-9; + else + beginTime = gpuTick + - double(gpuTimestamp - beginTimestamp) * 1e-9; + if (endTimestamp > gpuTimestamp) + endTime = gpuTick + + double(endTimestamp - gpuTimestamp) * 1e-9; + else + endTime = gpuTick + - double(gpuTimestamp - endTimestamp) * 1e-9; + stats->setAttribute(itr->frameNumber, "GPU draw begin time", + beginTime); + stats->setAttribute(itr->frameNumber, "GPU draw end time", endTime); + stats->setAttribute(itr->frameNumber, "GPU draw time taken", + timeElapsedSeconds); + itr = _queryFrameList.erase(itr); + _availableQueryObjects.push_back(queries); + } + else + { + ++itr; + } + } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -162,7 +327,6 @@ static OpenThreads::Mutex s_drawSerializerMutex; // Renderer Renderer::Renderer(osg::Camera* camera): osg::GraphicsOperation("Renderer",true), - OpenGLQuerySupport(), _targetFrameRate(100.0), _minimumTimeAvailableForGLCompileAndDeletePerFrame(0.001), _flushTimeRatio(0.5), @@ -170,7 +334,9 @@ Renderer::Renderer(osg::Camera* camera): _camera(camera), _done(false), _graphicsThreadDoesCull(true), - _compileOnNextDraw(true) + _compileOnNextDraw(true), + _initialized(false), + _startTick(0) { DEBUG_MESSAGE<<"Render::Render() "<getContextID(), true); + if (ext->isARBTimerQuerySupported()) + _querySupport = new ARBQuerySupport(); + else if (ext->isTimerQuerySupported()) + _querySupport = new EXTQuerySupport(); + if (_querySupport.valid()) + _querySupport->initialize(state, _startTick); + } +} + void Renderer::setGraphicsThreadDoesCull(bool flag) { if (_graphicsThreadDoesCull==flag) return; @@ -296,6 +477,7 @@ void Renderer::updateSceneView(osgUtil::SceneView* sceneView) sceneView->setDisplaySettings(ds); if (view) _startTick = view->getStartTick(); + if (state) state->setStartTick(_startTick); } void Renderer::compile() @@ -477,18 +659,18 @@ void Renderer::draw() state->getDynamicObjectRenderingCompletedCallback()->completed(state); } - bool acquireGPUStats = stats && _timerQuerySupported && stats->collectStats("gpu"); + bool acquireGPUStats = stats && _querySupport && stats->collectStats("gpu"); if (acquireGPUStats) { - checkQuery(stats); + _querySupport->checkQuery(stats, state, _startTick); } // do draw traversal if (acquireGPUStats) { - checkQuery(stats); - beginQuery(frameNumber); + _querySupport->checkQuery(stats, state, _startTick); + _querySupport->beginQuery(frameNumber, state); } osg::Timer_t beforeDrawTick; @@ -519,8 +701,8 @@ void Renderer::draw() if (acquireGPUStats) { - endQuery(); - checkQuery(stats); + _querySupport->endQuery(state); + _querySupport->checkQuery(stats, state, _startTick); } //glFlush(); @@ -585,11 +767,11 @@ void Renderer::cull_draw() initialize(state); } - bool acquireGPUStats = stats && _timerQuerySupported && stats->collectStats("gpu"); + bool acquireGPUStats = stats && _querySupport && stats->collectStats("gpu"); if (acquireGPUStats) { - checkQuery(stats); + _querySupport->checkQuery(stats, state, _startTick); } // do cull traversal @@ -626,8 +808,8 @@ void Renderer::cull_draw() // do draw traversal if (acquireGPUStats) { - checkQuery(stats); - beginQuery(frameNumber); + _querySupport->checkQuery(stats, state, _startTick); + _querySupport->beginQuery(frameNumber, state); } osg::Timer_t beforeDrawTick; @@ -656,8 +838,8 @@ void Renderer::cull_draw() if (acquireGPUStats) { - endQuery(); - checkQuery(stats); + _querySupport->endQuery(state); + _querySupport->checkQuery(stats, state, _startTick); } osg::Timer_t afterDrawTick = osg::Timer::instance()->tick();