/*********************************************************************** * Copyright 2011-2012 Computer Graphics Group RWTH Aachen University. * * All rights reserved. * * Distributed under the terms of the MIT License (see LICENSE.TXT). * **********************************************************************/ #ifndef ACGL_OPENGL_OBJECTS_QUERY_HH #define ACGL_OPENGL_OBJECTS_QUERY_HH #include #include #include #include #ifndef ACGL_OPENGLES_VERSION_20 namespace ACGL{ namespace OpenGL{ /** * A generic OpenGL asynchronous query, target types can be: * SAMPLES_PASSED * ANY_SAMPLES_PASSED * PRIMITIVES_GENERATED * TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN * TIME_ELAPSED * * See specialized queries below. * * Note: * Indexed queries are not jet supported. * * Only one query per type is alowed to be active at any time. * * Before the result can get read out, the query must end() ! */ class AsynchronousQuery { public: AsynchronousQuery( GLenum _defaultTarget ) : mTarget(_defaultTarget) { glGenQueries( 1, &mObjectName ); } virtual ~AsynchronousQuery() { glDeleteQueries( 1, &mObjectName ); } //! start the query, only one query per type is allowed to be active at any time. void begin(void) { glBeginQuery( mTarget, mObjectName ); } //! end the query void end(void) { glEndQuery( mTarget ); } //! returns true if the result of the query is available, if not, trying to get the result will stall the CPU GLboolean isResultAvailable(void) { GLint resultAvailable; glGetQueryObjectiv(mObjectName, GL_QUERY_RESULT_AVAILABLE, &resultAvailable); return (GLboolean) resultAvailable; } //! get the query result, what it is depents on the query target GLuint getResult(void) { GLuint queryResult; glGetQueryObjectuiv( mObjectName, GL_QUERY_RESULT, &queryResult ); return queryResult; } //! get the query result in 64 bit, what it is depents on the query target GLuint64 getResult64(void) { #if (ACGL_OPENGL_VERSION >= 33) GLuint64 queryResult; glGetQueryObjectui64v( mObjectName, GL_QUERY_RESULT, &queryResult ); return queryResult; #else return (GLuint64) getResult(); // default to 32 bit version on pre GL 3.3 systems #endif } //! returns the raw object name to be used directly in OpenGL functions inline GLuint getObjectName(void) const { return mObjectName; } protected: GLuint mObjectName; GLenum mTarget; }; ACGL_SMARTPOINTER_TYPEDEFS(AsynchronousQuery) /** * Occlusion queries count the fragments that pass the z-test. * * There are two variants: * GL_SAMPLES_PASSED - will count the fragments * GL_ANY_SAMPLES_PASSED - will just tell whether fragments have passed the z-test, not how many (0 or any number) */ class OcclusionQuery : public AsynchronousQuery { public: OcclusionQuery() : AsynchronousQuery( GL_SAMPLES_PASSED ) {} OcclusionQuery( GLenum _queryType ) : AsynchronousQuery( _queryType ) { setType( _queryType ); } //! _queryType has to be GL_SAMPLES_PASSED or GL_ANY_SAMPLES_PASSED void setType( GLenum _queryType ) { #if (ACGL_OPENGL_VERSION >= 33) if (_queryType == GL_ANY_SAMPLES_PASSED) _queryType = GL_SAMPLES_PASSED; // GL_ANY_SAMPLES_PASSED is OpenGL 3.3 or later! But GL_SAMPLES_PASSED is a good substitute #endif if (_queryType != GL_SAMPLES_PASSED) { Utils::error() << "OcclusionQuery type " << _queryType << " not supported" << std::endl; _queryType = GL_SAMPLES_PASSED; } mTarget = _queryType; } //! get the actual number of fragments, unless the type is GL_ANY_SAMPLES_PASSED, than it only tells 0 or any value GLuint samplesPassed(void) { return getResult(); } }; ACGL_SMARTPOINTER_TYPEDEFS(OcclusionQuery) #if (ACGL_OPENGL_VERSION >= 33) /** * TimerQueries can get the GPU timestamp and measure GPU execution speed. * * Only available since OpenGL 3.3 or GL_ARB_timer_query (on OpenGL 3.2) */ class TimerQuery : public AsynchronousQuery { public: TimerQuery() : AsynchronousQuery( GL_TIME_ELAPSED ) {} //! Mark the moment in the pipeline of which the time should get queried. void saveTimestamp(void) { glQueryCounter( mObjectName, GL_TIMESTAMP ); } //! Get the current GPU timestamp. GLint64 getCurrentTimestamp(void) { GLint64 time; glGetInteger64v( GL_TIMESTAMP, &time ); return time; } //! Get the timestamp saved by 'saveTimestamp'. GLuint64 getSavedTimestamp(void) { return getResult64(); } }; ACGL_SMARTPOINTER_TYPEDEFS(TimerQuery) #endif // OpenGL >= 3.3 #if (ACGL_OPENGL_VERSION >= 31) /** * Primitive queries count the number of processed geometry. Sounds trivial as the app should * know the number from the glDraw* calls, but this query will also count geometry generated * by geometry/tessellation shaders. * * During transform feedback let one query of each type run and compare the results: if more * primitives were generated than written to the TF buffer, the buffer overflowd. */ class PrimitiveQuery : public AsynchronousQuery { public: PrimitiveQuery() : AsynchronousQuery( GL_PRIMITIVES_GENERATED ) {} PrimitiveQuery( GLenum _queryType ) : AsynchronousQuery( _queryType ) { setType( _queryType ); } //! _queryType has to be GL_PRIMITIVES_GENERATED or GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN void setType( GLenum _queryType ) { if ((_queryType != GL_PRIMITIVES_GENERATED) && (_queryType != GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN)) { Utils::error() << "PrimitiveQuery type " << _queryType << " not supported" << std::endl; _queryType = GL_PRIMITIVES_GENERATED; } mTarget = _queryType; } }; ACGL_SMARTPOINTER_TYPEDEFS(PrimitiveQuery) #endif // OpenGL >= 3.1 } // OpenGL } // ACGL #endif // ES 2.0 #endif // ACGL_OPENGL_OBJECTS_QUERY_HH