この記事は The Qt Blog の OpenGL Core Profile Context support in QPainter を翻訳したものです。
執筆: Laszlo Agocs, 2017年1月27日
みなさんご存知のとおり、QPainter は複数のバックエンドに対応していて、Qt 5 では主に2つの実装が利用されています。一つは ラスターペイントエンジン で、もう一つは OpenGL ES 2.0 向けの OpenGL2 ペイントエンジンです。
様々な側面からラスターペイントエンジンが Qt では主役となっていますが、今回は脇役の方についてお話ししたいと思います。GL ペイントエンジンは QPainter が以下に対しての描画の際に使われます。
最近の OpenGL の状況はどうでしょう?
問題の元がなにかというと、Qt 5.0 当時、core profile context を使用して特殊な OpenGL の描画をする必要に迫られている人たちは様々な障害にぶちあたってきました。非推奨や削除された機能(例えば、クライアント側のポインター)に依存していたり、Vertex Array Object が使えなかったり、必要な GLSL のシェーダーのバージョンがサポートされていなかったりという理由で、Qt Quick のようなコンポーネントは当時はそういったコンテキストとは連携ができませんでした。
互換プロファイルの選択がワークアラウンドとして有効なケースもいくつかありましたが、Mac OS X / macOS では OpenGL 2.1 もしくは 3.2 以上の Core プロファイルの2択であったため、この手は使えませんでした。これを回避する方法として、一つのコンテキストの一つのテクスチャに描画をし、そのテクスチャをリソース共有をした別のコンテキストで利用するようなアプローチを取ることもありましたが、異なるバージョンやプロファイル間でのリソースの共有ができないプラットフォームがあり、あまりうまくはいきませんでした。
幸運なことに、 Qt 5 の開発を続けてきた間に状況は改善してきました。Qt Quick が最初で、それ以外も改善し、ユーザーが直接利用する機会の少ない GL ベースのコンポーネントについても Core と Compatibility の両方のコンテキストで動作する割合がだんだん高くなってきました。
Qt 5.8 の時点で残すは QPainter の GL をペイントエンジンとなりました。
うれしいことに、これはすぐになくなります。Krita によってはじめられた貢献により(詳細はこちらの記事を参照してください)、QPainter は Core プロファイルでも動作するようになります。機能的には何も変わらず、描画も以前と同様に行われます。
最初のパッチの修正に続き、Lancelot と呼ばれる QPainter 内部のリグレッションテストシステムの対応も行いました。これにより、(様々な QImage のフォーマットでの)ラスターエンジンと、 OpenGL 2 エンジンに加え core profile context に関してもテストが実行され、Qt のリリースで今まではちゃんと動いていた QPainter の出力が動かなくなるということがなくなるでしょう。
ということで、以下のようなコードが期待通りに動作するようになります。
class Window : public QOpenGLWindow {
void initializeGL() override {
QSurfaceFormat fmt;
fmt.setVersion(4, 5); // or anything >= 3.2
fmt.setProfile(QSurfaceFormat::CoreProfile);
setFormat(fmt);
}
void paintGL() override {
QPainter p(this);
p.fillRect(10, 10, 50, 50, Qt::red);
...
}
...
};
Qt 5.9 です。
このパッチは(この記事を書いた当時の)dev ブランチにマージされました。これはまもなく 5.9 ブランチになる予定で、その名のとおり Qt 5.9 になる予定です。それまで待てないという方はこのパッチを(QTBUG-33535 を参考に)適用してください。適用はおそらくそれほど手間はかからないはずです。
今回は以上になります。core profile context での QPainter を是非お試しください!