diff options
Diffstat (limited to 'src/gui/opengl')
-rw-r--r-- | src/gui/opengl/opengl.pri | 9 | ||||
-rw-r--r-- | src/gui/opengl/qopengldebug.cpp | 1826 | ||||
-rw-r--r-- | src/gui/opengl/qopengldebug.h | 221 | ||||
-rw-r--r-- | src/gui/opengl/qopenglqueryhelper_p.h | 186 | ||||
-rw-r--r-- | src/gui/opengl/qopengltexture.cpp | 2 | ||||
-rw-r--r-- | src/gui/opengl/qopengltexture.h | 2 | ||||
-rw-r--r-- | src/gui/opengl/qopengltimerquery.cpp | 880 | ||||
-rw-r--r-- | src/gui/opengl/qopengltimerquery.h | 116 |
8 files changed, 4 insertions, 3238 deletions
diff --git a/src/gui/opengl/opengl.pri b/src/gui/opengl/opengl.pri index 24758afdeb..26060ea5df 100644 --- a/src/gui/opengl/opengl.pri +++ b/src/gui/opengl/opengl.pri @@ -27,7 +27,6 @@ qtConfig(opengl) { opengl/qopenglversionfunctions.h \ opengl/qopenglversionfunctionsfactory_p.h \ opengl/qopenglvertexarrayobject.h \ - opengl/qopengldebug.h \ opengl/qopengltextureblitter.h \ opengl/qopengltexture.h \ opengl/qopengltexture_p.h \ @@ -53,7 +52,6 @@ qtConfig(opengl) { opengl/qopenglversionfunctions.cpp \ opengl/qopenglversionfunctionsfactory.cpp \ opengl/qopenglvertexarrayobject.cpp \ - opengl/qopengldebug.cpp \ opengl/qopengltextureblitter.cpp \ opengl/qopengltexture.cpp \ opengl/qopengltexturehelper.cpp \ @@ -87,9 +85,7 @@ qtConfig(opengl) { opengl/qopenglfunctions_4_2_compatibility.h \ opengl/qopenglfunctions_4_3_compatibility.h \ opengl/qopenglfunctions_4_4_compatibility.h \ - opengl/qopenglfunctions_4_5_compatibility.h \ - opengl/qopenglqueryhelper_p.h \ - opengl/qopengltimerquery.h + opengl/qopenglfunctions_4_5_compatibility.h SOURCES += opengl/qopenglfunctions_1_0.cpp \ opengl/qopenglfunctions_1_1.cpp \ @@ -116,8 +112,7 @@ qtConfig(opengl) { opengl/qopenglfunctions_4_2_compatibility.cpp \ opengl/qopenglfunctions_4_3_compatibility.cpp \ opengl/qopenglfunctions_4_4_compatibility.cpp \ - opengl/qopenglfunctions_4_5_compatibility.cpp \ - opengl/qopengltimerquery.cpp + opengl/qopenglfunctions_4_5_compatibility.cpp } qtConfig(opengles2) { diff --git a/src/gui/opengl/qopengldebug.cpp b/src/gui/opengl/qopengldebug.cpp deleted file mode 100644 index 310006feaf..0000000000 --- a/src/gui/opengl/qopengldebug.cpp +++ /dev/null @@ -1,1826 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtCore/private/qobject_p.h> -#include <QtCore/qglobal.h> -#include <QtCore/qvarlengtharray.h> -#include <QtGui/qopengl.h> -#include <QtGui/qopenglfunctions.h> -#include <QtGui/qoffscreensurface.h> - -#include "qopengldebug.h" - -QT_BEGIN_NAMESPACE - -/*! - \class QOpenGLDebugMessage - \brief The QOpenGLDebugMessage class wraps an OpenGL debug message. - \inmodule QtGui - \reentrant - \since 5.1 - \ingroup shared - \ingroup painting-3D - - Debug messages are usually created by the OpenGL server and then read by - OpenGL clients (either from the OpenGL internal debug log, or logged in real-time). - A debug message has a textual representation, a vendor-specific numeric id, - a source, a type and a severity. - - It's also possible for applications or third-party libraries and toolkits - to create and insert messages in the debug log. In order to do so, you can use - the createApplicationMessage() or the createThirdPartyMessage() static functions. - - \sa QOpenGLDebugLogger -*/ - -/*! - \class QOpenGLDebugLogger - \brief The QOpenGLDebugLogger enables logging of OpenGL debugging messages. - \inmodule QtGui - \since 5.1 - \ingroup painting-3D - - \tableofcontents - - \section1 Introduction - - OpenGL programming can be very error prone. Most of the time, a single - failing call to OpenGL can cause an entire portion of an application to - stop working, with nothing being drawn on the screen. - - The only way to be sure that no errors are being returned from the OpenGL - implementation is checking with \c{glGetError} after each and every API - call. Moreover, OpenGL errors stack up, therefore glGetError should always - be used in a loop like this: - - \snippet code/src_gui_opengl_qopengldebug.cpp 0 - - If you try to clear the error stack, make sure not just keep going until - GL_NO_ERROR is returned but also break on GL_CONTEXT_LOST as that error - value will keep repeating. - - There are also many other information we are interested in (as application - developers), for instance performance issues, or warnings about using - deprecated APIs. Those kind of messages are not reported through the - ordinary OpenGL error reporting mechanisms. - - QOpenGLDebugLogger aims at addressing these issues by providing access to - the \e{OpenGL debug log}. If your OpenGL implementation supports it (by - exposing the \c{GL_KHR_debug} extension), messages from the OpenGL server - will be either logged in an internal OpenGL log, or passed in "real-time" - to listeners as they're generated from OpenGL. - - QOpenGLDebugLogger supports both these modes of operation. Refer to the - following sections to find out the differences between them. - - \section1 Creating an OpenGL Debug Context - - For efficiency reasons, OpenGL implementations are allowed not to create - any debug output at all, unless the OpenGL context is a debug context. In order - to create a debug context from Qt, you must set the QSurfaceFormat::DebugContext - format option on the QSurfaceFormat used to create the QOpenGLContext object: - - \snippet code/src_gui_opengl_qopengldebug.cpp 1 - - Note that requesting a 3.2 OpenGL Core Profile is just for the example's - purposes; this class is not tied to any specific OpenGL or OpenGL ES - version, as it relies on the availability of the \c{GL_KHR_debug} extension - (see below). - - \section1 Creating and Initializing a QOpenGLDebugLogger - - QOpenGLDebugLogger is a simple QObject-derived class. Just like all QObject - subclasses, you create an instance (and optionally specify a parent - object), and like the other OpenGL functions in Qt you \e{must} initialize - it before usage by calling initialize() whilst there is a current OpenGL context: - - \snippet code/src_gui_opengl_qopengldebug.cpp 2 - - Note that the \c{GL_KHR_debug} extension \e{must} be available in the context - in order to access the messages logged by OpenGL. You can check the - presence of this extension by calling: - - \snippet code/src_gui_opengl_qopengldebug.cpp 3 - - where \c{ctx} is a valid QOpenGLContext. If the extension is not available, - initialize() will return false. - - \section1 Reading the Internal OpenGL Debug Log - - OpenGL implementations keep an internal log of debug messages. Messages - stored in this log can be retrieved by using the loggedMessages() function: - - \snippet code/src_gui_opengl_qopengldebug.cpp 4 - - The internal log has a limited size; when it fills up, older messages will - get discarded to make room for the new incoming messages. When you call - loggedMessages(), the internal log will be emptied as well. - - If you want to be sure not to lose any debug message, you must use real-time - logging instead of calling this function. However, debug messages might - still be generated in the timespan between context creation and activation - of real-time logging (or, in general, when the real-time logging is disabled). - - \section1 Real-time logging of messages - - It is also possible to receive a stream of debug messages from the OpenGL - server \e{as they are generated} by the implementation. In order to do so, - you need to connect a suitable slot to the messageLogged() signal, and - start logging by calling startLogging(): - - \snippet code/src_gui_opengl_qopengldebug.cpp 5 - - Similarly, logging can be disabled at any time by calling the stopLogging() - function. - - Real-time logging can be either asynchronous or synchronous, depending on - the parameter passed to startLogging(). When logging in asynchronous mode - (the default, as it has a very small overhead), the OpenGL implementation - can generate messages at any time, and/or in an order which is different from the - order of the OpenGL commands which caused those messages to be logged. - The messages could also be generated from a thread that it's different from - the thread the context is currently bound to. This is because OpenGL - implementations are usually highly threaded and asynchronous, and therefore - no warranties are made about the relative order and the timings of the - debug messages. - - On the other hand, logging in synchronous mode has a high overhead, but - the OpenGL implementation guarantees that all the messages caused by a - certain command are received in order, before the command returns, - and from the same thread the OpenGL context is bound to. - - This means that when logging in synchronous mode you will be able to run - your OpenGL application in a debugger, put a breakpoint on a slot connected - to the messageLogged() signal, and see in the backtrace the exact call - that caused the logged message. This can be extremely useful to debug - an OpenGL problem. Note that if OpenGL rendering is happening in another - thread, you must force the signal/slot connection type to Qt::DirectConnection - in order to be able to see the actual backtrace. - - Refer to the LoggingMode enum documentation for more information about - logging modes. - - \note When real-time logging is enabled, debug messages will \e{not} be - inserted in the internal OpenGL debug log any more; messages already - present in the internal log will not be deleted, nor they will be emitted - through the messageLogged() signal. Since some messages might be generated - before real-time logging is started (and therefore be kept in the internal - OpenGL log), it is important to always check if it contains any message - after calling startLogging(). - - \section1 Inserting Messages in the Debug Log - - It is possible for applications and libraries to insert custom messages in - the debug log, for instance for marking a group of related OpenGL commands - and therefore being then able to identify eventual messages coming from them. - - In order to do so, you can create a QOpenGLDebugMessage object by calling - \l{QOpenGLDebugMessage::}{createApplicationMessage()} or - \l{QOpenGLDebugMessage::}{createThirdPartyMessage()}, and then inserting it - into the log by calling logMessage(): - - \snippet code/src_gui_opengl_qopengldebug.cpp 6 - - Note that OpenGL implementations have a vendor-specific limit to the length - of the messages that can be inserted in the debug log. You can retrieve - this length by calling the maximumMessageLength() method; messages longer - than the limit will automatically get truncated. - - \section1 Controlling the Debug Output - - QOpenGLDebugMessage is also able to apply filters to the debug messages, and - therefore limit the amount of messages logged. You can enable or disable - logging of messages by calling enableMessages() and disableMessages() - respectively. By default, all messages are logged. - - It is possible to enable or disable messages by selecting them by: - - \list - \li source, type and severity (and including all ids in the selection); - \li id, source and type (and including all severities in the selection). - \endlist - - Note that the "enabled" status for a given message is a property of the - (id, source, type, severity) tuple; the message attributes \e{do not} form - a hierarchy of any kind. You should be careful about the order of the calls - to enableMessages() and disableMessages(), as it will change which - messages will are enabled / disabled. - - It's not possible to filter by the message text itself; applications - have to do that on their own (in slots connected to the messageLogged() - signal, or after fetching the messages in the internal debug log - through loggedMessages()). - - In order to simplify the management of the enabled / disabled statuses, - QOpenGLDebugMessage also supports the concept of \c{debug groups}. A debug - group contains the group of enabled / disabled configurations of debug - messages. Moreover, debug groups are organized in a stack: it is possible - to push and pop groups by calling pushGroup() and popGroup() respectively. - (When an OpenGL context is created, there is already a group in the stack). - - The enableMessages() and disableMessages() functions will modify the - configuration in the current debug group, that is, the one at the top of - the debug groups stack. - - When a new group is pushed onto the debug groups stack, it will inherit - the configuration of the group that was previously on the top of the stack. - Vice versa, popping a debug group will restore the configuration of - the debug group that becomes the new top. - - Pushing (respectively popping) debug groups will also automatically generate - a debug message of type QOpenGLDebugMessage::GroupPushType (respectively - \l{QOpenGLDebugMessage::}{GroupPopType}). - - \sa QOpenGLDebugMessage -*/ - -/*! - \enum QOpenGLDebugMessage::Source - - The Source enum defines the source of the debug message. - - \value InvalidSource - The source of the message is invalid; this is the source of a - default-constructed QOpenGLDebugMessage object. - - \value APISource - The message was generated in response to OpenGL API calls. - - \value WindowSystemSource - The message was generated by the window system. - - \value ShaderCompilerSource - The message was generated by the shader compiler. - - \value ThirdPartySource - The message was generated by a third party, for instance an OpenGL - framework a or debugging toolkit. - - \value ApplicationSource - The message was generated by the application itself. - - \value OtherSource - The message was generated by a source not included in this - enumeration. - - \omitvalue LastSource - - \value AnySource - This value corresponds to a mask of all possible message sources. -*/ - -/*! - \enum QOpenGLDebugMessage::Type - - The Type enum defines the type of the debug message. - - \value InvalidType - The type of the message is invalid; this is the type of a - default-constructed QOpenGLDebugMessage object. - - \value ErrorType - The message represents an error. - - \value DeprecatedBehaviorType - The message represents an usage of deprecated behavior. - - \value UndefinedBehaviorType - The message represents an usage of undefined behavior. - - \value PortabilityType - The message represents an usage of vendor-specific behavior, - that might pose portability concerns. - - \value PerformanceType - The message represents a performance issue. - - \value OtherType - The message represents a type not included in this - enumeration. - - \value MarkerType - The message represents a marker in the debug log. - - \value GroupPushType - The message represents a debug group push operation. - - \value GroupPopType - The message represents a debug group pop operation. - - \omitvalue LastType - - \value AnyType - This value corresponds to a mask of all possible message types. -*/ - -/*! - \enum QOpenGLDebugMessage::Severity - - The Severity enum defines the severity of the debug message. - - \value InvalidSeverity - The severity of the message is invalid; this is the severity of a - default-constructed QOpenGLDebugMessage object. - - \value HighSeverity - The message has a high severity. - - \value MediumSeverity - The message has a medium severity. - - \value LowSeverity - The message has a low severity. - - \value NotificationSeverity - The message is a notification. - - \omitvalue LastSeverity - - \value AnySeverity - This value corresponds to a mask of all possible message severities. -*/ - -/*! - \property QOpenGLDebugLogger::loggingMode - - \brief the logging mode passed to startLogging(). - - Note that logging must have been started or the value of this property - will be meaningless. - - \sa startLogging(), isLogging() -*/ -/*! - \enum QOpenGLDebugLogger::LoggingMode - - The LoggingMode enum defines the logging mode of the logger object. - - \value AsynchronousLogging - Messages from the OpenGL server are logged asynchronously. This means - that messages can be logged some time after the corresponding OpenGL - actions that caused them, and even be received in an out-of-order - fashion, depending on the OpenGL implementation. This mode has a very low - performance penalty, as OpenGL implementations are heavily threaded - and asynchronous by nature. - - \value SynchronousLogging - Messages from the OpenGL server are logged synchronously and - sequentially. This has a severe performance hit, as OpenGL - implementations are very asynchronous by nature; but it's very useful - to debug OpenGL problems, as OpenGL guarantees that the messages - generated by a OpenGL command will be logged before the corresponding - command execution has returned. Therefore, you can install a breakpoint - on the messageLogged() signal and see in the backtrace which OpenGL - command caused it; the only caveat is that if you are using OpenGL from - multiple threads you may need to force direct connection when - connecting to the messageLogged() signal. -*/ - -// When using OpenGL ES 2.0, all the necessary GL_KHR_debug constants are -// provided in qopengles2ext.h. Unfortunately, newer versions of that file -// suffix everything with _KHR which causes extra headache when the goal is -// to have a single piece of code that builds in all our target -// environments. Therefore, try to detect this and use our custom defines -// instead, which we anyway need for OS X. - -#if defined(GL_KHR_debug) && defined(GL_DEBUG_SOURCE_API_KHR) -#define USE_MANUAL_DEFS -#endif - -// Under OSX (at least up to 10.8) we cannot include our copy of glext.h, -// but we use the system-wide one, which unfortunately lacks all the needed -// defines/typedefs. In order to make the code compile, we just add here -// the GL_KHR_debug defines. - -#ifndef GL_KHR_debug -#define GL_KHR_debug 1 -#define USE_MANUAL_DEFS -#endif - -#ifdef USE_MANUAL_DEFS - -#ifndef GL_DEBUG_OUTPUT_SYNCHRONOUS -#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 -#endif -#ifndef GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH -#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 -#endif -#ifndef GL_DEBUG_CALLBACK_FUNCTION -#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 -#endif -#ifndef GL_DEBUG_CALLBACK_USER_PARAM -#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 -#endif -#ifndef GL_DEBUG_SOURCE_API -#define GL_DEBUG_SOURCE_API 0x8246 -#endif -#ifndef GL_DEBUG_SOURCE_WINDOW_SYSTEM -#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 -#endif -#ifndef GL_DEBUG_SOURCE_SHADER_COMPILER -#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 -#endif -#ifndef GL_DEBUG_SOURCE_THIRD_PARTY -#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 -#endif -#ifndef GL_DEBUG_SOURCE_APPLICATION -#define GL_DEBUG_SOURCE_APPLICATION 0x824A -#endif -#ifndef GL_DEBUG_SOURCE_OTHER -#define GL_DEBUG_SOURCE_OTHER 0x824B -#endif -#ifndef GL_DEBUG_TYPE_ERROR -#define GL_DEBUG_TYPE_ERROR 0x824C -#endif -#ifndef GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR -#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D -#endif -#ifndef GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR -#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E -#endif -#ifndef GL_DEBUG_TYPE_PORTABILITY -#define GL_DEBUG_TYPE_PORTABILITY 0x824F -#endif -#ifndef GL_DEBUG_TYPE_PERFORMANCE -#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 -#endif -#ifndef GL_DEBUG_TYPE_OTHER -#define GL_DEBUG_TYPE_OTHER 0x8251 -#endif -#ifndef GL_DEBUG_TYPE_MARKER -#define GL_DEBUG_TYPE_MARKER 0x8268 -#endif -#ifndef GL_DEBUG_TYPE_PUSH_GROUP -#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 -#endif -#ifndef GL_DEBUG_TYPE_POP_GROUP -#define GL_DEBUG_TYPE_POP_GROUP 0x826A -#endif -#ifndef GL_DEBUG_SEVERITY_NOTIFICATION -#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B -#endif -#ifndef GL_MAX_DEBUG_GROUP_STACK_DEPTH -#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C -#endif -#ifndef GL_DEBUG_GROUP_STACK_DEPTH -#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D -#endif -#ifndef GL_BUFFER -#define GL_BUFFER 0x82E0 -#endif -#ifndef GL_SHADER -#define GL_SHADER 0x82E1 -#endif -#ifndef GL_PROGRAM -#define GL_PROGRAM 0x82E2 -#endif -#ifndef GL_QUERY -#define GL_QUERY 0x82E3 -#endif -#ifndef GL_PROGRAM_PIPELINE -#define GL_PROGRAM_PIPELINE 0x82E4 -#endif -#ifndef GL_SAMPLER -#define GL_SAMPLER 0x82E6 -#endif -#ifndef GL_DISPLAY_LIST -#define GL_DISPLAY_LIST 0x82E7 -#endif -#ifndef GL_MAX_LABEL_LENGTH -#define GL_MAX_LABEL_LENGTH 0x82E8 -#endif -#ifndef GL_MAX_DEBUG_MESSAGE_LENGTH -#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 -#endif -#ifndef GL_MAX_DEBUG_LOGGED_MESSAGES -#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 -#endif -#ifndef GL_DEBUG_LOGGED_MESSAGES -#define GL_DEBUG_LOGGED_MESSAGES 0x9145 -#endif -#ifndef GL_DEBUG_SEVERITY_HIGH -#define GL_DEBUG_SEVERITY_HIGH 0x9146 -#endif -#ifndef GL_DEBUG_SEVERITY_MEDIUM -#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 -#endif -#ifndef GL_DEBUG_SEVERITY_LOW -#define GL_DEBUG_SEVERITY_LOW 0x9148 -#endif -#ifndef GL_DEBUG_OUTPUT -#define GL_DEBUG_OUTPUT 0x92E0 -#endif -#ifndef GL_CONTEXT_FLAG_DEBUG_BIT -#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 -#endif -#ifndef GL_STACK_OVERFLOW -#define GL_STACK_OVERFLOW 0x0503 -#endif -#ifndef GL_STACK_UNDERFLOW -#define GL_STACK_UNDERFLOW 0x0504 -#endif - -typedef void (QOPENGLF_APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const GLvoid *userParam); - -#endif /* USE_MANUAL_DEFS */ - - -/*! - \internal -*/ -static QOpenGLDebugMessage::Source qt_messageSourceFromGL(GLenum source) -{ - switch (source) { - case GL_DEBUG_SOURCE_API: - return QOpenGLDebugMessage::APISource; - case GL_DEBUG_SOURCE_WINDOW_SYSTEM: - return QOpenGLDebugMessage::WindowSystemSource; - case GL_DEBUG_SOURCE_SHADER_COMPILER: - return QOpenGLDebugMessage::ShaderCompilerSource; - case GL_DEBUG_SOURCE_THIRD_PARTY: - return QOpenGLDebugMessage::ThirdPartySource; - case GL_DEBUG_SOURCE_APPLICATION: - return QOpenGLDebugMessage::ApplicationSource; - case GL_DEBUG_SOURCE_OTHER: - return QOpenGLDebugMessage::OtherSource; - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown message source from GL"); - return QOpenGLDebugMessage::OtherSource; -} - -/*! - \internal -*/ -static GLenum qt_messageSourceToGL(QOpenGLDebugMessage::Source source) -{ - switch (source) { - case QOpenGLDebugMessage::InvalidSource: - break; - case QOpenGLDebugMessage::APISource: - return GL_DEBUG_SOURCE_API; - case QOpenGLDebugMessage::WindowSystemSource: - return GL_DEBUG_SOURCE_WINDOW_SYSTEM; - case QOpenGLDebugMessage::ShaderCompilerSource: - return GL_DEBUG_SOURCE_SHADER_COMPILER; - case QOpenGLDebugMessage::ThirdPartySource: - return GL_DEBUG_SOURCE_THIRD_PARTY; - case QOpenGLDebugMessage::ApplicationSource: - return GL_DEBUG_SOURCE_APPLICATION; - case QOpenGLDebugMessage::OtherSource: - return GL_DEBUG_SOURCE_OTHER; - case QOpenGLDebugMessage::AnySource: - break; - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message source"); - return GL_DEBUG_SOURCE_OTHER; -} - -/*! - \internal -*/ -static QString qt_messageSourceToString(QOpenGLDebugMessage::Source source) -{ - switch (source) { - case QOpenGLDebugMessage::InvalidSource: - return QStringLiteral("InvalidSource"); - case QOpenGLDebugMessage::APISource: - return QStringLiteral("APISource"); - case QOpenGLDebugMessage::WindowSystemSource: - return QStringLiteral("WindowSystemSource"); - case QOpenGLDebugMessage::ShaderCompilerSource: - return QStringLiteral("ShaderCompilerSource"); - case QOpenGLDebugMessage::ThirdPartySource: - return QStringLiteral("ThirdPartySource"); - case QOpenGLDebugMessage::ApplicationSource: - return QStringLiteral("ApplicationSource"); - case QOpenGLDebugMessage::OtherSource: - return QStringLiteral("OtherSource"); - case QOpenGLDebugMessage::AnySource: - return QStringLiteral("AnySource"); - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown message source"); - return QString(); -} - -/*! - \internal -*/ -static QOpenGLDebugMessage::Type qt_messageTypeFromGL(GLenum type) -{ - switch (type) { - case GL_DEBUG_TYPE_ERROR: - return QOpenGLDebugMessage::ErrorType; - case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: - return QOpenGLDebugMessage::DeprecatedBehaviorType; - case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: - return QOpenGLDebugMessage::UndefinedBehaviorType; - case GL_DEBUG_TYPE_PORTABILITY: - return QOpenGLDebugMessage::PortabilityType; - case GL_DEBUG_TYPE_PERFORMANCE: - return QOpenGLDebugMessage::PerformanceType; - case GL_DEBUG_TYPE_OTHER: - return QOpenGLDebugMessage::OtherType; - case GL_DEBUG_TYPE_MARKER: - return QOpenGLDebugMessage::MarkerType; - case GL_DEBUG_TYPE_PUSH_GROUP: - return QOpenGLDebugMessage::GroupPushType; - case GL_DEBUG_TYPE_POP_GROUP: - return QOpenGLDebugMessage::GroupPopType; - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown message type from GL"); - return QOpenGLDebugMessage::OtherType; -} - -/*! - \internal -*/ -static GLenum qt_messageTypeToGL(QOpenGLDebugMessage::Type type) -{ - switch (type) { - case QOpenGLDebugMessage::InvalidType: - break; - case QOpenGLDebugMessage::ErrorType: - return GL_DEBUG_TYPE_ERROR; - case QOpenGLDebugMessage::DeprecatedBehaviorType: - return GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR; - case QOpenGLDebugMessage::UndefinedBehaviorType: - return GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR; - case QOpenGLDebugMessage::PortabilityType: - return GL_DEBUG_TYPE_PORTABILITY; - case QOpenGLDebugMessage::PerformanceType: - return GL_DEBUG_TYPE_PERFORMANCE; - case QOpenGLDebugMessage::OtherType: - return GL_DEBUG_TYPE_OTHER; - case QOpenGLDebugMessage::MarkerType: - return GL_DEBUG_TYPE_MARKER; - case QOpenGLDebugMessage::GroupPushType: - return GL_DEBUG_TYPE_PUSH_GROUP; - case QOpenGLDebugMessage::GroupPopType: - return GL_DEBUG_TYPE_POP_GROUP; - case QOpenGLDebugMessage::AnyType: - break; - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type"); - return GL_DEBUG_TYPE_OTHER; -} - -/*! - \internal -*/ -static QString qt_messageTypeToString(QOpenGLDebugMessage::Type type) -{ - switch (type) { - case QOpenGLDebugMessage::InvalidType: - return QStringLiteral("InvalidType"); - case QOpenGLDebugMessage::ErrorType: - return QStringLiteral("ErrorType"); - case QOpenGLDebugMessage::DeprecatedBehaviorType: - return QStringLiteral("DeprecatedBehaviorType"); - case QOpenGLDebugMessage::UndefinedBehaviorType: - return QStringLiteral("UndefinedBehaviorType"); - case QOpenGLDebugMessage::PortabilityType: - return QStringLiteral("PortabilityType"); - case QOpenGLDebugMessage::PerformanceType: - return QStringLiteral("PerformanceType"); - case QOpenGLDebugMessage::OtherType: - return QStringLiteral("OtherType"); - case QOpenGLDebugMessage::MarkerType: - return QStringLiteral("MarkerType"); - case QOpenGLDebugMessage::GroupPushType: - return QStringLiteral("GroupPushType"); - case QOpenGLDebugMessage::GroupPopType: - return QStringLiteral("GroupPopType"); - case QOpenGLDebugMessage::AnyType: - return QStringLiteral("AnyType"); - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown message type"); - return QString(); -} - -/*! - \internal -*/ -static QOpenGLDebugMessage::Severity qt_messageSeverityFromGL(GLenum severity) -{ - switch (severity) { - case GL_DEBUG_SEVERITY_HIGH: - return QOpenGLDebugMessage::HighSeverity; - case GL_DEBUG_SEVERITY_MEDIUM: - return QOpenGLDebugMessage::MediumSeverity; - case GL_DEBUG_SEVERITY_LOW: - return QOpenGLDebugMessage::LowSeverity; - case GL_DEBUG_SEVERITY_NOTIFICATION: - return QOpenGLDebugMessage::NotificationSeverity; - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown message severity from GL"); - return QOpenGLDebugMessage::NotificationSeverity; -} - -/*! - \internal -*/ -static GLenum qt_messageSeverityToGL(QOpenGLDebugMessage::Severity severity) -{ - switch (severity) { - case QOpenGLDebugMessage::InvalidSeverity: - break; - case QOpenGLDebugMessage::HighSeverity: - return GL_DEBUG_SEVERITY_HIGH; - case QOpenGLDebugMessage::MediumSeverity: - return GL_DEBUG_SEVERITY_MEDIUM; - case QOpenGLDebugMessage::LowSeverity: - return GL_DEBUG_SEVERITY_LOW; - case QOpenGLDebugMessage::NotificationSeverity: - return GL_DEBUG_SEVERITY_NOTIFICATION; - case QOpenGLDebugMessage::AnySeverity: - break; - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message severity"); - return GL_DEBUG_SEVERITY_NOTIFICATION; -} - -/*! - \internal -*/ -static QString qt_messageSeverityToString(QOpenGLDebugMessage::Severity severity) -{ - switch (severity) { - case QOpenGLDebugMessage::InvalidSeverity: - return QStringLiteral("InvalidSeverity"); - case QOpenGLDebugMessage::HighSeverity: - return QStringLiteral("HighSeverity"); - case QOpenGLDebugMessage::MediumSeverity: - return QStringLiteral("MediumSeverity"); - case QOpenGLDebugMessage::LowSeverity: - return QStringLiteral("LowSeverity"); - case QOpenGLDebugMessage::NotificationSeverity: - return QStringLiteral("NotificationSeverity"); - case QOpenGLDebugMessage::AnySeverity: - return QStringLiteral("AnySeverity"); - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown message severity"); - return QString(); -} - -class QOpenGLDebugMessagePrivate : public QSharedData -{ -public: - QOpenGLDebugMessagePrivate(); - - QString message; - GLuint id; - QOpenGLDebugMessage::Source source; - QOpenGLDebugMessage::Type type; - QOpenGLDebugMessage::Severity severity; -}; - -/*! - \internal -*/ -QOpenGLDebugMessagePrivate::QOpenGLDebugMessagePrivate() - : message(), - id(0), - source(QOpenGLDebugMessage::InvalidSource), - type(QOpenGLDebugMessage::InvalidType), - severity(QOpenGLDebugMessage::InvalidSeverity) -{ -} - - -/*! - Constructs a debug message with an empty message string, id set to 0, - source set to InvalidSource, type set to InvalidType, and severity set to - InvalidSeverity. - - \note This constructor should not be used to create a debug message; - instead, use the createApplicationMessage() or the createThirdPartyMessage() - static functions. - - \sa createApplicationMessage(), createThirdPartyMessage() -*/ -QOpenGLDebugMessage::QOpenGLDebugMessage() - : d(new QOpenGLDebugMessagePrivate) -{ -} - -/*! - Constructs a debug message as a copy of \a debugMessage. - - \sa operator=() -*/ -QOpenGLDebugMessage::QOpenGLDebugMessage(const QOpenGLDebugMessage &debugMessage) - : d(debugMessage.d) -{ -} - -/*! - Destroys this debug message. -*/ -QOpenGLDebugMessage::~QOpenGLDebugMessage() -{ -} - -/*! - Assigns the message \a debugMessage to this object, and returns a reference - to the copy. -*/ -QOpenGLDebugMessage &QOpenGLDebugMessage::operator=(const QOpenGLDebugMessage &debugMessage) -{ - d = debugMessage.d; - return *this; -} - -/*! - \fn QOpenGLDebugMessage &QOpenGLDebugMessage::operator=(QOpenGLDebugMessage &&debugMessage) - - Move-assigns \a debugMessage to this object. -*/ - -/*! - \fn void QOpenGLDebugMessage::swap(QOpenGLDebugMessage &debugMessage) - - Swaps the message \a debugMessage with this message. This operation is very - fast and never fails. -*/ - -/*! - Returns the source of the debug message. -*/ -QOpenGLDebugMessage::Source QOpenGLDebugMessage::source() const -{ - return d->source; -} - -/*! - Returns the type of the debug message. -*/ -QOpenGLDebugMessage::Type QOpenGLDebugMessage::type() const -{ - return d->type; -} - -/*! - Returns the severity of the debug message. -*/ -QOpenGLDebugMessage::Severity QOpenGLDebugMessage::severity() const -{ - return d->severity; -} - -/*! - Returns the id of the debug message. Ids are generally vendor-specific. -*/ -GLuint QOpenGLDebugMessage::id() const -{ - return d->id; -} - -/*! - Returns the textual message contained by this debug message. -*/ -QString QOpenGLDebugMessage::message() const -{ - return d->message; -} - -/*! - Constructs and returns a debug message with \a text as its text, \a id - as id, \a severity as severity, and \a type as type. The message source - will be set to ApplicationSource. - - \sa QOpenGLDebugLogger::logMessage(), createThirdPartyMessage() -*/ -QOpenGLDebugMessage QOpenGLDebugMessage::createApplicationMessage(const QString &text, - GLuint id, - QOpenGLDebugMessage::Severity severity, - QOpenGLDebugMessage::Type type) -{ - QOpenGLDebugMessage m; - m.d->message = text; - m.d->id = id; - m.d->severity = severity; - m.d->type = type; - m.d->source = ApplicationSource; - return m; -} - -/*! - Constructs and returns a debug message with \a text as its text, \a id - as id, \a severity as severity, and \a type as type. The message source - will be set to ThirdPartySource. - - \sa QOpenGLDebugLogger::logMessage(), createApplicationMessage() -*/ -QOpenGLDebugMessage QOpenGLDebugMessage::createThirdPartyMessage(const QString &text, - GLuint id, - QOpenGLDebugMessage::Severity severity, - QOpenGLDebugMessage::Type type) -{ - QOpenGLDebugMessage m; - m.d->message = text; - m.d->id = id; - m.d->severity = severity; - m.d->type = type; - m.d->source = ThirdPartySource; - return m; -} - -/*! - Returns \c true if this debug message is equal to \a debugMessage, or false - otherwise. Two debugging messages are equal if they have the same textual - message, the same id, the same source, the same type and the same severity. - - \sa operator!=() -*/ -bool QOpenGLDebugMessage::operator==(const QOpenGLDebugMessage &debugMessage) const -{ - return (d == debugMessage.d) - || (d->id == debugMessage.d->id - && d->source == debugMessage.d->source - && d->type == debugMessage.d->type - && d->severity == debugMessage.d->severity - && d->message == debugMessage.d->message); -} - -/*! - \fn bool QOpenGLDebugMessage::operator!=(const QOpenGLDebugMessage &debugMessage) const - - Returns \c true if this message is different from \a debugMessage, or false - otherwise. - - \sa operator==() -*/ - -#ifndef QT_NO_DEBUG_STREAM -/*! - \relates QOpenGLDebugMessage - - Writes the source \a source into the debug object \a debug for debugging - purposes. -*/ -QDebug operator<<(QDebug debug, QOpenGLDebugMessage::Source source) -{ - QDebugStateSaver saver(debug); - debug.nospace() << "QOpenGLDebugMessage::Source(" - << qt_messageSourceToString(source) - << ')'; - return debug; -} - -/*! - \relates QOpenGLDebugMessage - - Writes the type \a type into the debug object \a debug for debugging - purposes. -*/ -QDebug operator<<(QDebug debug, QOpenGLDebugMessage::Type type) -{ - QDebugStateSaver saver(debug); - debug.nospace() << "QOpenGLDebugMessage::Type(" - << qt_messageTypeToString(type) - << ')'; - return debug; -} - -/*! - \relates QOpenGLDebugMessage - - Writes the severity \a severity into the debug object \a debug for debugging - purposes. -*/ -QDebug operator<<(QDebug debug, QOpenGLDebugMessage::Severity severity) -{ - QDebugStateSaver saver(debug); - debug.nospace() << "QOpenGLDebugMessage::Severity(" - << qt_messageSeverityToString(severity) - << ')'; - return debug; -} - -/*! - \relates QOpenGLDebugMessage - - Writes the message \a message into the debug object \a debug for debugging - purposes. -*/ -QDebug operator<<(QDebug debug, const QOpenGLDebugMessage &message) -{ - QDebugStateSaver saver(debug); - debug.nospace() << "QOpenGLDebugMessage(" - << qt_messageSourceToString(message.source()) << ", " - << message.id() << ", " - << message.message() << ", " - << qt_messageSeverityToString(message.severity()) << ", " - << qt_messageTypeToString(message.type()) << ')'; - return debug; - -} -#endif // QT_NO_DEBUG_STREAM - -typedef void (QOPENGLF_APIENTRYP qt_glDebugMessageControl_t)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -typedef void (QOPENGLF_APIENTRYP qt_glDebugMessageInsert_t)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -typedef void (QOPENGLF_APIENTRYP qt_glDebugMessageCallback_t)(GLDEBUGPROC callback, const void *userParam); -typedef GLuint (QOPENGLF_APIENTRYP qt_glGetDebugMessageLog_t)(GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); -typedef void (QOPENGLF_APIENTRYP qt_glPushDebugGroup_t)(GLenum source, GLuint id, GLsizei length, const GLchar *message); -typedef void (QOPENGLF_APIENTRYP qt_glPopDebugGroup_t)(); -typedef void (QOPENGLF_APIENTRYP qt_glGetPointerv_t)(GLenum pname, GLvoid **params); - -class QOpenGLDebugLoggerPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QOpenGLDebugLogger) -public: - QOpenGLDebugLoggerPrivate(); - - void handleMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *rawMessage); - void controlDebugMessages(QOpenGLDebugMessage::Sources sources, - QOpenGLDebugMessage::Types types, - QOpenGLDebugMessage::Severities severities, - const QVector<GLuint> &ids, - const QByteArray &callerName, - bool enable); - void _q_contextAboutToBeDestroyed(); - - qt_glDebugMessageControl_t glDebugMessageControl; - qt_glDebugMessageInsert_t glDebugMessageInsert; - qt_glDebugMessageCallback_t glDebugMessageCallback; - qt_glGetDebugMessageLog_t glGetDebugMessageLog; - qt_glPushDebugGroup_t glPushDebugGroup; - qt_glPopDebugGroup_t glPopDebugGroup; - qt_glGetPointerv_t glGetPointerv; - - GLDEBUGPROC oldDebugCallbackFunction; - void *oldDebugCallbackParameter; - QOpenGLContext *context; - GLint maxMessageLength; - QOpenGLDebugLogger::LoggingMode loggingMode; - bool initialized : 1; - bool isLogging : 1; - bool debugWasEnabled : 1; - bool syncDebugWasEnabled : 1; -}; - -/*! - \internal -*/ -QOpenGLDebugLoggerPrivate::QOpenGLDebugLoggerPrivate() - : glDebugMessageControl(nullptr), - glDebugMessageInsert(nullptr), - glDebugMessageCallback(nullptr), - glGetDebugMessageLog(nullptr), - glPushDebugGroup(nullptr), - glPopDebugGroup(nullptr), - oldDebugCallbackFunction(nullptr), - context(nullptr), - maxMessageLength(0), - loggingMode(QOpenGLDebugLogger::AsynchronousLogging), - initialized(false), - isLogging(false), - debugWasEnabled(false), - syncDebugWasEnabled(false) -{ -} - -/*! - \internal -*/ -void QOpenGLDebugLoggerPrivate::handleMessage(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar *rawMessage) -{ - if (oldDebugCallbackFunction) - oldDebugCallbackFunction(source, type, id, severity, length, rawMessage, oldDebugCallbackParameter); - - QOpenGLDebugMessage message; - - QOpenGLDebugMessagePrivate *messagePrivate = message.d.data(); - messagePrivate->source = qt_messageSourceFromGL(source); - messagePrivate->type = qt_messageTypeFromGL(type); - messagePrivate->id = id; - messagePrivate->severity = qt_messageSeverityFromGL(severity); - // not passing the length to fromUtf8, as some bugged OpenGL drivers - // do not handle the length correctly. Just rely on the message to be NUL terminated. - messagePrivate->message = QString::fromUtf8(rawMessage); - - Q_Q(QOpenGLDebugLogger); - emit q->messageLogged(message); -} - -/*! - \internal -*/ -void QOpenGLDebugLoggerPrivate::controlDebugMessages(QOpenGLDebugMessage::Sources sources, - QOpenGLDebugMessage::Types types, - QOpenGLDebugMessage::Severities severities, - const QVector<GLuint> &ids, - const QByteArray &callerName, - bool enable) -{ - if (!initialized) { - qWarning("QOpenGLDebugLogger::%s(): object must be initialized before enabling/disabling messages", callerName.constData()); - return; - } - if (sources == QOpenGLDebugMessage::InvalidSource) { - qWarning("QOpenGLDebugLogger::%s(): invalid source specified", callerName.constData()); - return; - } - if (types == QOpenGLDebugMessage::InvalidType) { - qWarning("QOpenGLDebugLogger::%s(): invalid type specified", callerName.constData()); - return; - } - if (severities == QOpenGLDebugMessage::InvalidSeverity) { - qWarning("QOpenGLDebugLogger::%s(): invalid severity specified", callerName.constData()); - return; - } - - QVarLengthArray<GLenum, 8> glSources; - QVarLengthArray<GLenum, 8> glTypes; - QVarLengthArray<GLenum, 8> glSeverities; - - if (ids.count() > 0) { - Q_ASSERT(severities == QOpenGLDebugMessage::AnySeverity); - - // The GL_KHR_debug extension says: - // - // - If <count> is greater than zero, then <ids> is an array of <count> - // message IDs for the specified combination of <source> and <type>. In - // this case, if <source> or <type> is DONT_CARE, or <severity> is not - // DONT_CARE, the error INVALID_OPERATION is generated. If <count> is - // zero, the value if <ids> is ignored. - // - // This means we can't convert AnySource or AnyType into DONT_CARE, but we have to roll - // them into individual sources/types. - - if (sources == QOpenGLDebugMessage::AnySource) { - sources = QOpenGLDebugMessage::InvalidSource; - for (uint i = 1; i <= QOpenGLDebugMessage::LastSource; i = i << 1) - sources |= QOpenGLDebugMessage::Source(i); - } - - if (types == QOpenGLDebugMessage::AnyType) { - types = QOpenGLDebugMessage::InvalidType; - for (uint i = 1; i <= QOpenGLDebugMessage::LastType; i = i << 1) - types |= QOpenGLDebugMessage::Type(i); - } - } - -#define CONVERT_TO_GL_DEBUG_MESSAGE_CONTROL_PARAMETERS(type, source, target) \ - if (source == QOpenGLDebugMessage::Any ## type) { \ - target << GL_DONT_CARE; \ - } else { \ - for (uint i = 1; i <= QOpenGLDebugMessage::Last ## type; i = i << 1) \ - if (source.testFlag(QOpenGLDebugMessage:: type (i))) \ - target << qt_message ## type ## ToGL (QOpenGLDebugMessage:: type (i)); \ - } - - CONVERT_TO_GL_DEBUG_MESSAGE_CONTROL_PARAMETERS(Source, sources, glSources) - CONVERT_TO_GL_DEBUG_MESSAGE_CONTROL_PARAMETERS(Type, types, glTypes) - CONVERT_TO_GL_DEBUG_MESSAGE_CONTROL_PARAMETERS(Severity, severities, glSeverities) -#undef CONVERT_TO_GL_DEBUG_MESSAGE_CONTROL_PARAMETERS - - const GLsizei idCount = ids.count(); - // The GL_KHR_debug extension says that if idCount is 0, idPtr must be ignored. - // Unfortunately, some bugged drivers do NOT ignore it, so pass NULL in case. - const GLuint * const idPtr = idCount ? ids.constData() : nullptr; - - for (GLenum source : glSources) - for (GLenum type : glTypes) - for (GLenum severity : glSeverities) - glDebugMessageControl(source, type, severity, idCount, idPtr, GLboolean(enable)); -} - -/*! - \internal -*/ -void QOpenGLDebugLoggerPrivate::_q_contextAboutToBeDestroyed() -{ - Q_ASSERT(context); - - // Re-make our context current somehow, otherwise stopLogging will fail. - - // Save the current context and its surface in case we need to set them back - QOpenGLContext *currentContext = QOpenGLContext::currentContext(); - QSurface *currentSurface = nullptr; - - QScopedPointer<QOffscreenSurface> offscreenSurface; - - if (context != currentContext) { - // Make our old context current on a temporary surface - if (currentContext) - currentSurface = currentContext->surface(); - - offscreenSurface.reset(new QOffscreenSurface); - offscreenSurface->setFormat(context->format()); - offscreenSurface->create(); - if (!context->makeCurrent(offscreenSurface.data())) - qWarning("QOpenGLDebugLoggerPrivate::_q_contextAboutToBeDestroyed(): could not make the owning GL context current for cleanup"); - } - - Q_Q(QOpenGLDebugLogger); - q->stopLogging(); - - if (offscreenSurface) { - // We did change the current context: set it back - if (currentContext) - currentContext->makeCurrent(currentSurface); - else - context->doneCurrent(); - } - - QObject::disconnect(context, SIGNAL(aboutToBeDestroyed()), q, SLOT(_q_contextAboutToBeDestroyed())); - context = nullptr; - initialized = false; -} - -extern "C" { -static void QOPENGLF_APIENTRY qt_opengl_debug_callback(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar *rawMessage, - const GLvoid *userParam) -{ - QOpenGLDebugLoggerPrivate *loggerPrivate = static_cast<QOpenGLDebugLoggerPrivate *>(const_cast<GLvoid *>(userParam)); - loggerPrivate->handleMessage(source, type, id, severity, length, rawMessage); -} -} - -/*! - Constructs a new logger object with the given \a parent. - - \note The object must be initialized before logging can happen. - - \sa initialize() -*/ -QOpenGLDebugLogger::QOpenGLDebugLogger(QObject *parent) - : QObject(*new QOpenGLDebugLoggerPrivate, parent) -{ - // QOpenGLDebugMessage is going to be mostly used as an argument - // of a cross thread connection, therefore let's ease the life for the users - // and register the type for them. - qRegisterMetaType<QOpenGLDebugMessage>(); -} - -/*! - Destroys the logger object. -*/ -QOpenGLDebugLogger::~QOpenGLDebugLogger() -{ - stopLogging(); -} - -/*! - Initializes the object in the current OpenGL context. The context must - support the \c{GL_KHR_debug} extension for the initialization to succeed. - The object must be initialized before any logging can happen. - - It is safe to call this function multiple times from the same context. - - This function can also be used to change the context of a previously - initialized object; note that in this case the object must not be logging - when you call this function. - - Returns \c true if the logger is successfully initialized; false otherwise. - - \sa QOpenGLContext -*/ -bool QOpenGLDebugLogger::initialize() -{ - QOpenGLContext *context = QOpenGLContext::currentContext(); - if (!context) { - qWarning("QOpenGLDebugLogger::initialize(): no current OpenGL context found."); - return false; - } - - Q_D(QOpenGLDebugLogger); - if (d->context == context) { - // context is non-NULL, d->context is non NULL only on successful initialization. - Q_ASSERT(d->initialized); - return true; - } - - if (d->isLogging) { - qWarning("QOpenGLDebugLogger::initialize(): cannot initialize the object while logging. Please stop the logging first."); - return false; - } - - if (d->context) - disconnect(d->context, SIGNAL(aboutToBeDestroyed()), this, SLOT(_q_contextAboutToBeDestroyed())); - - d->initialized = false; - d->context = nullptr; - - if (!context->hasExtension(QByteArrayLiteral("GL_KHR_debug"))) - return false; - - d->context = context; - connect(d->context, SIGNAL(aboutToBeDestroyed()), this, SLOT(_q_contextAboutToBeDestroyed())); - -#define GET_DEBUG_PROC_ADDRESS(procName) \ - d->procName = reinterpret_cast< qt_ ## procName ## _t >( \ - d->context->getProcAddress(d->context->isOpenGLES() ? (#procName "KHR") : (#procName)) \ - ); - - GET_DEBUG_PROC_ADDRESS(glDebugMessageControl); - GET_DEBUG_PROC_ADDRESS(glDebugMessageInsert); - GET_DEBUG_PROC_ADDRESS(glDebugMessageCallback); - GET_DEBUG_PROC_ADDRESS(glGetDebugMessageLog); - GET_DEBUG_PROC_ADDRESS(glPushDebugGroup); - GET_DEBUG_PROC_ADDRESS(glPopDebugGroup); - GET_DEBUG_PROC_ADDRESS(glGetPointerv) - -#undef GET_DEBUG_PROC_ADDRESS - - QOpenGLContext::currentContext()->functions()->glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH, &d->maxMessageLength); - -#ifndef QT_NO_DEBUG - if (!d->context->format().testOption(QSurfaceFormat::DebugContext)) { - qWarning("QOpenGLDebugLogger::initialize(): the current context is not a debug context:\n" - " this means that the GL may not generate any debug output at all.\n" - " To avoid this warning, try creating the context with the\n" - " QSurfaceFormat::DebugContext surface format option."); - } -#endif // QT_NO_DEBUG - - d->initialized = true; - return true; -} - -/*! - Returns \c true if this object is currently logging, false otherwise. - - \sa startLogging() -*/ -bool QOpenGLDebugLogger::isLogging() const -{ - Q_D(const QOpenGLDebugLogger); - return d->isLogging; -} - -/*! - Starts logging messages coming from the OpenGL server. When a new message - is received, the signal messageLogged() is emitted, carrying the logged - message as argument. - - \a loggingMode specifies whether the logging must be asynchronous (the default) - or synchronous. - - QOpenGLDebugLogger will record the values of \c{GL_DEBUG_OUTPUT} and - \c{GL_DEBUG_OUTPUT_SYNCHRONOUS} when logging is started, and set them back - when logging is stopped. Moreover, any user-defined OpenGL debug callback - installed when this function is invoked will be restored when logging is - stopped; QOpenGLDebugLogger will ensure that the pre-existing callback will - still be invoked when logging. - - \note It's not possible to change the logging mode without stopping and - starting logging again. This might change in a future version of Qt. - - \note The object must be initialized before logging can happen. - - \sa stopLogging(), initialize() -*/ -void QOpenGLDebugLogger::startLogging(QOpenGLDebugLogger::LoggingMode loggingMode) -{ - Q_D(QOpenGLDebugLogger); - if (!d->initialized) { - qWarning("QOpenGLDebugLogger::startLogging(): object must be initialized before logging can start"); - return; - } - if (d->isLogging) { - qWarning("QOpenGLDebugLogger::startLogging(): this object is already logging"); - return; - } - - d->isLogging = true; - d->loggingMode = loggingMode; - - d->glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION, reinterpret_cast<void **>(&d->oldDebugCallbackFunction)); - d->glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM, &d->oldDebugCallbackParameter); - - d->glDebugMessageCallback(&qt_opengl_debug_callback, d); - - QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); - d->debugWasEnabled = funcs->glIsEnabled(GL_DEBUG_OUTPUT); - d->syncDebugWasEnabled = funcs->glIsEnabled(GL_DEBUG_OUTPUT_SYNCHRONOUS); - - if (d->loggingMode == SynchronousLogging) - funcs->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - else - funcs->glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - - funcs->glEnable(GL_DEBUG_OUTPUT); -} - -/*! - Returns the logging mode of the object. - - \sa startLogging() -*/ -QOpenGLDebugLogger::LoggingMode QOpenGLDebugLogger::loggingMode() const -{ - Q_D(const QOpenGLDebugLogger); - return d->loggingMode; -} - -/*! - Stops logging messages from the OpenGL server. - - \sa startLogging() -*/ -void QOpenGLDebugLogger::stopLogging() -{ - Q_D(QOpenGLDebugLogger); - if (!d->isLogging) - return; - - QOpenGLContext *currentContext = QOpenGLContext::currentContext(); - if (!currentContext || currentContext != d->context) { - qWarning("QOpenGLDebugLogger::stopLogging(): attempting to stop logging with the wrong OpenGL context current"); - return; - } - - d->isLogging = false; - - d->glDebugMessageCallback(d->oldDebugCallbackFunction, d->oldDebugCallbackParameter); - - QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); - if (!d->debugWasEnabled) - funcs->glDisable(GL_DEBUG_OUTPUT); - - if (d->syncDebugWasEnabled) - funcs->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - else - funcs->glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS); -} - -/*! - Inserts the message \a debugMessage into the OpenGL debug log. This provides - a way for applications or libraries to insert custom messages that can - ease the debugging of OpenGL applications. - - \note \a debugMessage must have QOpenGLDebugMessage::ApplicationSource or - QOpenGLDebugMessage::ThirdPartySource as its source, and a valid - type and severity, otherwise it will not be inserted into the log. - - \note The object must be initialized before logging can happen. - - \sa initialize() -*/ -void QOpenGLDebugLogger::logMessage(const QOpenGLDebugMessage &debugMessage) -{ - Q_D(QOpenGLDebugLogger); - if (!d->initialized) { - qWarning("QOpenGLDebugLogger::logMessage(): object must be initialized before logging messages"); - return; - } - if (debugMessage.source() != QOpenGLDebugMessage::ApplicationSource - && debugMessage.source() != QOpenGLDebugMessage::ThirdPartySource) { - qWarning("QOpenGLDebugLogger::logMessage(): using a message source different from ApplicationSource\n" - " or ThirdPartySource is not supported by GL_KHR_debug. The message will not be logged."); - return; - } - if (debugMessage.type() == QOpenGLDebugMessage::InvalidType - || debugMessage.type() == QOpenGLDebugMessage::AnyType - || debugMessage.severity() == QOpenGLDebugMessage::InvalidSeverity - || debugMessage.severity() == QOpenGLDebugMessage::AnySeverity) { - qWarning("QOpenGLDebugLogger::logMessage(): the message has a non-valid type and/or severity. The message will not be logged."); - return; - } - - const GLenum source = qt_messageSourceToGL(debugMessage.source()); - const GLenum type = qt_messageTypeToGL(debugMessage.type()); - const GLenum severity = qt_messageSeverityToGL(debugMessage.severity()); - QByteArray rawMessage = debugMessage.message().toUtf8(); - rawMessage.append('\0'); - - if (rawMessage.length() > d->maxMessageLength) { - qWarning("QOpenGLDebugLogger::logMessage(): message too long, truncating it\n" - " (%d bytes long, but the GL accepts up to %d bytes)", rawMessage.length(), d->maxMessageLength); - rawMessage.resize(d->maxMessageLength - 1); - rawMessage.append('\0'); - } - - // Don't pass rawMessage.length(), as unfortunately bugged - // OpenGL drivers will eat the trailing NUL in the message. Just rely - // on the message being NUL terminated. - d->glDebugMessageInsert(source, - type, - debugMessage.id(), - severity, - -1, - rawMessage.constData()); -} - -/*! - Pushes a debug group with name \a name, id \a id, and source \a source onto - the debug groups stack. If the group is successfully pushed, OpenGL will - automatically log a message with message \a name, id \a id, source \a - source, type QOpenGLDebugMessage::GroupPushType and severity - QOpenGLDebugMessage::NotificationSeverity. - - The newly pushed group will inherit the same filtering settings of the - group that was on the top of the stack; that is, the filtering will not be - changed by pushing a new group. - - \note The \a source must either be QOpenGLDebugMessage::ApplicationSource or - QOpenGLDebugMessage::ThirdPartySource, otherwise the group will not be pushed. - - \note The object must be initialized before managing debug groups. - - \sa popGroup(), enableMessages(), disableMessages() -*/ -void QOpenGLDebugLogger::pushGroup(const QString &name, GLuint id, QOpenGLDebugMessage::Source source) -{ - Q_D(QOpenGLDebugLogger); - if (!d->initialized) { - qWarning("QOpenGLDebugLogger::pushGroup(): object must be initialized before pushing a debug group"); - return; - } - if (source != QOpenGLDebugMessage::ApplicationSource - && source != QOpenGLDebugMessage::ThirdPartySource) { - qWarning("QOpenGLDebugLogger::pushGroup(): using a source different from ApplicationSource\n" - " or ThirdPartySource is not supported by GL_KHR_debug. The group will not be pushed."); - return; - } - - QByteArray rawName = name.toUtf8(); - rawName.append('\0'); - if (rawName.length() > d->maxMessageLength) { - qWarning("QOpenGLDebugLogger::pushGroup(): group name too long, truncating it\n" - " (%d bytes long, but the GL accepts up to %d bytes)", rawName.length(), d->maxMessageLength); - rawName.resize(d->maxMessageLength - 1); - rawName.append('\0'); - } - - // Don't pass rawMessage.length(), as unfortunately bugged - // OpenGL drivers will eat the trailing NUL in the name. Just rely - // on the name being NUL terminated. - d->glPushDebugGroup(qt_messageSourceToGL(source), id, -1, rawName.constData()); -} - -/*! - Pops the topmost debug group from the debug groups stack. If the group is - successfully popped, OpenGL will automatically log a message with message, - id and source matching those of the popped group, type - QOpenGLDebugMessage::GroupPopType and severity - QOpenGLDebugMessage::NotificationSeverity. - - Popping a debug group will restore the message filtering settings of the - group that becomes the top of the debug groups stack. - - \note The object must be initialized before managing debug groups. - - \sa pushGroup() -*/ -void QOpenGLDebugLogger::popGroup() -{ - Q_D(QOpenGLDebugLogger); - if (!d->initialized) { - qWarning("QOpenGLDebugLogger::pushGroup(): object must be initialized before popping a debug group"); - return; - } - - d->glPopDebugGroup(); -} - -/*! - Enables the logging of messages from the given \a sources, of the given \a - types and with the given \a severities and any message id. - - The logging will be enabled in the current control group. - - \sa disableMessages(), pushGroup(), popGroup() -*/ -void QOpenGLDebugLogger::enableMessages(QOpenGLDebugMessage::Sources sources, - QOpenGLDebugMessage::Types types, - QOpenGLDebugMessage::Severities severities) -{ - Q_D(QOpenGLDebugLogger); - d->controlDebugMessages(sources, - types, - severities, - QVector<GLuint>(), - QByteArrayLiteral("enableMessages"), - true); -} - -/*! - Enables the logging of messages with the given \a ids, from the given \a - sources and of the given \a types and any severity. - - The logging will be enabled in the current control group. - - \sa disableMessages(), pushGroup(), popGroup() -*/ -void QOpenGLDebugLogger::enableMessages(const QVector<GLuint> &ids, - QOpenGLDebugMessage::Sources sources, - QOpenGLDebugMessage::Types types) -{ - Q_D(QOpenGLDebugLogger); - d->controlDebugMessages(sources, - types, - QOpenGLDebugMessage::AnySeverity, - ids, - QByteArrayLiteral("enableMessages"), - true); -} - -/*! - Disables the logging of messages with the given \a sources, of the given \a - types and with the given \a severities and any message id. - - The logging will be disabled in the current control group. - - \sa enableMessages(), pushGroup(), popGroup() -*/ -void QOpenGLDebugLogger::disableMessages(QOpenGLDebugMessage::Sources sources, - QOpenGLDebugMessage::Types types, - QOpenGLDebugMessage::Severities severities) -{ - Q_D(QOpenGLDebugLogger); - d->controlDebugMessages(sources, - types, - severities, - QVector<GLuint>(), - QByteArrayLiteral("disableMessages"), - false); -} - -/*! - Disables the logging of messages with the given \a ids, from the given \a - sources and of the given \a types and any severity. - - The logging will be disabled in the current control group. - - \sa enableMessages(), pushGroup(), popGroup() -*/ -void QOpenGLDebugLogger::disableMessages(const QVector<GLuint> &ids, - QOpenGLDebugMessage::Sources sources, - QOpenGLDebugMessage::Types types) -{ - Q_D(QOpenGLDebugLogger); - d->controlDebugMessages(sources, - types, - QOpenGLDebugMessage::AnySeverity, - ids, - QByteArrayLiteral("disableMessages"), - false); -} - -/*! - Reads all the available messages in the OpenGL internal debug log and - returns them. Moreover, this function will clear the internal debug log, - so that subsequent invocations will not return messages that were - already returned. - - \sa startLogging() -*/ -QList<QOpenGLDebugMessage> QOpenGLDebugLogger::loggedMessages() const -{ - Q_D(const QOpenGLDebugLogger); - if (!d->initialized) { - qWarning("QOpenGLDebugLogger::loggedMessages(): object must be initialized before reading logged messages"); - return QList<QOpenGLDebugMessage>(); - } - - static const GLuint maxMessageCount = 128; - GLuint messagesRead; - GLenum messageSources[maxMessageCount]; - GLenum messageTypes[maxMessageCount]; - GLuint messageIds[maxMessageCount]; - GLenum messageSeverities[maxMessageCount]; - GLsizei messageLengths[maxMessageCount]; - - QByteArray messagesBuffer; - messagesBuffer.resize(maxMessageCount * d->maxMessageLength); - - QList<QOpenGLDebugMessage> messages; - do { - messagesRead = d->glGetDebugMessageLog(maxMessageCount, - GLsizei(messagesBuffer.size()), - messageSources, - messageTypes, - messageIds, - messageSeverities, - messageLengths, - messagesBuffer.data()); - - const char *messagesBufferPtr = messagesBuffer.constData(); - for (GLuint i = 0; i < messagesRead; ++i) { - QOpenGLDebugMessage message; - - QOpenGLDebugMessagePrivate *messagePrivate = message.d.data(); - messagePrivate->source = qt_messageSourceFromGL(messageSources[i]); - messagePrivate->type = qt_messageTypeFromGL(messageTypes[i]); - messagePrivate->id = messageIds[i]; - messagePrivate->severity = qt_messageSeverityFromGL(messageSeverities[i]); - messagePrivate->message = QString::fromUtf8(messagesBufferPtr, messageLengths[i] - 1); - - messagesBufferPtr += messageLengths[i]; - messages << message; - } - } while (messagesRead == maxMessageCount); - - return messages; -} - -/*! - \fn void QOpenGLDebugLogger::messageLogged(const QOpenGLDebugMessage &debugMessage) - - This signal is emitted when a debug message (wrapped by the \a debugMessage - argument) is logged from the OpenGL server. - - Depending on the OpenGL implementation, this signal can be emitted - from other threads than the one(s) the receiver(s) lives in, and even - different from the thread the QOpenGLContext in which this object has - been initialized lives in. Moreover, the signal could be emitted from - multiple threads at the same time. This is normally not a problem, - as Qt will utilize a queued connection for cross-thread signal emissions, - but if you force the connection type to Direct then you must be aware of - the potential races in the slots connected to this signal. - - If logging have been started in SynchronousLogging mode, OpenGL guarantees - that this signal will be emitted from the same thread the QOpenGLContext - has been bound to, and no concurrent invocations will ever happen. - - \note Logging must have been started, or this signal will not be emitted. - - \sa startLogging() -*/ - -/*! - Returns the maximum supported length, in bytes, for the text of the messages - passed to logMessage(). This is also the maximum length of a debug group - name, as pushing or popping groups will automatically log a message with - the debug group name as the message text. - - If a message text is too long, it will be automatically truncated by - QOpenGLDebugLogger. - - \note Message texts are encoded in UTF-8 when they get passed to OpenGL, so - their size in bytes does not usually match the amount of UTF-16 code units, - as returned, for instance, by QString::length(). (It does if the message contains - 7-bit ASCII only data, which is typical for debug messages.) -*/ -qint64 QOpenGLDebugLogger::maximumMessageLength() const -{ - Q_D(const QOpenGLDebugLogger); - if (!d->initialized) { - qWarning("QOpenGLDebugLogger::maximumMessageLength(): object must be initialized before reading the maximum message length"); - return -1; - } - return d->maxMessageLength; -} - - -QT_END_NAMESPACE - -#include "moc_qopengldebug.cpp" diff --git a/src/gui/opengl/qopengldebug.h b/src/gui/opengl/qopengldebug.h deleted file mode 100644 index 7363985d60..0000000000 --- a/src/gui/opengl/qopengldebug.h +++ /dev/null @@ -1,221 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QOPENGLDEBUG_H -#define QOPENGLDEBUG_H - -#include <QtGui/qtguiglobal.h> - -#ifndef QT_NO_OPENGL - -#include <QtCore/qshareddata.h> -#include <QtCore/qflags.h> -#include <QtCore/qlist.h> -#include <QtCore/qvector.h> -#include <QtCore/qmetatype.h> -#include <QtCore/qdebug.h> -#include <QtGui/qopenglcontext.h> - -#if defined(Q_CLANG_QDOC) -#undef GLuint -typedef unsigned int GLuint; -#endif - -QT_BEGIN_NAMESPACE - -class QOpenGLDebugLogger; -class QOpenGLDebugLoggerPrivate; -class QOpenGLDebugMessagePrivate; - -class Q_GUI_EXPORT QOpenGLDebugMessage -{ -public: - enum Source { - InvalidSource = 0x00000000, - APISource = 0x00000001, - WindowSystemSource = 0x00000002, - ShaderCompilerSource = 0x00000004, - ThirdPartySource = 0x00000008, - ApplicationSource = 0x00000010, - OtherSource = 0x00000020, - LastSource = OtherSource, // private API - AnySource = 0xffffffff - }; - Q_DECLARE_FLAGS(Sources, Source) - - enum Type { - InvalidType = 0x00000000, - ErrorType = 0x00000001, - DeprecatedBehaviorType = 0x00000002, - UndefinedBehaviorType = 0x00000004, - PortabilityType = 0x00000008, - PerformanceType = 0x00000010, - OtherType = 0x00000020, - MarkerType = 0x00000040, - GroupPushType = 0x00000080, - GroupPopType = 0x00000100, - LastType = GroupPopType, // private API - AnyType = 0xffffffff - }; - Q_DECLARE_FLAGS(Types, Type) - - enum Severity { - InvalidSeverity = 0x00000000, - HighSeverity = 0x00000001, - MediumSeverity = 0x00000002, - LowSeverity = 0x00000004, - NotificationSeverity = 0x00000008, - LastSeverity = NotificationSeverity, // private API - AnySeverity = 0xffffffff - }; - Q_DECLARE_FLAGS(Severities, Severity) - - QOpenGLDebugMessage(); - QOpenGLDebugMessage(const QOpenGLDebugMessage &debugMessage); - - QOpenGLDebugMessage &operator=(const QOpenGLDebugMessage &debugMessage); - QOpenGLDebugMessage &operator=(QOpenGLDebugMessage &&other) noexcept { swap(other); return *this; } - ~QOpenGLDebugMessage(); - - void swap(QOpenGLDebugMessage &other) noexcept { qSwap(d, other.d); } - - Source source() const; - Type type() const; - Severity severity() const; - GLuint id() const; - QString message() const; - - static QOpenGLDebugMessage createApplicationMessage(const QString &text, - GLuint id = 0, - Severity severity = NotificationSeverity, - Type type = OtherType); - static QOpenGLDebugMessage createThirdPartyMessage(const QString &text, - GLuint id = 0, - Severity severity = NotificationSeverity, - Type type = OtherType); - - bool operator==(const QOpenGLDebugMessage &debugMessage) const; - inline bool operator!=(const QOpenGLDebugMessage &debugMessage) const { return !operator==(debugMessage); } - -private: - friend class QOpenGLDebugLogger; - friend class QOpenGLDebugLoggerPrivate; - QSharedDataPointer<QOpenGLDebugMessagePrivate> d; -}; - -Q_DECLARE_SHARED(QOpenGLDebugMessage) -Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLDebugMessage::Sources) -Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLDebugMessage::Types) -Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLDebugMessage::Severities) - -#ifndef QT_NO_DEBUG_STREAM -Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QOpenGLDebugMessage &message); -Q_GUI_EXPORT QDebug operator<<(QDebug debug, QOpenGLDebugMessage::Source source); -Q_GUI_EXPORT QDebug operator<<(QDebug debug, QOpenGLDebugMessage::Type type); -Q_GUI_EXPORT QDebug operator<<(QDebug debug, QOpenGLDebugMessage::Severity severity); -#endif - -class QOpenGLDebugLoggerPrivate; - -class Q_GUI_EXPORT QOpenGLDebugLogger : public QObject -{ - Q_OBJECT - Q_PROPERTY(LoggingMode loggingMode READ loggingMode) - -public: - enum LoggingMode { - AsynchronousLogging, - SynchronousLogging - }; - Q_ENUM(LoggingMode) - - explicit QOpenGLDebugLogger(QObject *parent = nullptr); - ~QOpenGLDebugLogger(); - - bool initialize(); - - bool isLogging() const; - LoggingMode loggingMode() const; - - qint64 maximumMessageLength() const; - - void pushGroup(const QString &name, - GLuint id = 0, - QOpenGLDebugMessage::Source source = QOpenGLDebugMessage::ApplicationSource); - void popGroup(); - - void enableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, - QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, - QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity); - - void enableMessages(const QVector<GLuint> &ids, - QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, - QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType); - - void disableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, - QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, - QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity); - - void disableMessages(const QVector<GLuint> &ids, - QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, - QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType); - - QList<QOpenGLDebugMessage> loggedMessages() const; - -public Q_SLOTS: - void logMessage(const QOpenGLDebugMessage &debugMessage); - void startLogging(LoggingMode loggingMode = AsynchronousLogging); - void stopLogging(); - -Q_SIGNALS: - void messageLogged(const QOpenGLDebugMessage &debugMessage); - -private: - Q_DISABLE_COPY(QOpenGLDebugLogger) - Q_DECLARE_PRIVATE(QOpenGLDebugLogger) - Q_PRIVATE_SLOT(d_func(), void _q_contextAboutToBeDestroyed()) -}; - -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(QOpenGLDebugMessage) - -#endif // QT_NO_OPENGL - -#endif // QOPENGLDEBUG_H diff --git a/src/gui/opengl/qopenglqueryhelper_p.h b/src/gui/opengl/qopenglqueryhelper_p.h deleted file mode 100644 index ad91ca9f96..0000000000 --- a/src/gui/opengl/qopenglqueryhelper_p.h +++ /dev/null @@ -1,186 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QOPENGLQUERYHELPER_P_H -#define QOPENGLQUERYHELPER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtGui/private/qtguiglobal_p.h> - -#if !defined(QT_OPENGL_ES_2) - -#include <QtGui/QOpenGLContext> - -QT_BEGIN_NAMESPACE - -// Helper class used by QOpenGLTimerQuery and later will be used by -// QOpenGLOcclusionQuery -class QOpenGLQueryHelper -{ -public: - QOpenGLQueryHelper(QOpenGLContext *context) - : GetQueryObjectuiv(nullptr), - GetQueryObjectiv(nullptr), - GetQueryiv(nullptr), - EndQuery(nullptr), - BeginQuery(nullptr), - IsQuery(nullptr), - DeleteQueries(nullptr), - GenQueries(nullptr), - GetInteger64v(nullptr), - GetQueryObjectui64v(nullptr), - GetQueryObjecti64v(nullptr), - QueryCounter(nullptr) - { - Q_ASSERT(context); - - // Core in OpenGL >=1.5 - GetQueryObjectuiv = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLuint *)>(context->getProcAddress("glGetQueryObjectuiv")); - GetQueryObjectiv = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint *)>(context->getProcAddress("glGetQueryObjectiv")); - GetQueryiv = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLenum , GLint *)>(context->getProcAddress("glGetQueryiv")); - EndQuery = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum )>(context->getProcAddress("glEndQuery")); - BeginQuery = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLuint )>(context->getProcAddress("glBeginQuery")); - IsQuery = reinterpret_cast<GLboolean (QOPENGLF_APIENTRYP)(GLuint )>(context->getProcAddress("glIsQuery")); - DeleteQueries = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLsizei , const GLuint *)>(context->getProcAddress("glDeleteQueries")); - GenQueries = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLsizei , GLuint *)>(context->getProcAddress("glGenQueries")); - - // Core in OpenGL >=3.2 - GetInteger64v = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint64 *)>(context->getProcAddress("glGetInteger64v")); - - // Core in OpenGL >=3.3 / ARB_timer_query - GetQueryObjectui64v = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLuint64 *)>(context->getProcAddress("glGetQueryObjectui64v")); - GetQueryObjecti64v = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint64 *)>(context->getProcAddress("glGetQueryObjecti64v")); - QueryCounter = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum )>(context->getProcAddress("glQueryCounter")); - } - - inline void glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) - { - GetQueryObjectuiv(id, pname, params); - } - - inline void glGetQueryObjectiv(GLuint id, GLenum pname, GLint *params) - { - GetQueryObjectiv(id, pname, params); - } - - inline void glGetQueryiv(GLenum target, GLenum pname, GLint *params) - { - GetQueryiv(target, pname, params); - } - - inline void glEndQuery(GLenum target) - { - EndQuery(target); - } - - inline void glBeginQuery(GLenum target, GLuint id) - { - BeginQuery(target, id); - } - - inline GLboolean glIsQuery(GLuint id) - { - return IsQuery(id); - } - - inline void glDeleteQueries(GLsizei n, const GLuint *ids) - { - DeleteQueries(n, ids); - } - - inline void glGenQueries(GLsizei n, GLuint *ids) - { - GenQueries(n, ids); - } - - inline void glGetInteger64v(GLenum pname, GLint64 *params) - { - GetInteger64v(pname, params); - } - - inline void glGetQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params) - { - GetQueryObjectui64v(id, pname, params); - } - - inline void glGetQueryObjecti64v(GLuint id, GLenum pname, GLint64 *params) - { - GetQueryObjecti64v(id, pname, params); - } - - inline void glQueryCounter(GLuint id, GLenum target) - { - QueryCounter(id, target); - } - -private: - // Core in OpenGL >=1.5 - void (QOPENGLF_APIENTRYP GetQueryObjectuiv)(GLuint id, GLenum pname, GLuint *params); - void (QOPENGLF_APIENTRYP GetQueryObjectiv)(GLuint id, GLenum pname, GLint *params); - void (QOPENGLF_APIENTRYP GetQueryiv)(GLenum target, GLenum pname, GLint *params); - void (QOPENGLF_APIENTRYP EndQuery)(GLenum target); - void (QOPENGLF_APIENTRYP BeginQuery)(GLenum target, GLuint id); - GLboolean (QOPENGLF_APIENTRYP IsQuery)(GLuint id); - void (QOPENGLF_APIENTRYP DeleteQueries)(GLsizei n, const GLuint *ids); - void (QOPENGLF_APIENTRYP GenQueries)(GLsizei n, GLuint *ids); - - // Core in OpenGL >=3.2 - void (QOPENGLF_APIENTRYP GetInteger64v)(GLenum pname, GLint64 *params); - - // Core in OpenGL >=3.3 and provided by ARB_timer_query - void (QOPENGLF_APIENTRYP GetQueryObjectui64v)(GLuint id, GLenum pname, GLuint64 *params); - void (QOPENGLF_APIENTRYP GetQueryObjecti64v)(GLuint id, GLenum pname, GLint64 *params); - void (QOPENGLF_APIENTRYP QueryCounter)(GLuint id, GLenum target); -}; - -QT_END_NAMESPACE - -#endif - -#endif // QOPENGLQUERYHELPER_P_H diff --git a/src/gui/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp index cf4a8dee8d..fd282e3ba0 100644 --- a/src/gui/opengl/qopengltexture.cpp +++ b/src/gui/opengl/qopengltexture.cpp @@ -4612,7 +4612,7 @@ QOpenGLTexture::WrapMode QOpenGLTexture::wrapMode(QOpenGLTexture::CoordinateDire \note This function has no effect on Mac and Qt built for OpenGL ES 2. \sa borderColor() */ -void QOpenGLTexture::setBorderColor(QColor color) +void QOpenGLTexture::setBorderColor(const QColor &color) { setBorderColor(static_cast<float>(color.redF()), static_cast<float>(color.greenF()), static_cast<float>(color.blueF()), static_cast<float>(color.alphaF())); diff --git a/src/gui/opengl/qopengltexture.h b/src/gui/opengl/qopengltexture.h index 7d984babc8..539b6aa7b2 100644 --- a/src/gui/opengl/qopengltexture.h +++ b/src/gui/opengl/qopengltexture.h @@ -621,7 +621,7 @@ public: void setWrapMode(CoordinateDirection direction, WrapMode mode); WrapMode wrapMode(CoordinateDirection direction) const; - void setBorderColor(QColor color); + void setBorderColor(const QColor &color); void setBorderColor(float r, float g, float b, float a); void setBorderColor(int r, int g, int b, int a); void setBorderColor(uint r, uint g, uint b, uint a); diff --git a/src/gui/opengl/qopengltimerquery.cpp b/src/gui/opengl/qopengltimerquery.cpp deleted file mode 100644 index a4e10b42f7..0000000000 --- a/src/gui/opengl/qopengltimerquery.cpp +++ /dev/null @@ -1,880 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qopengltimerquery.h" - -#include "qopenglqueryhelper_p.h" -#include <QtCore/private/qobject_p.h> -#include <QtGui/QOpenGLContext> -#include <QtGui/QOpenGLFunctions> - -QT_BEGIN_NAMESPACE - -// Helper class used as fallback if OpenGL <3.3 is being used with EXT_timer_query -class QExtTimerQueryHelper -{ -public: - QExtTimerQueryHelper(QOpenGLContext *context) - { - Q_ASSERT(context); - GetQueryObjectui64vEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLuint64EXT *)>(context->getProcAddress("glGetQueryObjectui64vEXT")); - GetQueryObjecti64vEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint64EXT *)>(context->getProcAddress("glGetQueryObjecti64vEXT")); - } - - inline void glGetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params) - { - GetQueryObjectui64vEXT(id, pname, params); - } - - inline void glGetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params) - { - GetQueryObjecti64vEXT(id, pname, params); - } - -private: - void (QOPENGLF_APIENTRYP GetQueryObjectui64vEXT)(GLuint id, GLenum pname, GLuint64EXT *params); - void (QOPENGLF_APIENTRYP GetQueryObjecti64vEXT)(GLuint id, GLenum pname, GLint64EXT *params); -}; - -class QOpenGLTimerQueryPrivate : public QObjectPrivate -{ -public: - QOpenGLTimerQueryPrivate() - : QObjectPrivate(), - context(nullptr), - ext(nullptr), - timeInterval(0), - timer(0) - { - } - - ~QOpenGLTimerQueryPrivate() - { - delete core; - delete ext; - } - - bool create(); - void destroy(); - void begin(); - void end(); - GLuint64 waitForTimeStamp() const; - void recordTimestamp(); - bool isResultAvailable() const; - GLuint64 result() const; - - // There are several cases we must handle: - // OpenGL >=3.3 includes timer queries as a core feature - // ARB_timer_query has same functionality as above. Requires OpenGL 3.2 - // EXT_timer_query offers limited support. Can be used with OpenGL >=1.5 - // - // Note that some implementations (OS X) provide OpenGL 3.2 but do not expose the - // ARB_timer_query extension. In such situations we must also be able to handle - // using the EXT_timer_query extension with any version of OpenGL. - // - // OpenGL 1.5 or above contains the generic query API and OpenGL 3.3 and - // ARB_timer_query provide the 64-bit query API. These are wrapped by - // QOpenGLQueryHelper. All we need to handle in addition is the EXT_timer_query - // case and to take care not to call the Core/ARB functions when we only - // have EXT_timer_query available. - QOpenGLContext *context; - QOpenGLQueryHelper *core; - QExtTimerQueryHelper *ext; - mutable GLuint64 timeInterval; - GLuint timer; -}; - -bool QOpenGLTimerQueryPrivate::create() -{ - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - - if (timer && context == ctx) - return true; - - context = ctx; - if (!context) { - qWarning("A current OpenGL context is required to create timer query objects"); - return false; - } - - if (context->isOpenGLES()) { - qWarning("QOpenGLTimerQuery: Not supported on OpenGL ES"); - return false; - } - - // Resolve the functions provided by OpenGL 1.5 and OpenGL 3.3 or ARB_timer_query - core = new QOpenGLQueryHelper(context); - - // Check to see if we also need to resolve the functions for EXT_timer_query - QSurfaceFormat f = context->format(); - if (f.version() <= qMakePair<int, int>(3, 2) - && !context->hasExtension(QByteArrayLiteral("GL_ARB_timer_query")) - && context->hasExtension(QByteArrayLiteral("GL_EXT_timer_query"))) { - ext = new QExtTimerQueryHelper(context); - } else if (f.version() <= qMakePair<int, int>(3, 2) - && !context->hasExtension(QByteArrayLiteral("GL_ARB_timer_query")) - && !context->hasExtension(QByteArrayLiteral("GL_EXT_timer_query"))) { - qWarning("QOpenGLTimerQuery requires one of:\n" - " OpenGL 3.3 or newer,\n" - " OpenGL 3.2 and the ARB_timer_query extension\n" - " or the EXT_timer query extension"); - return false; - } - - core->glGenQueries(1, &timer); - return (timer != 0); -} - -void QOpenGLTimerQueryPrivate::destroy() -{ - if (!timer) - return; - - core->glDeleteQueries(1, &timer); - timer = 0; - context = nullptr; -} - -// GL_TIME_ELAPSED_EXT is not defined on OS X 10.6 -#if !defined(GL_TIME_ELAPSED_EXT) -#define GL_TIME_ELAPSED_EXT 0x88BF -#endif - -// GL_TIME_ELAPSED is not defined on OS X 10.7 or 10.8 yet -#if !defined(GL_TIME_ELAPSED) -#define GL_TIME_ELAPSED GL_TIME_ELAPSED_EXT -#endif - -void QOpenGLTimerQueryPrivate::begin() -{ - core->glBeginQuery(GL_TIME_ELAPSED, timer); -} - -void QOpenGLTimerQueryPrivate::end() -{ - core->glEndQuery(GL_TIME_ELAPSED); -} - -void QOpenGLTimerQueryPrivate::recordTimestamp() -{ - // Don't call glQueryCounter if we only have EXT_timer_query -#if defined(GL_TIMESTAMP) - if (!ext) - core->glQueryCounter(timer, GL_TIMESTAMP); - else - qWarning("QOpenGLTimerQuery::recordTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query"); -#else - qWarning("QOpenGLTimerQuery::recordTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query"); -#endif -} - -GLuint64 QOpenGLTimerQueryPrivate::waitForTimeStamp() const -{ - GLint64 tmp = 0; -#if defined(GL_TIMESTAMP) - if (!ext) - core->glGetInteger64v(GL_TIMESTAMP, &tmp); - else - qWarning("QOpenGLTimerQuery::waitForTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query"); -#else - qWarning("QOpenGLTimerQuery::waitForTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query"); -#endif - GLuint64 timestamp(tmp); - return timestamp; -} - -bool QOpenGLTimerQueryPrivate::isResultAvailable() const -{ - GLuint available = GL_FALSE; - core->glGetQueryObjectuiv(timer, GL_QUERY_RESULT_AVAILABLE, &available); - return available; -} - -GLuint64 QOpenGLTimerQueryPrivate::result() const -{ - if (!ext) - core->glGetQueryObjectui64v(timer, GL_QUERY_RESULT, &timeInterval); - else - ext->glGetQueryObjectui64vEXT(timer, GL_QUERY_RESULT, &timeInterval); - return timeInterval; -} - -/*! - \class QOpenGLTimerQuery - \brief The QOpenGLTimerQuery class wraps an OpenGL timer query object. - \inmodule QtGui - \since 5.1 - \ingroup painting-3D - - OpenGL timer query objects are OpenGL managed resources to measure the - execution times of sequences of OpenGL commands on the GPU. - - OpenGL offers various levels of support for timer queries, depending on - the version of OpenGL you have and the presence of the ARB_timer_query or - EXT_timer_query extensions. The support can be summarized as: - - \list - \li OpenGL >=3.3 offers full support for all timer query functionality. - \li OpenGL 3.2 with the ARB_timer_query extension offers full support - for all timer query functionality. - \li OpenGL <=3.2 with the EXT_timer_query extension offers limited support - in that the timestamp of the GPU cannot be queried. Places where this - impacts functions provided by Qt classes will be highlighted in the - function documentation. - \li OpenGL ES 2 (and OpenGL ES 3) do not provide any support for OpenGL - timer queries. - \endlist - - OpenGL represents time with a granularity of 1 nanosecond (1e-9 seconds). As a - consequence of this, 32-bit integers would only give a total possible duration - of approximately 4 seconds, which would not be difficult to exceed in poorly - performing or lengthy operations. OpenGL therefore uses 64 bit integer types - to represent times. A GLuint64 variable has enough width to contain a duration - of hundreds of years, which is plenty for real-time rendering needs. - - As with the other Qt OpenGL classes, QOpenGLTimerQuery has a create() - function to create the underlying OpenGL object. This is to allow the developer to - ensure that there is a valid current OpenGL context at the time. - - Once created, timer queries can be issued in one of several ways. The simplest - method is to delimit a block of commands with calls to begin() and end(). This - instructs OpenGL to measure the time taken from completing all commands issued - prior to begin() until the completion of all commands issued prior to end(). - - At the end of a frame we can retrieve the results by calling waitForResult(). - As this function's name implies, it blocks CPU execution until OpenGL notifies - that the timer query result is available. To avoid blocking, you can check - if the query result is available by calling isResultAvailable(). Note that - modern GPUs are deeply pipelined and query results may not become available for - between 1-5 frames after they were issued. - - Note that OpenGL does not permit nesting or interleaving of multiple timer queries - using begin() and end(). Using multiple timer queries and recordTimestamp() avoids - this limitation. When using recordTimestamp() the result can be obtained at - some later time using isResultAvailable() and waitForResult(). Qt provides the - convenience class QOpenGLTimeMonitor that helps with using multiple query objects. - - \sa QOpenGLTimeMonitor -*/ - -/*! - Creates a QOpenGLTimerQuery instance with the given \a parent. You must call create() - with a valid OpenGL context before using. -*/ -QOpenGLTimerQuery::QOpenGLTimerQuery(QObject *parent) - : QObject(*new QOpenGLTimerQueryPrivate, parent) -{ -} - -/*! - Destroys the QOpenGLTimerQuery and the underlying OpenGL resource. -*/ -QOpenGLTimerQuery::~QOpenGLTimerQuery() -{ - QOpenGLContext* ctx = QOpenGLContext::currentContext(); - - Q_D(QOpenGLTimerQuery); - QOpenGLContext *oldContext = nullptr; - if (d->context != ctx) { - oldContext = ctx; - if (d->context->makeCurrent(oldContext->surface())) { - ctx = d->context; - } else { - qWarning("QOpenGLTimerQuery::~QOpenGLTimerQuery() failed to make query objects's context current"); - ctx = nullptr; - } - } - - if (ctx) - destroy(); - - if (oldContext) { - if (!oldContext->makeCurrent(oldContext->surface())) - qWarning("QOpenGLTimerQuery::~QOpenGLTimerQuery() failed to restore current context"); - } -} - -/*! - Creates the underlying OpenGL timer query object. There must be a valid OpenGL context - that supports query objects current for this function to succeed. - - Returns \c true if the OpenGL timer query object was successfully created. -*/ -bool QOpenGLTimerQuery::create() -{ - Q_D(QOpenGLTimerQuery); - return d->create(); -} - -/*! - Destroys the underlying OpenGL timer query object. The context that was current when - create() was called must be current when calling this function. -*/ -void QOpenGLTimerQuery::destroy() -{ - Q_D(QOpenGLTimerQuery); - d->destroy(); -} - -/*! - Returns \c true if the underlying OpenGL query object has been created. If this - returns \c true and the associated OpenGL context is current, then you are able to issue - queries with this object. -*/ -bool QOpenGLTimerQuery::isCreated() const -{ - Q_D(const QOpenGLTimerQuery); - return (d->timer != 0); -} - -/*! - Returns the id of the underlying OpenGL query object. -*/ -GLuint QOpenGLTimerQuery::objectId() const -{ - Q_D(const QOpenGLTimerQuery); - return d->timer; -} - -/*! - Marks the start point in the OpenGL command queue for a sequence of commands to - be timed by this query object. - - This is useful for simple use-cases. Usually it is better to use recordTimestamp(). - - \sa end(), isResultAvailable(), waitForResult(), recordTimestamp() -*/ -void QOpenGLTimerQuery::begin() -{ - Q_D(QOpenGLTimerQuery); - d->begin(); -} - -/*! - Marks the end point in the OpenGL command queue for a sequence of commands to - be timed by this query object. - - This is useful for simple use-cases. Usually it is better to use recordTimestamp(). - - \sa begin(), isResultAvailable(), waitForResult(), recordTimestamp() -*/ -void QOpenGLTimerQuery::end() -{ - Q_D(QOpenGLTimerQuery); - d->end(); -} - -/*! - Places a marker in the OpenGL command queue for the GPU to record the timestamp - when this marker is reached by the GPU. This function is non-blocking and the - result will become available at some later time. - - The availability of the result can be checked with isResultAvailable(). The result - can be fetched with waitForResult() which will block if the result is not yet - available. - - \sa waitForResult(), isResultAvailable(), begin(), end() -*/ -void QOpenGLTimerQuery::recordTimestamp() -{ - Q_D(QOpenGLTimerQuery); - return d->recordTimestamp(); -} - -/*! - Returns the current timestamp of the GPU when all previously issued OpenGL - commands have been received but not necessarily executed by the GPU. - - This function blocks until the result is returned. - - \sa recordTimestamp() -*/ -GLuint64 QOpenGLTimerQuery::waitForTimestamp() const -{ - Q_D(const QOpenGLTimerQuery); - return d->waitForTimeStamp(); -} - -/*! - Returns \c true if the OpenGL timer query result is available. - - This function is non-blocking and ideally should be used to check for the - availability of the query result before calling waitForResult(). - - \sa waitForResult() -*/ -bool QOpenGLTimerQuery::isResultAvailable() const -{ - Q_D(const QOpenGLTimerQuery); - return d->isResultAvailable(); -} - -/*! - Returns the result of the OpenGL timer query. - - This function will block until the result is made available by OpenGL. It is - recommended to call isResultAvailable() to ensure that the result is available - to avoid unnecessary blocking and stalling. - - \sa isResultAvailable() -*/ -GLuint64 QOpenGLTimerQuery::waitForResult() const -{ - Q_D(const QOpenGLTimerQuery); - return d->result(); -} - - -class QOpenGLTimeMonitorPrivate : public QObjectPrivate -{ -public: - QOpenGLTimeMonitorPrivate() - : QObjectPrivate(), - timers(), - timeSamples(), - context(nullptr), - core(nullptr), - ext(nullptr), - requestedSampleCount(2), - currentSample(-1), - timerQueryActive(false) - { - } - - ~QOpenGLTimeMonitorPrivate() - { - delete core; - delete ext; - } - - bool create(); - void destroy(); - void recordSample(); - bool isResultAvailable() const; - QVector<GLuint64> samples() const; - QVector<GLuint64> intervals() const; - void reset(); - - QVector<GLuint> timers; - mutable QVector<GLuint64> timeSamples; - - QOpenGLContext *context; - QOpenGLQueryHelper *core; - QExtTimerQueryHelper *ext; - - int requestedSampleCount; - int currentSample; - mutable bool timerQueryActive; -}; - -bool QOpenGLTimeMonitorPrivate::create() -{ - if (!timers.isEmpty() && timers.at(0) != 0 && timers.size() == requestedSampleCount) - return true; - - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (context && context != ctx) { - qWarning("QTimeMonitor: Attempting to use different OpenGL context to recreate timers.\n" - "Please call destroy() first or use the same context to previously create"); - return false; - } - - context = ctx; - if (!context) { - qWarning("A current OpenGL context is required to create timer query objects"); - return false; - } - - // Resize the vectors that hold the timers and the recorded samples - timers.resize(requestedSampleCount); - timeSamples.resize(requestedSampleCount); - - // Resolve the functions provided by OpenGL 1.5 and OpenGL 3.3 or ARB_timer_query - core = new QOpenGLQueryHelper(context); - - // Check to see if we also need to resolve the functions for EXT_timer_query - QSurfaceFormat f = context->format(); - if (f.version() <= qMakePair<int, int>(3, 2) - && !context->hasExtension(QByteArrayLiteral("GL_ARB_timer_query")) - && context->hasExtension(QByteArrayLiteral("GL_EXT_timer_query"))) { - ext = new QExtTimerQueryHelper(context); - } else if (f.version() <= qMakePair<int, int>(3, 2) - && !context->hasExtension(QByteArrayLiteral("GL_ARB_timer_query")) - && !context->hasExtension(QByteArrayLiteral("GL_EXT_timer_query"))) { - qWarning("QOpenGLTimeMonitor requires one of:\n" - " OpenGL 3.3 or newer,\n" - " OpenGL 3.2 and the ARB_timer_query extension\n" - " or the EXT_timer query extension"); - return false; - } - - core->glGenQueries(requestedSampleCount, timers.data()); - return (timers.at(0) != 0); -} - -void QOpenGLTimeMonitorPrivate::destroy() -{ - if (timers.isEmpty() || timers.at(0) == 0) - return; - - core->glDeleteQueries(timers.size(), timers.data()); - timers.clear(); - delete core; - core = nullptr; - delete ext; - ext = nullptr; - context = nullptr; -} - -void QOpenGLTimeMonitorPrivate::recordSample() -{ - // Use glQueryCounter() and GL_TIMESTAMP where available. - // Otherwise, simulate it with glBeginQuery()/glEndQuery() - if (!ext) { -#if defined(GL_TIMESTAMP) - core->glQueryCounter(timers.at(++currentSample), GL_TIMESTAMP); -#endif - } else { - if (currentSample == -1) { - core->glBeginQuery(GL_TIME_ELAPSED_EXT, timers.at(++currentSample)); - timerQueryActive = true; - } else if (currentSample < timers.size() - 1) { - core->glEndQuery(GL_TIME_ELAPSED_EXT); - core->glBeginQuery(GL_TIME_ELAPSED_EXT, timers.at(++currentSample)); - } else { - if (timerQueryActive) { - core->glEndQuery(GL_TIME_ELAPSED_EXT); - timerQueryActive = false; - } - } - } -} - -bool QOpenGLTimeMonitorPrivate::isResultAvailable() const -{ - // The OpenGL spec says that if a query result is ready then the results of all queries - // of the same type issued before it must also be ready. Therefore we only need to check - // the availability of the result for the last issued query - GLuint available = GL_FALSE; - core->glGetQueryObjectuiv(timers.at(currentSample), GL_QUERY_RESULT_AVAILABLE, &available); - return available; -} - -QVector<GLuint64> QOpenGLTimeMonitorPrivate::samples() const -{ - // For the Core and ARB options just ask for the timestamp for each timer query. - // For the EXT implementation we cannot obtain timestamps so we defer any result - // collection to the intervals() function - if (!ext) { - for (int i = 0; i <= currentSample; ++i) - core->glGetQueryObjectui64v(timers.at(i), GL_QUERY_RESULT, &timeSamples[i]); - } else { - qWarning("QOpenGLTimeMonitor::samples() requires OpenGL >=3.3\n" - "or OpenGL 3.2 and GL_ARB_timer_query"); - } - return timeSamples; -} - -QVector<GLuint64> QOpenGLTimeMonitorPrivate::intervals() const -{ - QVector<GLuint64> intervals(timers.size() - 1); - if (!ext) { - // Obtain the timestamp samples and calculate the interval durations - const QVector<GLuint64> timeStamps = samples(); - for (int i = 0; i < intervals.size(); ++i) - intervals[i] = timeStamps[i+1] - timeStamps[i]; - } else { - // Stop the last timer if needed - if (timerQueryActive) { - core->glEndQuery(GL_TIME_ELAPSED_EXT); - timerQueryActive = false; - } - - // Obtain the results from all timers apart from the redundant last one. In this - // case the results actually are the intervals not timestamps - for (int i = 0; i < currentSample; ++i) - ext->glGetQueryObjectui64vEXT(timers.at(i), GL_QUERY_RESULT, &intervals[i]); - } - - return intervals; -} - -void QOpenGLTimeMonitorPrivate::reset() -{ - currentSample = -1; - timeSamples.fill(0); -} - - -/*! - \class QOpenGLTimeMonitor - \brief The QOpenGLTimeMonitor class wraps a sequence of OpenGL timer query objects. - \inmodule QtGui - \since 5.1 - \ingroup painting-3D - - The QOpenGLTimeMonitor class is a convenience wrapper around a collection of OpenGL - timer query objects used to measure intervals of time on the GPU to the level of - granularity required by your rendering application. - - The OpenGL timer queries objects are queried in sequence to record the GPU - timestamps at positions of interest in your rendering code. Once the results for - all issues timer queries become available, the results can be fetched and - QOpenGLTimerMonitor will calculate the recorded time intervals for you. - - The typical use case of this class is to either profile your application's rendering - algorithms or to adjust those algorithms in real-time for dynamic performance/quality - balancing. - - Prior to using QOpenGLTimeMonitor in your rendering function you should set the - required number of sample points that you wish to record by calling setSamples(). Note - that measuring N sample points will produce N-1 time intervals. Once you have set the - number of sample points, call the create() function with a valid current OpenGL context - to create the necessary query timer objects. These steps are usually performed just - once in an initialization function. - - Use the recordSample() function to delimit blocks of code containing OpenGL commands - that you wish to time. You can check availability of the resulting time - samples and time intervals with isResultAvailable(). The calculated time intervals and - the raw timestamp samples can be retrieved with the blocking waitForIntervals() and - waitForSamples() functions respectively. - - After retrieving the results and before starting a new round of taking samples - (for example, in the next frame) be sure to call the reset() function which will clear - the cached results and reset the timer index back to the first timer object. - - \sa QOpenGLTimerQuery -*/ - -/*! - Creates a QOpenGLTimeMonitor instance with the given \a parent. You must call create() - with a valid OpenGL context before using. - - \sa setSampleCount(), create() -*/ -QOpenGLTimeMonitor::QOpenGLTimeMonitor(QObject *parent) - : QObject(*new QOpenGLTimeMonitorPrivate, parent) -{ -} - -/*! - Destroys the QOpenGLTimeMonitor and any underlying OpenGL resources. -*/ -QOpenGLTimeMonitor::~QOpenGLTimeMonitor() -{ - QOpenGLContext* ctx = QOpenGLContext::currentContext(); - - Q_D(QOpenGLTimeMonitor); - QOpenGLContext *oldContext = nullptr; - if (d->context != ctx) { - oldContext = ctx; - if (d->context->makeCurrent(oldContext->surface())) { - ctx = d->context; - } else { - qWarning("QOpenGLTimeMonitor::~QOpenGLTimeMonitor() failed to make time monitor's context current"); - ctx = nullptr; - } - } - - if (ctx) - destroy(); - - if (oldContext) { - if (!oldContext->makeCurrent(oldContext->surface())) - qWarning("QOpenGLTimeMonitor::~QOpenGLTimeMonitor() failed to restore current context"); - } -} - -/*! - Sets the number of sample points to \a sampleCount. After setting the number - of samples with this function, you must call create() to instantiate the underlying - OpenGL timer query objects. - - The new \a sampleCount must be at least 2. - - \sa sampleCount(), create(), recordSample() -*/ -void QOpenGLTimeMonitor::setSampleCount(int sampleCount) -{ - // We need at least 2 samples to get an interval - if (sampleCount < 2) - return; - Q_D(QOpenGLTimeMonitor); - d->requestedSampleCount = sampleCount; -} - -/*! - Returns the number of sample points that have been requested with - setSampleCount(). If create was successfully called following setSampleCount(), - then the value returned will be the actual number of sample points - that can be used. - - The default value for sample count is 2, leading to the measurement of a - single interval. - - \sa setSampleCount() -*/ -int QOpenGLTimeMonitor::sampleCount() const -{ - Q_D(const QOpenGLTimeMonitor); - return d->requestedSampleCount; -} - -/*! - Instantiate sampleCount() OpenGL timer query objects that will be used - to track the amount of time taken to execute OpenGL commands between - successive calls to recordSample(). - - Returns \c true if the OpenGL timer query objects could be created. - - \sa destroy(), setSampleCount(), recordSample() -*/ -bool QOpenGLTimeMonitor::create() -{ - Q_D(QOpenGLTimeMonitor); - return d->create(); -} - -/*! - Destroys any OpenGL timer query objects used within this instance. - - \sa create() -*/ -void QOpenGLTimeMonitor::destroy() -{ - Q_D(QOpenGLTimeMonitor); - d->destroy(); -} - -/*! - Returns \c true if the underlying OpenGL query objects have been created. If this - returns \c true and the associated OpenGL context is current, then you are able to record - time samples with this object. -*/ -bool QOpenGLTimeMonitor::isCreated() const -{ - Q_D(const QOpenGLTimeMonitor); - return (!d->timers.isEmpty() && d->timers.at(0) != 0); -} - -/*! - Returns a QVector containing the object Ids of the OpenGL timer query objects. -*/ -QVector<GLuint> QOpenGLTimeMonitor::objectIds() const -{ - Q_D(const QOpenGLTimeMonitor); - return d->timers; -} - -/*! - Issues an OpenGL timer query at this point in the OpenGL command queue. Calling this - function in a sequence in your application's rendering function, will build up - details of the GPU time taken to execute the OpenGL commands between successive - calls to this function. - - \sa setSampleCount(), isResultAvailable(), waitForSamples(), waitForIntervals() -*/ -int QOpenGLTimeMonitor::recordSample() -{ - Q_D(QOpenGLTimeMonitor); - d->recordSample(); - return d->currentSample; -} - -/*! - Returns \c true if the OpenGL timer query results are available. - - \sa waitForSamples(), waitForIntervals() -*/ -bool QOpenGLTimeMonitor::isResultAvailable() const -{ - Q_D(const QOpenGLTimeMonitor); - return d->isResultAvailable(); -} - -/*! - Returns a QVector containing the GPU timestamps taken with recordSample(). - - This function will block until OpenGL indicates the results are available. It - is recommended to check the availability of the result prior to calling this - function with isResultAvailable(). - - \note This function only works on systems that have OpenGL >=3.3 or the - ARB_timer_query extension. See QOpenGLTimerQuery for more details. - - \sa waitForIntervals(), isResultAvailable() -*/ -QVector<GLuint64> QOpenGLTimeMonitor::waitForSamples() const -{ - Q_D(const QOpenGLTimeMonitor); - return d->samples(); -} - -/*! - Returns a QVector containing the time intervals delimited by the calls to - recordSample(). The resulting vector will contain one fewer element as - this represents the intervening intervals rather than the actual timestamp - samples. - - This function will block until OpenGL indicates the results are available. It - is recommended to check the availability of the result prior to calling this - function with isResultAvailable(). - - \sa waitForSamples(), isResultAvailable() -*/ -QVector<GLuint64> QOpenGLTimeMonitor::waitForIntervals() const -{ - Q_D(const QOpenGLTimeMonitor); - return d->intervals(); -} - -/*! - Resets the time monitor ready for use in another frame of rendering. Call - this once you have obtained the previous results and before calling - recordSample() for the first time on the next frame. - - \sa recordSample() -*/ -void QOpenGLTimeMonitor::reset() -{ - Q_D(QOpenGLTimeMonitor); - d->reset(); -} - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopengltimerquery.h b/src/gui/opengl/qopengltimerquery.h deleted file mode 100644 index 27da74a3fb..0000000000 --- a/src/gui/opengl/qopengltimerquery.h +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QOPENGLTIMERQUERY_H -#define QOPENGLTIMERQUERY_H - -#include <QtGui/qtguiglobal.h> - -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) - -#include <QtCore/QObject> -#include <QtGui/qopengl.h> - -QT_BEGIN_NAMESPACE - -class QOpenGLTimerQueryPrivate; - -class Q_GUI_EXPORT QOpenGLTimerQuery : public QObject -{ - Q_OBJECT - -public: - explicit QOpenGLTimerQuery(QObject *parent = nullptr); - ~QOpenGLTimerQuery(); - - bool create(); - void destroy(); - bool isCreated() const; - GLuint objectId() const; - - void begin(); - void end(); - GLuint64 waitForTimestamp() const; - void recordTimestamp(); - bool isResultAvailable() const; - GLuint64 waitForResult() const; - -private: - Q_DECLARE_PRIVATE(QOpenGLTimerQuery) - Q_DISABLE_COPY(QOpenGLTimerQuery) -}; - - -class QOpenGLTimeMonitorPrivate; - -class Q_GUI_EXPORT QOpenGLTimeMonitor : public QObject -{ - Q_OBJECT - -public: - explicit QOpenGLTimeMonitor(QObject *parent = nullptr); - ~QOpenGLTimeMonitor(); - - void setSampleCount(int sampleCount); - int sampleCount() const; - - bool create(); - void destroy(); - bool isCreated() const; - QVector<GLuint> objectIds() const; - - int recordSample(); - - bool isResultAvailable() const; - - QVector<GLuint64> waitForSamples() const; - QVector<GLuint64> waitForIntervals() const; - - void reset(); - -private: - Q_DECLARE_PRIVATE(QOpenGLTimeMonitor) - Q_DISABLE_COPY(QOpenGLTimeMonitor) -}; - -QT_END_NAMESPACE - -#endif // QT_NO_OPENGL - -#endif // QOPENGLTIMERQUERY_H |