QOpenGLDebugLogger Class
QOpenGLDebugLogger は、OpenGL デバッグ・メッセージのロギングを可能にします。詳細...
Header: | #include <QOpenGLDebugLogger> |
CMake: | find_package(Qt6 REQUIRED COMPONENTS OpenGL) target_link_libraries(mytarget PRIVATE Qt6::OpenGL) |
qmake: | QT += opengl |
Inherits: | QObject |
- 継承されたメンバーを含む、すべてのメンバーのリスト
- QOpenGLDebugLoggerは、Rendering in 3D に含まれます。
パブリックタイプ
enum | LoggingMode { AsynchronousLogging, SynchronousLogging } |
プロパティ
- loggingMode : const LoggingMode
パブリック関数
QOpenGLDebugLogger(QObject *parent = nullptr) | |
virtual | ~QOpenGLDebugLogger() |
void | disableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity) |
void | disableMessages(const QList<GLuint> &ids, QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType) |
void | enableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity) |
void | enableMessages(const QList<GLuint> &ids, QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType) |
bool | initialize() |
bool | isLogging() const |
QList<QOpenGLDebugMessage> | loggedMessages() const |
QOpenGLDebugLogger::LoggingMode | loggingMode() const |
qint64 | maximumMessageLength() const |
void | popGroup() |
void | pushGroup(const QString &name, GLuint id = 0, QOpenGLDebugMessage::Source source = QOpenGLDebugMessage::ApplicationSource) |
パブリックスロット
void | logMessage(const QOpenGLDebugMessage &debugMessage) |
void | startLogging(QOpenGLDebugLogger::LoggingMode loggingMode = AsynchronousLogging) |
void | stopLogging() |
シグナル
void | messageLogged(const QOpenGLDebugMessage &debugMessage) |
詳しい説明
はじめに
OpenGLプログラミングは非常にエラーを起こしやすいものです。たいていの場合、OpenGLの呼び出しに1回失敗しただけで、アプリケーション全体が動作しなくなり、画面には何も描画されなくなります。
OpenGLの実装からエラーが返されていないことを確認する唯一の方法は、API呼び出しのたびにglGetError
。さらに、OpenGLのエラーは積み重なるので、glGetErrorは常にこのようなループの中で使うべきです:
GLenum error = GL_NO_ERROR; do { error = glGetError(); if (error != GL_NO_ERROR) { // handle the error } } while (error != GL_NO_ERROR);
エラースタックをクリアしようとする場合、GL_NO_ERRORが返されるまで続けるだけでなく、エラー値が繰り返されるので、GL_CONTEXT_LOSTでブレークするようにしてください。
私たちが(アプリケーション開発者として)興味を持つ情報は他にもたくさんあります。例えば、パフォーマンスの問題や、非推奨APIの使用に関する警告などです。そのようなメッセージは、通常のOpenGLのエラー報告メカニズムでは報告されません。
QOpenGLDebugLoggerは、OpenGLデバッグ・ログへのアクセスを提供することで、これらの問題に対処することを目的としています。OpenGL実装が(GL_KHR_debug
拡張を公開することで)それをサポートしている場合、OpenGLサーバーからのメッセージは、内部のOpenGLログに記録されるか、OpenGLから生成されるときにリスナーに「リアルタイム」で渡されます。
QOpenGLDebugLoggerは、この両方の動作モードをサポートしています。両者の違いについては、以下のセクションを参照してください。
OpenGLデバッグコンテキストの作成
効率上の理由から、OpenGL実装では、OpenGLコンテキストがデバッグコンテキストでない限り、デバッグ出力をまったく作成しないことが許されています。Qtからデバッグコンテキストを作成するには、QOpenGLContext オブジェクトの作成に使用するQSurfaceFormat で、QSurfaceFormat::DebugContext format オプションを設定する必要があります:
QSurfaceFormat format; // asks for a OpenGL 3.2 debug context using the Core profile format.setMajorVersion(3); format.setMinorVersion(2); format.setProfile(QSurfaceFormat::CoreProfile); format.setOption(QSurfaceFormat::DebugContext); QOpenGLContext *context = new QOpenGLContext; context->setFormat(format); context->create();
3.2のOpenGL Core Profileを要求するのは、この例の目的のためだけであることに注意してください。このクラスは、GL_KHR_debug
拡張機能(下記参照)の可用性に依存しているため、特定のOpenGLやOpenGL ESのバージョンに縛られているわけではありません。
QOpenGLDebugLoggerの作成と初期化
QOpenGLDebugLogger はシンプルなQObject 由来のクラスです。すべてのQObject サブクラスと同様に、インスタンスを作成し(オプションで親オブジェクトを指定します)、Qt の他の OpenGL 関数と同様に、現在の OpenGL コンテキストがあるときにinitialize() を呼び出して、使用前に初期化する必要があります:
QOpenGLContext *ctx = QOpenGLContext::currentContext(); QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); logger->initialize(); // initializes in the current context, i.e. ctx
OpenGLによって記録されたメッセージにアクセスするためには、GL_KHR_debug
拡張がコンテキストで利用可能でなければならないことに注意してください。OpenGLによって記録されたメッセージにアクセスするためには、 拡張機能がコンテキストで利用可能でなければならないことに注意してください:
ctx->hasExtension(QByteArrayLiteral("GL_KHR_debug"));
ここで、ctx
は有効なQOpenGLContext です。拡張が利用できない場合、initialize() は false を返します。
内部OpenGLデバッグログの読み込み
OpenGLの実装は、デバッグメッセージの内部ログを保持します。このログに保存されたメッセージは、loggedMessages() 関数を使用して取得できます:
const QList<QOpenGLDebugMessage> messages = logger->loggedMessages(); for (const QOpenGLDebugMessage &message : messages) qDebug() << message;
内部ログのサイズには制限があり、いっぱいになると、新しいメッセージのために古いメッセージは捨てられます。loggedMessages() を呼び出すと、内部ログも空になります。
デバッグ・メッセージを失わないようにするには、この関数を呼び出す代わりにリアル タイム・ロギングを使用しなければなりません。しかし、デバッグ・メッセージは、コンテキストの作成からリアルタイム・ロギングを有効にするまでの間(または、一般的には、リアルタイム・ロギングが無効になっている間)に生成される可能性があります。
メッセージのリアルタイムロギング
実装によって生成されたデバッグメッセージのストリームをOpenGLサーバーから受け取ることも可能です。そのためには、messageLogged() シグナルに適切なスロットを接続し、startLogging() を呼び出してロギングを開始する必要があります:
connect(logger, &QOpenGLDebugLogger::messageLogged, receiver, &LogHandler::handleLoggedMessage); logger->startLogging();
同様に、stopLogging ()関数を呼び出すことで、いつでもロギングを無効にすることができます。
リアルタイムのロギングは、startLogging ()に渡されるパラメータによって、非同期または同期のいずれかになります。非同期モード(オーバーヘッドが非常に小さいのでデフォルト)でロギングする場合、OpenGLの実装は、いつでもメッセージを生成することができ、また、ロギングされるメッセージの原因となったOpenGLコマンドの順序とは異なる順序でメッセージを生成することができます。また、コンテキストが現在バインドされているスレッドとは異なるスレッドからメッセージを生成することもできます。これは、OpenGLの実装が通常、高度にスレッド化され、非同期であるため、デバッグメッセージの相対的な順序とタイミングについて保証されないためです。
一方、同期モードでのロギングは高いオーバーヘッドを持ちますが、OpenGL実装は、あるコマンドによって引き起こされたすべてのメッセージが、コマンドが戻る前に、OpenGLコンテキストがバインドされているのと同じスレッドから、順番に受信されることを保証します。
これは、同期モードでログを記録するとき、デバッガでOpenGLアプリケーションを実行し、messageLogged ()シグナルに接続されたスロットにブレークポイントを置き、バックトレースで、ログに記録されたメッセージの原因となった正確な呼び出しを見ることができることを意味します。これはOpenGLの問題をデバッグするのに非常に役立ちます。OpenGLレンダリングが別のスレッドで行われている場合、実際のバックトレースを見るためには、シグナル/スロット接続タイプを強制的にQt::DirectConnection 。
ロギング・モードの詳細については、LoggingMode enum documentationを参照してください。
注意: リアルタイム・ロギングが有効になると、デバッグ・メッセージはOpenGLの内部デバッグ・ログに挿入されなくなります。すでに内部ログに存在するメッセージは削除されず、messageLogged() シグナルを通して出力されます。いくつかのメッセージは、リアルタイム・ロギングが開始される前に生成されるかもしれないので(したがって、内部OpenGLログに保持される)、startLogging ()を呼び出した後、そのログにメッセージが含まれているかどうかを常にチェックすることが重要です。
デバッグログにメッセージを挿入する
アプリケーションやライブラリは、デバッグログにカスタムメッセージを挿入することができます。例えば、関連するOpenGLコマンドのグループをマークし、それらから来るメッセージを識別することができます。
そのためには、createApplicationMessage ()またはcreateThirdPartyMessage ()を呼び出してQOpenGLDebugMessage オブジェクトを作成し、logMessage ()を呼び出してログに挿入します:
QOpenGLDebugMessage message = QOpenGLDebugMessage::createApplicationMessage(QStringLiteral("Custom message")); logger->logMessage(message);
OpenGLの実装には、デバッグ・ログに挿入できるメッセージの長さにベンダー固有の制限があることに注意してください。この長さはmaximumMessageLength() メソッドを呼び出すことで取得できます。制限を超えるメッセージは自動的に切り捨てられます。
デバッグ出力の制御
QOpenGLDebugMessage は、デバッグ・メッセージにフィルタを適用して、ログに記録されるメッセージの量を制限することもできます。 () と () をそれぞれ呼び出すことで、メッセージのロギングを有効または無効にできます。デフォルトでは、すべてのメッセージが記録される。enableMessages disableMessages
メッセージの有効/無効を切り替えるには、以下の方法で選択します:
- ソース、タイプ、重大度(そして選択にはすべての ID を含む);
- id、ソース、タイプ(そして全ての深刻度を含む)。
与えられたメッセージの "enabled" ステータスは、(id, source, type, severity) タプルのプロパティであることに注意してください。enableMessages() とdisableMessages() を呼び出す順番に注意する必要があります。どのメッセー ジが有効/無効になるかが変わってしまうからです。
messageLogged() シグナルに接続されたスロットで、あるいはloggedMessages() を通して内部デバッグ・ログにあるメッセージをフェッチした後で)アプリケーション側でフィルタリングを行う必要があります。
有効/無効ステータスの管理を簡素化するために、QOpenGLDebugMessage はdebug groups
の概念もサポートしています。 デバッグ・グループには、デバッグ・メッセージの有効/無効設定のグループが含まれます。さらに、デバッグ・グループはスタックで構成されます。pushGroup() とpopGroup() をそれぞれ呼び出すことで、グループをプッシュしたりポップしたりすることができます。(OpenGLコンテキストが作成されると、スタックにすでにグループが存在します)。
enableMessages() とdisableMessages() 関数は、現在のデバッグ・グループ、つまりデバッグ・グループ・スタックの最上位にあるグループの設定を変更します。
新しいグループがデバッグ・グループ・スタックにプッシュされると、それまでスタックの最上位にあったグループの構成が継承されます。その逆で、デバッググループをポップすると、新しい最上位になるデバッググルー プの構成が復元されます。
デバッグ・グループをプッシュ(それぞれポップ)すると、QOpenGLDebugMessage::GroupPushType (それぞれGroupPopType )タイプのデバッグ・メッセージも自動的に生成されます。
QOpenGLDebugMessageも参照のこと 。
メンバ型ドキュメント
enum QOpenGLDebugLogger::LoggingMode
LoggingMode enum は、ロガーオブジェクトのロギングモードを定義します。
定数 | 値 | 説明 |
---|---|---|
QOpenGLDebugLogger::AsynchronousLogging | 0 | OpenGLサーバーからのメッセージは非同期で記録されます。これは、メッセージが、それを引き起こした対応するOpenGLアクションのしばらく後にログに記録され、OpenGL実装によっては、アウトオブオーダーで受信されることさえあることを意味します。このモードは、OpenGLの実装がもともとスレッド化され、非同期であるため、非常に低いパフォーマンス・ペナルティを持っています。 |
QOpenGLDebugLogger::SynchronousLogging | 1 | OpenGLサーバーからのメッセージは、同期的に順次記録されます。OpenGLの実装は本質的に非常に非同期なので、このモードはパフォーマンスに深刻な打撃を与えます。しかし、OpenGLコマンドによって生成されたメッセージが、対応するコマンドの実行が戻る前にログに記録されることをOpenGLが保証しているので、OpenGLの問題をデバッグするのに非常に便利です。したがって、messageLogged ()シグナルにブレークポイントを設置し、バックトレースでどのOpenGLコマンドがそれを引き起こしたかを確認することができます。唯一の注意点は、複数のスレッドからOpenGLを使用している場合、messageLogged ()シグナルに接続するときに直接接続を強制する必要があるかもしれないということです。 |
プロパティ Documentation
[read-only]
loggingMode : const LoggingMode
このプロパティは、startLogging ()に渡されたロギングモードを保持します。
ロギングが開始されていなければ、このプロパティの値は意味をなさないことに注意。
アクセス関数:
QOpenGLDebugLogger::LoggingMode | loggingMode() const |
startLogging() およびisLogging()も参照 。
メンバー関数ドキュメント
[explicit]
QOpenGLDebugLogger::QOpenGLDebugLogger(QObject *parent = nullptr)
与えられたparent で新しいロガーオブジェクトを構築する。
注意: ロギングを行う前に、オブジェクトを初期化する必要があります。
initialize()も参照してください 。
[virtual noexcept]
QOpenGLDebugLogger::~QOpenGLDebugLogger()
ロガー・オブジェクトを破棄します。
void QOpenGLDebugLogger::disableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity)
与えられたsources 、与えられたtypes 、与えられたseverities および任意のメッセージ ID を持つメッセージのロギングを無効にします。
ロギングは、現在のコントロール・グループで無効になります。
enableMessages()、pushGroup()、popGroup()も参照して ください。
void QOpenGLDebugLogger::disableMessages(const QList<GLuint> &ids, QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType)
指定されたids 、指定されたsources からの、指定されたtypes の、任意の重要度を持つメッセージのロギングを無効にします。
ロギングは現在の制御グループで無効になります。
enableMessages()、pushGroup()、popGroup()も参照して ください。
void QOpenGLDebugLogger::enableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity)
指定されたsources 、指定されたtypes の、指定されたseverities の、任意のメッセージ ID のメッセージのロギングを有効にします。
ロギングは現在のコントロール・グループで有効になる。
disableMessages()、pushGroup()、popGroup()も参照のこと 。
void QOpenGLDebugLogger::enableMessages(const QList<GLuint> &ids, QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType)
指定されたids 、指定されたsources からの、指定されたtypes の、任意の重要度のメッセージのロギングを有効にします。
ロギングは現在の制御グループで有効になります。
disableMessages()、pushGroup()、popGroup()も参照して ください。
bool QOpenGLDebugLogger::initialize()
現在のOpenGLコンテキストでオブジェクトを初期化します。初期化を成功させるには、コンテキストがGL_KHR_debug
拡張をサポートしていなければなりません。ロギングを行う前にオブジェクトを初期化する必要があります。
同じコンテキストからこの関数を複数回呼び出しても安全です。
この関数は、以前に初期化されたオブジェクトのコンテキストを変更するのにも使えます。
ロガーが正常に初期化された場合はtrue
を返し、そうでない場合は false を返します。
QOpenGLContextも参照してください 。
bool QOpenGLDebugLogger::isLogging() const
このオブジェクトが現在ロギングしている場合はtrue
を返し、そうでない場合は false を返します。
startLogging()も参照して ください。
[slot]
void QOpenGLDebugLogger::logMessage(const QOpenGLDebugMessage &debugMessage)
メッセージdebugMessage を OpenGL デバッグ・ログに挿入します。これは、アプリケーションやライブラリがOpenGLアプリケーションのデバッグを容易にするカスタムメッセージを挿入する方法を提供します。
注意: debugMessage は、そのソースとしてQOpenGLDebugMessage::ApplicationSource またはQOpenGLDebugMessage::ThirdPartySource を持っている必要があり、有効な型と重大度を持っている必要があります。
注意: ロギングが行われる前に、オブジェクトは初期化されていなければなりません。
initialize()も参照のこと 。
QList<QOpenGLDebugMessage> QOpenGLDebugLogger::loggedMessages() const
OpenGLの内部デバッグ・ログで利用可能なメッセージをすべて読み込み、それを返します。さらに、この関数は内部デバッグログをクリアし、それ以降の呼び出しでは、すでに返されたメッセージを返さないようにします。
startLogging()も参照してください 。
QOpenGLDebugLogger::LoggingMode QOpenGLDebugLogger::loggingMode() const
オブジェクトのロギング・モードを返します。
注釈 loggingMode プロパティのゲッター関数です。
startLogging()も参照して ください。
qint64 QOpenGLDebugLogger::maximumMessageLength() const
logMessage() に渡されたメッセージのテキストがサポートする最大長をバイト単位で返します。これは、デバッグ・グループ名の最大長でもあります。グループをプッシュまたはポップすると、メッセージ・テキストとしてデバッグ・グループ名を持つメッセージが自動的にログに記録されるためです。
メッセージ・テキストが長すぎる場合、QOpenGLDebugLogger によって自動的に切り捨てられます。
注意: メッセージテキストはOpenGLに渡されるときにUTF-8でエンコードされます。そのため、そのバイトサイズは通常、例えばQString::length()によって返されるようなUTF-16コードユニットの量とは一致しません。(デバッグメッセージに典型的な7ビットのASCIIデータのみを含むメッセージの場合は一致します)。
[signal]
void QOpenGLDebugLogger::messageLogged(const QOpenGLDebugMessage &debugMessage)
このシグナルは、OpenGLサーバーからデバッグ・メッセージ(debugMessage 引数でラップされたもの)がログに記録されたときに発せられます。
OpenGLの実装によっては、このシグナルは、レシーバーが住んでいるスレッドとは別のスレッドから発信されることもあり、このオブジェクトが初期化されたQOpenGLContext のスレッドとは異なるスレッドから発信されることもあります。さらに、シグナルは複数のスレッドから同時に発せられる可能性もあります。Qtはクロススレッドシグナルの発信にキュー接続を利用するため、通常は問題ありませんが、接続タイプをDirectに強制した場合、このシグナルに接続されたスロットの潜在的な競合に注意する必要があります。
ロギングがSynchronousLogging モードで開始されている場合、OpenGL は、このシグナルがQOpenGLContext がバインドされているスレッドと同じスレッドから発行されることを保証します。
注意: ロギングが開始されていなければ、このシグナルは発せられない。
startLogging()も参照のこと 。
void QOpenGLDebugLogger::popGroup()
デバッグ・グループ・スタックから最上位のデバッグ・グループをポップします。グループが正常にポップされると、OpenGLは自動的に、ポップされたグループのメッセージ、id、ソースに一致するメッセージ、タイプQOpenGLDebugMessage::GroupPopType 、重大度QOpenGLDebugMessage::NotificationSeverity をログに記録します。
デバッググループをポップすると、デバッググループスタックのトップになるグループのメッセージフィルタリング設定が復元されます。
注意: デバッグ・グループを管理する前に、オブジェクトを初期化する必要があります。
pushGroup()も参照してください 。
void QOpenGLDebugLogger::pushGroup(const QString &name, GLuint id = 0, QOpenGLDebugMessage::Source source = QOpenGLDebugMessage::ApplicationSource)
名前name 、idid 、ソースsource を持つデバッグ・グループをデバッグ・グループ・スタックにプッシュします。グループが正常にプッシュされると、OpenGLは自動的にメッセージname 、idid 、ソースsource 、タイプQOpenGLDebugMessage::GroupPushType 、重大度QOpenGLDebugMessage::NotificationSeverity のメッセージをログに記録します。
つまり、新しいグループをプッシュしてもフィルタリングは変更されません。
注: source は、QOpenGLDebugMessage::ApplicationSource またはQOpenGLDebugMessage::ThirdPartySource のいずれかでなければなりません。そうでない場合、グループはプッシュされません。
注: デバッグ・グループを管理する前に、オブジェクトを初期化する必要があります。
popGroup()、enableMessages()、disableMessages()も参照して ください。
[slot]
void QOpenGLDebugLogger::startLogging(QOpenGLDebugLogger::LoggingMode loggingMode = AsynchronousLogging)
OpenGLサーバーから来るメッセージのロギングを開始します。新しいメッセージを受信すると、ログに記録されたメッセージを引数としてシグナルmessageLogged() が発せられます。
loggingMode はロギングが非同期(デフォルト)か同期かを指定します。
QOpenGLDebugLogger は、ロギングが開始されたときに と の値を記録し、ロギングが停止されたときにそれらを戻します。さらに、この関数が呼び出されたときにインストールされたユーザー定義のOpenGLデバッグ・コールバックは、ロギングが停止されたときに復元されます。 は、ロギングが行われるときに、既存のコールバックがまだ呼び出されることを保証します。GL_DEBUG_OUTPUT
GL_DEBUG_OUTPUT_SYNCHRONOUS
QOpenGLDebugLogger
注意: ロギングを停止し、再び開始することなく、ロギングモードを変更することはできません。これは Qt の将来のバージョンで変更されるかもしれません。
注意: ロギングを行う前に、オブジェクトを初期化する必要があります。
stopLogging() およびinitialize()も参照してください 。
[slot]
void QOpenGLDebugLogger::stopLogging()
OpenGL サーバーからのメッセージのロギングを停止します。
startLogging()も参照して ください。
©2024 The Qt Company Ltd. 本書に含まれるドキュメントの著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。