この投稿は英語ブログ記事「Qt Quick on Vulkan, Metal, and Direct3D」の和訳です。
Qt 5.14の最初のベータ版公開が近づいているので、主な新機能の一つについてお話したいと思います。この投稿内で、グラフィックスタックの改善点とQt 6に向けての詳細を全てご説明することは難しいので、パート1とパート2にて背景と5.14に関連するものについてお話し、技術的な部分の詳細と今後の方向性については、後に別の投稿でお話しようと思います。
5.14の新機能に関するページ概要:グラフィックスAPIに依存しないシーングラフレンダラーの、最初のプレビューがオプトイン機能として追加されました。これにより、OpenGLの代わりにVulkan、Metal、またはDirect3D 11上でほとんどのQt Quickアプリケーションを実行できます。
Qt 6テクニカルビジョンの投稿でご説明したように、Qt 6の主な目標の1つは、Qt上での直接的なOpenGLの使用をできるだけ避け、Vulkan、Metal、Direct3Dなどの幅広いグラフィックスAPIの利用を可能にすることです。 OpenGL(およびOpenGL ES)も選択肢として当然残ります。その背景にある主な動機は、パフォーマンスを発揮する事だけではなく、OpenGLが利用できないか、もしくは既に望ましくないプラットフォームやデバイス上であっても、Qt Everywhereが今後も確かなもので有り続けることを保証することにもあります。それと同時に、最新かつ低レベルなAPIをベースに構築できるため、パフォーマンスの改善(APIオーバーヘッドの減少によるCPU使用率の低下など)や、Qt Quickおよび最近発表されたQt Quick 3Dのようなモジュールの背後にあるレンダリングエンジンの可能性も広がります。
さらに、プラットフォームで最もサポートされているグラフィックスAPIでレンダリングできることは、Qtを使用してUIをレンダリングしながら独自のネイティブ2Dまたは3Dグラフィックレンダリングを実行するアプリケーションにとって嬉しいポイントです。
そのような場合、使用するグラフィックスAPIの決定に関しては、Qtに主導権が無いことも多々あります。たとえば、macOSのデスクトップアプリケーションが、2DのレンダリングをQt Quickに依存しながら独自の3DコンテンツにMetalを使用したい場合、Qt QuickもMetal経由でレンダリングすると非常に便利です。これは、Qt 5.xのグラフィックスの進化過程を見ていた人には馴染みがあるのでは無いでしょうか。概念的には、OpenGLコアプロファイルコンテキストでの操作のサポートがQt Quickレンダラーに導入されたときと変わりません。Qt Quick自体にはその必要性や関連はありませんが、コアプロファイル機能に関連付けられた外部レンダリングコードを統合できるようにするために、Qt Quick側でそれを認識し、対応できる必要がありました。つまり、これはQt 5で行われてきたことからの自然な流れであり、現在OpenGL以外のグラフィックスAPIをカバーするように拡張されています。
これにより、次の2つの疑問点が上がってくることと思います。
Qtのグラフィックスの完全なオーバーホールを行うことは、Qt 6のターゲットになっています。しかし、Qt 5.x上での作業や開発を止めて、一度に全てが上手くいくことを期待するのは現実的ではありません。Qt開発者がよく口にするように、APIの最初の試作は”最適”というには満たない傾向にあります。そのため、並行して開発を行う代わりに、QtのUIテクノロジーであるQt Quickに焦点をあてていきます。
Qt 5.14には、新しいQt Quickレンダリングパスのプレビュー版が付属される予定です。 デフォルトでは、非アクティブであるため、アプリケーションに対して目に見える変更は一切ありません。内部では、以前のバージョンと同じダイレクトOpenGLベースのコードパスを通過します。 ただし、新しいアプローチを試してみたい人は、環境変数を設定するか、main関数のC ++ APIを介して要求することでオプトインできます。 ここでは、フィードバックを早期に取得して、Qt 6.0のリリースを待たずに繰り返し、発展させていけることを期待しています。
Qt 5.14ドキュメントをみると、次のようなことがわかります。
QSG_RHIをセットして実行すると、すべてのアプリケーションがすぐに動作するわけではありません。ダイレクトOpenGL呼び出しを実行するシーングラフノード、またはカスタムマテリアルにGLSLシェーダーコードを含むカスタムQQuickItemは、RHIベースのレンダリングを有効にすると機能しなくなります。同じことが、GLSLソースコードを含むShaderEffectアイテムにも当てはまります。 カスタムマテリアルとエフェクトを最新の方法で実行するためのソリューションは、ほとんどがすでに存在しますが、必要に応じてアプリケーションを移行する必要があります。アーリーアダプターは、5.14および5.15のタイムフレームで試すことも出来ますが、Qt 6.0より前での幅広い普及と移行は期待されていません。 一方で、多くの既存QMLアプリケーションは、ベースとなるレンダリングエンジンがVulkanやMetalなどのまったく異なるAPIを経由する場合でも機能する可能性があります。
なにより先に、もし仮に常に直ぐに使える状態でなかったとしても、MoltenVK、MoltenGL、ANGLE、ZinkなどのAPIやシェーダートランスレーションレイヤーを使用する際の実現性について予めお伝えしておく必要があります。たとえば、MoltenVKでは、macOSのVulkanを介してQt Quick UIをレンダリングすることもできます。 Qt QuickアプリケーションがVulkanのみを使用したい、かつmacOSに対応したい場合、MoltenVKはひとつの選択肢です。(適切に構成されたQtビルドが使用され、MoltenVKがユーザーのシステムで利用可能な限り)
このようなトランスレーションレイヤーの存在を前提とし、それゆえにQtに含め、一緒にデプロイすることは全く別の話です。
そのため、Qtは低レベルAPIトランスレーターに依存する代わりに、3Dグラフィックスの独自の高レベルな抽象化を定義します(当面は内部使用向け)。これは、その裏側でAPI固有のバックエンド実装に変換される、Qtの多くのコンポーネントでよく使われているパターンです。場合によっては、バックエンドは特定のプラットフォームを対象としていますが、(Metal、Direct3D)、1つのバックエンド・1つのAPIで複数のプラットフォームを対象とするものもあります(Vulkan、OpenGL)。これは、glslangやSPIRV-Crossなどのいくつかのサードパーティプロジェクトに基づいた新しいシェーダー管理パイプラインによって補完されます。より細かい部分については、この投稿内で後ほど説明します。ひとまず、スタックについて触れて、Qt 5.14のQt Quickにてこれが何を可能にするかを見てみましょう。
QUIt Codingの有名なQt5 Cinematic Experienceデモアプリケーションを例として見てみましょう。 Qt Quickシーングラフの両方のレンダリングパスで機能するように、いくつかのShaderEffectアイテムをわずかに修正しています。そのコードはこちらにあります。
:QSG_INFO = 1を設定してアプリケーションを通常どおり起動すると、次のようになります。
デバッグ出力ログが示すように、これはLinuxデスクトップのOpenGLで実行されています。
qt.scenegraph.general: threaded render loop
qt.scenegraph.general: Using sg animation driver
qt.scenegraph.general: Animation Driver: using vsync: 16.95 ms
qt.scenegraph.general: opengl texture atlas dimensions: 2048x1024
qt.scenegraph.general: GL_VENDOR: X.Org
qt.scenegraph.general: GL_RENDERER: AMD Radeon (TM) R9 M360 (VERDE, DRM 3.23.0, 4.15.0-62-generic, LLVM 8.0.1)
qt.scenegraph.general: GL_VERSION: 4.5 (Compatibility Profile) Mesa 19.2.0-devel (git-08f1cef 2019-07-25 bionic-oibaf-ppa)
qt.scenegraph.general: GL_EXTENSIONS: ...
qt.scenegraph.general: Max Texture Size: 16384
qt.scenegraph.general: Debug context: false
QSG_RHI = 1に設定すると、どのようになるでしょうか。
qt.scenegraph.general: Using QRhi with backend OpenGL
graphics API debug/validation layers: 0
QRhi profiling and debug markers: 0
qt.scenegraph.general: threaded render loop
qt.scenegraph.general: Using sg animation driver
qt.scenegraph.general: Animation Driver: using vsync: 16.95 ms
qt.rhi.general: Created OpenGL context QSurfaceFormat(version 4.5, options QFlags<QSurfaceFormat::FormatOption>(DeprecatedFunctions), depthBufferSize 24, redBufferSize 8, greenBufferSize 8, blueBufferSize 8, alphaBufferSize 0, stencilBufferSize 8, samples -1, swapBehavior QSurfaceFormat::DoubleBuffer, swapInterval 1, colorSpace QSurfaceFormat::DefaultColorSpace, profile QSurfaceFormat::CompatibilityProfile)
qt.rhi.general: OpenGL VENDOR: X.Org RENDERER: AMD Radeon (TM) R9 M360 (VERDE, DRM 3.23.0, 4.15.0-62-generic, LLVM 8.0.1) VERSION: 4.5 (Compatibility Profile) Mesa 19.2.0-devel (git-08f1cef 2019-07-25 bionic-oibaf-ppa)
qt.scenegraph.general: MSAA sample count for the swapchain is 1. Alpha channel requested = no.
qt.scenegraph.general: rhi texture atlas dimensions: 2048x1024
一見したところ、それほど違いはありません。 まだOpenGLを介しているようです。 ただし、内部ではOpenGLを直接使用することはなく、Qt Quickシーングラフ内を飛び回るGLSLシェーダーソースはもうありません。 代わりに、レンダリングはQt Rendering Hardware Interface、QRhiで行います。(当面はQtGuiモジュールのプライベートAPI)
では早速、QSG_RHI_BACKEND = vulkanを設定してみましょう。
qt.scenegraph.general: Using QRhi with backend Vulkan
graphics API debug/validation layers: 0
QRhi profiling and debug markers: 0
qt.scenegraph.general: threaded render loop
qt.scenegraph.general: Using sg animation driver
qt.scenegraph.general: Animation Driver: using vsync: 16.95 ms
WARNING: radv is not a conformant vulkan implementation, testing use only.
qt.rhi.general: Physical device 0: 'AMD RADV CAPE VERDE (LLVM 8.0.1)' 19.1.99
qt.rhi.general: using this physical device
qt.rhi.general: queue family 0: flags=0xf count=1
qt.rhi.general: queue family 1: flags=0xe count=2
qt.rhi.general: 55 device extensions available
qt.scenegraph.general: MSAA sample count for the swapchain is 1. Alpha channel requested = no.
qt.scenegraph.general: rhi texture atlas dimensions: 2048x1024
qt.rhi.general: Creating new swapchain of 3 buffers, size 1280x720, presentation mode 2
良い感じですね。 どうやら今ではVulkanを介してレンダリングしています。 しかし、ディスタンスフィールドのテキストレンダリング、シェーダーエフェクト、パーティクルなど、よりエキゾチックなQt Quick機能もすべて期待どおりにあります。
RenderDoc でアプリケーションを実行し、フレームをキャプチャすると、次のようになります。 Qt QuickはVulkanパイプライン状態オブジェクトとコマンドバッファーを実際に構築しており、シェーダーコードはSPIR-Vバイトコードとして提供されています。
今のところ、このような感じです。 このシリーズの第2部では、macOSおよびWindows用にQt 5.14が提供するものについて見ていきます。 その後、これらすべてが内部でどのように機能するか、およびカスタムマテリアルとエフェクトを必要とするアプリケーションにどのような影響があるかを考察します。
お楽しみに!