From Tim More and Robert Osfield, implementation of ARB_timer_query based GPU timing stats syncronization.
Initial email from Tim : "I've implemented using a timestamp, available with ARB_timer_query and OpenGL 3.3, to gather GPU stats. This is nice because it can accurately fix the GPU draw time with respect to the other times on the stats graph, rather than having to estimate the wall time of the end of GPU drawing. This also prevents anomalies like the GPU phase starting before the draw phase..." Changes to Tim's submission by Robert: Removal of need for swap buffer callback in ViewerBase.cpp, by integrating a osg::State::frameCompleted() method that does the stats timing collection. Introduction of a GraphicsContext::swapBuffersCallbackOrImplementation() method that calls the State::frameCompleted() and the swap buffers callback or the swapImplementation as required.
This commit is contained in:
@@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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> _graphicsThread;
|
||||
|
||||
ref_ptr<ResizedCallback> _resizedCallback;
|
||||
ref_ptr<SwapCallback> _swapCallback;
|
||||
|
||||
Timer_t _lastClearTick;
|
||||
};
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <osg/Uniform>
|
||||
#include <osg/BufferObject>
|
||||
#include <osg/Observer>
|
||||
#include <osg/Timer>
|
||||
|
||||
#include <osg/ShaderComposer>
|
||||
#include <osg/FrameStamp>
|
||||
@@ -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)
|
||||
|
||||
@@ -21,38 +21,23 @@
|
||||
|
||||
namespace osgViewer {
|
||||
|
||||
class OSGVIEWER_EXPORT OpenGLQuerySupport
|
||||
class OSGVIEWER_EXPORT OpenGLQuerySupport : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
OpenGLQuerySupport();
|
||||
|
||||
typedef std::pair<GLuint, int> QueryFrameNumberPair;
|
||||
typedef std::list<QueryFrameNumberPair> QueryFrameNumberList;
|
||||
typedef std::vector<GLuint> 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<OpenGLQuerySupport> _querySupport;
|
||||
osg::Timer_t _startTick;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user