Query.hh 7.35 KB
Newer Older
1 2 3 4 5
/***********************************************************************
 * Copyright 2011-2012 Computer Graphics Group RWTH Aachen University. *
 * All rights reserved.                                                *
 * Distributed under the terms of the MIT License (see LICENSE.TXT).   *
 **********************************************************************/
6 7 8 9 10 11 12 13 14

#ifndef ACGL_OPENGL_OBJECTS_QUERY_HH
#define ACGL_OPENGL_OBJECTS_QUERY_HH

#include <ACGL/ACGL.hh>

#include <ACGL/Base/Macros.hh>
#include <ACGL/OpenGL/GL.hh>
#include <ACGL/OpenGL/Tools.hh>
15
#include <ACGL/OpenGL/Debug.hh>
16

Robert Menzel's avatar
Robert Menzel committed
17 18
// only exclude ES 2 for now:
#if ((ACGL_OPENGLES_VERSION > 20) || (ACGL_OPENGL_VERSION > 20))
19 20 21 22

namespace ACGL{
namespace OpenGL{

Robert Menzel's avatar
Robert Menzel committed
23
/**
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
 * 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 );
    }

49 50 51 52 53 54 55 56 57 58 59 60 61 62
    // ===================================================================================================== \/
    // =========================================================================================== KHR_DEBUG \/
    // ===================================================================================================== \/
public:
    // Sets and gets a label visible inside of a OpenGL debugger if KHR_debug is supported at runtime *and*
    // if ACGL_OPENGL_DEBUGGER_SUPPORT was defined during compile time. Does nothing otherwise!
#ifdef ACGL_OPENGL_DEBUGGER_SUPPORT
    void setObjectLabel( const std::string &_label ) { setObjectLabelT<GL_QUERY>(getObjectName(),_label); }
    std::string getObjectLabel() { return getObjectLabelT<GL_QUERY>(getObjectName()); }
#else
    void setObjectLabel( const std::string & ) {}
    std::string getObjectLabel() { return ""; }
#endif

63 64 65 66 67 68 69 70 71 72 73 74
    //! 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) {
75 76 77 78
#if (ACGL_OPENGLES_VERSION >= 30)
        GLuint resultAvailable;
        glGetQueryObjectuiv(mObjectName, GL_QUERY_RESULT_AVAILABLE, &resultAvailable);
#else
79 80
        GLint resultAvailable;
        glGetQueryObjectiv(mObjectName, GL_QUERY_RESULT_AVAILABLE, &resultAvailable);
81
#endif
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
        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;
};
Robert Menzel's avatar
Robert Menzel committed
111
ACGL_SMARTPOINTER_TYPEDEFS(AsynchronousQuery)
112

Robert Menzel's avatar
Robert Menzel committed
113
/**
114 115 116 117 118 119
 * 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)
 */
120 121 122 123 124 125
    
// On ES only ANY_SAMPLES is supported, so use this as a substitute:
#if ( !defined(GL_SAMPLES_PASSED) && (ACGL_OPENGLES_VERSION >= 30))
#define GL_SAMPLES_PASSED GL_ANY_SAMPLES_PASSED
#endif
    
126 127 128 129 130 131 132 133 134
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 ) {
135
#if (ACGL_OPENGL_VERSION < 33)
136 137
        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
138
        if (_queryType != GL_SAMPLES_PASSED) {
139 140 141 142 143 144 145 146 147 148 149
            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();
    }
};
Robert Menzel's avatar
Robert Menzel committed
150
ACGL_SMARTPOINTER_TYPEDEFS(OcclusionQuery)
151 152 153


#if (ACGL_OPENGL_VERSION >= 33)
Robert Menzel's avatar
Robert Menzel committed
154
/**
155 156 157 158 159 160 161 162 163
 * 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.
Robert Menzel's avatar
Robert Menzel committed
164
    void saveTimestamp(void) {
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
        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();
    }
};
Robert Menzel's avatar
Robert Menzel committed
180
ACGL_SMARTPOINTER_TYPEDEFS(TimerQuery)
181 182 183
#endif // OpenGL >= 3.3

#if (ACGL_OPENGL_VERSION >= 31)
Robert Menzel's avatar
Robert Menzel committed
184
/**
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
 * 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;
    }
};
Robert Menzel's avatar
Robert Menzel committed
208
ACGL_SMARTPOINTER_TYPEDEFS(PrimitiveQuery)
209 210 211 212 213
#endif // OpenGL >= 3.1

} // OpenGL
} // ACGL

214 215
#endif // ES 2.0

216
#endif // ACGL_OPENGL_OBJECTS_QUERY_HH