この記事は The Qt Blog の Compressed Textures in Qt 5.11 を翻訳したものです。
執筆: Eirik Aavitsland, 2018年05月07日
最近のユーザーインターフェースはグラフィックスがどんどん派手になっていて、グラフィックメモリに収めたいテクスチャの数もどんどん増えています。リソースが比較的高価な組み込みシステムでは特にこの傾向が強く、パフォーマンスとの格闘にも成り得ます。1つの解として、グラフィックのアセットのメモリの使用量を減らすということがあげられます。
OpenGL テクスチャの圧縮には、起動時間と実行時のパフォーマンスを大きく改善する可能性があります:
Qt Quick 2 のソースコードには長い間 textureprovider というサンプルが含まれていました。これは ETC1 圧縮のテクスチャを pkm 形式のコンテナファイルから読み込んで画像として提供するようなものを実現する際に有用なサンプルでした。
Qt 5.10 で、この機能は Qt Quick 自体に密かにインポートされていました。と言うわけで特になにもしなくても、ローカルやリソース内の pkm ファイルを Image の source に指定することで実現が可能です。また、ETC2 圧縮スキームの対応も行われました。
Qt 5.11 では、この機能が刷新され、拡張されました。一番重要な点は、Khronos のテクスチャコンテナのファイル形式である ktx に対応したことです。この形式はとても幅広い圧縮スキームを許容するため、実質的な制限は Qt Quick ではなく、GPU とドライバ由来ということになるでしょう。
Qt Quick アプリケーションで圧縮テクスチャを使うために必要なものは特にありません。上記のスクリーンショットのメイン部分のコードは以下のようになっています。
Grid {
columns: 2
Image { source: "slides.png" }
Image { source: "slides.ktx" }
...
}
常にメモリの削減にはコストが伴います。メモリの消費量と画質はトレードオフです。上記のスクリーンショットでは、緑のエリアの下端が、元の画像に比べて少し荒くなっているのが分かるでしょう。異なるテクスチャの圧縮スキームは、メモリの消費量的にも画質的にも異なる結果になります。
特に考慮が必要なのは、透明な部分があるテクスチャの扱いです。パフォーマンス的な観点で、Qt Quick はそういったテクスチャはカラーチャンネルに除算済みのアルファチャンネルが存在する事を期待しています。通常の画像であれば、Qt は自動的にこれに対応します。しかし、圧縮テクスチャの場合は、画像の圧縮が実行される前にこの作業を行う必要があります。テクスチャ圧縮ツールの中には、こういった機能が備わっているものもあるようです。もしそうではないものをお使いの場合は、そのアセットに対して前処理をするような別のツールを使うことも可能です。ImageMagick の場合は以下のようにすることで除算済みのアルファ値を持つ画像のコピーを生成することが可能です。
convert mytexture.png \( +clone -alpha Extract \) -channel RGB
-compose Multiply -composite mytexture_pm.png
ここで、png 自体は除算済みのアルファ値には対応していないため、mytexture_pm.png を一般的な png のビューアーで表示ても正しく表示はされないでしょう。しかし、テクスチャの圧縮を通して Qt Quick で利用すると、正常に扱われます。
圧縮テクスチャがまだ無い場合や利用できない状況でアプリケーションを実行する場合はどうしたらいいでしょう?これは例えば、開発時のまだ元の画像しか存在しない段階や、OpenGL に非対応の環境などが想定されます。この場合、それぞれに別々の qml のコードを用意するのは本意ではありません。当然、Qt Quick では、これに対応するいくつかの方法を用意しています。さらに、Qt 5.11 で新たに対応した、拡張子の自動判別機能 を利用することでこれがより簡単になりました。つまり、Image エレメントが存在しないファイルやリソース名を参照している際に、Qt Quick は同じベース名で既知の拡張子を持つものを代わりに探してくれます。例えば、前述のコードを以下のように変えた場合、
Image { source: "slides" }
Qt Quick は以下のような動作をします
ということで、Qt Quick のコードから、単に source のファイルの拡張子を取り除いてしまうことで、フォールバックの対応が可能になってしまいます。