C
テキストのレンダリングとフォント
概要
Qt Quick Ultralite では、テキストは `Text ` および `StaticText ` アイテムを使用して画面にレンダリングされます。これらのアイテムには、選択された `font ` の設定を制御するための `font` プロパティがあります。利用可能な API やフォントエンジン固有の詳細については、font 型のドキュメントを参照してください。
Qt Quick Ultralite には、Monotype Spark および Static の 2 つのフォントエンジンオプションが用意されています。
Monotype フォントエンジン
- 幅広い文字を使用する国際化アプリケーションに対するサポートが強化されています。
- 正しいレイアウトを確保するためにテキストシェイピングを必要とする言語に対するサポートが強化されています。
- パフォーマンスやテキストの品質を損なうことなく、テキストのスケーリングをランタイムでサポートします。
静的フォントエンジン
- 複雑なテキストを使用せず、メモリ使用量が少ないアプリケーションに対するサポートを強化しました。
- 静的な事前計算済みデータを処理するため、非常に高速な検索操作が可能です。
- ビルド時にフォントを処理するため、実行時のオーバーヘッドが発生しません。
2つのフォントエンジンの詳細な比較については、「機能比較表」を参照してください。
言語および文字体系
国際化対応の一環として、Qt Quick Ultralite は、選択したエンジンがサポートするすべての表記体系に対応した入力コントロールおよびテキスト描画メソッドを提供します。テキストサブシステムは、さまざまな表記体系の文字が混在するテキストを同時にレンダリングすることができます。
サポートされる言語、テキストシェーピング機能、およびフォントファイルの機能は、選択したフォントエンジンによって異なります。テキストシェーピングは、テキストを表示可能な状態にするために不可欠なプロセスです。Unicodeでサポートされているすべての文字体系がテキストシェーピングを必要とするわけではありませんが、その他の文字体系(いわゆる「複雑な文字体系」)では、読みやすいテキストをレンダリングするためにテキストシェーピングが必須となります。 アプリケーションが複雑な文字体系に依存する言語を一切使用しない場合は、MCU.Config.complexTextRenderingを使用して、テキストシェーピングエンジンをバイナリにリンクしないように設定できます。複雑な文字体系の例としては、アラビア文字やインド系文字体系などが挙げられます。
Unicode 準拠の双方向テキストもサポートされており、その正確な動作はUnicode 技術付属書 #9 に定義されています。ただし、「テキスト」アイテムは例外であり、アプリケーションが静的フォントエンジンを使用している場合、双方向テキストをサポートしません。
機能比較表
以下の表では、2つのテキスト処理オプションの主な違いをまとめており、適切なオプションを選択するのに役立ちます。
| 機能 | 静的フォントエンジン | Monotype Spark フォントエンジン | 備考 |
|---|---|---|---|
| フォントのラスタライズ | フォントコンパイラによるビルド時処理(FreeTypeを使用)。 | 実行時は Monotype Spark によって行われます。ビルド時には Monotype Spark によるStaticText が使用されます。 | なし |
| メモリ要件 | MCU では、使用されるすべての文字を事前にラスタライズするという従来のアプローチを採用しています。欠点は、国際化されたアプリケーションではバイト数が膨大になる可能性があることです。静的フォントエンジンの使用に伴う唯一のメモリ要件は、ラスタライズされたグリフおよびフォントメトリックの事前計算済みデータを格納するための十分な空き容量を確保することです。 静的フォントエンジンの実装は、このデータを扱うための軽量なAPIです。 | Monotype Spark フォントエンジンはアプリケーションにリンクされます。MCU.Config.complexTextRendering が`true` に設定されている場合、WorldType Shaper Spark エンジンがアプリケーションにリンクされます。コードサイズの参考については、<QT_INSTALL_PATH>\QtMCUs\<VERSION>\docs\monotype\ を参照してください。このエンジンを使用するには、フォントファイルをアプリケーションにバンドルする必要があります。 フォントエンジンの実行時データには追加のRAMが必要です。詳細はMCU.Config.fontHeapSizeを参照してください。フォントエンジンのキャッシュが有効になっている場合、追加のRAMが必要になります。MCU.Config.maxParagraphSizeを100に設定すると、テキストシェーピングエンジンに必要なRAMは最小で3.1 KBになります。 | なし |
| キャッシュシステム | すべてのデータは事前に計算されているため、不要です。 | フォントエンジンのキャッシュは、有効にされており、キャッシュ用に十分なメモリが割り当てられている場合、パフォーマンスを劇的に向上させます。キャッシュメモリは、グリフ、アドバンス幅、および Unicode-グリフ ID マッピング (CMAP) を格納するために使用されます。キャッシュの内容は、キャッシュプライミング機能を使用して、事前に準備することも可能です。 | なし |
| 動的テキスト | グリフは、font.unicodeCoverage プロパティを使用して事前に登録する必要があります。これにより、事前計算済みデータのサイズが増加します。 | フォントファイルにグリフ情報が含まれている場合、アプリケーション開発者による特別な処理は必要ありません。 | 本文書における「動的テキスト」とは、コンパイル時に未知のテキストを指します。これには、例えば、ネットワークから取得されたテキスト、ファイルから読み込まれたテキスト、またはユーザー入力などが含まれます。C++ コードで定義された文字列も、Qt for MCUs における動的文字列として扱われます。 |
| フォント形式 | FreeTypeがサポートするあらゆるフォントファイル形式。 | TrueType フォント、CCC 圧縮フォント、およびFontmaps。 | なし |
| フォント・ヒンティング | FreeTypeのヒント処理機能を使用します。 | Spark は、マイクロコントローラ・プラットフォームの限られたリソースに合わせて最適化された 2 種類のヒント処理方式、すなわち「Spark ヒント処理」と「自動ヒント処理」を採用しています。実行時のメモリを節約するため、TrueType のヒント処理命令はサポートされていません。 | フォントヒンティングは、グリフのラスタライズ処理中に適用されるステップです。 ヒントとは、フォントレンダラーによるピクセル値の割り当て方法を制御する指示のことです。ヒントは通常、グリフのステム、ウェイト、高さなど、特定の書体の一貫性を維持するために使用されます。ヒントはフォントにエンコードすることも、フォント処理中に動的に適用することもできます。 |
| グリフ圧縮 | 現在、実装されていません。 | グリフデータに対するランレングスエンコーディングをサポートしていますが、この機能はまだ統合されていません。 | なし |
| グリフのレンダリングモード | Qt for MCUs 現在は、ビットマップモードとグレイマップ8モードのみを利用しています。 | Spark のラスタライザは、ビットマップ、graymap2、graymap4、graymap6、graymap8 の各フォーマットをサポートしています。Qt for MCUs は現在、ビットマップと graymap8 のみをサポートしています。 | レンダリングモードは、font.quality プロパティを使用して設定できます。font.quality の値は、Font.QualityVeryLow ではbitmap に、Font.QualityVeryHigh ではgraymap8 にマッピングされます。これらの値は、両方のフォントエンジンで同じです。 |
| テキストシェーピング | StaticText 項目のみでサポートされています。テキストシェーピングはアプリケーションのビルド時に実行され、その際にはHarfBuzzライブラリが使用されます。このフォントエンジンには実行時のシェーピング実装がないため、MCU.Config.complexTextRendering設定は無視されます。 | Text およびStaticText でサポートされています。Monotype社のWorldType Shaper Sparkエンジンを使用します。 | 最適なパフォーマンスを得るには、テキストブロックに複雑なスクリプトが含まれていない場合、そのような文字列をシェーピングエンジンに渡さないようにしてください。一部のフォントでは、複雑なスクリプト用のシェーピングテーブルを通じて、非複雑なスクリプトに対して純粋に外観上の機能を実装しています。Qt Quick Ultralite アプリケーションでそのようなフォントを使用すると、意図しないテキストのレンダリングが発生する可能性があります。Qt Quick では、この動作はfont.preferShapingプロパティによって制御されます。Qt Quick Ultraliteでは、このプロパティは利用できませんが、代わりに常にfont.preferShaping = false とみなされます。注: 上記の挙動は 、静的フォントエンジンには適用されません。これは、CPU負荷の高いテキストシェーピング処理がMCU上では実行されないためです。 |
テキストの配置
テキスト項目の水平方向の配置が明示的に設定されていない場合、そのテキスト要素はテキストの自然な読み順に合わせて自動的に配置されます。デフォルトでは、英語のような左から右へのテキストはテキスト領域の左端に、アラビア語のような右から左へのテキストはテキスト領域の右端に配置されます。
この暗黙的な配置は、テキスト要素の `horizontalAlignment` プロパティを設定することで上書きできます。
// automatically aligned to the left Text { text: "Phone" width: 200 } // automatically aligned to the right Text { text: "خامل" width: 200 } // aligned to the left Text { text: "خامل" horizontalAlignment: Text.AlignLeft width: 200 }
静的フォントエンジン
フォントファイルの処理はアプリケーションのビルド時に実行され、fontcompiler によって行われます。fontcompilerツールは、Qt の FreeType ベースのフォントエンジンに依存しています。fontcompilerからの出力は、ラスタライズされたグリフとフォントメトリクスの事前計算済みデータです。 実行時にこのデータに何かが追加されたり削除されたりすることはなく、利用可能なグリフのセットはビルド時に決定されます。このデータに対するすべての操作は O(1) または O(log n) です。このフォントエンジンは、constant font configurations のみをサポートしています。
フォント
このフォントエンジンは、QmlProjectのプロパティであるFontFiles.filesを使用して、アプリケーションで使用されるフォントを特定し、必要なフォントデータを抽出します。
事前計算済みデータ
異なるフォント設定を持つアイテム間でテキストを割り当てることをサポートするため、デフォルトでは、fontcompiler はアプリケーションで使用されるすべてのフォント構成において、使用されるすべての文字をラスタライズします。これに対する例外は、font.unicodeCoverage およびStaticText であり、これらは使用されるフォント構成に対してのみ文字を登録します。
さらに、fontcompiler はデフォルトで、数字など、一般的に使用される少数のグリフセットを含んでいます。
メモリ使用量を削減するために、MCU.Config.autoGenerateGlyphs を使用してこの動作を無効にすることができます。その場合、font.unicodeCoverage で明示的に定義された文字のみがラスタライズされます。
事前計算されたデータは、テキストのレンダリングを必要とするあらゆる機能(Text やStaticText など)で共有されるデータソースとなります。
このデータの実行時ストレージの設定に関する詳細については、MCU.Config.glyphsCachePolicy、MCU.Config.glyphsStorageSection、およびMCU.Config.glyphsRuntimeAllocationType を参照してください。
グリフの埋め込み
MCU.Config.autoGenerateGlyphsの設定に応じて、fontcompilerは、QMLの文字列リテラルおよびすべてのフォント設定で使用されるすべての文字のグリフを、生成されるバイナリに埋め込むことができます。font.unicodeCoverage プロパティを使用することで、文字の選択範囲を拡張できます。これは、文字列が動的に生成され、コンパイル時にその内容が不明なシナリオで必要となります。
MCU.Config.autoGenerateGlyphs が`false ` に設定されている場合、font.unicodeCoverage を使用して定義されたグリフのみが埋め込まれます。アプリケーションを慎重に設計することで、この手法によりメモリ使用量を大幅に削減できます。
font.unicodeCoverage プロパティの設定は、同じフォント設定を使用するすべてのQMLアイテムに影響を与えます。
QML での動的文字列のレンダリング
C++モデルからの文字列
C++モデルは、コンパイル時には未知の動的文字列を生成することができます。次の例を考えてみましょう:
// MyModel.h struct MyModelData { std::string stringField; }; inline bool operator==(const MyModelData &lhs, const MyModelData &rhs) { return lhs.stringField == rhs.stringField; } struct MyModel : public Qul::ListModel<MyModelData> { int count() const override { return 10; }; MyModelData data(int index) const override { std::string data; for (int i = 0; i <= index; ++i) { data += 'a' + i; } return {data}; } }; // MyView.qml Item { ListView { anchors.fill: parent model: MyModel { } delegate: Text { height: 20 text: model.stringField } } }
fontcompilerは、どのグリフが必要になるかを予測できないため、このようなモデルデータに対してグリフを生成することができません。その結果、QMLコンテンツのレンダリング時にグリフが欠落してしまいます。
モデルによって生成可能な文字範囲や、生成が必要なグリフをfontcompiler に指定するには、デリゲートで使用されるフォントの `font.unicodeCoverage ` プロパティを使用します。
Item { ListView { anchors.fill: parent model: MyModel { } delegate: Text { height: 20 font: Qt.font({ unicodeCoverage: [Font.UnicodeBlock_BasicLatin] // << define character set }) text: model.stringField } } }
C++関数からの文字列
文字列を返す C++ 関数は、C++ モデルと同じルールに従います。次の例を考えてみましょう。
// MyObject.h struct MyObject : public Qul::Object { std::string getDynamicString() const { std::string data; for (int i = 0; i < 26; ++i) { data += 'A' + i; } return data; } }; // MyView.qml Item { MyObject { id: myObject } Text { text: myObject.getDynamicString() } }
動的文字列を使用する「Text」アイテムに対してfont.unicodeCoverage プロパティが設定されていない限り、前述のサンプルコードではグリフを正しく表示できません:
Item { MyObject { id: myobject } Text { text: myobject.getDynamicString() font: Qt.font({ unicodeCoverage: [Font.UnicodeBlock_BasicLatin] // << define character set }) } }
Monotype
Monotype Spark 製品のページhttps://www.monotype.com/products/embedded-solutions/spark。
ドキュメントは<QT_INSTALL_PATH>\QtMCUs\<VERSION>\docs\monotype\ にインストールされています。これにはFAQを含むドキュメントも含まれています。
iType Spark フォントエンジン。
Monotype社のSparkフォントエンジンは、業界標準のTrueTypeフォント規格に基づいた、スケーラブルなフォントレンダリングサブシステムです。 これは、自動車用ディスプレイ、医療機器、白物家電、ウェアラブルデバイス、テレビセットトップボックス、ポータブルメディアプレーヤー、制御パネルなど、リソースに制約のある環境向けに設計されています。これにより、スケーラブルな書体と高品質な多言語フォント表示の利点を、組み込み環境にもたらします。
スペース効率と速度の両方に最適化された高性能アーキテクチャ。 Sparkは、数千文字を必要とする東アジア言語をサポートするアプリケーションやデバイスを含め、多くのアプリケーションやデバイスが求める厳しいサイズ要件を満たしています。Monotypeの最適化されたフォントと組み合わせることで、Monotype Sparkソリューションは、メモリの制約、複雑さ、またはプラットフォームのコストなどの理由で、これまでスケーラブルフォントの利用が困難だった状況においても、その利点を活用できるようにします。
Monotypeは、メモリ要件を削減し、処理速度を最適化するためにフォントファイルに適用できるさまざまな技術を提供しています。これらの技術の一部は、以下のセクションに記載されています。Monotype Sparkライブラリは、高度な設定が可能です。最適なパフォーマンスとメモリ使用量を実現するには、詳細なパフォーマンスガイドを含むSparkのドキュメントをご参照ください。
WorldType Shaper Sparkエンジン。
WorldType Shaper Sparkは、複雑な言語の文字体系を用いたテキストのシェーピングを行うためのライブラリです。ウェアラブル端末などの小型デバイスでのシェーピング処理に高度に最適化されています。
WorldType Shaper Sparkは、OpenTypeテーブル、すなわちGSUBおよびGPOSをサポートしていません。 AppleのAdvanced Typographyフォーマットである「morx」/「kerx」テーブルを持つフォント、またはアラビア語、ヘブライ語、タイ語のUnicode間シェーピングに対応するように設計されたフォント(すなわち、すべての表示形式に対応するグリフを持つフォント)でのみ動作します。 有限状態マシンを採用することで、「morx」テーブルのサイズを比較的小さく抑え、処理も比較的高速に行うことができます。
また、テキストの並べ替えを含め、双方向スクリプトに必要なすべての処理も対応しています。WorldType Shaper Sparkは、Unicode 12.1.0仕様に完全に準拠しています。
このライブラリは、アプリケーションでフォントエンジンとしてSparkフォントエンジンが選択された場合に、テキストシェーピングエンジンによって使用されます。
有効にする方法
デフォルトでは、Qt Quick のUltraliteアプリケーションは静的フォントエンジンを使用します。Monotype Sparkフォントエンジンを選択するには、MCU.Config.fontEngineターゲットプロパティを「Spark」に設定してください。サポートされているフォントエンジンの一覧については、「サポートされているフォントエンジン」を参照してください。このQmlProjectプロパティを設定すると、アプリケーションはMonotypeライブラリとリンクされます。
Monotype Spark フォントエンジンに切り替える際は、FontFiles.filesに、サポートされている形式のフォントファイルを指すエントリが 1 つだけ含まれていることを確認することが重要です。
MCU.Config { fontEngine: "Spark" } FontFiles { files: ["fonts/SampleFontmap.fmp"] }
アプリケーションのフォントファイルのランタイムストレージの設定に関する詳細については、MCU.Config.fontFilesCachePolicy、MCU.Config.fontFilesStorageSection、およびMCU.Config.fontFilesRuntimeAllocationType を参照してください。
フォントとフォント形式
Monotypeの最適化されたフォントファイルは、<QT_INSTALL_PATH>\QtMCUs\<VERSION>\src\3rdparty\monotype\fonts\ にインストールされます。
TrueTypeフォント
あらゆるTrueTypeフォントがサポートされていますが、TrueTypeのヒンティング指示は無視される点に注意してください。「sparkヒンティング」および「自動ヒンティング」のセクションを参照してください。
フォントマップ
フォントマップとは、複数のフォントファイルを1つのフォントマップファイルに統合できる仕組みです。フォントマップコンポーネントで使用できるのはTTFファイルのみです。さらに、フォントマップでは、Unicode範囲、Unicodeスクリプト、およびフォントクラスに基づいたフォント選択が可能です。フォントマップにおいて、Unicodeスクリプトのエントリは「言語」と呼ばれます。
Fontmapエディタは、Fontmapファイルの作成や編集に使用できるアプリケーションです。 エディタは、<QT_INSTALL_PATH>\QtMCUs\<VERSION>\bin\ に抽出されます。エディタはインストーラファイルとして提供され、ユーザーによる手動でのインストールが必要です。Qt for MCUs 2.8以降のバージョンには、Fontmapエディタv3.1.1以降が同梱されており、Fontmapファイルから未使用のグリフを削除して、アプリケーションへの負荷を軽減することも可能です。 このツールのドキュメントは、Fontmapエディタのメニュー「Help -> HelpTopics 」からアクセスできます。フォント選択アルゴリズムやパフォーマンスに関するヒントの詳細については、<QT_INSTALL_PATH>\QtMCUs\<VERSION>\docs\monotype\ をご覧ください。
注:現在 、Fontmap におけるコンポーネントフォントの検索は、言語に依存しません。
CCC 圧縮フォント
CCCフォントは、Monotypeのフォント形式の一つであり、CCCと呼ばれるロスレス圧縮アルゴリズムを使用して、大容量のフォントテーブルを圧縮します。解凍時のオーバーヘッドがほとんどないため、圧縮率とリソースのバランスに優れています。すべてのTTFフォントをCCC形式に変換することができます。
注:CCC 圧縮フォントは、現時点ではFontmapコンポーネントとしてまだサポートされていません。
エンジンの設定
フォントエンジンは、以下の QmlProject プロパティを通じて設定できます:
フォントキャッシュバッファの事前割り当てを制御します。 | |
フォントキャッシュの初期化を制御します。 | |
フォントエンジンが使用するキャッシュの最大サイズを設定します。 | |
フォントエンジンが使用するヒープバッファの事前割り当てを制御します。 | |
フォントエンジンの最大ヒープサイズを定義します。 | |
テキストのレンダリングにベクターアウトラインを使用するかどうかを制御します | |
段落の最大文字数を設定します。 |
ヒープサイズとキャッシュサイズの最適な値については、入念なテストと調整が必要です。
Sparkは、外部で割り当てられたヒープメモリやキャッシュメモリでも動作します。
フォントクラスのマッピング
注:この セクションは、Fontmap フォントファイルを使用する場合にのみ適用されます。
Fontmapファイルからのフォント選択に影響を与える要素の一つに、フォントクラス名があります。フォント選択の仕組みについては、Fontmapのドキュメントを参照してください。サポートされているフォントクラスの命名形式は「"<font.family> <font.weight> <font.italic>" 」であり、ここで:
- font.family - 設定されていない場合、MCU.Config.defaultFontFamilyターゲットプロパティの値が使用されます。設定されている場合は、指定された文字列がそのまま使用されます。
- font.weight - 列挙型を文字列に変換します。例えば、
Font.ExtraLightは「Extralight」になります。ただし、Font.Normalは例外で、これは空の文字列に変換されます。 - font.bold - これは
font.weight: Font.Bold - font.italic - 設定されている場合は「Italic」にマッピングされ、設定されていない場合は空の文字列にマッピングされます。
マッピングの例
フォントのバインディングの例を参照してください。
既存のアプリケーションの移植
次の例のように、sans-serifフォントファミリーを使用している QML アプリケーションがあると仮定しましょう:
Text {
font.family: "sans-serif"
}上記の例に合わせてフォントマップを作成するには、フォントファイル(TTF)を「sans-serif」というフォントクラス名にマッピングする必要があります。これは、FontmapEditor GUI ツールを使用すれば簡単に実行できます。 QMLソースを変更したくないが、SansSerif.ttf 以外のフォントファイルを使用したい場合は、Fontmapファイル内でsans-serif を FrutigerOTS_S12-29g.ttfにマッピングすれば問題ありません。 あるいは、ソースコード内の「sans-serif」という記述をすべて、例えば「FrutigerOTS」に変更することもできます。その後、FontmapEditorで「FrutigerOTS」を「FrutigerOTS_S12-29g.ttf」にマッピングします。
フォントヒンティング
Spark ヒンティング
Sparkのヒンティング命令は、メモリ要件を極限まで抑え、パフォーマンスを向上させるように設計されています。なお、フォントに従来のTrueTypeヒンティングが含まれている場合、Sparkはそれらを処理しない点にご注意ください。新しいヒンティング命令に加え、Sparkは独自のヒンティング技術を適用することで、フォントサイズを大幅に縮小します。Sparkのヒンティングは、オプションで圧縮することができ、これによりメモリ使用量をさらに削減できます。
自動ヒンティング
実行時のメモリを節約するため、TrueTypeフォントのヒンティングはサポートされていないため、自動ヒンティング機能がSparkフォントエンジンに組み込まれています。システムフォントにSparkヒンティングが含まれていない場合、Sparkは自動ヒンティングを実行します。 自動ヒント処理のみでは、特に小さな文字サイズにおいて、Sparkヒントと組み合わせた自動ヒント処理と同等の高品質な結果は得られません。
フォントエンジンのキャッシュ
グリフを初めてレンダリングする際、Sparkはそのグリフを作成し、キャッシュに保存します。その後、そのグリフを再度レンダリングしようとする場合、再作成することなくキャッシュから直接取得されるため、パフォーマンスが向上します。 グリフキャッシュに加え、SparkはCMAPキャッシュおよびアドバンスキャッシュもサポートしています。これにより、TrueTypeフォントの「CMAP」テーブルや「HMTX」テーブルをそれぞれ解析する場合に比べ、グリフIDやグリフアドバンスの取得が高速化されます。キャッシュが満杯になると、Sparkは使用頻度の低いエントリをキャッシュから削除します。
その他のキャッシュ設定として、Sparkでは、決して削除されないキャッシュエントリや、キャッシュに追加すべきでないグリフのサイズしきい値などを設定できます。これらの機能の一部は、Qt for MCUs ではまだ利用できません。
このキャッシュはフォントエンジンに属しており、テキストキャッシュやグリフレイアウトキャッシュとは別個のものです。これらについては、Qt Quick Ultraliteがフォントエンジンを介さずに独自に管理しています。 フォントエンジンがRAMに消費する容量を見積もるには、そのキャッシュをヒープに追加します(QUL_FONT_CACHE_SIZE+QUL_FONT_HEAP_SIZE)。他の2つのキャッシュは別途カウントされます。パフォーマンスログでは、このキャッシュは「Monotype spark cache 」として表示されます。
フォントエンジンのキャッシュ初期化
キャッシュのプリミングでは、ビルド時に選択されたグリフセットをラスタライズし、アプリケーションバイナリに格納します。デバイス上では、ラスタライズされるのではなく、グリフキャッシュにコピーされます。
文字の選択には、font.unicodeCoverage を使用します。 コピーは、フォントエンジンに初めてアクセスされた際に一度だけ行われ、QUL_GLYPHS_RESOURCE_STORAGE_SECTIONから Spark のキャッシュメモリへコピーされます。このキャッシュメモリのサイズはQUL_FONT_CACHE_SIZEで指定され、QUL_FONT_CACHE_PREALLOC に基づいて割り当てられます。
有効にする方法については、QUL_FONT_CACHE_PRIMINGを参照してください。
キャッシュのプライミングによるトレードオフ
プリミングを行わない場合、グリフは最初に描画されるフレームでラスタライズされます。ビューの切り替え、画面の読み込み、言語の変更などを行うUIにおいて、これが遷移の途中で発生した場合、どの遷移がその処理の負荷を負担するかは、ユーザーの操作順序によって異なります。
プリミングを行うと、デバイスはグリフをラスタライズする代わりにコピーするため、グリフあたりの処理コストが大幅に低減され、また処理が複数のフレームに分散することなく、あらかじめ決まった1つの時点で一括して行われます。その代償として、宣言されたすべてのグリフは、実際に描画されるかどうかに関わらず処理コストが発生し、プリミングデータがフラッシュメモリを占有することになります。
フレーム予算が固定されているアプリケーションの場合、そのコストがどこで発生するかは、そのコストの大きさよりも通常重要です。遷移中にラスタライズを行うと予算を超過してフレームがドロップされる可能性がありますが、フォントエンジンへの最初のアクセス時に一度だけ費やされる数ミリ秒は、ドロップされたフレームとして目に見えることはありません。
注:プリミングされた エントリは固定されません。これらは実行時にラスタライズされるグリフと同じ置換ポリシーの対象となるため、負荷のかかったキャッシュでは他のエントリと同様に排除され、次に描画される際にグリフは再度ラスタライズされます。
カバレッジのサイズ設定
コストは、実際に描画される文字数ではなく、宣言されたカバレッジに応じて変動します。アプリケーションが必要とする量以上に宣言すると、一度も使用されないグリフのためにフラッシュメモリとキャッシュメモリの両方を消費することになります。
参考として、フォントマップを外部QSPIフラッシュに配置したSTM32F769I-DISCO上で、3つの構成フォントにまたがる12個のテキストを12、16、20、24ピクセルで描画し、結果として得られる12のフォント構成それぞれに対して同じカバレッジを宣言した場合の測定結果は以下の通りです:
| 宣言されたカバレッジ | コードポイント | プライミングデータ | 充填時間 | Sparkキャッシュが必要 |
|---|---|---|---|---|
| なし(実行時にラスタ化) | 0 | 0 | 該当なし | 46 KB |
| 数字のみ | 10 | 21 KB | 2 ms | 46 KB |
| 描画された文字そのもの | 18 | 37 KB | 3 ms | 46 KB |
| 印刷可能なすべてのASCII文字 | 95 | 188 KB | 14 ms | 217 KB |
| ASCIIおよびLatin-1 Supplement | 191 | 399 KB | 29 ms | 454 KB |
注意すべき点が2つあります。アプリケーションが描画する文字のみを宣言しても、キャッシュへの負荷はほぼゼロです。なぜなら、キャッシュには結局のところ、もともとラスタライズされるはずだったのと同じグリフが保持されることになるからです。メリットは、デバイス上でそれらをラスタライズしなくて済むという点にあります。
第二に、コストは実際に描画される内容ではなく、宣言されたカバレッジに応じて増加し、その増加は急速です。12個のテキストが表示される画面の場合、最後の2行にはデフォルトの200000バイトを超えるキャッシュが必要となります。ご自身のプロジェクトでは、フォントデータレポートに出力される数値からQUL_FONT_CACHE_SIZEのサイズを算出してください。
この表は予測値ではなく、あくまで大まかな目安として扱ってください。これは、1つのボード、1つのフォント、1つの画面を対象としたものであり、プライミングデータは外部のQSPIフラッシュに格納されているため、タイミングにはそのバス速度とこのプロセッサのクロックが反映されています。 また、このボードではグリフのアライメントが不要であるため、各エントリは個別にパディングされることなくそのままコピーされます。これに対し、グリフのアライメントが必要なボードでは、その処理にコストがかかります。独自の数値を確認するには、フォントデータレポートでビルド時のサイズを確認するか、Qt Quick のUltraliteパフォーマンスロギングでデバイス上のコピーコストを確認してください。
注: キャッシュに収まらないカバレッジは 、フォールバックではなく構成エラーです。 ビルド自体は成功しますが、実行時にラスタライズされるグリフのためのキャッシュ領域が不足し、プライムされたエントリは固定されていないため、その領域を確保するためにエジェクションされます。カバレッジを縮小するか、QUL_FONT_CACHE_SIZE を増やすかしてください。
キャッシュのプライミング処理において、StaticText 用に保存されているグリフと共通するグリフが検出された場合、実行時にSparkキャッシュを充填する際、StaticText データからそれらのグリフを取得することで最適化が行われます。この最適化により、必要なフラッシュメモリの容量を節約できます。
テキストのキャッシュ
Qt Quick Ultraliteは、テキスト内の各グリフや文字を個別に描画します。このデフォルトの動作では、描画エンジンへの頻繁な呼び出しにより、パフォーマンス上のオーバーヘッドが発生します。この動作によってパフォーマンスが低下するプラットフォームでは、テキストキャッシュの代替方式に切り替えてください。これにより、各テキスト要素をCPU側で個別の画像としてキャッシュできるようになり、描画エンジンへの呼び出し回数が削減されます。
さらに、MCU.Config.fontVectorOutlinesDrawing が有効になっている場合、テキストのアウトラインもキャッシュされます。これにより、テキスト要素が描画されるたびに、対応するPathData を再計算する必要がなくなります。
アプリケーションでテキストキャッシュを有効にするには、Qul::Application クラスの代替コンストラクタを実装してください。このコンストラクタは、次の例に示すように、Qul::ApplicationConfiguration インスタンスを受け入れる必要があります。
Qul::initHardware(); Qul::initPlatform(); Qul::ApplicationConfiguration appConfig; appConfig.setTextCacheEnabled(true); appConfig.setTextCacheSize(128 * 1024); Qul::Application app(appConfig); static MainScreen item; app.setRootItem(&item); while (true) { uint64_t now = Qul::Platform::getPlatformInstance()->currentTimestamp(); // <handle timers> uint64_t nextUpdate = app.update(); if (nextUpdate > now) { // Device can go to sleep until next update is due // enterLowPowerMode(nextUpdate - now); } }
注: NXP MIMXRT1170-EVKB、Renesas RH850/D1M1A、およびInfineon TRAVEO T2Gボードでは、テキストキャッシュが デフォルトで有効になっています。
テキストキャッシュのサイズが設定されていない場合、Qt Quick Ultraliteは、プラットフォームのメインCMakeLists.txt ファイルで設定されたデフォルトサイズである24KBを使用します。サイズを変更するには、プラットフォームのCMakeLists.txt ファイルに、QUL_PLATFORM_DEFAULT_TEXT_CACHE_SIZE用のPlatform ターゲットプロパティを追加してください。
テキストキャッシュ用のメモリは、Qul::PlatformInterface::MemoryAllocator::TextCache を介してプラットフォーム層から割り当てられます。単一のメモリバッファが事前に割り当てられ、テキストキャッシュによって内部的に管理されます。内部的な管理処理を考慮するため、実際のバッファサイズはアプリケーションが要求した値よりわずかに大きくなる場合があります。
テキストキャッシュはこのバッファ内でキャッシュエントリの割り当てを管理し、LRU戦略を用いてエントリを再利用します。エントリはQUL_PLATFORM_DEFAULT_NUM_FRAMES_TO_PRESERVE_ASSETS に従って保持される場合があります。キャッシュのメモリが不足した場合、テキストのレンダリングは次のフレームまでデフォルトの挙動に切り替わります。
StaticText 項目については、text cache は使用されません。これは、fontcompilerツールが--mergeStaticTextGlyphs オプションを使用して、StaticText 項目のグリフを単一の画像に結合できるためです。このオプションを使用するには、プラットフォームがBoardDefaults.qmlprojectconfig 内のMCU.Config ノードでMCU.Config.mergeStaticTextGlyphs を有効にする必要があります:
MCU.Config {
mergeStaticTextGlyphs: true
}mergeStaticTextGlyphs これは実験的なAPIであり、以下の制限があります:
- テキストは常に左揃えとなり、実行時に設定されたプロパティは無視されます。
- Monotype Spark フォントエンジンはサポートされていません。
- QtQuick::Text::textFormat はサポートされていません。
アプリケーションで使用されるテキストキャッシュのサイズは、パフォーマンスログを確認することで確認できます。
適切なキャッシュサイズの選定に関するヒントについては、「リソースキャッシュ」を参照してください。
グリフレイアウトのキャッシュ
詳細については、MCU.Config.glyphsLayoutCacheSize を参照してください。
特定のQtライセンスの下で利用可能です。
詳細はこちらをご覧ください。