Qt 6に向けた議論が深まる「Qt Contributors' Summit 2018」参加レポート

はじめに

6月11、12日の2日間、ノルウェーのオスロで「Qt Contributors' Summit 2018」⁠以下QtCS)が開催されました。QtCSはQtの開発者・貢献者たちが集まって今後のQt自体の開発について議論をするイベントです。一昨年はQtCon、昨年はQt World Summitとの同時開催(共にドイツにて)という形でしたが、3年ぶりに単独開催となった今年は、場所も3年前と同じくThe Qt CompanyのQtの開発拠点があるオスロでの開催となりました。会場はオスロのBIというビジネススクールで、The Qt Companyのオスロオフィスのすぐそばにあるビルです。

Qt Contributors' Summit会場
Qt Contributors' Summit会場

2日間にわたって実施されたイベントから、興味深かったセッションをいくつか紹介しようと思います。

QtCSの詳細については、Qt Contributors' Summit 2018の公式ページをご覧ください。

Keynote:“Path towards Qt 6”

QtコミュニティマネージャのTero Kojoによる挨拶、諸注意と、スポンサーへの謝辞の後、Qt ProjectのChief MaintainerであるLars Knollのキーノートでイベントの幕が開きます。

まずは「Why do we development Qt?」という問いかけからスタートしました。人によってその答は異なるとは思いますが、Larsが提示したのは「Make software development fun and easy」という一文でした。

それをふまえた上で、QtのAPI design conceptsが提示されます。その内容は、昨年のQtCS 2017やQt World Summit 2017のキーノートと同じですが、まとめると

  • 直感的でわかりやすく
  • 柔軟で
  • 効率の良い

APIを目指そうということになります。方針としてはわかりやすさ・使いやすさを重視し、パフォーマンスのためにそれらを犠牲にしないことなどが説明されました。

また、Qtを取り巻く環境として、他のクロスプラットフォームアプリケーションフレームワークについても図で示しました。現状はQtやUnityなどが成熟期にあると考えられ、Qtとしてはこの後衰退期に入らずに、さらに飛躍したいということでした。

Qtと対抗フレームワーク
Qtと対抗フレームワーク

これからのアプリケーションフレームワークに求められる機能としては、

  • アプリの開発だけではなくパッケージングや配布の手間の削減
  • モバイルプラットフォームの最重要視
  • SiriやCortana、AlexaなどのデジタルアシスタントによるUIへの影響
  • AI

などが挙げられました。

その他にも、新しいC++の規格や、クラウド、MR/VRなども関連する技術として挙げられます。これらの状況に、Qtとしては「Qt 6」で対応していくことになります。

Qt 6のビジョンとしては

  • 2020年代の10年間に対応できること
  • Qt 5系からのスムーズな移行ができること
  • そのためにC++17を活用すること
  • フレームワークとそのツールの統合
  • メンテナンスコストの削減

が挙げられました。

しかし、C++17を採用することで古いコンパイラがサポート対象外となり、Qt 5からの移行の妨げになるのではないかとの指摘もありました。かといって、古い環境をいつまでもサポートするのではQt 6を作る意義が薄れてしまいます。

そういった古い環境が必要な場合は、Qt 5を使い続けてもらえばいいのではないかなどの意見も出ました。実際、The Qt Companyでは未だにQt 3向けの開発者ライセンスの販売が毎年行われているそうです。

またC++についても、C++20を使用しないのかとの意見もありました。これについては、C++11でもコンパイラの実装が出そろうのにかなり時間がかかったことから、C++20の使いたい機能がQtのサポートするプラットフォームのすべてで利用できるようになるまで時間がかかる見込みであり、そのためC++20の採用はアグレッシブすぎるのではないかとの話が出ました。

Qt 6のビジョン
Qt 6のビジョン

より具体的な Qt 6 の検討課題として、Qt Coreモジュールでは以下の項目などが挙げられました。

  • 利用頻度の低い機能の別モジュール化(Qt Coreのスリム化)
  • 新しいC++の機能の活用
  • QMLからの機能の取り込み(バインディングなど)

グラフィック関連ではOpenGLへの強い依存性を解消し、VulkanやMetalなどのAPIへも対応できるようにすること、2Dと3Dのより良い統合などが主な課題となります。

QML/Qt Quickでは、QMLの採用事例が増えてきたことから、より大規模なアプリへの対応についての検討、コードをより厳密に解釈するStrictモード、ECMAScriptのバージョンアップ、パフォーマンスの改善などが挙げられます。

また、以前から要望の多いQt QuickのAPIをC++から使えるように検討することも、項目として挙げられました。

この他にはデザイン系ツールの改善・統合や、リポジトリ構成やサードパーティ製のOSSライブラリの扱いの検討なども課題となります。

Qt 6のリリースまでのタイムラインとして、これまではQt 5系としては今年の年末の5.12 LTSまでのリリースが決定されていましたが、その後に5.13~5.15までのリリースを追加して、5.15をQt 5系の最終バージョンとしてLTSにすること、その後にQt 6.0を2020年末にリリースする案が提案されました。この案ではQt 5とQt 6の開発は並行して行われる形となります。

今後のリリースタイムライン案
今後のリリースタイムライン案

ただし、その場合にQt 5とQt 6のリポジトリ管理をどのように行うかが課題となります。早めにQt 6用ブランチを作成すればそれだけQt 6の開発を速く行うことが可能になりますが、Qt 5の開発の成果を取り込むための手間が増えます。かといって、ブランチの作成が遅れれば、それだけQt 6に使える時間が少なくなる形となります。この段階ではその時期は議論対象となっており決まっていませんが、5.14以後になるかもしれません。

Qt 6の開発プロセスとしては、まずはJIRA上での開発要件の定義から始まります。必要なタスクはこちらのタスクのサブタスクとして作成する形となります。

また、Qt 6で削除したいAPIに関しては、今後Qt 5で非推奨にマークした後にQt 6で削除する形となります。このため、今後のアプリケーション開発で非推奨(Deprecated)なAPIを使用するとQt 6では使えなくなることに注意してください。

以上がキーノートの概要です。キーノートの最中にもさまざまな議論が始まりそうになり、長めのセッションとなりました。

Plenary session:Graphics vision 2020

このセッションでは、Qt 6に向けてグラフィック関連のアーキテクチャをどのように変えていくかが議題となりました。

Qt 5では、描画パフォーマンスの向上のためにOpenGLをそのベースとして採用し、それまでオプションモジュールであったOpenGL用クラスの標準モジュール化や、OpenGLを活かしたQt Quick Scene Graphの開発などが行われました。しかし、グラフィック用APIの抽象化は行われておらず、特にQt Quick 2などはOpenGLに強い依存性を持ったAPIとなってしまいました。このため、Qtの利用者は時には OpenGLの命令やシェーダー(GLSL)などを直接使用する必要があります。また、他のグラフィックAPIに対応する場合(たとえばDirect3D12)には、それぞれのAPI用に個別にシェーダーを作成する必要があります。

Qt 5の開発初期には、OpenGLへ対応すればほとんどのプラットフォームに対応できるであろうとの予測がありました。しかし、その後の3D系APIの変化は激しく、Metal、Direct3D12、Vulkanと、次々に新たなAPIが登場し、今後はOpenGLだけではすべてのプラットフォームへは対応できなくなることが予想されています。

実際、Apple社はOpenGLを非推奨にして、MetalのみをグラフィックAPIとして推進していく予定です。このことから、キーノートでもあったようにOpenGL以外へのグラフィックAPIへの対応がQt 6の課題としてあげられました。

もうひとつの課題がQt Quickモジュール(2D)とQt 3Dモジュールの統合です。Qt 3D Studio 2.0にQt 3Dベースのランタイムエンジンが実装されたことで、Qtの2D(Qt Quick)と3D(Qt 3D)機能が一通りそろいました。しかし、これらはOpenGLを使用しているにもかかわらず、それぞれが全く別のエンジンとなっています。

Qt 5でも機能的には2D(Qt Quick)のUIに3Dを埋め込んだり、その逆を行うことは可能です。しかし、それらの同期を取るのは(Qtの開発者にとっては)簡単なことではなく、また描画内容の取り込みはどちらも OpenGL のテクスチャを経由して行っているため効率的ではありません。

このセッションでは、Qt QuickのシーングラフをQt 3D側へ取り込むことで2Dと3Dを透過的に扱う方法が提案されました。2020年代のグラフィックエンジンとして2Dと3Dを同じシーングラフで統合的に扱うための仕組みを、Qt 6では目指すことになりそうです。

Qt 5.11とQt 6の2D/3Dアーキテクチャ案
Qt 5.11とQt 6の2D/3Dアーキテクチャ案

Qt Widgets

Qt 5ではバグ修正や小さな機能追加などがメインであったQt Widgetsモジュールですが、重要なモジュールであることには変わりなく、Qt 6でも引き続きメンテナンスしていく予定です。

Qt 5の途中でメンテナンスの主体がThe Qt CompanyからKDAB社に移っていることもあり、この巨大なモジュールの現状の説明からセッションが開始しました。

リリースブロッカーとも呼ばれる致命的(P0)なバグは現状無いそうですが、P1が60、P2、P3ではそれぞれ数百のバグが登録されているそうです。マンパワーの問題ですべてのバグの確認はできておらず、コミュニティの助けが必要なこと、おそらく重複した報告もあると思われること、再現が困難な特殊ケースが含まれることなどが報告されました。特にバグが多い機能としては MDI(Multiple Document Interface⁠⁠、ドックエリア・ドックウィジェット、グラフィックスビューなどがあり、これらはバグ修正が別のバグの原因となることも少なくないようです。

このセッションでの主な議題はスタイル機能でした。Qtでウィジェットアプリのスタイルを変更する際は、QStyleクラスやその派生クラスを継承してC++で書くか、スタイルシートを使って書くかのどちらかになります。スタイルシートは比較的わかりやすいものの、パフォーマンスに問題があります。Qt的にはC++でスタイルを書いて欲しいところですが、QStyleの派生クラスの実装はQtのスタイルへの理解が必要なため、簡単ではないという問題があります。

パレットクラス(QPalette)のQStyleへの統合など、Qtの開発者側・利用者側のそれぞれからさまざまな意見がでてくるセッションとなりました。スタイルシートに関してはQt内部に特別扱いをするようなコードもあるとのことで、Qt 6ではスタイル関連機能は整理が行われそうです。

Text in Qt

テキスト表示はUIで多用される機能ですが、しばしばパフォーマンスのボトルネックにもなります。このセッションではQt 5、6でのテキスト機能のパフォーマンス改善について議論になりました。

まずは従来のQtで実施されてきたテキスト描画の最適化手法についての紹介から始まりました。いくつかの実装がこれまでありましたが、どれも方向性としてはおなじで、文字列の整形処理(Shaping)を削減することです。整形処理とは文字のサイズを計算し、カーニングやリガチャ(合字)などを行って、文字を正しく美しく描画できるようにすることです。

QPainter::drawText() では必ず整形処理が実行されるため、テキスト描画のコストが最も重くなります。Qt 4ではQStaticTextクラスが導入されて、整形処理の結果をキャッシュすることが可能となり、Qt Quick 1のパフォーマンス改善に使用されました。Qt Quick 2ではQGlyphRunクラスでキャッシュするようになっています。Qt 5.10ではQFont::PreferNoShapingが導入され、ラテン系文字などで整形を簡略化してパフォーマンスの改善を図ることもできるようになりました。

こういった工夫は実施されていますが、テキストの一部だけが変化するような場合でも全体を整形し直したり、整形以外にもQt Quick 2でフォントのグリフ情報として使用しているディスタンスフィールドデータの生成や、そのGPUへのアップロードに時間がかかるなどの課題があります。

このセッションではディスタンスフィールドデータのファイルキャッシュによる起動時間の高速化やそのGPUへのアップロードの非同期化、引数でその一部が変化するような文字列で変化しない場所の整形結果をキャッシュするFormattedTextが提案されたりしました。

FormattedText
FormattedText

FormattedTextは個人的には面白い提案でしたが、これまではQString::arg()で指定される引数を、子オブジェクトのArgument系クラスで指定する方式の評判が良くなかったようでした。QMLのJavaScriptのarg()ではQString::arg()に比べて幅やフォーマットの指定ができないなどの制限があり、それらの解消にも使えるのではないかという個人的な思いもあったため、採用しない方向に向かいそうなのは残念です。

このセッションで提案された方法はキャッシングや別スレッドの利用による非同期化などのこれまでに実施されてきた手法の延長線上にあるもののため、実装的には大変そうですが理解しやすいものでした。

Qt + unique_ptr

30分のショートセッションでしたが、個人的に一番興味深かったのがこのセッションです。

Qtに限らずフレームワークでは 所有権(ownership)という考え方がよく用いられます。Qtの場合はオブジェクトの親子関係がその代表的な例です。オブジェクトが親子関係を持つ場合には、子オブジェクトの所有権は親オブジェクトが持ち、親オブジェクトが破棄される際に子オブジェクトも自動的に破棄されます。所有権を導入することでオブジェクトの管理が容易になりますが、フレームワークの利用者はどのAPIが所有権の変更を伴うのかを理解しておく必要があります。

親子関係のように使用頻度も多くわかりやすい場合には問題はないのですが、Model/ViewやQActionなどで複数のオブジェクトが1つのオブジェクトを参照する場合のように、所有権が移動しない場合を正しく認識していないと、メモリリークの原因となります。そのため、C++11で導入されたスマートポインタの1つであるstd::unique_ptrを用いて所有権をコード上で明記しようというのがこのセッションでの提案になります。

たとえば、従来

QWidget widget;
QLabel *label = new QLabel(&widget);

としていたようなコードは

QWidget widget;
QLabel *label = widget.makeChild<QLabel>();

と書いたり、

QWidget widget;
auto label = std::make_unique<QLabel>();
widget.adoptChild(std::move(label));

と書くようになり、コンストラクタでの親オブジェクトの指定やQObject::setParent()は非推奨のAPIとなります。

上記の例では記述量が増えただけでメリットはほとんどありませんが、たとえばQWidget::addAction(QAction *)のような生のポインタを受け取るメソッドでは所有権が移動しないため、呼び出し元に所有権が残ることが読み取れます。逆にQLayout::addWidget(std::unique_ptr)のようなメソッドでは、呼び出しを通じて所有権の移動が発生することがわかります。

非常に面白い提案で、 std::unique_ptr を用いることでコード上で所有権が明確になり、プログラムの安全性を高めることが可能になります。

しかし、問題もあります。メジャーバージョンアップ時もソースコード互換性をできるだけ維持するという方針があるため、std::unique_ptrを使用しない従来のAPIを(非推奨にできても)廃止できません。std::unique_ptrを使用する場合にはコードの記述量も増加するため、より安全な仕組みとして用意したものがQtの利用者には使ってもらえない可能性があります。

また多くの場合、所有権を持つオブジェクト以外のオブジェクトからも被所有オブジェクトへのアクセスが発生します。このために生のポインタを保存したりしてしまってはせっかくAPIで担保しようとした安全性を損ねる原因ともなりえます。

このように課題は残るものの、コード上で所有権を明確化すること自体は有用な提案です。LarsやQt CoreのメンテナであるThiago Macieiraなどの主要な開発者が興味を持っていました。更なる研究が必要だと言うことで、上述の課題があるため現状のコンセプトをそのまま使用する形にはならないと思いますが、Qt 6ではこの提案をベースとした改良がくわえられるかもしれません。

Final session: Conclusions

サミットの最後はまとめのセッションとなります。各セッションの概要をそれぞれが説明していきます。

まとめ

昨年のQtCS 2017から具体化しはじめたQt 6ですが、今年はその機能的な部分以外のリポジトリや開発プロセス、タイムラインなども議論され、いよいよ開発に向けて本格化が始まった形となりました。まだまだ実際にQt 6向けリポジトリが準備されてるのは先となりますが、調査や設計などは既に始まっており、今回のサミットでは議論できなかった項目についてもJIRA上にタスクが作成されたりしています。ぜひ、Qt 6にむけてそれらのタスクを確認したり、議論や開発に参加してみてください。

おすすめ記事

記事・ニュース一覧