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