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