Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
4#include "qopengltimerquery.h"
5
7#include <QtCore/private/qobject_p.h>
8#include <QtGui/QOpenGLContext>
9#include <QtGui/QOpenGLFunctions>
10
12
13// Helper class used as fallback if OpenGL <3.3 is being used with EXT_timer_query
15{
16public:
18 {
20 GetQueryObjectui64vEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLuint64EXT *)>(context->getProcAddress("glGetQueryObjectui64vEXT"));
21 GetQueryObjecti64vEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint64EXT *)>(context->getProcAddress("glGetQueryObjecti64vEXT"));
22 }
23
25 {
26 GetQueryObjectui64vEXT(id, pname, params);
27 }
28
30 {
31 GetQueryObjecti64vEXT(id, pname, params);
32 }
33
34private:
35 void (QOPENGLF_APIENTRYP GetQueryObjectui64vEXT)(GLuint id, GLenum pname, GLuint64EXT *params);
36 void (QOPENGLF_APIENTRYP GetQueryObjecti64vEXT)(GLuint id, GLenum pname, GLint64EXT *params);
37};
38
40{
41public:
50
52 {
53 delete core;
54 delete ext;
55 }
56
57 bool create();
58 void destroy();
59 void begin();
60 void end();
62 void recordTimestamp();
63 bool isResultAvailable() const;
64 GLuint64 result() const;
65
66 // There are several cases we must handle:
67 // OpenGL >=3.3 includes timer queries as a core feature
68 // ARB_timer_query has same functionality as above. Requires OpenGL 3.2
69 // EXT_timer_query offers limited support. Can be used with OpenGL >=1.5
70 //
71 // Note that some implementations (OS X) provide OpenGL 3.2 but do not expose the
72 // ARB_timer_query extension. In such situations we must also be able to handle
73 // using the EXT_timer_query extension with any version of OpenGL.
74 //
75 // OpenGL 1.5 or above contains the generic query API and OpenGL 3.3 and
76 // ARB_timer_query provide the 64-bit query API. These are wrapped by
77 // QOpenGLQueryHelper. All we need to handle in addition is the EXT_timer_query
78 // case and to take care not to call the Core/ARB functions when we only
79 // have EXT_timer_query available.
85};
86
88{
90
91 if (timer && context == ctx)
92 return true;
93
94 context = ctx;
95 if (!context) {
96 qWarning("A current OpenGL context is required to create timer query objects");
97 return false;
98 }
99
100 if (context->isOpenGLES()) {
101 qWarning("QOpenGLTimerQuery: Not supported on OpenGL ES");
102 return false;
103 }
104
105 // Resolve the functions provided by OpenGL 1.5 and OpenGL 3.3 or ARB_timer_query
107
108 // Check to see if we also need to resolve the functions for EXT_timer_query
110 if (f.version() <= qMakePair(3, 2)
111 && !context->hasExtension(QByteArrayLiteral("GL_ARB_timer_query"))
112 && context->hasExtension(QByteArrayLiteral("GL_EXT_timer_query"))) {
114 } else if (f.version() <= qMakePair(3, 2)
115 && !context->hasExtension(QByteArrayLiteral("GL_ARB_timer_query"))
116 && !context->hasExtension(QByteArrayLiteral("GL_EXT_timer_query"))) {
117 qWarning("QOpenGLTimerQuery requires one of:\n"
118 " OpenGL 3.3 or newer,\n"
119 " OpenGL 3.2 and the ARB_timer_query extension\n"
120 " or the EXT_timer query extension");
121 return false;
122 }
123
124 core->glGenQueries(1, &timer);
125 return (timer != 0);
126}
127
129{
130 if (!timer)
131 return;
132
134 timer = 0;
135 context = nullptr;
136}
137
138// GL_TIME_ELAPSED_EXT is not defined on OS X 10.6
139#if !defined(GL_TIME_ELAPSED_EXT)
140#define GL_TIME_ELAPSED_EXT 0x88BF
141#endif
142
143// GL_TIME_ELAPSED is not defined on OS X 10.7 or 10.8 yet
144#if !defined(GL_TIME_ELAPSED)
145#define GL_TIME_ELAPSED GL_TIME_ELAPSED_EXT
146#endif
147
152
157
159{
160 // Don't call glQueryCounter if we only have EXT_timer_query
161#if defined(GL_TIMESTAMP)
162 if (!ext)
164 else
165 qWarning("QOpenGLTimerQuery::recordTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query");
166#else
167 qWarning("QOpenGLTimerQuery::recordTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query");
168#endif
169}
170
172{
173 GLint64 tmp = 0;
174#if defined(GL_TIMESTAMP)
175 if (!ext)
177 else
178 qWarning("QOpenGLTimerQuery::waitForTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query");
179#else
180 qWarning("QOpenGLTimerQuery::waitForTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query");
181#endif
182 GLuint64 timestamp(tmp);
183 return timestamp;
184}
185
187{
188 GLuint available = GL_FALSE;
190 return available;
191}
192
201
268
273{
275
277 QOpenGLContext *oldContext = nullptr;
278 if (d->context != ctx) {
279 oldContext = ctx;
280 if (d->context->makeCurrent(oldContext->surface())) {
281 ctx = d->context;
282 } else {
283 qWarning("QOpenGLTimerQuery::~QOpenGLTimerQuery() failed to make query objects's context current");
284 ctx = nullptr;
285 }
286 }
287
288 if (ctx)
289 destroy();
290
291 if (oldContext) {
292 if (!oldContext->makeCurrent(oldContext->surface()))
293 qWarning("QOpenGLTimerQuery::~QOpenGLTimerQuery() failed to restore current context");
294 }
295}
296
304{
306 return d->create();
307}
308
314{
316 d->destroy();
317}
318
325{
326 Q_D(const QOpenGLTimerQuery);
327 return (d->timer != 0);
328}
329
334{
335 Q_D(const QOpenGLTimerQuery);
336 return d->timer;
337}
338
348{
350 d->begin();
351}
352
362{
364 d->end();
365}
366
379{
381 return d->recordTimestamp();
382}
383
393{
394 Q_D(const QOpenGLTimerQuery);
395 return d->waitForTimeStamp();
396}
397
407{
408 Q_D(const QOpenGLTimerQuery);
409 return d->isResultAvailable();
410}
411
422{
423 Q_D(const QOpenGLTimerQuery);
424 return d->result();
425}
426
427
429{
430public:
443
445 {
446 delete core;
447 delete ext;
448 }
449
450 bool create();
451 void destroy();
452 void recordSample();
453 bool isResultAvailable() const;
454 QList<GLuint64> samples() const;
455 QList<GLuint64> intervals() const;
456 void reset();
457
458 QList<GLuint> timers;
459 mutable QList<GLuint64> timeSamples;
460
464
467 mutable bool timerQueryActive;
468};
469
471{
472 if (!timers.isEmpty() && timers.at(0) != 0 && timers.size() == requestedSampleCount)
473 return true;
474
476 if (context && context != ctx) {
477 qWarning("QTimeMonitor: Attempting to use different OpenGL context to recreate timers.\n"
478 "Please call destroy() first or use the same context to previously create");
479 return false;
480 }
481
482 context = ctx;
483 if (!context) {
484 qWarning("A current OpenGL context is required to create timer query objects");
485 return false;
486 }
487
488 // Resize the vectors that hold the timers and the recorded samples
491
492 // Resolve the functions provided by OpenGL 1.5 and OpenGL 3.3 or ARB_timer_query
494
495 // Check to see if we also need to resolve the functions for EXT_timer_query
497 if (f.version() <= qMakePair(3, 2)
498 && !context->hasExtension(QByteArrayLiteral("GL_ARB_timer_query"))
499 && context->hasExtension(QByteArrayLiteral("GL_EXT_timer_query"))) {
501 } else if (f.version() <= qMakePair(3, 2)
502 && !context->hasExtension(QByteArrayLiteral("GL_ARB_timer_query"))
503 && !context->hasExtension(QByteArrayLiteral("GL_EXT_timer_query"))) {
504 qWarning("QOpenGLTimeMonitor requires one of:\n"
505 " OpenGL 3.3 or newer,\n"
506 " OpenGL 3.2 and the ARB_timer_query extension\n"
507 " or the EXT_timer query extension");
508 return false;
509 }
510
512 return (timers.at(0) != 0);
513}
514
516{
517 if (timers.isEmpty() || timers.at(0) == 0)
518 return;
519
521 timers.clear();
522 delete core;
523 core = nullptr;
524 delete ext;
525 ext = nullptr;
526 context = nullptr;
527}
528
530{
531 // Use glQueryCounter() and GL_TIMESTAMP where available.
532 // Otherwise, simulate it with glBeginQuery()/glEndQuery()
533 if (!ext) {
534#if defined(GL_TIMESTAMP)
536#endif
537 } else {
538 if (currentSample == -1) {
540 timerQueryActive = true;
541 } else if (currentSample < timers.size() - 1) {
544 } else {
545 if (timerQueryActive) {
547 timerQueryActive = false;
548 }
549 }
550 }
551}
552
554{
555 // The OpenGL spec says that if a query result is ready then the results of all queries
556 // of the same type issued before it must also be ready. Therefore we only need to check
557 // the availability of the result for the last issued query
558 GLuint available = GL_FALSE;
560 return available;
561}
562
564{
565 // For the Core and ARB options just ask for the timestamp for each timer query.
566 // For the EXT implementation we cannot obtain timestamps so we defer any result
567 // collection to the intervals() function
568 if (!ext) {
569 for (int i = 0; i <= currentSample; ++i)
571 } else {
572 qWarning("QOpenGLTimeMonitor::samples() requires OpenGL >=3.3\n"
573 "or OpenGL 3.2 and GL_ARB_timer_query");
574 }
575 return timeSamples;
576}
577
579{
580 QList<GLuint64> intervals(timers.size() - 1);
581 if (!ext) {
582 // Obtain the timestamp samples and calculate the interval durations
583 const QList<GLuint64> timeStamps = samples();
584 for (int i = 0; i < intervals.size(); ++i)
585 intervals[i] = timeStamps[i+1] - timeStamps[i];
586 } else {
587 // Stop the last timer if needed
588 if (timerQueryActive) {
590 timerQueryActive = false;
591 }
592
593 // Obtain the results from all timers apart from the redundant last one. In this
594 // case the results actually are the intervals not timestamps
595 for (int i = 0; i < currentSample; ++i)
597 }
598
599 return intervals;
600}
601
607
608
659
664{
666
668 QOpenGLContext *oldContext = nullptr;
669 if (d->context != ctx) {
670 oldContext = ctx;
671 if (d->context->makeCurrent(oldContext->surface())) {
672 ctx = d->context;
673 } else {
674 qWarning("QOpenGLTimeMonitor::~QOpenGLTimeMonitor() failed to make time monitor's context current");
675 ctx = nullptr;
676 }
677 }
678
679 if (ctx)
680 destroy();
681
682 if (oldContext) {
683 if (!oldContext->makeCurrent(oldContext->surface()))
684 qWarning("QOpenGLTimeMonitor::~QOpenGLTimeMonitor() failed to restore current context");
685 }
686}
687
698{
699 // We need at least 2 samples to get an interval
700 if (sampleCount < 2)
701 return;
703 d->requestedSampleCount = sampleCount;
704}
705
718{
719 Q_D(const QOpenGLTimeMonitor);
720 return d->requestedSampleCount;
721}
722
733{
735 return d->create();
736}
737
744{
746 d->destroy();
747}
748
755{
756 Q_D(const QOpenGLTimeMonitor);
757 return (!d->timers.isEmpty() && d->timers.at(0) != 0);
758}
759
763QList<GLuint> QOpenGLTimeMonitor::objectIds() const
764{
765 Q_D(const QOpenGLTimeMonitor);
766 return d->timers;
767}
768
778{
780 d->recordSample();
781 return d->currentSample;
782}
783
790{
791 Q_D(const QOpenGLTimeMonitor);
792 return d->isResultAvailable();
793}
794
808{
809 Q_D(const QOpenGLTimeMonitor);
810 return d->samples();
811}
812
826{
827 Q_D(const QOpenGLTimeMonitor);
828 return d->intervals();
829}
830
839{
841 d->reset();
842}
843
845
846#include "moc_qopengltimerquery.cpp"
QExtTimerQueryHelper(QOpenGLContext *context)
void glGetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params)
void glGetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params)
qsizetype size() const noexcept
Definition qlist.h:397
QList< T > & fill(parameter_type t, qsizetype size=-1)
Definition qlist.h:903
bool isEmpty() const noexcept
Definition qlist.h:401
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
pointer data()
Definition qlist.h:431
void resize(qsizetype size)
Definition qlist.h:403
void clear()
Definition qlist.h:434
\inmodule QtCore
Definition qobject.h:103
\inmodule QtGui
QSurfaceFormat format() const
Returns the format of the underlying platform context, if create() has been called.
bool hasExtension(const QByteArray &extension) const
Returns true if this OpenGL context supports the specified OpenGL extension, false otherwise.
static QOpenGLContext * currentContext()
Returns the last context which called makeCurrent in the current thread, or \nullptr,...
bool isOpenGLES() const
Returns true if the context is an OpenGL ES context.
void glEndQuery(GLenum target)
void glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
void glGetQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params)
void glGetInteger64v(GLenum pname, GLint64 *params)
void glGenQueries(GLsizei n, GLuint *ids)
void glQueryCounter(GLuint id, GLenum target)
void glBeginQuery(GLenum target, GLuint id)
void glDeleteQueries(GLsizei n, const GLuint *ids)
QList< GLuint64 > intervals() const
QExtTimerQueryHelper * ext
QList< GLuint64 > samples() const
The QOpenGLTimeMonitor class wraps a sequence of OpenGL timer query objects.
QList< GLuint > objectIds() const
Returns a QList containing the object Ids of the OpenGL timer query objects.
int sampleCount() const
Returns the number of sample points that have been requested with setSampleCount().
bool create()
Instantiate sampleCount() OpenGL timer query objects that will be used to track the amount of time ta...
void destroy()
Destroys any OpenGL timer query objects used within this instance.
int recordSample()
Issues an OpenGL timer query at this point in the OpenGL command queue.
QList< GLuint64 > waitForSamples() const
Returns a QList containing the GPU timestamps taken with recordSample().
QList< GLuint64 > waitForIntervals() const
Returns a QList containing the time intervals delimited by the calls to recordSample().
bool isResultAvailable() const
Returns true if the OpenGL timer query results are available.
bool isCreated() const
Returns true if the underlying OpenGL query objects have been created.
void reset()
Resets the time monitor ready for use in another frame of rendering.
void setSampleCount(int sampleCount)
Sets the number of sample points to sampleCount.
~QOpenGLTimeMonitor()
Destroys the QOpenGLTimeMonitor and any underlying OpenGL resources.
QOpenGLTimeMonitor(QObject *parent=nullptr)
Creates a QOpenGLTimeMonitor instance with the given parent.
QExtTimerQueryHelper * ext
QOpenGLQueryHelper * core
The QOpenGLTimerQuery class wraps an OpenGL timer query object.
~QOpenGLTimerQuery()
Destroys the QOpenGLTimerQuery and the underlying OpenGL resource.
bool isResultAvailable() const
Returns true if the OpenGL timer query result is available.
void destroy()
Destroys the underlying OpenGL timer query object.
void end()
Marks the end point in the OpenGL command queue for a sequence of commands to be timed by this query ...
bool isCreated() const
Returns true if the underlying OpenGL query object has been created.
GLuint objectId() const
Returns the id of the underlying OpenGL query object.
void recordTimestamp()
Places a marker in the OpenGL command queue for the GPU to record the timestamp when this marker is r...
GLuint64 waitForTimestamp() const
Returns the current timestamp of the GPU when all previously issued OpenGL commands have been receive...
bool create()
Creates the underlying OpenGL timer query object.
void begin()
Marks the start point in the OpenGL command queue for a sequence of commands to be timed by this quer...
GLuint64 waitForResult() const
Returns the result of the OpenGL timer query.
QOpenGLTimerQuery(QObject *parent=nullptr)
Creates a QOpenGLTimerQuery instance with the given parent.
The QSurfaceFormat class represents the format of a QSurface. \inmodule QtGui.
EGLContext ctx
Combined button and popup list for selecting options.
static void * context
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
#define qWarning
Definition qlogging.h:166
int64_t GLint64EXT
Definition qopengl.h:227
uint64_t GLuint64
Definition qopengl.h:233
uint64_t GLuint64EXT
Definition qopengl.h:228
#define QOPENGLF_APIENTRYP
Definition qopengl.h:275
int64_t GLint64
Definition qopengl.h:232
GLenum GLuint id
[7]
GLenum pname
GLfloat GLfloat f
typedef GLenum(GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSKHRPROC)(void)
void ** params
#define GL_TIMESTAMP
#define GL_QUERY_RESULT
Definition qopenglext.h:485
#define GL_QUERY_RESULT_AVAILABLE
Definition qopenglext.h:486
#define GL_TIME_ELAPSED
#define GL_TIME_ELAPSED_EXT
QT_BEGIN_NAMESPACE constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define GLuint
QObject::connect nullptr