Query.hh 5.95 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 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 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2012, Computer Graphics Group RWTH Aachen University         //
// All rights reserved.                                                       //
////////////////////////////////////////////////////////////////////////////////

#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>


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_SHARED_TYPEDEF(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) && (_queryType != GL_ANY_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_SHARED_TYPEDEF(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.
Robert Menzel's avatar
Robert Menzel committed
135
    void saveTimestamp(void) {
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
        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_SHARED_TYPEDEF(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_SHARED_TYPEDEF(PrimitiveQuery)
#endif // OpenGL >= 3.1

} // OpenGL
} // ACGL

185
#endif // ACGL_OPENGL_OBJECTS_QUERY_HH