メイン・コンテンツまでスキップ

パーシャル・フレームバッファによるメモリ使用量の軽減

このセクションでは、時計のアプリケーションを例に取り上げ、GRAMを搭載するディスプレイでパーシャル・フレームバッファを設定および使用することで(一部の性能を犠牲にしながらも)メモリ要件を軽減する方法について説明します。

STM32L4R9Discovery評価キット上で実行されるアプリケーションに関するビデオを以下からご覧になれます。

フルサイズのフレームバッファ・メモリ

通常、フレームバッファは、ディスプレイで使用可能なすべてのピクセルを保持するのに十分なメモリを備えた大規模なメモリ・アレイになります。 解像度480 x 272の24bitディスプレイを使用している場合、フルサイズのフレームバッファは480 x 272 x 3バイト = 391,680バイトのデータを保持しています。

アプリケーションによっては、2つ(ダブル・バッファリング)または3つのフレームバッファを使用することもあります。 この場合の必要なメモリ容量の合計は、783,360バイトまたは1,175,040バイトになります。

TouchGFXは、UIのどの部分を描画するときにもピクセルのデータをフレームバッファに書き込みます。すべての描画処理が完了した後、フレームバッファがディスプレイに転送されます。 通常、UIの一部のみが更新された場合でも、フレームバッファ全体がディスプレイに転送されます。 一般的に、多くの小さいブロックに分けて更新された後、フレームバッファは転送されます。

更新1, 更新2, 更新3, ..., 更新Nのように更新した後、ディスプレイへ転送

一部のケースでは、特に外部RAMを使用しない低コストのソリューションでは、フレームバッファとアプリケーションが必要とするメモリ容量が、内部RAMに収まるようにフレームバッファのサイズを十分小さくする必要があります。 このような場合に、パーシャル・フレームバッファが役立ちます。

パーシャル・フレームバッファ・メモリ

パーシャル・フレームバッファを使用すると、フルサイズよりも小さいフレームバッファ上で、TouchGFXアプリケーションを実行可能です。 フレームバッファの数とサイズは設定可能です。 この手法により、アプリケーションのメモリ要件をかなりの量削減できますが、いくつか制限事項も発生します。

  • パーシャル・フレームバッファはメモリが内蔵されたディスプレイでのみ動作します。 これは通常はDSIディスプレイか、パラレル・バス接続(DBIタイプA/B、8080/6800)またはSPIバス接続を備えたディスプレイになります。
  • 複雑なアプリケーションではティアリングの可能性があります。

フレームバッファを使用してディスプレイ上のすべてのピクセルを表すのとは異なり、パーシャル・フレームバッファは通常は小さな部分を対象とします。 この記事で使用する時計のアプリケーションの例では、それぞれ11,700バイトの3つのフレームバッファが使用されています。 この結果、フレームバッファに必要なメモリ量は35,100バイトになります。

アプリケーションでUIの一部を更新する必要がある場合、必ずTouchGFXは設定済みのパーシャル・フレームバッファのいずれかを選択し、そのパーシャル・フレームバッファ内で描画処理を完了させ、その部分をディスプレイに転送します。 レンダリングの必要があるUIのすべてのエリアに対してこの操作が繰り返されます。これにより、描画データの更新と転送の式は以下のように変更されます。

更新1, 転送1, 更新2, 転送2, 更新3, 転送3, ..., 更新N, 転送N

場合によっては、1つのパーシャル・フレームバッファの転送を、次のバッファの更新中に実行することもできます。

ディスプレイのティアリング

フルサイズのフレームバッファの使用とは対照的に、TouchGFXでパーシャル・フレームバッファを使用するときには、UIの各部分が更新後すぐに転送されます。 ディスプレイの画面上には、受信した更新が最大でも16ms後(60fpsのディスプレイの場合)に表示されます。ディスプレイは定期的にリフレッシュする必要があるからです。 このため、すべての更新が転送される前に、ディスプレイへの最初の更新が表示され、ユーザが気づく可能性があります。

描画処理と転送のシーケンス全体が完了するまでに時間がかかる(> 16ms)場合、ユーザには前のフレームと新しい更新の一部が混在して表示される可能性が高くなります。 これはディスプレイのティアリングと呼ばれる現象で、望ましいものではありません。 このため、パーシャル・フレームバッファは、レンダリングに時間のかかる複雑なアニメーションを使用するアプリケーションには適さないといえます。

ディスプレイの更新例

アプリケーション内でパーシャル・フレームバッファを設定する方法について説明する前に、秒を表す円弧が移動するデジタル時計の具体例を見てみたいと思います。 この緑色の円弧は毎秒6度ずつ移動しており、1分で1周します。 下の画像に示すように、UIは次の4つのウィジェットから構築されています。

デジタル時計と円弧を更新するコードを次に示します。

MainView.cpp
void MainView::handleTickEvent()
{
ticks++;
if (ticks == 10)
{
ticks = 0;
secs += 1;
if (secs == 60) //increment minutes
{
secs = 0;
min += 1;
if (min == 60) //increment hours
{
min = 0;
hour += 1;
if (hour == 24)
{
hour = 0;
}
}
//Only update digital clock when minutes or hours change
digitalClock.setTime24Hour(hour, min, secs);
}
//Always update seconds
circleSeconds.updateArc(secs*6 - 20, secs*6);
}
}

以下の画像は、円弧が一番上に到達し、デジタル時計が更新された時点で、最初の数秒間に更新される領域を示しています(灰色の長方形)。 最初の2つのフレームでは、秒のみが変化しています(58秒と59秒)。 3つ目のフレームでは60秒に到達し、時間と分のテキストが更新されています。

上の3つ目の画像で更新された長方形は、154x60ピクセル、20x12ピクセル、33x8ピクセルです。 標準のフレームバッファを使用する場合、この3つの長方形はフレームバッファ全体に描画(以前のピクセルに上書き)され、後からディスプレイに転送されることになります。 パーシャル・フレームバッファを使用すると、この3つの長方形はそれぞれ独自の小さいフレームバッファに描画され、更新されると即座にディスプレイに転送され表示されることになります。

パーシャル・フレームバッファの設定

TouchGFXでパーシャル・フレームバッファを使用するために必要な手順は以下のとおりです。

  1. メモリ・バッファを含むフレームバッファ・アロケータ・オブジェクトを作成する
  2. そのアロケータを使用するためのTouchGFX HALクラスを設定する
  3. バッファをディスプレイに転送するためのコードを作成する

ステップ1と2は、TouchGFX GeneratorによってSTM32CubeMXを介して自動生成されますが、ステップ3はピクセルをディスプレイに転送するための独自のドライバが必要です。

Further reading
パーシャル・フレームバッファの設定方法については、TouchGFX Generatorユーザガイドを参照してください。

サイズが1,920バイトの3つのパーシャル・フレームバッファを使用して、上記のセクションの更新領域を描画するための設定例を以下に示します。

まずは、小さい円の更新を描画する(上の2つ目の画像)(24Bppを想定)ために割り当てられた2つのフレームバッファの位置とサイズを確認してみましょう。

長方形xy高さピクセル
長方形1112562214308ピクセル = 924バイト
長方形2153422911319ピクセル = 957バイト

どちらの長方形も非常に小さいので、フレームバッファ・アロケータによって割り当てられたブロックに収まります。

上の3つ目の画像では、3つの長方形が更新されています。円への更新は少なく、大きな長方形がテキストを覆っています。

長方形xy高さピクセル
長方形1126512012240ピクセル = 720バイト
長方形216542338264ピクセル = 792バイト
長方形3118165154609,240ピクセル = 27,720バイト

繰り返しますが、長方形1と2は非常に小さいので、フレームバッファ・アロケータによって割り当てられたブロックに収まります。ただし、フレームバッファ3は大きすぎます。 この長方形3は大きすぎるので、それぞれがフレームバッファ(11,700バイト)に収まる複数の長方形に分割されます。

次に、3つの長方形を更新しますが、アロケータには2つのブロックしかありません。 こうした状況では、TouchGFXは最初のブロックが転送されるのを待ってから、ブロックを再利用します。

画面へのフレームバッファの転送

パーシャル・フレームバッファ・ブロックをディスプレイに転送するコードの実装方法は、使用するディスプレイ・インタフェースによって異なります。 これらの実行例については、以下の記事を参照してください。

まとめ

この記事では、パーシャル・フレームバッファ戦略によって、フレームバッファ・メモリが内蔵されたディスプレイを実装したプラットフォームのメモリ要件を、軽減する方法について説明しました。