qopengltimerquery.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/gui/opengl/qopengltimerquery.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
1/****************************************************************************-
2**-
3** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB).-
4** Contact: http://www.qt.io/licensing/-
5**-
6** This file is part of the QtGui module of the Qt Toolkit.-
7**-
8** $QT_BEGIN_LICENSE:LGPL21$-
9** Commercial License Usage-
10** Licensees holding valid commercial Qt licenses may use this file in-
11** accordance with the commercial license agreement provided with the-
12** Software or, alternatively, in accordance with the terms contained in-
13** a written agreement between you and The Qt Company. For licensing terms-
14** and conditions see http://www.qt.io/terms-conditions. For further-
15** information use the contact form at http://www.qt.io/contact-us.-
16**-
17** GNU Lesser General Public License Usage-
18** Alternatively, this file may be used under the terms of the GNU Lesser-
19** General Public License version 2.1 or version 3 as published by the Free-
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and-
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the-
22** following information to ensure the GNU Lesser General Public License-
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and-
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.-
25**-
26** As a special exception, The Qt Company gives you certain additional-
27** rights. These rights are described in The Qt Company LGPL Exception-
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.-
29**-
30** $QT_END_LICENSE$-
31**-
32****************************************************************************/-
33-
34#include "qopengltimerquery.h"-
35-
36#include "qopenglqueryhelper_p.h"-
37#include <QtCore/private/qobject_p.h>-
38#include <QtGui/QOpenGLContext>-
39#include <QtGui/QOpenGLFunctions>-
40-
41QT_BEGIN_NAMESPACE-
42-
43// Helper class used as fallback if OpenGL <3.3 is being used with EXT_timer_query-
44class QExtTimerQueryHelper-
45{-
46public:-
47 QExtTimerQueryHelper(QOpenGLContext *context)-
48 {-
49 Q_ASSERT(context);-
50 GetQueryObjectui64vEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLuint64EXT *)>(context->getProcAddress("glGetQueryObjectui64vEXT"));-
51 GetQueryObjecti64vEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint64EXT *)>(context->getProcAddress("glGetQueryObjecti64vEXT"));-
52 }
never executed: end of block
0
53-
54 inline void glGetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params)-
55 {-
56 GetQueryObjectui64vEXT(id, pname, params);-
57 }
never executed: end of block
0
58-
59 inline void glGetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params)-
60 {-
61 GetQueryObjecti64vEXT(id, pname, params);-
62 }
never executed: end of block
0
63-
64private:-
65 void (QOPENGLF_APIENTRYP GetQueryObjectui64vEXT)(GLuint id, GLenum pname, GLuint64EXT *params);-
66 void (QOPENGLF_APIENTRYP GetQueryObjecti64vEXT)(GLuint id, GLenum pname, GLint64EXT *params);-
67};-
68-
69class QOpenGLTimerQueryPrivate : public QObjectPrivate-
70{-
71public:-
72 QOpenGLTimerQueryPrivate()-
73 : QObjectPrivate(),-
74 context(0),-
75 ext(0),-
76 timeInterval(0),-
77 timer(0)-
78 {-
79 }
never executed: end of block
0
80-
81 ~QOpenGLTimerQueryPrivate()-
82 {-
83 delete core;-
84 delete ext;-
85 }
never executed: end of block
0
86-
87 bool create();-
88 void destroy();-
89 void begin();-
90 void end();-
91 GLuint64 waitForTimeStamp() const;-
92 void recordTimestamp();-
93 bool isResultAvailable() const;-
94 GLuint64 result() const;-
95-
96 // There are several cases we must handle:-
97 // OpenGL >=3.3 includes timer queries as a core feature-
98 // ARB_timer_query has same functionality as above. Requires OpenGL 3.2-
99 // EXT_timer_query offers limited support. Can be used with OpenGL >=1.5-
100 //-
101 // Note that some implementations (OS X) provide OpenGL 3.2 but do not expose the-
102 // ARB_timer_query extension. In such situations we must also be able to handle-
103 // using the EXT_timer_query extension with any version of OpenGL.-
104 //-
105 // OpenGL 1.5 or above contains the generic query API and OpenGL 3.3 and-
106 // ARB_timer_query provide the 64-bit query API. These are wrapped by-
107 // QOpenGLQueryHelper. All we need to handle in addition is the EXT_timer_query-
108 // case and to take care not to call the Core/ARB functions when we only-
109 // have EXT_timer_query available.-
110 QOpenGLContext *context;-
111 QOpenGLQueryHelper *core;-
112 QExtTimerQueryHelper *ext;-
113 mutable GLuint64 timeInterval;-
114 GLuint timer;-
115};-
116-
117bool QOpenGLTimerQueryPrivate::create()-
118{-
119 QOpenGLContext *ctx = QOpenGLContext::currentContext();-
120-
121 if (timer && context == ctx)
timerDescription
TRUEnever evaluated
FALSEnever evaluated
context == ctxDescription
TRUEnever evaluated
FALSEnever evaluated
0
122 return true;
never executed: return true;
0
123-
124 context = ctx;-
125 if (!context) {
!contextDescription
TRUEnever evaluated
FALSEnever evaluated
0
126 qWarning("A current OpenGL context is required to create timer query objects");-
127 return false;
never executed: return false;
0
128 }-
129-
130 if (context->isOpenGLES()) {
context->isOpenGLES()Description
TRUEnever evaluated
FALSEnever evaluated
0
131 qWarning("QOpenGLTimerQuery: Not supported on OpenGL ES");-
132 return false;
never executed: return false;
0
133 }-
134-
135 // Resolve the functions provided by OpenGL 1.5 and OpenGL 3.3 or ARB_timer_query-
136 core = new QOpenGLQueryHelper(context);-
137-
138 // Check to see if we also need to resolve the functions for EXT_timer_query-
139 QSurfaceFormat f = context->format();-
140 if (f.version() <= qMakePair<int, int>(3, 2)
f.version() <=...nt, int>(3, 2)Description
TRUEnever evaluated
FALSEnever evaluated
0
141 && !context->hasExtension(QByteArrayLiteral("GL_ARB_timer_query"))
never executed: return ba;
!context->hasE...turn ba; }()))Description
TRUEnever evaluated
FALSEnever evaluated
0
142 && context->hasExtension(QByteArrayLiteral("GL_EXT_timer_query"))) {
never executed: return ba;
context->hasEx...turn ba; }()))Description
TRUEnever evaluated
FALSEnever evaluated
0
143 ext = new QExtTimerQueryHelper(context);-
144 } else if (f.version() <= qMakePair<int, int>(3, 2)
never executed: end of block
f.version() <=...nt, int>(3, 2)Description
TRUEnever evaluated
FALSEnever evaluated
0
145 && !context->hasExtension(QByteArrayLiteral("GL_ARB_timer_query"))
never executed: return ba;
!context->hasE...turn ba; }()))Description
TRUEnever evaluated
FALSEnever evaluated
0
146 && !context->hasExtension(QByteArrayLiteral("GL_EXT_timer_query"))) {
never executed: return ba;
!context->hasE...turn ba; }()))Description
TRUEnever evaluated
FALSEnever evaluated
0
147 qWarning("QOpenGLTimerQuery requires one of:\n"-
148 " OpenGL 3.3 or newer,\n"-
149 " OpenGL 3.2 and the ARB_timer_query extension\n"-
150 " or the EXT_timer query extension");-
151 return false;
never executed: return false;
0
152 }-
153-
154 core->glGenQueries(1, &timer);-
155 return (timer != 0);
never executed: return (timer != 0);
0
156}-
157-
158void QOpenGLTimerQueryPrivate::destroy()-
159{-
160 if (!timer)
!timerDescription
TRUEnever evaluated
FALSEnever evaluated
0
161 return;
never executed: return;
0
162-
163 core->glDeleteQueries(1, &timer);-
164 timer = 0;-
165 context = 0;-
166}
never executed: end of block
0
167-
168// GL_TIME_ELAPSED_EXT is not defined on OS X 10.6-
169#if !defined(GL_TIME_ELAPSED_EXT)-
170#define GL_TIME_ELAPSED_EXT 0x88BF-
171#endif-
172-
173// GL_TIME_ELAPSED is not defined on OS X 10.7 or 10.8 yet-
174#if !defined(GL_TIME_ELAPSED)-
175#define GL_TIME_ELAPSED GL_TIME_ELAPSED_EXT-
176#endif-
177-
178void QOpenGLTimerQueryPrivate::begin()-
179{-
180 core->glBeginQuery(GL_TIME_ELAPSED, timer);-
181}
never executed: end of block
0
182-
183void QOpenGLTimerQueryPrivate::end()-
184{-
185 core->glEndQuery(GL_TIME_ELAPSED);-
186}
never executed: end of block
0
187-
188void QOpenGLTimerQueryPrivate::recordTimestamp()-
189{-
190 // Don't call glQueryCounter if we only have EXT_timer_query-
191#if defined(GL_TIMESTAMP)-
192 if (!ext)
!extDescription
TRUEnever evaluated
FALSEnever evaluated
0
193 core->glQueryCounter(timer, GL_TIMESTAMP);
never executed: core->glQueryCounter(timer, 0x8E28);
0
194 else-
195 qWarning("QOpenGLTimerQuery::recordTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query");
never executed: QMessageLogger(__FILE__, 195, __PRETTY_FUNCTION__).warning("QOpenGLTimerQuery::recordTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query");
0
196#else-
197 qWarning("QOpenGLTimerQuery::recordTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query");-
198#endif-
199}-
200-
201GLuint64 QOpenGLTimerQueryPrivate::waitForTimeStamp() const-
202{-
203 GLint64 tmp = 0;-
204#if defined(GL_TIMESTAMP)-
205 if (!ext)
!extDescription
TRUEnever evaluated
FALSEnever evaluated
0
206 core->glGetInteger64v(GL_TIMESTAMP, &tmp);
never executed: core->glGetInteger64v(0x8E28, &tmp);
0
207 else-
208 qWarning("QOpenGLTimerQuery::waitForTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query");
never executed: QMessageLogger(__FILE__, 208, __PRETTY_FUNCTION__).warning("QOpenGLTimerQuery::waitForTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query");
0
209#else-
210 qWarning("QOpenGLTimerQuery::waitForTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query");-
211#endif-
212 GLuint64 timestamp(tmp);-
213 return timestamp;
never executed: return timestamp;
0
214}-
215-
216bool QOpenGLTimerQueryPrivate::isResultAvailable() const-
217{-
218 GLuint available = GL_FALSE;-
219 core->glGetQueryObjectuiv(timer, GL_QUERY_RESULT_AVAILABLE, &available);-
220 return available;
never executed: return available;
0
221}-
222-
223GLuint64 QOpenGLTimerQueryPrivate::result() const-
224{-
225 if (!ext)
!extDescription
TRUEnever evaluated
FALSEnever evaluated
0
226 core->glGetQueryObjectui64v(timer, GL_QUERY_RESULT, &timeInterval);
never executed: core->glGetQueryObjectui64v(timer, 0x8866, &timeInterval);
0
227 else-
228 ext->glGetQueryObjectui64vEXT(timer, GL_QUERY_RESULT, &timeInterval);
never executed: ext->glGetQueryObjectui64vEXT(timer, 0x8866, &timeInterval);
0
229 return timeInterval;
never executed: return timeInterval;
0
230}-
231-
232/*!-
233 \class QOpenGLTimerQuery-
234 \brief The QOpenGLTimerQuery class wraps an OpenGL timer query object.-
235 \inmodule QtGui-
236 \since 5.1-
237 \ingroup painting-3D-
238-
239 OpenGL timer query objects are OpenGL managed resources to measure the-
240 execution times of sequences of OpenGL commands on the GPU.-
241-
242 OpenGL offers various levels of support for timer queries, depending on-
243 the version of OpenGL you have and the presence of the ARB_timer_query or-
244 EXT_timer_query extensions. The support can be summarized as:-
245-
246 \list-
247 \li OpenGL >=3.3 offers full support for all timer query functionality.-
248 \li OpenGL 3.2 with the ARB_timer_query extension offers full support-
249 for all timer query functionality.-
250 \li OpenGL <=3.2 with the EXT_timer_query extension offers limited support-
251 in that the timestamp of the GPU cannot be queried. Places where this-
252 impacts functions provided by Qt classes will be highlighted in the-
253 function documentation.-
254 \li OpenGL ES 2 (and OpenGL ES 3) do not provide any support for OpenGL-
255 timer queries.-
256 \endlist-
257-
258 OpenGL represents time with a granularity of 1 nanosecond (1e-9 seconds). As a-
259 consequence of this, 32-bit integers would only give a total possible duration-
260 of approximately 4 seconds, which would not be difficult to exceed in poorly-
261 performing or lengthy operations. OpenGL therefore uses 64 bit integer types-
262 to represent times. A GLuint64 variable has enough width to contain a duration-
263 of hundreds of years, which is plenty for real-time rendering needs.-
264-
265 As with the other Qt OpenGL classes, QOpenGLTimerQuery has a create()-
266 function to create the underlying OpenGL object. This is to allow the developer to-
267 ensure that there is a valid current OpenGL context at the time.-
268-
269 Once created, timer queries can be issued in one of several ways. The simplest-
270 method is to delimit a block of commands with calls to begin() and end(). This-
271 instructs OpenGL to measure the time taken from completing all commands issued-
272 prior to begin() until the completion of all commands issued prior to end().-
273-
274 At the end of a frame we can retrieve the results by calling waitForResult().-
275 As this function's name implies, it blocks CPU execution until OpenGL notifies-
276 that the timer query result is available. To avoid blocking, you can check-
277 if the query result is available by calling isResultAvailable(). Note that-
278 modern GPUs are deeply pipelined and query results may not become available for-
279 between 1-5 frames after they were issued.-
280-
281 Note that OpenGL does not permit nesting or interleaving of multiple timer queries-
282 using begin() and end(). Using multiple timer queries and recordTimestamp() avoids-
283 this limitation. When using recordTimestamp() the result can be obtained at-
284 some later time using isResultAvailable() and waitForResult(). Qt provides the-
285 convenience class QOpenGLTimeMonitor that helps with using multiple query objects.-
286-
287 \sa QOpenGLTimeMonitor-
288*/-
289-
290/*!-
291 Creates a QOpenGLTimerQuery instance with the given \a parent. You must call create()-
292 with a valid OpenGL context before using.-
293*/-
294QOpenGLTimerQuery::QOpenGLTimerQuery(QObject *parent)-
295 : QObject(*new QOpenGLTimerQueryPrivate, parent)-
296{-
297}
never executed: end of block
0
298-
299/*!-
300 Destroys the QOpenGLTimerQuery and the underlying OpenGL resource.-
301*/-
302QOpenGLTimerQuery::~QOpenGLTimerQuery()-
303{-
304 QOpenGLContext* ctx = QOpenGLContext::currentContext();-
305-
306 Q_D(QOpenGLTimerQuery);-
307 QOpenGLContext *oldContext = 0;-
308 if (d->context != ctx) {
d->context != ctxDescription
TRUEnever evaluated
FALSEnever evaluated
0
309 oldContext = ctx;-
310 if (d->context->makeCurrent(oldContext->surface())) {
d->context->ma...xt->surface())Description
TRUEnever evaluated
FALSEnever evaluated
0
311 ctx = d->context;-
312 } else {
never executed: end of block
0
313 qWarning("QOpenGLTimerQuery::~QOpenGLTimerQuery() failed to make query objects's context current");-
314 ctx = 0;-
315 }
never executed: end of block
0
316 }-
317-
318 if (ctx)
ctxDescription
TRUEnever evaluated
FALSEnever evaluated
0
319 destroy();
never executed: destroy();
0
320-
321 if (oldContext) {
oldContextDescription
TRUEnever evaluated
FALSEnever evaluated
0
322 if (!oldContext->makeCurrent(oldContext->surface()))
!oldContext->m...xt->surface())Description
TRUEnever evaluated
FALSEnever evaluated
0
323 qWarning("QOpenGLTimerQuery::~QOpenGLTimerQuery() failed to restore current context");
never executed: QMessageLogger(__FILE__, 323, __PRETTY_FUNCTION__).warning("QOpenGLTimerQuery::~QOpenGLTimerQuery() failed to restore current context");
0
324 }
never executed: end of block
0
325}
never executed: end of block
0
326-
327/*!-
328 Creates the underlying OpenGL timer query object. There must be a valid OpenGL context-
329 that supports query objects current for this function to succeed.-
330-
331 Returns \c true if the OpenGL timer query object was successfully created.-
332*/-
333bool QOpenGLTimerQuery::create()-
334{-
335 Q_D(QOpenGLTimerQuery);-
336 return d->create();
never executed: return d->create();
0
337}-
338-
339/*!-
340 Destroys the underlying OpenGL timer query object. The context that was current when-
341 create() was called must be current when calling this function.-
342*/-
343void QOpenGLTimerQuery::destroy()-
344{-
345 Q_D(QOpenGLTimerQuery);-
346 d->destroy();-
347}
never executed: end of block
0
348-
349/*!-
350 Returns \c true if the underlying OpenGL query object has been created. If this-
351 returns \c true and the associated OpenGL context is current, then you are able to issue-
352 queries with this object.-
353*/-
354bool QOpenGLTimerQuery::isCreated() const-
355{-
356 Q_D(const QOpenGLTimerQuery);-
357 return (d->timer != 0);
never executed: return (d->timer != 0);
0
358}-
359-
360/*!-
361 Returns the id of the underlying OpenGL query object.-
362*/-
363GLuint QOpenGLTimerQuery::objectId() const-
364{-
365 Q_D(const QOpenGLTimerQuery);-
366 return d->timer;
never executed: return d->timer;
0
367}-
368-
369/*!-
370 Marks the start point in the OpenGL command queue for a sequence of commands to-
371 be timed by this query object.-
372-
373 This is useful for simple use-cases. Usually it is better to use recordTimestamp().-
374-
375 \sa end(), isResultAvailable(), waitForResult(), recordTimestamp()-
376*/-
377void QOpenGLTimerQuery::begin()-
378{-
379 Q_D(QOpenGLTimerQuery);-
380 d->begin();-
381}
never executed: end of block
0
382-
383/*!-
384 Marks the end point in the OpenGL command queue for a sequence of commands to-
385 be timed by this query object.-
386-
387 This is useful for simple use-cases. Usually it is better to use recordTimestamp().-
388-
389 \sa begin(), isResultAvailable(), waitForResult(), recordTimestamp()-
390*/-
391void QOpenGLTimerQuery::end()-
392{-
393 Q_D(QOpenGLTimerQuery);-
394 d->end();-
395}
never executed: end of block
0
396-
397/*!-
398 Places a marker in the OpenGL command queue for the GPU to record the timestamp-
399 when this marker is reached by the GPU. This function is non-blocking and the-
400 result will become available at some later time.-
401-
402 The availability of the result can be checked with isResultAvailable(). The result-
403 can be fetched with waitForResult() which will block if the result is not yet-
404 available.-
405-
406 \sa waitForResult(), isResultAvailable(), begin(), end()-
407*/-
408void QOpenGLTimerQuery::recordTimestamp()-
409{-
410 Q_D(QOpenGLTimerQuery);-
411 return d->recordTimestamp();
never executed: return d->recordTimestamp();
0
412}-
413-
414/*!-
415 Returns the current timestamp of the GPU when all previously issued OpenGL-
416 commands have been received but not necessarily executed by the GPU.-
417-
418 This function blocks until the result is returned.-
419-
420 \sa recordTimestamp()-
421*/-
422GLuint64 QOpenGLTimerQuery::waitForTimestamp() const-
423{-
424 Q_D(const QOpenGLTimerQuery);-
425 return d->waitForTimeStamp();
never executed: return d->waitForTimeStamp();
0
426}-
427-
428/*!-
429 Returns \c true if the OpenGL timer query result is available.-
430-
431 This function is non-blocking and ideally should be used to check for the-
432 availability of the query result before calling waitForResult().-
433-
434 \sa waitForResult()-
435*/-
436bool QOpenGLTimerQuery::isResultAvailable() const-
437{-
438 Q_D(const QOpenGLTimerQuery);-
439 return d->isResultAvailable();
never executed: return d->isResultAvailable();
0
440}-
441-
442/*!-
443 Returns the result of the OpenGL timer query.-
444-
445 This function will block until the result is made available by OpenGL. It is-
446 recommended to call isResultAvailable() to ensure that the result is available-
447 to avoid unnecessary blocking and stalling.-
448-
449 \sa isResultAvailable()-
450*/-
451GLuint64 QOpenGLTimerQuery::waitForResult() const-
452{-
453 Q_D(const QOpenGLTimerQuery);-
454 return d->result();
never executed: return d->result();
0
455}-
456-
457-
458class QOpenGLTimeMonitorPrivate : public QObjectPrivate-
459{-
460public:-
461 QOpenGLTimeMonitorPrivate()-
462 : QObjectPrivate(),-
463 timers(),-
464 timeSamples(),-
465 context(0),-
466 core(0),-
467 ext(0),-
468 requestedSampleCount(2),-
469 currentSample(-1),-
470 timerQueryActive(false)-
471 {-
472 }
never executed: end of block
0
473-
474 ~QOpenGLTimeMonitorPrivate()-
475 {-
476 delete core;-
477 delete ext;-
478 }
never executed: end of block
0
479-
480 bool create();-
481 void destroy();-
482 void recordSample();-
483 bool isResultAvailable() const;-
484 QVector<GLuint64> samples() const;-
485 QVector<GLuint64> intervals() const;-
486 void reset();-
487-
488 QVector<GLuint> timers;-
489 mutable QVector<GLuint64> timeSamples;-
490-
491 QOpenGLContext *context;-
492 QOpenGLQueryHelper *core;-
493 QExtTimerQueryHelper *ext;-
494-
495 int requestedSampleCount;-
496 int currentSample;-
497 mutable bool timerQueryActive;-
498};-
499-
500bool QOpenGLTimeMonitorPrivate::create()-
501{-
502 if (!timers.isEmpty() && timers.at(0) != 0 && timers.size() == requestedSampleCount)
!timers.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
timers.at(0) != 0Description
TRUEnever evaluated
FALSEnever evaluated
timers.size() ...tedSampleCountDescription
TRUEnever evaluated
FALSEnever evaluated
0
503 return true;
never executed: return true;
0
504-
505 QOpenGLContext *ctx = QOpenGLContext::currentContext();-
506 if (context && context != ctx) {
contextDescription
TRUEnever evaluated
FALSEnever evaluated
context != ctxDescription
TRUEnever evaluated
FALSEnever evaluated
0
507 qWarning("QTimeMonitor: Attempting to use different OpenGL context to recreate timers.\n"-
508 "Please call destroy() first or use the same context to previously create");-
509 return false;
never executed: return false;
0
510 }-
511-
512 context = ctx;-
513 if (!context) {
!contextDescription
TRUEnever evaluated
FALSEnever evaluated
0
514 qWarning("A current OpenGL context is required to create timer query objects");-
515 return false;
never executed: return false;
0
516 }-
517-
518 // Resize the vectors that hold the timers and the recorded samples-
519 timers.resize(requestedSampleCount);-
520 timeSamples.resize(requestedSampleCount);-
521-
522 // Resolve the functions provided by OpenGL 1.5 and OpenGL 3.3 or ARB_timer_query-
523 core = new QOpenGLQueryHelper(context);-
524-
525 // Check to see if we also need to resolve the functions for EXT_timer_query-
526 QSurfaceFormat f = context->format();-
527 if (f.version() <= qMakePair<int, int>(3, 2)
f.version() <=...nt, int>(3, 2)Description
TRUEnever evaluated
FALSEnever evaluated
0
528 && !context->hasExtension(QByteArrayLiteral("GL_ARB_timer_query"))
never executed: return ba;
!context->hasE...turn ba; }()))Description
TRUEnever evaluated
FALSEnever evaluated
0
529 && context->hasExtension(QByteArrayLiteral("GL_EXT_timer_query"))) {
never executed: return ba;
context->hasEx...turn ba; }()))Description
TRUEnever evaluated
FALSEnever evaluated
0
530 ext = new QExtTimerQueryHelper(context);-
531 } else if (f.version() <= qMakePair<int, int>(3, 2)
never executed: end of block
f.version() <=...nt, int>(3, 2)Description
TRUEnever evaluated
FALSEnever evaluated
0
532 && !context->hasExtension(QByteArrayLiteral("GL_ARB_timer_query"))
never executed: return ba;
!context->hasE...turn ba; }()))Description
TRUEnever evaluated
FALSEnever evaluated
0
533 && !context->hasExtension(QByteArrayLiteral("GL_EXT_timer_query"))) {
never executed: return ba;
!context->hasE...turn ba; }()))Description
TRUEnever evaluated
FALSEnever evaluated
0
534 qWarning("QOpenGLTimeMonitor requires one of:\n"-
535 " OpenGL 3.3 or newer,\n"-
536 " OpenGL 3.2 and the ARB_timer_query extension\n"-
537 " or the EXT_timer query extension");-
538 return false;
never executed: return false;
0
539 }-
540-
541 core->glGenQueries(requestedSampleCount, timers.data());-
542 return (timers.at(0) != 0);
never executed: return (timers.at(0) != 0);
0
543}-
544-
545void QOpenGLTimeMonitorPrivate::destroy()-
546{-
547 if (timers.isEmpty() || timers.at(0) == 0)
timers.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
timers.at(0) == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
548 return;
never executed: return;
0
549-
550 core->glDeleteQueries(timers.size(), timers.data());-
551 timers.clear();-
552 delete core;-
553 core = 0;-
554 delete ext;-
555 ext = 0;-
556 context = 0;-
557}
never executed: end of block
0
558-
559void QOpenGLTimeMonitorPrivate::recordSample()-
560{-
561 // Use glQueryCounter() and GL_TIMESTAMP where available.-
562 // Otherwise, simulate it with glBeginQuery()/glEndQuery()-
563 if (!ext) {
!extDescription
TRUEnever evaluated
FALSEnever evaluated
0
564#if defined(GL_TIMESTAMP)-
565 core->glQueryCounter(timers.at(++currentSample), GL_TIMESTAMP);-
566#endif-
567 } else {
never executed: end of block
0
568 if (currentSample == -1) {
currentSample == -1Description
TRUEnever evaluated
FALSEnever evaluated
0
569 core->glBeginQuery(GL_TIME_ELAPSED_EXT, timers.at(++currentSample));-
570 timerQueryActive = true;-
571 } else if (currentSample < timers.size() - 1) {
never executed: end of block
currentSample ...ers.size() - 1Description
TRUEnever evaluated
FALSEnever evaluated
0
572 core->glEndQuery(GL_TIME_ELAPSED_EXT);-
573 core->glBeginQuery(GL_TIME_ELAPSED_EXT, timers.at(++currentSample));-
574 } else {
never executed: end of block
0
575 if (timerQueryActive) {
timerQueryActiveDescription
TRUEnever evaluated
FALSEnever evaluated
0
576 core->glEndQuery(GL_TIME_ELAPSED_EXT);-
577 timerQueryActive = false;-
578 }
never executed: end of block
0
579 }
never executed: end of block
0
580 }-
581}-
582-
583bool QOpenGLTimeMonitorPrivate::isResultAvailable() const-
584{-
585 // The OpenGL spec says that if a query result is ready then the results of all queries-
586 // of the same type issued before it must also be ready. Therefore we only need to check-
587 // the availability of the result for the last issued query-
588 GLuint available = GL_FALSE;-
589 core->glGetQueryObjectuiv(timers.at(currentSample), GL_QUERY_RESULT_AVAILABLE, &available);-
590 return available;
never executed: return available;
0
591}-
592-
593QVector<GLuint64> QOpenGLTimeMonitorPrivate::samples() const-
594{-
595 // For the Core and ARB options just ask for the timestamp for each timer query.-
596 // For the EXT implementation we cannot obtain timestamps so we defer any result-
597 // collection to the intervals() function-
598 if (!ext) {
!extDescription
TRUEnever evaluated
FALSEnever evaluated
0
599 for (int i = 0; i <= currentSample; ++i)
i <= currentSampleDescription
TRUEnever evaluated
FALSEnever evaluated
0
600 core->glGetQueryObjectui64v(timers.at(i), GL_QUERY_RESULT, &timeSamples[i]);
never executed: core->glGetQueryObjectui64v(timers.at(i), 0x8866, &timeSamples[i]);
0
601 } else {
never executed: end of block
0
602 qWarning("QOpenGLTimeMonitor::samples() requires OpenGL >=3.3\n"-
603 "or OpenGL 3.2 and GL_ARB_timer_query");-
604 }
never executed: end of block
0
605 return timeSamples;
never executed: return timeSamples;
0
606}-
607-
608QVector<GLuint64> QOpenGLTimeMonitorPrivate::intervals() const-
609{-
610 QVector<GLuint64> intervals(timers.size() - 1);-
611 if (!ext) {
!extDescription
TRUEnever evaluated
FALSEnever evaluated
0
612 // Obtain the timestamp samples and calculate the interval durations-
613 const QVector<GLuint64> timeStamps = samples();-
614 for (int i = 0; i < intervals.size(); ++i)
i < intervals.size()Description
TRUEnever evaluated
FALSEnever evaluated
0
615 intervals[i] = timeStamps[i+1] - timeStamps[i];
never executed: intervals[i] = timeStamps[i+1] - timeStamps[i];
0
616 } else {
never executed: end of block
0
617 // Stop the last timer if needed-
618 if (timerQueryActive) {
timerQueryActiveDescription
TRUEnever evaluated
FALSEnever evaluated
0
619 core->glEndQuery(GL_TIME_ELAPSED_EXT);-
620 timerQueryActive = false;-
621 }
never executed: end of block
0
622-
623 // Obtain the results from all timers apart from the redundant last one. In this-
624 // case the results actually are the intervals not timestamps-
625 for (int i = 0; i < currentSample; ++i)
i < currentSampleDescription
TRUEnever evaluated
FALSEnever evaluated
0
626 ext->glGetQueryObjectui64vEXT(timers.at(i), GL_QUERY_RESULT, &intervals[i]);
never executed: ext->glGetQueryObjectui64vEXT(timers.at(i), 0x8866, &intervals[i]);
0
627 }
never executed: end of block
0
628-
629 return intervals;
never executed: return intervals;
0
630}-
631-
632void QOpenGLTimeMonitorPrivate::reset()-
633{-
634 currentSample = -1;-
635 timeSamples.fill(0);-
636}
never executed: end of block
0
637-
638-
639/*!-
640 \class QOpenGLTimeMonitor-
641 \brief The QOpenGLTimeMonitor class wraps a sequence of OpenGL timer query objects.-
642 \inmodule QtGui-
643 \since 5.1-
644 \ingroup painting-3D-
645-
646 The QOpenGLTimeMonitor class is a convenience wrapper around a collection of OpenGL-
647 timer query objects used to measure intervals of time on the GPU to the level of-
648 granularity required by your rendering application.-
649-
650 The OpenGL timer queries objects are queried in sequence to record the GPU-
651 timestamps at positions of interest in your rendering code. Once the results for-
652 all issues timer queries become available, the results can be fetched and-
653 QOpenGLTimerMonitor will calculate the recorded time intervals for you.-
654-
655 The typical use case of this class is to either profile your application's rendering-
656 algorithms or to adjust those algorithms in real-time for dynamic performance/quality-
657 balancing.-
658-
659 Prior to using QOpenGLTimeMonitor in your rendering function you should set the-
660 required number of sample points that you wish to record by calling setSamples(). Note-
661 that measuring N sample points will produce N-1 time intervals. Once you have set the-
662 number of sample points, call the create() function with a valid current OpenGL context-
663 to create the necessary query timer objects. These steps are usually performed just-
664 once in an initialization function.-
665-
666 Use the recordSample() function to delimit blocks of code containing OpenGL commands-
667 that you wish to time. You can check availability of the resulting time-
668 samples and time intervals with isResultAvailable(). The calculated time intervals and-
669 the raw timestamp samples can be retrieved with the blocking waitForIntervals() and-
670 waitForSamples() functions respectively.-
671-
672 After retrieving the results and before starting a new round of taking samples-
673 (for example, in the next frame) be sure to call the reset() function which will clear-
674 the cached results and reset the timer index back to the first timer object.-
675-
676 \sa QOpenGLTimerQuery-
677*/-
678-
679/*!-
680 Creates a QOpenGLTimeMonitor instance with the given \a parent. You must call create()-
681 with a valid OpenGL context before using.-
682-
683 \sa setSampleCount(), create()-
684*/-
685QOpenGLTimeMonitor::QOpenGLTimeMonitor(QObject *parent)-
686 : QObject(*new QOpenGLTimeMonitorPrivate, parent)-
687{-
688}
never executed: end of block
0
689-
690/*!-
691 Destroys the QOpenGLTimeMonitor and any underlying OpenGL resources.-
692*/-
693QOpenGLTimeMonitor::~QOpenGLTimeMonitor()-
694{-
695 QOpenGLContext* ctx = QOpenGLContext::currentContext();-
696-
697 Q_D(QOpenGLTimeMonitor);-
698 QOpenGLContext *oldContext = 0;-
699 if (d->context != ctx) {
d->context != ctxDescription
TRUEnever evaluated
FALSEnever evaluated
0
700 oldContext = ctx;-
701 if (d->context->makeCurrent(oldContext->surface())) {
d->context->ma...xt->surface())Description
TRUEnever evaluated
FALSEnever evaluated
0
702 ctx = d->context;-
703 } else {
never executed: end of block
0
704 qWarning("QOpenGLTimeMonitor::~QOpenGLTimeMonitor() failed to make time monitor's context current");-
705 ctx = 0;-
706 }
never executed: end of block
0
707 }-
708-
709 if (ctx)
ctxDescription
TRUEnever evaluated
FALSEnever evaluated
0
710 destroy();
never executed: destroy();
0
711-
712 if (oldContext) {
oldContextDescription
TRUEnever evaluated
FALSEnever evaluated
0
713 if (!oldContext->makeCurrent(oldContext->surface()))
!oldContext->m...xt->surface())Description
TRUEnever evaluated
FALSEnever evaluated
0
714 qWarning("QOpenGLTimeMonitor::~QOpenGLTimeMonitor() failed to restore current context");
never executed: QMessageLogger(__FILE__, 714, __PRETTY_FUNCTION__).warning("QOpenGLTimeMonitor::~QOpenGLTimeMonitor() failed to restore current context");
0
715 }
never executed: end of block
0
716}
never executed: end of block
0
717-
718/*!-
719 Sets the number of sample points to \a sampleCount. After setting the number-
720 of samples with this function, you must call create() to instantiate the underlying-
721 OpenGL timer query objects.-
722-
723 The new \a sampleCount must be at least 2.-
724-
725 \sa sampleCount(), create(), recordSample()-
726*/-
727void QOpenGLTimeMonitor::setSampleCount(int sampleCount)-
728{-
729 // We need at least 2 samples to get an interval-
730 if (sampleCount < 2)
sampleCount < 2Description
TRUEnever evaluated
FALSEnever evaluated
0
731 return;
never executed: return;
0
732 Q_D(QOpenGLTimeMonitor);-
733 d->requestedSampleCount = sampleCount;-
734}
never executed: end of block
0
735-
736/*!-
737 Returns the number of sample points that have been requested with-
738 setSampleCount(). If create was successfully called following setSampleCount(),-
739 then the value returned will be the actual number of sample points-
740 that can be used.-
741-
742 The default value for sample count is 2, leading to the measurement of a-
743 single interval.-
744-
745 \sa setSampleCount()-
746*/-
747int QOpenGLTimeMonitor::sampleCount() const-
748{-
749 Q_D(const QOpenGLTimeMonitor);-
750 return d->requestedSampleCount;
never executed: return d->requestedSampleCount;
0
751}-
752-
753/*!-
754 Instantiate sampleCount() OpenGL timer query objects that will be used-
755 to track the amount of time taken to execute OpenGL commands between-
756 successive calls to recordSample().-
757-
758 Returns \c true if the OpenGL timer query objects could be created.-
759-
760 \sa destroy(), setSampleCount(), recordSample()-
761*/-
762bool QOpenGLTimeMonitor::create()-
763{-
764 Q_D(QOpenGLTimeMonitor);-
765 return d->create();
never executed: return d->create();
0
766}-
767-
768/*!-
769 Destroys any OpenGL timer query objects used within this instance.-
770-
771 \sa create()-
772*/-
773void QOpenGLTimeMonitor::destroy()-
774{-
775 Q_D(QOpenGLTimeMonitor);-
776 d->destroy();-
777}
never executed: end of block
0
778-
779/*!-
780 Returns \c true if the underlying OpenGL query objects have been created. If this-
781 returns \c true and the associated OpenGL context is current, then you are able to record-
782 time samples with this object.-
783*/-
784bool QOpenGLTimeMonitor::isCreated() const-
785{-
786 Q_D(const QOpenGLTimeMonitor);-
787 return (!d->timers.isEmpty() && d->timers.at(0) != 0);
never executed: return (!d->timers.isEmpty() && d->timers.at(0) != 0);
!d->timers.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
d->timers.at(0) != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
788}-
789-
790/*!-
791 Returns a QVector containing the object Ids of the OpenGL timer query objects.-
792*/-
793QVector<GLuint> QOpenGLTimeMonitor::objectIds() const-
794{-
795 Q_D(const QOpenGLTimeMonitor);-
796 return d->timers;
never executed: return d->timers;
0
797}-
798-
799/*!-
800 Issues an OpenGL timer query at this point in the OpenGL command queue. Calling this-
801 function in a sequence in your application's rendering function, will build up-
802 details of the GPU time taken to execute the OpenGL commands between successive-
803 calls to this function.-
804-
805 \sa setSampleCount(), isResultAvailable(), waitForSamples(), waitForIntervals()-
806*/-
807int QOpenGLTimeMonitor::recordSample()-
808{-
809 Q_D(QOpenGLTimeMonitor);-
810 d->recordSample();-
811 return d->currentSample;
never executed: return d->currentSample;
0
812}-
813-
814/*!-
815 Returns \c true if the OpenGL timer query results are available.-
816-
817 \sa waitForSamples(), waitForIntervals()-
818*/-
819bool QOpenGLTimeMonitor::isResultAvailable() const-
820{-
821 Q_D(const QOpenGLTimeMonitor);-
822 return d->isResultAvailable();
never executed: return d->isResultAvailable();
0
823}-
824-
825/*!-
826 Returns a QVector containing the GPU timestamps taken with recordSample().-
827-
828 This function will block until OpenGL indicates the results are available. It-
829 is recommended to check the availability of the result prior to calling this-
830 function with isResultAvailable().-
831-
832 \note This function only works on systems that have OpenGL >=3.3 or the-
833 ARB_timer_query extension. See QOpenGLTimerQuery for more details.-
834-
835 \sa waitForIntervals(), isResultAvailable()-
836*/-
837QVector<GLuint64> QOpenGLTimeMonitor::waitForSamples() const-
838{-
839 Q_D(const QOpenGLTimeMonitor);-
840 return d->samples();
never executed: return d->samples();
0
841}-
842-
843/*!-
844 Returns a QVector containing the time intervals delimited by the calls to-
845 recordSample(). The resulting vector will contain one fewer element as-
846 this represents the intervening intervals rather than the actual timestamp-
847 samples.-
848-
849 This function will block until OpenGL indicates the results are available. It-
850 is recommended to check the availability of the result prior to calling this-
851 function with isResultAvailable().-
852-
853 \sa waitForSamples(), isResultAvailable()-
854*/-
855QVector<GLuint64> QOpenGLTimeMonitor::waitForIntervals() const-
856{-
857 Q_D(const QOpenGLTimeMonitor);-
858 return d->intervals();
never executed: return d->intervals();
0
859}-
860-
861/*!-
862 Resets the time monitor ready for use in another frame of rendering. Call-
863 this once you have obtained the previous results and before calling-
864 recordSample() for the first time on the next frame.-
865-
866 \sa recordSample()-
867*/-
868void QOpenGLTimeMonitor::reset()-
869{-
870 Q_D(QOpenGLTimeMonitor);-
871 d->reset();-
872}
never executed: end of block
0
873-
874QT_END_NAMESPACE-
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9