Query.hh 7.29 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

17
#if (ACGL_OPENGLES_VERSION > 20)
18 19 20 21

namespace ACGL{
namespace OpenGL{

Robert Menzel's avatar
Robert Menzel committed
22
/**
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
 * 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 );
    }

48 49 50 51 52 53 54 55 56 57 58 59 60 61
    // ===================================================================================================== \/
    // =========================================================================================== 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

62 63 64 65 66 67 68 69 70 71 72 73
    //! 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) {
74 75 76 77
#if (ACGL_OPENGLES_VERSION >= 30)
        GLuint resultAvailable;
        glGetQueryObjectuiv(mObjectName, GL_QUERY_RESULT_AVAILABLE, &resultAvailable);
#else
78 79
        GLint resultAvailable;
        glGetQueryObjectiv(mObjectName, GL_QUERY_RESULT_AVAILABLE, &resultAvailable);
80
#endif
81 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
        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
110
ACGL_SMARTPOINTER_TYPEDEFS(AsynchronousQuery)
111

Robert Menzel's avatar
Robert Menzel committed
112
/**
113 114 115 116 117 118
 * 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)
 */
119 120 121 122 123 124
    
// 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
    
125 126 127 128 129 130 131 132 133
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 ) {
134
#if (ACGL_OPENGL_VERSION < 33)
135 136
        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
137
        if (_queryType != GL_SAMPLES_PASSED) {
138 139 140 141 142 143 144 145 146 147 148
            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
149
ACGL_SMARTPOINTER_TYPEDEFS(OcclusionQuery)
150 151 152


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

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

} // OpenGL
} // ACGL

213 214
#endif // ES 2.0

215
#endif // ACGL_OPENGL_OBJECTS_QUERY_HH