Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qopengldebug.cpp
Go to the documentation of this file.
1// Copyright (C) 2013 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtCore/private/qobject_p.h>
5#include <QtCore/qglobal.h>
6#include <QtCore/qvarlengtharray.h>
7#include <QtGui/qopengl.h>
8#include <QtGui/qopenglfunctions.h>
9#include <QtGui/qoffscreensurface.h>
10
11#include "qopengldebug.h"
12
14
16
17
381// When using OpenGL ES 2.0, all the necessary GL_KHR_debug constants are
382// provided in qopengles2ext.h. Unfortunately, newer versions of that file
383// suffix everything with _KHR which causes extra headache when the goal is
384// to have a single piece of code that builds in all our target
385// environments. Therefore, try to detect this and use our custom defines
386// instead, which we anyway need for OS X.
387
388#if defined(GL_KHR_debug) && defined(GL_DEBUG_SOURCE_API_KHR)
389#define USE_MANUAL_DEFS
390#endif
391
392// Under OSX (at least up to 10.8) we cannot include our copy of glext.h,
393// but we use the system-wide one, which unfortunately lacks all the needed
394// defines/typedefs. In order to make the code compile, we just add here
395// the GL_KHR_debug defines.
396
397#ifndef GL_KHR_debug
398#define GL_KHR_debug 1
399#define USE_MANUAL_DEFS
400#endif
401
402#ifdef USE_MANUAL_DEFS
403
404#ifndef GL_DEBUG_OUTPUT_SYNCHRONOUS
405#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
406#endif
407#ifndef GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH
408#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
409#endif
410#ifndef GL_DEBUG_CALLBACK_FUNCTION
411#define GL_DEBUG_CALLBACK_FUNCTION 0x8244
412#endif
413#ifndef GL_DEBUG_CALLBACK_USER_PARAM
414#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245
415#endif
416#ifndef GL_DEBUG_SOURCE_API
417#define GL_DEBUG_SOURCE_API 0x8246
418#endif
419#ifndef GL_DEBUG_SOURCE_WINDOW_SYSTEM
420#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247
421#endif
422#ifndef GL_DEBUG_SOURCE_SHADER_COMPILER
423#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248
424#endif
425#ifndef GL_DEBUG_SOURCE_THIRD_PARTY
426#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249
427#endif
428#ifndef GL_DEBUG_SOURCE_APPLICATION
429#define GL_DEBUG_SOURCE_APPLICATION 0x824A
430#endif
431#ifndef GL_DEBUG_SOURCE_OTHER
432#define GL_DEBUG_SOURCE_OTHER 0x824B
433#endif
434#ifndef GL_DEBUG_TYPE_ERROR
435#define GL_DEBUG_TYPE_ERROR 0x824C
436#endif
437#ifndef GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR
438#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
439#endif
440#ifndef GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR
441#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
442#endif
443#ifndef GL_DEBUG_TYPE_PORTABILITY
444#define GL_DEBUG_TYPE_PORTABILITY 0x824F
445#endif
446#ifndef GL_DEBUG_TYPE_PERFORMANCE
447#define GL_DEBUG_TYPE_PERFORMANCE 0x8250
448#endif
449#ifndef GL_DEBUG_TYPE_OTHER
450#define GL_DEBUG_TYPE_OTHER 0x8251
451#endif
452#ifndef GL_DEBUG_TYPE_MARKER
453#define GL_DEBUG_TYPE_MARKER 0x8268
454#endif
455#ifndef GL_DEBUG_TYPE_PUSH_GROUP
456#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269
457#endif
458#ifndef GL_DEBUG_TYPE_POP_GROUP
459#define GL_DEBUG_TYPE_POP_GROUP 0x826A
460#endif
461#ifndef GL_DEBUG_SEVERITY_NOTIFICATION
462#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
463#endif
464#ifndef GL_MAX_DEBUG_GROUP_STACK_DEPTH
465#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C
466#endif
467#ifndef GL_DEBUG_GROUP_STACK_DEPTH
468#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D
469#endif
470#ifndef GL_BUFFER
471#define GL_BUFFER 0x82E0
472#endif
473#ifndef GL_SHADER
474#define GL_SHADER 0x82E1
475#endif
476#ifndef GL_PROGRAM
477#define GL_PROGRAM 0x82E2
478#endif
479#ifndef GL_QUERY
480#define GL_QUERY 0x82E3
481#endif
482#ifndef GL_PROGRAM_PIPELINE
483#define GL_PROGRAM_PIPELINE 0x82E4
484#endif
485#ifndef GL_SAMPLER
486#define GL_SAMPLER 0x82E6
487#endif
488#ifndef GL_DISPLAY_LIST
489#define GL_DISPLAY_LIST 0x82E7
490#endif
491#ifndef GL_MAX_LABEL_LENGTH
492#define GL_MAX_LABEL_LENGTH 0x82E8
493#endif
494#ifndef GL_MAX_DEBUG_MESSAGE_LENGTH
495#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143
496#endif
497#ifndef GL_MAX_DEBUG_LOGGED_MESSAGES
498#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144
499#endif
500#ifndef GL_DEBUG_LOGGED_MESSAGES
501#define GL_DEBUG_LOGGED_MESSAGES 0x9145
502#endif
503#ifndef GL_DEBUG_SEVERITY_HIGH
504#define GL_DEBUG_SEVERITY_HIGH 0x9146
505#endif
506#ifndef GL_DEBUG_SEVERITY_MEDIUM
507#define GL_DEBUG_SEVERITY_MEDIUM 0x9147
508#endif
509#ifndef GL_DEBUG_SEVERITY_LOW
510#define GL_DEBUG_SEVERITY_LOW 0x9148
511#endif
512#ifndef GL_DEBUG_OUTPUT
513#define GL_DEBUG_OUTPUT 0x92E0
514#endif
515#ifndef GL_CONTEXT_FLAG_DEBUG_BIT
516#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
517#endif
518#ifndef GL_STACK_OVERFLOW
519#define GL_STACK_OVERFLOW 0x0503
520#endif
521#ifndef GL_STACK_UNDERFLOW
522#define GL_STACK_UNDERFLOW 0x0504
523#endif
524
526
527#endif /* USE_MANUAL_DEFS */
528
529
553
581
586{
587 switch (source) {
589 return QStringLiteral("InvalidSource");
591 return QStringLiteral("APISource");
593 return QStringLiteral("WindowSystemSource");
595 return QStringLiteral("ShaderCompilerSource");
597 return QStringLiteral("ThirdPartySource");
599 return QStringLiteral("ApplicationSource");
601 return QStringLiteral("OtherSource");
603 return QStringLiteral("AnySource");
604 }
605
606 Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown message source");
607 return QString();
608}
609
639
673
678{
679 switch (type) {
681 return QStringLiteral("InvalidType");
683 return QStringLiteral("ErrorType");
685 return QStringLiteral("DeprecatedBehaviorType");
687 return QStringLiteral("UndefinedBehaviorType");
689 return QStringLiteral("PortabilityType");
691 return QStringLiteral("PerformanceType");
693 return QStringLiteral("OtherType");
695 return QStringLiteral("MarkerType");
697 return QStringLiteral("GroupPushType");
699 return QStringLiteral("GroupPopType");
701 return QStringLiteral("AnyType");
702 }
703
704 Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown message type");
705 return QString();
706}
707
727
751
756{
757 switch (severity) {
759 return QStringLiteral("InvalidSeverity");
761 return QStringLiteral("HighSeverity");
763 return QStringLiteral("MediumSeverity");
765 return QStringLiteral("LowSeverity");
767 return QStringLiteral("NotificationSeverity");
769 return QStringLiteral("AnySeverity");
770 }
771
772 Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown message severity");
773 return QString();
774}
775
787
792 : message(),
793 id(0),
794 source(QOpenGLDebugMessage::InvalidSource),
795 type(QOpenGLDebugMessage::InvalidType),
796 severity(QOpenGLDebugMessage::InvalidSeverity)
797{
798}
799
800
816
823 : d(debugMessage.d)
824{
825}
826
833
839{
840 d = debugMessage.d;
841 return *this;
842}
843
864
872
880
885{
886 return d->id;
887}
888
893{
894 return d->message;
895}
896
905 GLuint id,
908{
910 m.d->message = text;
911 m.d->id = id;
912 m.d->severity = severity;
913 m.d->type = type;
914 m.d->source = ApplicationSource;
915 return m;
916}
917
926 GLuint id,
929{
931 m.d->message = text;
932 m.d->id = id;
933 m.d->severity = severity;
934 m.d->type = type;
935 m.d->source = ThirdPartySource;
936 return m;
937}
938
947{
948 return (d == debugMessage.d)
949 || (d->id == debugMessage.d->id
950 && d->source == debugMessage.d->source
951 && d->type == debugMessage.d->type
952 && d->severity == debugMessage.d->severity
953 && d->message == debugMessage.d->message);
954}
955
965#ifndef QT_NO_DEBUG_STREAM
973{
974 QDebugStateSaver saver(debug);
975 debug.nospace() << "QOpenGLDebugMessage::Source("
977 << ')';
978 return debug;
979}
980
988{
989 QDebugStateSaver saver(debug);
990 debug.nospace() << "QOpenGLDebugMessage::Type("
992 << ')';
993 return debug;
994}
995
1003{
1004 QDebugStateSaver saver(debug);
1005 debug.nospace() << "QOpenGLDebugMessage::Severity("
1007 << ')';
1008 return debug;
1009}
1010
1018{
1019 QDebugStateSaver saver(debug);
1020 debug.nospace() << "QOpenGLDebugMessage("
1021 << qt_messageSourceToString(message.source()) << ", "
1022 << message.id() << ", "
1023 << message.message() << ", "
1024 << qt_messageSeverityToString(message.severity()) << ", "
1025 << qt_messageTypeToString(message.type()) << ')';
1026 return debug;
1027
1028}
1029#endif // QT_NO_DEBUG_STREAM
1030
1032typedef void (QOPENGLF_APIENTRYP qt_glDebugMessageInsert_t)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
1033typedef void (QOPENGLF_APIENTRYP qt_glDebugMessageCallback_t)(GLDEBUGPROC callback, const void *userParam);
1035typedef void (QOPENGLF_APIENTRYP qt_glPushDebugGroup_t)(GLenum source, GLuint id, GLsizei length, const GLchar *message);
1036typedef void (QOPENGLF_APIENTRYP qt_glPopDebugGroup_t)();
1037typedef void (QOPENGLF_APIENTRYP qt_glGetPointerv_t)(GLenum pname, GLvoid **params);
1038
1040{
1041 Q_DECLARE_PUBLIC(QOpenGLDebugLogger)
1042public:
1044
1046 void controlDebugMessages(QOpenGLDebugMessage::Sources sources,
1047 QOpenGLDebugMessage::Types types,
1048 QOpenGLDebugMessage::Severities severities, const QList<GLuint> &ids,
1049 const QByteArray &callerName, bool enable);
1051
1052 qt_glDebugMessageControl_t glDebugMessageControl;
1053 qt_glDebugMessageInsert_t glDebugMessageInsert;
1054 qt_glDebugMessageCallback_t glDebugMessageCallback;
1055 qt_glGetDebugMessageLog_t glGetDebugMessageLog;
1056 qt_glPushDebugGroup_t glPushDebugGroup;
1057 qt_glPopDebugGroup_t glPopDebugGroup;
1058 qt_glGetPointerv_t glGetPointerv;
1059
1065 bool initialized : 1;
1066 bool isLogging : 1;
1069};
1070
1075 : glDebugMessageControl(nullptr),
1076 glDebugMessageInsert(nullptr),
1077 glDebugMessageCallback(nullptr),
1078 glGetDebugMessageLog(nullptr),
1079 glPushDebugGroup(nullptr),
1080 glPopDebugGroup(nullptr),
1081 oldDebugCallbackFunction(nullptr),
1083 maxMessageLength(0),
1084 loggingMode(QOpenGLDebugLogger::AsynchronousLogging),
1085 initialized(false),
1086 isLogging(false),
1087 debugWasEnabled(false),
1088 syncDebugWasEnabled(false)
1089{
1090}
1091
1096 GLenum type,
1097 GLuint id,
1100 const GLchar *rawMessage)
1101{
1104
1106
1107 QOpenGLDebugMessagePrivate *messagePrivate = message.d.data();
1108 messagePrivate->source = qt_messageSourceFromGL(source);
1109 messagePrivate->type = qt_messageTypeFromGL(type);
1110 messagePrivate->id = id;
1111 messagePrivate->severity = qt_messageSeverityFromGL(severity);
1112 // not passing the length to fromUtf8, as some bugged OpenGL drivers
1113 // do not handle the length correctly. Just rely on the message to be NUL terminated.
1114 messagePrivate->message = QString::fromUtf8(rawMessage);
1115
1116 Q_Q(QOpenGLDebugLogger);
1117 emit q->messageLogged(message);
1118}
1119
1124 QOpenGLDebugMessage::Types types,
1125 QOpenGLDebugMessage::Severities severities,
1126 const QList<GLuint> &ids,
1127 const QByteArray &callerName, bool enable)
1128{
1129 if (!initialized) {
1130 qWarning("QOpenGLDebugLogger::%s(): object must be initialized before enabling/disabling messages", callerName.constData());
1131 return;
1132 }
1134 qWarning("QOpenGLDebugLogger::%s(): invalid source specified", callerName.constData());
1135 return;
1136 }
1138 qWarning("QOpenGLDebugLogger::%s(): invalid type specified", callerName.constData());
1139 return;
1140 }
1142 qWarning("QOpenGLDebugLogger::%s(): invalid severity specified", callerName.constData());
1143 return;
1144 }
1145
1146 QVarLengthArray<GLenum, 8> glSources;
1147 QVarLengthArray<GLenum, 8> glTypes;
1148 QVarLengthArray<GLenum, 8> glSeverities;
1149
1150 if (ids.size() > 0) {
1152
1153 // The GL_KHR_debug extension says:
1154 //
1155 // - If <count> is greater than zero, then <ids> is an array of <count>
1156 // message IDs for the specified combination of <source> and <type>. In
1157 // this case, if <source> or <type> is DONT_CARE, or <severity> is not
1158 // DONT_CARE, the error INVALID_OPERATION is generated. If <count> is
1159 // zero, the value if <ids> is ignored.
1160 //
1161 // This means we can't convert AnySource or AnyType into DONT_CARE, but we have to roll
1162 // them into individual sources/types.
1163
1166 for (uint i = 1; i <= QOpenGLDebugMessage::LastSource; i = i << 1)
1168 }
1169
1172 for (uint i = 1; i <= QOpenGLDebugMessage::LastType; i = i << 1)
1174 }
1175 }
1176
1177#define CONVERT_TO_GL_DEBUG_MESSAGE_CONTROL_PARAMETERS(type, source, target) \
1178 if (source == QOpenGLDebugMessage::Any ## type) { \
1179 target << GL_DONT_CARE; \
1180 } else { \
1181 for (uint i = 1; i <= QOpenGLDebugMessage::Last ## type; i = i << 1) \
1182 if (source.testFlag(QOpenGLDebugMessage:: type (i))) \
1183 target << qt_message ## type ## ToGL (QOpenGLDebugMessage:: type (i)); \
1184 }
1185
1189#undef CONVERT_TO_GL_DEBUG_MESSAGE_CONTROL_PARAMETERS
1190
1191 const GLsizei idCount = ids.size();
1192 // The GL_KHR_debug extension says that if idCount is 0, idPtr must be ignored.
1193 // Unfortunately, some bugged drivers do NOT ignore it, so pass NULL in case.
1194 const GLuint * const idPtr = idCount ? ids.constData() : nullptr;
1195
1196 for (GLenum source : glSources)
1197 for (GLenum type : glTypes)
1198 for (GLenum severity : glSeverities)
1200}
1201
1206{
1208
1209 // Re-make our context current somehow, otherwise stopLogging will fail.
1210
1211 // Save the current context and its surface in case we need to set them back
1213 QSurface *currentSurface = nullptr;
1214
1215 QScopedPointer<QOffscreenSurface> offscreenSurface;
1216
1217 if (context != currentContext) {
1218 // Make our old context current on a temporary surface
1219 if (currentContext)
1220 currentSurface = currentContext->surface();
1221
1222 offscreenSurface.reset(new QOffscreenSurface);
1223 offscreenSurface->setFormat(context->format());
1224 offscreenSurface->create();
1225 if (!context->makeCurrent(offscreenSurface.data()))
1226 qWarning("QOpenGLDebugLoggerPrivate::_q_contextAboutToBeDestroyed(): could not make the owning GL context current for cleanup");
1227 }
1228
1229 Q_Q(QOpenGLDebugLogger);
1230 q->stopLogging();
1231
1232 if (offscreenSurface) {
1233 // We did change the current context: set it back
1234 if (currentContext)
1235 currentContext->makeCurrent(currentSurface);
1236 else
1238 }
1239
1241 context = nullptr;
1242 initialized = false;
1243}
1244
1245extern "C" {
1247 GLenum type,
1248 GLuint id,
1251 const GLchar *rawMessage,
1252 const GLvoid *userParam)
1253{
1254 QOpenGLDebugLoggerPrivate *loggerPrivate = static_cast<QOpenGLDebugLoggerPrivate *>(const_cast<GLvoid *>(userParam));
1255 loggerPrivate->handleMessage(source, type, id, severity, length, rawMessage);
1256}
1257}
1258
1267 : QObject(*new QOpenGLDebugLoggerPrivate, parent)
1268{
1269 // QOpenGLDebugMessage is going to be mostly used as an argument
1270 // of a cross thread connection, therefore let's ease the life for the users
1271 // and register the type for them.
1272 qRegisterMetaType<QOpenGLDebugMessage>();
1273}
1274
1282
1299{
1301 if (!context) {
1302 qWarning("QOpenGLDebugLogger::initialize(): no current OpenGL context found.");
1303 return false;
1304 }
1305
1306 Q_D(QOpenGLDebugLogger);
1307 if (d->context == context) {
1308 // context is non-NULL, d->context is non NULL only on successful initialization.
1309 Q_ASSERT(d->initialized);
1310 return true;
1311 }
1312
1313 if (d->isLogging) {
1314 qWarning("QOpenGLDebugLogger::initialize(): cannot initialize the object while logging. Please stop the logging first.");
1315 return false;
1316 }
1317
1318 if (d->context)
1319 disconnect(d->context, SIGNAL(aboutToBeDestroyed()), this, SLOT(_q_contextAboutToBeDestroyed()));
1320
1321 d->initialized = false;
1322 d->context = nullptr;
1323
1324 if (!context->hasExtension(QByteArrayLiteral("GL_KHR_debug")))
1325 return false;
1326
1327 d->context = context;
1328 connect(d->context, SIGNAL(aboutToBeDestroyed()), this, SLOT(_q_contextAboutToBeDestroyed()));
1329
1330#define GET_DEBUG_PROC_ADDRESS(procName) \
1331 d->procName = reinterpret_cast< qt_ ## procName ## _t >( \
1332 d->context->getProcAddress(d->context->isOpenGLES() ? (#procName "KHR") : (#procName)) \
1333 );
1334
1335 GET_DEBUG_PROC_ADDRESS(glDebugMessageControl);
1336 GET_DEBUG_PROC_ADDRESS(glDebugMessageInsert);
1337 GET_DEBUG_PROC_ADDRESS(glDebugMessageCallback);
1338 GET_DEBUG_PROC_ADDRESS(glGetDebugMessageLog);
1339 GET_DEBUG_PROC_ADDRESS(glPushDebugGroup);
1340 GET_DEBUG_PROC_ADDRESS(glPopDebugGroup);
1341 GET_DEBUG_PROC_ADDRESS(glGetPointerv)
1342
1343#undef GET_DEBUG_PROC_ADDRESS
1344
1345 QOpenGLContext::currentContext()->functions()->glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH, &d->maxMessageLength);
1346
1347#ifndef QT_NO_DEBUG
1348 if (!d->context->format().testOption(QSurfaceFormat::DebugContext)) {
1349 qWarning("QOpenGLDebugLogger::initialize(): the current context is not a debug context:\n"
1350 " this means that the GL may not generate any debug output at all.\n"
1351 " To avoid this warning, try creating the context with the\n"
1352 " QSurfaceFormat::DebugContext surface format option.");
1353 }
1354#endif // QT_NO_DEBUG
1355
1356 d->initialized = true;
1357 return true;
1358}
1359
1366{
1367 Q_D(const QOpenGLDebugLogger);
1368 return d->isLogging;
1369}
1370
1394{
1395 Q_D(QOpenGLDebugLogger);
1396 if (!d->initialized) {
1397 qWarning("QOpenGLDebugLogger::startLogging(): object must be initialized before logging can start");
1398 return;
1399 }
1400 if (d->isLogging) {
1401 qWarning("QOpenGLDebugLogger::startLogging(): this object is already logging");
1402 return;
1403 }
1404
1405 d->isLogging = true;
1406 d->loggingMode = loggingMode;
1407
1408 d->glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION, reinterpret_cast<void **>(&d->oldDebugCallbackFunction));
1409 d->glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM, &d->oldDebugCallbackParameter);
1410
1411 d->glDebugMessageCallback(&qt_opengl_debug_callback, d);
1412
1414 d->debugWasEnabled = funcs->glIsEnabled(GL_DEBUG_OUTPUT);
1415 d->syncDebugWasEnabled = funcs->glIsEnabled(GL_DEBUG_OUTPUT_SYNCHRONOUS);
1416
1417 if (d->loggingMode == SynchronousLogging)
1419 else
1421
1422 funcs->glEnable(GL_DEBUG_OUTPUT);
1423}
1424
1431{
1432 Q_D(const QOpenGLDebugLogger);
1433 return d->loggingMode;
1434}
1435
1442{
1443 Q_D(QOpenGLDebugLogger);
1444 if (!d->isLogging)
1445 return;
1446
1448 if (!currentContext || currentContext != d->context) {
1449 qWarning("QOpenGLDebugLogger::stopLogging(): attempting to stop logging with the wrong OpenGL context current");
1450 return;
1451 }
1452
1453 d->isLogging = false;
1454
1455 d->glDebugMessageCallback(d->oldDebugCallbackFunction, d->oldDebugCallbackParameter);
1456
1458 if (!d->debugWasEnabled)
1459 funcs->glDisable(GL_DEBUG_OUTPUT);
1460
1461 if (d->syncDebugWasEnabled)
1463 else
1465}
1466
1481{
1482 Q_D(QOpenGLDebugLogger);
1483 if (!d->initialized) {
1484 qWarning("QOpenGLDebugLogger::logMessage(): object must be initialized before logging messages");
1485 return;
1486 }
1487 if (debugMessage.source() != QOpenGLDebugMessage::ApplicationSource
1488 && debugMessage.source() != QOpenGLDebugMessage::ThirdPartySource) {
1489 qWarning("QOpenGLDebugLogger::logMessage(): using a message source different from ApplicationSource\n"
1490 " or ThirdPartySource is not supported by GL_KHR_debug. The message will not be logged.");
1491 return;
1492 }
1493 if (debugMessage.type() == QOpenGLDebugMessage::InvalidType
1494 || debugMessage.type() == QOpenGLDebugMessage::AnyType
1495 || debugMessage.severity() == QOpenGLDebugMessage::InvalidSeverity
1496 || debugMessage.severity() == QOpenGLDebugMessage::AnySeverity) {
1497 qWarning("QOpenGLDebugLogger::logMessage(): the message has a non-valid type and/or severity. The message will not be logged.");
1498 return;
1499 }
1500
1501 const GLenum source = qt_messageSourceToGL(debugMessage.source());
1502 const GLenum type = qt_messageTypeToGL(debugMessage.type());
1503 const GLenum severity = qt_messageSeverityToGL(debugMessage.severity());
1504 QByteArray rawMessage = debugMessage.message().toUtf8();
1505 rawMessage.append('\0');
1506
1507 if (rawMessage.size() > d->maxMessageLength) {
1508 qWarning("QOpenGLDebugLogger::logMessage(): message too long, truncating it\n"
1509 " (%d bytes long, but the GL accepts up to %d bytes)", int(rawMessage.size()), d->maxMessageLength);
1510 rawMessage.resize(d->maxMessageLength - 1);
1511 rawMessage.append('\0');
1512 }
1513
1514 // Don't pass rawMessage.length(), as unfortunately bugged
1515 // OpenGL drivers will eat the trailing NUL in the message. Just rely
1516 // on the message being NUL terminated.
1517 d->glDebugMessageInsert(source,
1518 type,
1519 debugMessage.id(),
1520 severity,
1521 -1,
1522 rawMessage.constData());
1523}
1524
1544{
1545 Q_D(QOpenGLDebugLogger);
1546 if (!d->initialized) {
1547 qWarning("QOpenGLDebugLogger::pushGroup(): object must be initialized before pushing a debug group");
1548 return;
1549 }
1552 qWarning("QOpenGLDebugLogger::pushGroup(): using a source different from ApplicationSource\n"
1553 " or ThirdPartySource is not supported by GL_KHR_debug. The group will not be pushed.");
1554 return;
1555 }
1556
1557 QByteArray rawName = name.toUtf8();
1558 rawName.append('\0');
1559 if (rawName.size() > d->maxMessageLength) {
1560 qWarning("QOpenGLDebugLogger::pushGroup(): group name too long, truncating it\n"
1561 " (%d bytes long, but the GL accepts up to %d bytes)", int(rawName.size()), d->maxMessageLength);
1562 rawName.resize(d->maxMessageLength - 1);
1563 rawName.append('\0');
1564 }
1565
1566 // Don't pass rawMessage.length(), as unfortunately bugged
1567 // OpenGL drivers will eat the trailing NUL in the name. Just rely
1568 // on the name being NUL terminated.
1569 d->glPushDebugGroup(qt_messageSourceToGL(source), id, -1, rawName.constData());
1570}
1571
1587{
1588 Q_D(QOpenGLDebugLogger);
1589 if (!d->initialized) {
1590 qWarning("QOpenGLDebugLogger::pushGroup(): object must be initialized before popping a debug group");
1591 return;
1592 }
1593
1594 d->glPopDebugGroup();
1595}
1596
1605void QOpenGLDebugLogger::enableMessages(QOpenGLDebugMessage::Sources sources,
1606 QOpenGLDebugMessage::Types types,
1607 QOpenGLDebugMessage::Severities severities)
1608{
1609 Q_D(QOpenGLDebugLogger);
1610 d->controlDebugMessages(sources, types, severities, QList<GLuint>(),
1611 QByteArrayLiteral("enableMessages"), true);
1612}
1613
1622void QOpenGLDebugLogger::enableMessages(const QList<GLuint> &ids,
1623 QOpenGLDebugMessage::Sources sources,
1624 QOpenGLDebugMessage::Types types)
1625{
1626 Q_D(QOpenGLDebugLogger);
1627 d->controlDebugMessages(sources,
1628 types,
1630 ids,
1631 QByteArrayLiteral("enableMessages"),
1632 true);
1633}
1634
1643void QOpenGLDebugLogger::disableMessages(QOpenGLDebugMessage::Sources sources,
1644 QOpenGLDebugMessage::Types types,
1645 QOpenGLDebugMessage::Severities severities)
1646{
1647 Q_D(QOpenGLDebugLogger);
1648 d->controlDebugMessages(sources, types, severities, QList<GLuint>(),
1649 QByteArrayLiteral("disableMessages"), false);
1650}
1651
1661 QOpenGLDebugMessage::Sources sources,
1662 QOpenGLDebugMessage::Types types)
1663{
1664 Q_D(QOpenGLDebugLogger);
1665 d->controlDebugMessages(sources,
1666 types,
1668 ids,
1669 QByteArrayLiteral("disableMessages"),
1670 false);
1671}
1672
1681QList<QOpenGLDebugMessage> QOpenGLDebugLogger::loggedMessages() const
1682{
1683 Q_D(const QOpenGLDebugLogger);
1684 if (!d->initialized) {
1685 qWarning("QOpenGLDebugLogger::loggedMessages(): object must be initialized before reading logged messages");
1686 return QList<QOpenGLDebugMessage>();
1687 }
1688
1689 static const GLuint maxMessageCount = 128;
1690 GLuint messagesRead;
1691 GLenum messageSources[maxMessageCount];
1692 GLenum messageTypes[maxMessageCount];
1693 GLuint messageIds[maxMessageCount];
1694 GLenum messageSeverities[maxMessageCount];
1695 GLsizei messageLengths[maxMessageCount];
1696
1697 QByteArray messagesBuffer;
1698 messagesBuffer.resize(maxMessageCount * d->maxMessageLength);
1699
1700 QList<QOpenGLDebugMessage> messages;
1701 do {
1702 messagesRead = d->glGetDebugMessageLog(maxMessageCount,
1703 GLsizei(messagesBuffer.size()),
1704 messageSources,
1705 messageTypes,
1706 messageIds,
1707 messageSeverities,
1708 messageLengths,
1709 messagesBuffer.data());
1710
1711 const char *messagesBufferPtr = messagesBuffer.constData();
1712 for (GLuint i = 0; i < messagesRead; ++i) {
1714
1715 QOpenGLDebugMessagePrivate *messagePrivate = message.d.data();
1716 messagePrivate->source = qt_messageSourceFromGL(messageSources[i]);
1717 messagePrivate->type = qt_messageTypeFromGL(messageTypes[i]);
1718 messagePrivate->id = messageIds[i];
1719 messagePrivate->severity = qt_messageSeverityFromGL(messageSeverities[i]);
1720 messagePrivate->message = QString::fromUtf8(messagesBufferPtr, messageLengths[i] - 1);
1721
1722 messagesBufferPtr += messageLengths[i];
1723 messages << message;
1724 }
1725 } while (messagesRead == maxMessageCount);
1726
1727 return messages;
1728}
1729
1769{
1770 Q_D(const QOpenGLDebugLogger);
1771 if (!d->initialized) {
1772 qWarning("QOpenGLDebugLogger::maximumMessageLength(): object must be initialized before reading the maximum message length");
1773 return -1;
1774 }
1775 return d->maxMessageLength;
1776}
1777
1778
1780
1781#include "moc_qopengldebug.cpp"
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
\inmodule QtCore
\inmodule QtCore
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
\inmodule QtGui
\inmodule QtGui
bool makeCurrent(QSurface *surface)
Makes the context current in the current thread, against the given surface.
QSurfaceFormat format() const
Returns the format of the underlying platform context, if create() has been called.
static QOpenGLContext * currentContext()
Returns the last context which called makeCurrent in the current thread, or \nullptr,...
void doneCurrent()
Convenience function for calling makeCurrent with a 0 surface.
QSurface * surface() const
Returns the surface the context has been made current with.
qt_glDebugMessageCallback_t glDebugMessageCallback
qt_glPushDebugGroup_t glPushDebugGroup
void controlDebugMessages(QOpenGLDebugMessage::Sources sources, QOpenGLDebugMessage::Types types, QOpenGLDebugMessage::Severities severities, const QList< GLuint > &ids, const QByteArray &callerName, bool enable)
qt_glDebugMessageInsert_t glDebugMessageInsert
qt_glGetPointerv_t glGetPointerv
QOpenGLDebugLogger::LoggingMode loggingMode
qt_glDebugMessageControl_t glDebugMessageControl
qt_glGetDebugMessageLog_t glGetDebugMessageLog
void handleMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *rawMessage)
qt_glPopDebugGroup_t glPopDebugGroup
The QOpenGLDebugLogger enables logging of OpenGL debugging messages.
LoggingMode loggingMode
the logging mode passed to startLogging().
void stopLogging()
Stops logging messages from the OpenGL server.
qint64 maximumMessageLength() const
Returns the maximum supported length, in bytes, for the text of the messages passed to logMessage().
bool isLogging() const
Returns true if this object is currently logging, false otherwise.
QOpenGLDebugLogger(QObject *parent=nullptr)
Constructs a new logger object with the given parent.
bool initialize()
Initializes the object in the current OpenGL context.
void disableMessages(QOpenGLDebugMessage::Sources sources=QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types=QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::Severities severities=QOpenGLDebugMessage::AnySeverity)
Disables the logging of messages with the given sources, of the given types and with the given severi...
LoggingMode
The LoggingMode enum defines the logging mode of the logger object.
~QOpenGLDebugLogger()
Destroys the logger object.
void logMessage(const QOpenGLDebugMessage &debugMessage)
Inserts the message debugMessage into the OpenGL debug log.
void pushGroup(const QString &name, GLuint id=0, QOpenGLDebugMessage::Source source=QOpenGLDebugMessage::ApplicationSource)
Pushes a debug group with name name, id id, and source source onto the debug groups stack.
void enableMessages(QOpenGLDebugMessage::Sources sources=QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types=QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::Severities severities=QOpenGLDebugMessage::AnySeverity)
Enables the logging of messages from the given sources, of the given types and with the given severit...
void startLogging(LoggingMode loggingMode=AsynchronousLogging)
Starts logging messages coming from the OpenGL server.
QList< QOpenGLDebugMessage > loggedMessages() const
Reads all the available messages in the OpenGL internal debug log and returns them.
void popGroup()
Pops the topmost debug group from the debug groups stack.
QOpenGLDebugMessage::Source source
QOpenGLDebugMessage::Type type
QOpenGLDebugMessage::Severity severity
The QOpenGLDebugMessage class wraps an OpenGL debug message.
QOpenGLDebugMessage & operator=(const QOpenGLDebugMessage &debugMessage)
Assigns the message debugMessage to this object, and returns a reference to the copy.
QOpenGLDebugMessage()
Constructs a debug message with an empty message string, id set to 0, source set to InvalidSource,...
static QOpenGLDebugMessage createThirdPartyMessage(const QString &text, GLuint id=0, Severity severity=NotificationSeverity, Type type=OtherType)
Constructs and returns a debug message with text as its text, id as id, severity as severity,...
QDebug operator<<(QDebug debug, const QOpenGLDebugMessage &message)
Writes the message message into the debug object debug for debugging purposes.
QDebug operator<<(QDebug debug, QOpenGLDebugMessage::Type type)
Writes the type type into the debug object debug for debugging purposes.
Source source() const
Returns the source of the debug message.
QString message() const
Returns the textual message contained by this debug message.
Type
The Type enum defines the type of the debug message.
static QOpenGLDebugMessage createApplicationMessage(const QString &text, GLuint id=0, Severity severity=NotificationSeverity, Type type=OtherType)
Constructs and returns a debug message with text as its text, id as id, severity as severity,...
Source
The Source enum defines the source of the debug message.
GLuint id() const
Returns the id of the debug message.
~QOpenGLDebugMessage()
Destroys this debug message.
Severity severity() const
Returns the severity of the debug message.
QDebug operator<<(QDebug debug, QOpenGLDebugMessage::Source source)
Writes the source source into the debug object debug for debugging purposes.
Severity
The Severity enum defines the severity of the debug message.
bool operator==(const QOpenGLDebugMessage &debugMessage) const
Returns true if this debug message is equal to debugMessage, or false otherwise.
Type type() const
Returns the type of the debug message.
QDebug operator<<(QDebug debug, QOpenGLDebugMessage::Severity severity)
Writes the severity severity into the debug object debug for debugging purposes.
The QOpenGLFunctions class provides cross-platform access to the OpenGL ES 2.0 API.
\inmodule QtCore
Definition qshareddata.h:19
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
\inmodule QtGui
Definition qsurface.h:21
static VulkanServerBufferGlFunctions * funcs
QString text
Combined button and popup list for selecting options.
static void * context
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
#define Q_FUNC_INFO
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
#define qWarning
Definition qlogging.h:166
#define QT_IMPL_METATYPE_EXTERN(TYPE)
Definition qmetatype.h:1390
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
#define QOPENGLF_APIENTRYP
Definition qopengl.h:275
#define QOPENGLF_APIENTRY
Definition qopengl.h:270
char GLchar
Definition qopengl.h:158
#define GL_DEBUG_TYPE_MARKER
#define GL_DEBUG_SEVERITY_LOW
GLsizei GLenum GLenum GLuint GLenum * severities
GLsizei GLenum GLenum GLuint GLenum GLsizei * lengths
#define GL_DEBUG_SOURCE_THIRD_PARTY
static void QOPENGLF_APIENTRY qt_opengl_debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *rawMessage, const GLvoid *userParam)
#define GL_DEBUG_TYPE_PORTABILITY
#define GL_DEBUG_TYPE_OTHER
static GLenum qt_messageTypeToGL(QOpenGLDebugMessage::Type type)
GLsizei GLenum GLenum GLuint GLenum GLsizei GLchar * messageLog
#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR
GLsizei GLenum * sources
GLenum GLenum GLsizei const GLuint * ids
#define GL_DEBUG_TYPE_PUSH_GROUP
GLvoid ** params
GLenum GLuint GLenum GLsizei length
#define GL_DEBUG_SOURCE_APPLICATION
const void * userParam
#define GL_DEBUG_SOURCE_OTHER
GLenum GLuint id
GLenum GLenum GLsizei const GLuint GLboolean enabled
#define GL_DEBUG_SEVERITY_MEDIUM
static QOpenGLDebugMessage::Severity qt_messageSeverityFromGL(GLenum severity)
static QOpenGLDebugMessage::Type qt_messageTypeFromGL(GLenum type)
#define GL_DEBUG_SOURCE_SHADER_COMPILER
static GLenum qt_messageSourceToGL(QOpenGLDebugMessage::Source source)
GLenum type
#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR
static GLenum qt_messageSeverityToGL(QOpenGLDebugMessage::Severity severity)
#define GL_DEBUG_SEVERITY_NOTIFICATION
#define GL_DEBUG_TYPE_POP_GROUP
GLenum GLenum GLsizei count
#define GL_DEBUG_SOURCE_WINDOW_SYSTEM
#define GL_DEBUG_SOURCE_API
static QString qt_messageTypeToString(QOpenGLDebugMessage::Type type)
GLsizei bufsize
void(QOPENGLF_APIENTRY * GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const GLvoid *userParam)
#define GL_DEBUG_TYPE_ERROR
#define CONVERT_TO_GL_DEBUG_MESSAGE_CONTROL_PARAMETERS(type, source, target)
GLuint GLsizei const GLchar * message
#define GL_DEBUG_SEVERITY_HIGH
#define GET_DEBUG_PROC_ADDRESS(procName)
GLenum GLenum severity
GLsizei GLenum GLenum * types
static QString qt_messageSourceToString(QOpenGLDebugMessage::Source source)
#define GL_DEBUG_TYPE_PERFORMANCE
static QOpenGLDebugMessage::Source qt_messageSourceFromGL(GLenum source)
GLenum GLuint GLenum GLsizei const GLchar * buf
static QString qt_messageSeverityToString(QOpenGLDebugMessage::Severity severity)
typedef GLint(GL_APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC)(GLuint program
GLsizei GLenum GLenum GLuint GLenum * severities
const GLfloat * m
GLenum GLenum GLsizei const GLuint * ids
GLsizei GLenum GLenum * types
GLenum GLuint GLenum GLsizei length
GLenum pname
const void * userParam
typedef GLsizei(GL_APIENTRYP PFNGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC)(GLuint target)
GLenum type
typedef GLenum(GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSKHRPROC)(void)
GLboolean enable
GLuint GLsizei const GLchar * message
typedef GLboolean(GL_APIENTRYP PFNGLISENABLEDIOESPROC)(GLenum target
GLenum GLenum severity
GLuint name
GLsizei GLenum * sources
GLsizei GLsizei GLchar * source
#define GL_MAX_DEBUG_MESSAGE_LENGTH
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
#define GL_DEBUG_CALLBACK_USER_PARAM
#define GL_DEBUG_CALLBACK_FUNCTION
#define GL_DEBUG_OUTPUT_SYNCHRONOUS
#define GL_DEBUG_OUTPUT
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
#define GLuint
#define QStringLiteral(str)
#define emit
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
QObject::connect nullptr
myObject disconnect()
[26]
Definition moc.h:23