このページでは

C

部分フレームバッファ

概要

通常、フレームバッファには、ディスプレイに表示されるすべてのピクセルが格納されます。レイヤーをサポートするプラットフォームでは、アプリケーションはディスプレイのサイズよりも小さい複数のレイヤーを含むことがあります。

ディスプレイ用に独立したメモリが提供されているプラットフォームでは、部分フレームバッファを使用して、再描画が必要なピクセル(ダーティ・レクタングルと呼ばれる)のみを格納することができます。

部分フレームバッファの戦略では、再描画される領域ごとにダーティ・レクタングルを提供し、ディスプレイへ転送する必要のあるデータ量を最小限に抑えます。

部分フレームバッファは、1つまたは複数使用できます。複数の部分フレームバッファを使用すると、フロント部分フレームバッファがフラッシュされている間も、バック部分フレームバッファ上でレンダリングを行うことができます。

あるいは、独立したディスプレイメモリを持たず、単一のフルフレームバッファを使用するプラットフォームでは、部分バッファリングを使用してレンダリングアーティファクトを低減することができます。 部分的にレンダリングされたコンテンツは、まず部分バッファでレンダリングし、その後、完全にレンダリングされたコンテンツをフルディスプレイフレームバッファにコピーすることで、その量を減らすことができます。ただし、この場合に部分バッファリングを使用すると、部分フレームバッファに完全に収まらない移動要素にティアリング現象が生じる可能性があります。

メモリ使用量

部分バッファリングは、シングルバッファおよびダブルバッファのグラフィックスと比較して、メモリ使用量を大幅に削減できます。

部分フレームバッファの最小ピクセル数は、レイヤーの幅となります。ピクセル数を多くするとレンダリングのオーバーヘッドは軽減されますが、メモリ要件は増加します。

部分フレームバッファの最適なサイズはプラットフォームによって異なります。まずはフル解像度の 1/8 のサイズから始め、必要に応じて徐々にサイズを調整していくとよいでしょう。

部分フレームバッファに必要なメモリ量は、次のように表すことができます。

Memory usage in bytes = width x height x bytes per pixel x number of buffers

以下に、解像度と部分フレームバッファリング戦略の組み合わせ例におけるメモリ使用量の要件を示します:

レイヤーの解像度(幅 × 高さ)色深度フレームバッファリング戦略メモリ使用量
320×24016 bppダブルバッファリング300 KB
320x24016 bppシングルバッファリング150 KB
320x48 (320x240/5)116 bpp部分バッファリング30 KB
320x24 (320x240/10)116 bpp2つの部分バッファによる部分バッファリング30 KB
320x1 (320x240/240)116 bpp部分バッファリング640 B

注: 1部分フレームバッファの解像度は固定ではなく、最大値を示していますpixel count of a single partial framebuffer

部分フレームバッファを使用したレンダリング

シングル/ダブルバッファリングされたグラフィックスのレンダリング

Qt Quick Ultralite コアは、視覚的な更新が必要な領域ごとに 1 回、beginFrame およびendFrame を呼び出します。更新された領域は、PlatformContext::beginFrame 内のrect で指定されます。

フレーム更新中、Qt Quick を呼び出すUltraliteコアは、各レイヤーに対してbeginFrame およびendFrame を呼び出します。これらの関数呼び出しの間に、変更された領域のフレームバッファへのレンダリングが行われます。

beginFrame の引数rect は、更新される変更領域を指定します。rect は、特定のレイヤーについて、すべての変更領域を結合したバウンディング矩形を表します。

presentFrame メソッドは、各レイヤーに対して最後に呼び出されます。通常、この関数はフロントフレームバッファとバックフレームバッファを入れ替え、ディスプレイ上に新しいコンテンツを表示します。シングルバッファ方式のグラフィックスでは、部分的にレンダリングされたUI要素が表示されることがあり、特に動いているUI要素の場合、ちらつきを引き起こす可能性があります。

以下の擬似コードは、Qt Quick Ultralite Core によってプラットフォーム適応関数がどのように呼び出されるかを示しています。ここで、render は、新しいコンテンツをフレームバッファにブリットまたはブレンドすることで行われるレンダリング操作を表します。

beginFrame(layer X, boundingRect(dirtyRects A|B|... ))
render(dirtyRect A)
...
render(dirtyRect B)
...
endFrame(layer X)

beginFrame(layer Y, ...)
...
endFrame(layer Y)

...

presentFrame(boundingRect(dirtyRects A|B|...)) // swap buffers if double buffered

部分バッファリング方式によるレンダリング

部分フレームバッファ戦略を使用する場合、Qt Quick Ultralite Core は、指定されたレイヤー内のすべてのダーティ領域に対して、beginFrame およびendFrame を呼び出します。

Qt Quick Ultralite Core は、部分フレームバッファのピクセルサイズに応じて、変更された領域の更新を、部分フレームバッファに収まる矩形(beginFramerect 入力引数)に分割し、それらに描画を行います。

以下の擬似コードはこの概念を説明しています。前述の通り、render は、部分フレームバッファへの新しいコンテンツのブリットまたはブレンディングによるレンダリングアクションを表します。

beginFrame(layer X, dirtyRect A)
render(dirtyRect A)
...
endFrame(layer X) // flush partial framebuffer to display

beginFrame(layer X, dirtyRect B)
render(dirtyRect B)
...
endFrame(layer X) // flush partial framebuffer to display

...

beginFrame(layer Y, ...)
...
endFrame(layer Y) // flush partial framebuffer to display

...

presentFrame(boundingRect(dirtyRects A|B|...))

次の例では、「Qt Quick Ultralite Thermostat Demo」の Room ビューのいずれかのボタンをユーザーが押してアプリケーションを操作した際の、ディスプレイメモリと部分フレームバッファの内容を示します。

次の画像は、ボタンが押される前の、アプリケーションがアイドル状態にあるときのディスプレイメモリの内容を示しています:

アプリケーションがアイドル状態のとき、ボタンが押される前に、メモリの内容を表示します。

このプラットフォーム適応では、部分フレームバッファ戦略が使用されており、部分フレームバッファのサイズは16320 ピクセルです。Qt Quick Ultralite Core は、partialBufferPixelCount 関数を呼び出すことで、ダーティ領域に必要な最大面積を計算します。

下部の矢印が押されて温度が下げられると、下部のボタン領域を更新するための再描画イベントがトリガーされます。点灯しているボタンのダーティ領域の合計は、285x132=37620 ピクセルの長方形ですが、これを3つのダーティ矩形に分割し、それぞれを部分フレームバッファに収める必要があります。

以下は、ユーザーの操作後の更新段階の説明であり、ディスプレイメモリの内容と部分フレームバッファの内容の両方を示しています:

  1. 最初の更新
    • 下矢印キーが押された後にendFrame が呼び出された際の部分フレームバッファの内容:

      下矢印キーが押された後に endFrame が呼び出された場合、フレームバッファの内容が一部表示される。

      x: 258, y: 291, width: 285 and height: 57 (total 16245 pixels).

    • endFrame 内でフレームバッファの一部内容がディスプレイにフラッシュされた後のディスプレイメモリの内容:

      endFrame 関数内でフレームバッファの一部内容がディスプレイにフラッシュされた後、メモリの内容を表示します。

  2. 2回目の更新
    • 2回目の更新時のフレームバッファの一部。これには、ダーティ領域の次の部分が含まれています。

      ダーティ領域の次の部分を含む、フレームバッファの内容の一部。

      x: 258, y: 291, width: 285 and height: 57 (total 16245 pixels).

    • フラッシュ後のディスプレイメモリの内容:

      フラッシュ処理後にメモリの内容を表示します。

  3. 3回目の更新
    • ダーティ領域の3番目かつ最後の部分に関するフレームバッファの内容の一部。

      ダーティ領域の最後の部分に対応するフレームバッファの内容の一部。

      x: 258, y: 405, width: 285 and height: 18 (total 5130 pixels).

    • 最後の部分がディスプレイにフラッシュされた後のメモリの内容を表示します:

      ディスプレイに最後に書き込まれた部分から順に、メモリの内容を表示します。

部分フレームバッファ機能の実装

部分フレームバッファの追加

この例では、ディスプレイサイズの ⅛ を部分フレームバッファのサイズとして使用しています。ディスプレイのフラッシュ用に、現在のダーティ・レクタングルを格納するための `dirtyRect ` が追加されています。

namespace Private {

static constexpr uint16_t displayWidth = 320;
static constexpr uint16_t displayHeight = 240;
static constexpr size_t bufferPixelCount = displayWidth * displayHeight / 8;
static constexpr uint8_t bytesPerPixel = 2;
static uchar framebuffer[bufferPixelCount * bytesPerPixel];
PlatformInterface::Rect dirtyRect;

} // namespace Private

フレームバッファリングタイプの設定

Qt Quick Ultralite Coreに使用中のフレームバッファリング戦略を通知するため、プラットフォーム適応処理では、framebuffering type としてPartialBuffering を返す必要があります。

FrameBufferingType frameBufferingType(const PlatformInterface::LayerEngine::ItemLayer *) const override
{
    return PartialBuffering;
}

部分バッファサイズ

partialBufferPixelCount のプラットフォーム適応コードは、ダーティ・レクタングルのサイズを計算するために、部分フレームバッファのサイズをピクセル単位で返す必要があります。

size_t partialBufferPixelCount(const PlatformInterface::LayerEngine::ItemLayer *) const override
{
    return Private::bufferPixelCount;
}

DrawingDevice のサイズおよび 1 行あたりのバイト数の設定

beginFrame 内のrect は、描画対象となるダーティ領域を指定します。PlatformInterface::DrawingDevice のサイズおよび 1 行あたりのバイト数はrect の幅と高さに基づいて設定されます。

プラットフォーム適応処理では、後でendFrame 内で使用するために、この矩形を保存しておく必要があります。

PlatformInterface::DrawingDevice *beginFrame(const PlatformInterface::LayerEngine::ItemLayer *,
                                             const PlatformInterface::Rect &rect,
                                             int refreshInterval) override
{
    static PlatformInterface::DrawingEngine drawingEngine;

    static PlatformInterface::DrawingDevice buffer = {Qul::PixelFormat_RGB16,
                                                      PlatformInterface::Size(Private::displayWidth,
                                                                              Private::displayHeight),
                                                      Private::framebuffer,
                                                      Private::displayWidth * Private::bytesPerPixel,
                                                      &drawingEngine};

    Private::dirtyRect = rect;

    buffer.setSize(PlatformInterface::Size(rect.width(), rect.height()));
    buffer.setBytesPerLine(rect.width() * Private::bytesPerPixel);
    buffer.setBits(Private::framebuffer);

    return &buffer;
}

フレームバッファの内容をディスプレイにフラッシュする

beginFrame に渡され、その後 DrawingEngine によって描画されるダーティ矩形は、後でendFrame において、更新された部分的なフレームバッファの内容をディスプレイにフラッシュするために使用されます。

void endFrame(const PlatformInterface::LayerEngine::ItemLayer *) override
{
    // Lcd_Flush(Private::dirtyRect.x(),
    //    Private::dirtyRect.y(),
    //    Private::dirtyRect.x() + Private::dirtyRect.width(),
    //    Private::dirtyRect.y() + Private::dirtyRect.height(),
    //    Private::framebuffer);
}

プラットフォームの要件に合わせたダーティ・レクタングルの調整

adjustedPartialUpdateRect を使用することで、プラットフォーム適応機能は、後でbeginFrame に渡されるダーティ・レクタングルを調整できます。これにより、プラットフォーム適応機能は、データのアラインメントやフラッシュされる領域の最小サイズなど、プラットフォーム固有の要件に基づいてレクタングルを調整できるようになります。

注: このメソッドの実装は 任意です。

PlatformInterface::Rect adjustedPartialUpdateRect(const PlatformInterface::LayerEngine::ItemLayer *layer,
                                                  const PlatformInterface::Rect &rect) const override
{
    auto r = PlatformInterface::Rect(rect);

    // r.setX(...);
    // r.setWidth(...);

    return r;
}

サポートされているプラットフォーム

部分フレームバッファをサポートするリファレンスポートの一覧については、「サポートされている機能」を参照してください。

注: この機能を有効にするには、これらのポートのプラットフォームライブラリを 、CMake オプションQUL_PLATFORM_PARTIAL_FRAMEBUFFERを指定して再ビルドする必要があります。詳細については、「評価用パッケージに対するQt Quick Ultralite プラットフォームライブラリのビルド」を参照してください。

画面へのグラフィックス表示も参照してください

特定のQtライセンスの下で利用可能です。
詳細はこちら。