Apple Developer Connection
高度な検索
Member Login ログイン | ご入会 ADC連絡先

Technical Note TN2153
QuickTime for Windowsのダブルバッファ機能によるWindowsスクリーン更新の向上

このテクニカルノートでは、Windowsアプリケーションの最適なスクリーン更新を可能にするQuickTimeの新しいダブルバッファ機能について説明します。





はじめに

QuickTime 6.4には、Windowsアプリケーションのスクリーン更新を向上させる新しいダブルバッファ機能が含まれています。この機能は、Mac OS X上と同様の、遅延フラッシュ方式を利用しています。また、QuickTimeのグラフィックスポートごとに完全なオフスクリーン(バック)バッファを提供しており、定期的に、または明示的なリクエストに応じて、バッファをスクリーンにフラッシュします。この方法には、クリッピング処理の向上や、UI要素の散発的なフラッシュの防止など、多くのメリットがあります。

もう少し詳しく説明します。

QuickTimeグラフィックスポートへの更新分のピクセルデータは、バックバッファに描画され、すぐにスクリーンに描画されるわけではありません。各ポートの「ダーティな」領域(変更された部分)は、フラッシュが実行されるまで蓄積され、フラッシュされた時点でダーティリージョン全体がスクリーンに描画されます。

重要:ムービーを描画するとき、またはムービーをアイドル状態にするときに、QuickTimeが自動的にダーティリージョンをスクリーンにフラッシュします。

また、必要な場合はアプリケーションで明示的にフラッシュを実行することもできます(「新しい機能」を参照)。

先頭に戻る

機能の使用は任意

アプリケーションによっては、この機能を使用しないことも考えられるため、この機能の使用は任意です(後述の「重要事項」を参照)。

この機能を使用するには、Windowsアプリケーションでは、次に示すように起動時にkInitializeQTMLEnableDoubleBufferedSurfaceフラグをInitializeQTMLに渡し有効にする必要があります。

リスト1:QuickTimeダブルバッファの有効化

// QuickTimeダブルバッファを有効にする
InitializeQTML(kInitializeQTMLEnableDoubleBufferedSurface);

この機能を有効にすると、QuickTimeは、要求元のアプリケーションに関連付けられているグラフィックスポートへのスクリーン更新に対して、自動的にダブルバッファ機能を使用します。

先頭に戻る

最も簡単な使い方

アプリケーションが更新リージョンの特殊な処理を実行しない場合でも、上記のリスト1に示すように、この機能を単に有効にしておくこともできます。QuickTimeは、デフォルトではこの機能を使用し、通常のスクリーン更新操作のためにダーティリージョンの蓄積と基本的なフラッシュを実行します。場合によっては、APIをそれ以上使用する必要はありません。

先頭に戻る

新しいAPIの使用

アプリケーションが更新リージョンの特殊な処理を実行する場合は、この機能を利用するために新しいダブルバッファAPIを使用する必要があります。このセクションでは、これらのAPIについて簡単に説明します。

新しいフラグ

 kInitializeQTMLEnableDoubleBufferedSurface

kInitializeQTMLEnableDoubleBufferedSurfaceフラグはInitializeQTMLの呼び出し時に渡され、ダブルバッファ機能を有効にします。

kQTMLNoDoubleBufferPort

kQTMLNoDoubleBufferPortフラグはCreatePortAssociationの呼び出し時に渡されて、特定のポートにおけるダブルバッファを無効にします。ダブルバッファ機能が有効になっていない場合、このフラグは無視されます。

先頭に戻る

新しい機能

以下の新しいAPIを使用すると、ポートに蓄積されるダーティリージョン(MacRegionRect、またはWindows HRGN)にリージョンを追加できます。

QTMLAddRgnToDirtyRgn

QTMLAddRectToDirtyRgn

QTMLAddNativeRgnToDirtyRgn

QTMLAddRgnToDirtyRgn(GrafPtr port, RgnHandle *dirtyRgn)
QTMLAddRectToDirtyRgn(GrafPtr port, Rect *dirtyRect)
QTMLAddNativeRgnToDirtyRgn(GrafPtr port, void *dirtyHRGN)

上記の新しいAPIは以下の用途に使用します。

  • バックバッファへのHDCアクセスを使用することにより(HDCアクセスAPIを通じて)、アプリケーションがバックバッファへ直接描画するよう指示する。

  • pixMapをロックした後で、そのビットを直接操作することによりダーティリージョンを追加する。

  • WM_PAINT処理時にダーティリージョンにWindows更新リージョンを追加して、それらを明示的にリフレッシュする。

注:上記の呼び出しは、最小限の変換処理で、コードに都合の良い方法でダーティリージョンを追加できるようにするために用意されています。対象となる更新処理に適した呼び出しを使用してください。

QTMLFlushDirtyPorts

すべてのダーティポートを1つずつ確認し、それらのダーティリージョンをスクリーンにフラッシュします。この呼び出しは、特定のポートのバックバッファをスクリーンと同期する必要があるために実行されるフラッシュではなく、定期的な全体のフラッシュに使用することを目的としています。

QTMLFlushDirtyPorts()

QTMLFlushPortDirtyRgn

指定されたポートのダーティリージョンをスクリーンにフラッシュします。この呼び出しは、WM_PAINT処理時にWindowsの更新リージョンをダーティリージョンに追加した後で、ウインドウの内容をスクリーンにフラッシュする場合によく使われます。

QTMLFlushPortDirtyRgn(GrafPtr port)

QTMLGetBackbufferHDC

GDIによるバックバッファへのアクセスを可能にします。呼び出し元は、QTMLReleaseBackbufferHDCを使ってバックバッファHDCを解放する必要があります。これは参照カウントによって管理されるため、Getの呼び出しに対応するReleaseの呼び出しを行う必要があります。

QTMLGetBackbufferHDC(GrafPtr port, HDC *backBufferHDC)

QTMLReleaseBackbufferHDC

GDIによるバックバッファへのアクセスを可能にします。呼び出し元は、バックバッファのうちダーティになった領域をQuickTimeに知らせるために、バックバッファHDCを解放した後でQTMLAddRegionToDirtyRgnを呼び出す必要があります。

QTMLReleaseBackbufferHDC(GrafPtr port, HDC *backBufferHDC)

先頭に戻る

重要事項

アプリケーションでは、QTMLとWindowsによる単一ウインドウへの描画を組み合わせて、互いを上書きし合うようなことは避けてください。Windowsが所有するウインドウ内でQTMLが所有する領域に、子hWndを使用することを推奨します。

アプリケーションで考慮すべきもう1つ重要なことは、pixMapポートのbaseAddressをキャッシュしてはならないということです。ポートがロックされると、pixMapはバックバッファbaseAddressとメトリック情報を反映して更新され、ポートがロック解除されると、スクリーンbaseAddressとメトリック情報が含まれます。このバックバッファbaseAddressは、ウインドウサイズの変更や、その他さまざまな理由で変わる可能性があります。

一般に、ポートへの描画方法は次の4つのカテゴリに分類され、それぞれ少しずつ動作が異なります。

QuickTime

QuickTimeによる描画では、ムービーに関連付けられているポートに、ムービーがビジュアル要素を描画する処理が伴います。このタイプの描画では、ダブルバッファが有効な場合はバックバッファへ描画され、ダーティリージョンがポートに自動的に追加されて、スクリーンにフラッシュされます。

先頭に戻る

QuickDraw

QuickDraw呼び出しを使って実行される描画は、ポートに適切なダーティリージョンを自動的に追加しますが、スクリーンに自動的にはフラッシュされません(これが行われるのは、スクリーンへ1回blitするだけで多数のQuickDrawレンダリングを実行できるようにするためです。スクリーンフラッシュは呼び出しの後で明示的に、またはタイマによって定期的に行う必要があります。

先頭に戻る

GDI

ポートに描画するには、GDIを使用して、QTMLGetBackbufferHDCから取得したHDCにレンダリングします。QuickTimeとQuickDrawには、影響を受けたピクセルに関するヒントがないため、QTMLAddDirtyRectまたは類似の何かを呼び出すことが重要です。そうしないと、影響を受けたピクセルがスクリーンにフラッシュされない可能性があります。QuickDrawレンダリングの場合と同様に、明示的なフラッシュが必要です。

先頭に戻る

PixMapへの直接アクセス

ポートを慎重にロックすることにより、baseAddressrowBytesがそのバックバッファを示すように更新されるため、バックバッファ内のピクセルを直接操作することができます。GDIによる描画と同様に、バックバッファでダーティにしたリージョンを明示的に宣言する必要があり、明示的なフラッシュが必要です。

あらゆる新しい機能の場合と同様に、ダブルバッファ機能を使用する一方で、古いQuickTimeバージョンとの下位互換性も維持したい場合は、アプリケーションの起動時に必ずQuickTimeのバージョンをチェックして、以前のQuickTimeバージョンで新しいAPIを使用しないでください。これらの呼び出しはQuickTime 6.4まで機能します。

以下のコードに、QuickTimeバージョンを取得する方法を示します。

リスト2:QuickTimeバージョンの取得

{
    /* インストールされているQuickTimeのバージョンをチェックする */

    long version;
    OSErr result;

    result = Gestalt(gestaltQuickTime,&version);
    if ((result == noErr) && (version >= 0x06408000))
    {
        /* バージョン6.4以降を使用する */
    }
}

先頭に戻る

例1

オフスクリーンバッファにはウインドウの有効な表現がすでに存在するため、この動作を選択するアプリケーションは、WM_PAINTメッセージの扱いを若干変えたいと思うかもしれません。Windowsの更新リージョンは、ポートのダーティリージョンに追加する必要があり、その後でポートをスクリーンにフラッシュできます。簡単な例を以下に示します。

リスト3:Windows更新リージョンをポートのダーティリージョンに追加し、ポートをスクリーンにフラッシュ

case WM_PAINT:
{
    RgnHandle   macUpdateRgn = nil;
    HRGN    winUpdateRgn = CreateRectRgn(0,0,0,0);

    macUpdateRgn = NewRgn();

    BeginUpdate((GrafPtr) moviePort);
    // アプリケーションで更新リージョンの特殊な処理を実行する場合は、
    // Mac更新リージョンを取得する。特殊な処理をしない場合は、
    // これをスキップできる。
    MacCopyRgn(moviePort->visRgn, macUpdateRgn);
    EndUpdate((GrafPtr) moviePort);

    // (MacUpdateRgnに応じて、または何らかの理由で)
    // アプリケーションで実行したい新しい描画がある場合は、
    // ここで実行する。この描画は
    // バックバッファで実行され、この呼び出しの終わりに
    // スクリーンにフラッシュされる。

    // Windows更新リージョンを取得する
    GetUpdateRgn(hWnd, winUpdateRgn, FALSE);
    // BeginPaint/EndPaintを呼び出して、更新リージョンをクリアする
    BeginPaint (hWnd, &ps);
    EndPaint(hWnd, &ps);

    // ポートのダーティリージョンに、Windowsが更新の必要を示す
    // リージョンを追加する。これによって、
    // 2つの和集合をバックバッファから次のフラッシュのスクリーンに
    // コピーできる。
    QTMLAddNativeRgnToDirtyRgn((GrafPtr) moviePort, winUpdateRgn);
    DeleteObject(winUpdateRgn);

    // ダーティリージョン全体をスクリーンにフラッシュする
    QTMLFlushPortDirtyRgn((GrafPtr) moviePort);
}

例2

長い一連の描画操作を結合し、最後に1回フラッシュを使用して、それらをすべて同時に表示すると都合がよい場合があります。次の例では、まずQuickDrawを使用して一連の縮小矩形を描画し、次にGDIを使用してバックバッファHDCに直接描画します。これらの描画はすべて、最後に一度にスクリーンへフラッシュされます。

リスト4:長い一連の描画操作を結合し、1回のフラッシュでそれらをすべて同時に表示

{
    Rect    myRect;
    Pattern currentPattern;

    myRect.top = myRect.left = 0;
    myRect.bottom = myRect.right = 200;

    SetPort(myWindowPort);

    // この描画はQuickDrawを使って実行する。
    // QuickDraw描画操作は、
    // 影響のあったエリアをポートに
    // 蓄積されたダーティリージョンに
    // 自動的に追加する。
    while (myRect.top < 50) {
        // パターンを入れ替える
        currentPattern =
            (currentPattern == pattern1) ? pattern2 : pattern1;
        // 現在の矩形を別のパターンで塗りつぶす
        MacFillRect(myRect, currentPattern);
        // 矩形をほんの少し縮小する。
        MacInsetRect(myRect, 10, 10);
    }

    {
        RECT winRect;
        HDC backbufferHDC = NULL;

        // ポートに関するバックバッファのHDCを取得する
        QTMLGetBackbufferHDC(myWindowPort, &backbufferHDC);

        // 上記のQuickDrawレンダリングを止めた場所に
        // Windows RECTを作成する
        winRect.top = myRect.top;
        winRect.left = myRect.left;
        winRect.bottom = myRect.bottom;
        winRect.right = myRect.right;

        // さらに別の矩形を塗りつぶす
        FillRect(backbufferHDC, &winRect, hBrush);

        // このバックバッファHDCを解放する必要がある。
        QTMLReleaseBackbufferHDC(myWindowPort, &backbufferHDC);

        // この描画はバックバッファに直接実行されるため、
        // ダーティリージョンをポートに追加する必要がある。
        QTMLAddRectToDirtyRgn(myWindowPort, & myRect);
    }

    // ここで、先へ進んで、すべての描画をスクリーンにフラッシュする
    QTMLFlushPortDirtyRgn(myWindowPort);
}

先頭に戻る

ドキュメント改訂履歴

日付メモ
2005-10-18QuickTime 6.4には、Windowsアプリケーションのスクリーン更新を改善する機能が含まれている

掲載日:2005-10-18




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.