モデルの反転、四角形のダーティ、スクロール領域

DXGI 1.2 では、新しいフリップ モデル スワップ チェーン、ダーティ四角形、スクロール領域がサポートされています。 新しいフリップ モデル スワップ チェーンを使用する利点と、四角形とスクロール領域ダーティ指定してプレゼンテーションを最適化する利点について説明します。

DXGI flip-model プレゼンテーション

DXGI 1.2 では、Direct3D 10 以降の API のフリップ プレゼンテーション モデルのサポートが追加されています。 Windows 7 では、Direct3D 9EX では、スワップ チェーン バッファーを不必要にコピーしないように、最初に フリップ モデル プレゼンテーション を採用しました。 フリップ モデルを使用すると、ランタイムとデスクトップ ウィンドウ マネージャー (DWM) の間でバック バッファーが反転されるため、DWM は常にバック バッファーの内容をコピーするのではなく、バック バッファーから直接作成します。

DXGI 1.2 API には、改訂された DXGI スワップ チェーン インターフェイス IDXGISwapChain1 が含まれています。 複数の IDXGIFactory2 インターフェイス メソッドを使用して、HWND ハンドル、CoreWindow オブジェクト、DirectComposition、または Windows.UI.Xaml フレームワークで使用する適切な IDXGISwapChain1 オブジェクトを作成できます。

反転プレゼンテーション モデルを選択するには、DXGI_SWAP_CHAIN_DESC1構造体の SwapEffect メンバーでDXGI_SWAP_EFFECT_FLIP_SEQUENTIAL列挙値を指定し、DXGI_SWAP_CHAIN_DESC1BufferCount メンバーを最小 2 に設定します。 DXGI フリップ モデルの使用方法の詳細については、「 DXGI フリップ モデル」を参照してください。 フリップ プレゼンテーション モデルのスムーズなプレゼンテーションとその他の新機能により、Direct3D 10 以降の API で作成するすべての新しいアプリに対してフリップ プレゼンテーション モデルを使用することをお勧めします。

スワップ チェーンプレゼンテーションでダーティ四角形とスクロール四角形を使用する

スワップ チェーンプレゼンテーションでダーティ四角形とスクロール四角形を使用すると、オペレーティング システムがフレーム全体を描画する必要がない場合に、オペレーティング システムが次に表示されるフレームを描画するために必要なピクセル データの量が減るため、メモリ帯域幅の使用量とシステム電力の関連する使用量を節約できます。 リモート デスクトップ接続やその他のリモート アクセス テクノロジを介して表示されることが多いアプリの場合、これらのテクノロジでは四角形とスクロール メタデータダーティ使用するため、表示品質の節約は特に顕著です。

スクロールは、フリップ プレゼンテーション モデルで実行される DXGI スワップ チェーンでのみ使用できます。 DXGI スワップ チェーンダーティ四角形を使用して、フリップ モデルとビットブル モデルの両方で実行できます (DXGI_SWAP_EFFECT_SEQUENTIALで設定)。

このシナリオと図では、四角形とスクロールダーティ使用する機能を示します。 ここでは、スクロール可能なアプリには、テキストとアニメーション化ビデオが含まれています。 アプリはダーティ四角形を使用して、ウィンドウ全体を更新するのではなく、アニメーション化ビデオとウィンドウの新しい行を更新するだけです。 スクロール四角形を使用すると、オペレーティング システムは、以前にレンダリングされたコンテンツを新しいフレームにコピーして翻訳し、新しいフレームに新しい行のみをレンダリングできます。

アプリは 、IDXGISwapChain1::P resent1 メソッドを呼び出してプレゼンテーションを実行します。 この呼び出しでは、アプリは、ダーティ四角形とダーティ四角形の数、スクロール四角形と関連するスクロール オフセット、またはダーティ四角形とスクロール四角形の両方を含むDXGI_PRESENT_PARAMETERS構造体へのポインターを渡します。 アプリは、2 つのダーティ四角形とスクロール四角形を渡します。 スクロール四角形は、オペレーティング システムが現在のフレームをレンダリングする前に現在のフレームにコピーする必要がある前のフレームの領域です。 アプリはアニメーション化ビデオと新しい行をダーティ四角形として指定し、オペレーティング システムによって現在のフレームにレンダリングされます。

スクロールとダーティの四角形の重なりの図

DirtyRectsCount = 2
pDirtyRects[ 0 ] = { 10, 30, 40, 50 } // Video
pDirtyRects[ 1 ] = { 0, 70, 50, 80 } // New line
*pScrollRect = { 0, 0, 50, 70 }
*pScrollOffset = { 0, -10 }

破線の四角形は、現在のフレーム内のスクロール四角形を示しています。 スクロール四角形は、DXGI_PRESENT_PARAMETERSpScrollRect メンバーによって指定されます。 矢印はスクロール オフセットを示しています。 スクロール オフセットは、DXGI_PRESENT_PARAMETERSpScrollOffset メンバーによって指定されます。 塗りつぶされた四角形ダーティ、アプリが新しいコンテンツで更新した四角形が表示されます。 塗りつぶされた四角形は、DXGI_PRESENT_PARAMETERSDirtyRectsCount メンバーと pDirtyRects メンバーによって指定されます。

ダーティ四角形とスクロール四角形を含むサンプル 2 バッファー フリップモデル スワップ チェーン

次の図とシーケンスは、ダーティ四角形とスクロール四角形を使用する DXGI フリップモデル プレゼンテーション操作の例を示しています。 この例では、flip-model プレゼンテーションのバッファーの最小数を使用します。バッファー数は 2 です。1 つは、アプリの表示コンテンツを含むフロント バッファーと、アプリがレンダリングする現在のフレームを含むバック バッファーです。

  1. フレームの先頭にあるフロント バッファーに示すように、スクロール可能なアプリは最初に、テキストを含むフレームを表示し、ビデオをアニメーション化します。
  2. 次のフレームをレンダリングするために、アプリはアニメーション化ビデオとウィンドウの新しい行を更新するダーティ四角形をバック バッファーにレンダリングします。
  3. アプリが IDXGISwapChain1::P resent1 を呼び出すと、ダーティ四角形とスクロール四角形とオフセットが指定されます。 ランタイムは次に、前のフレームから、更新されたダーティ四角形を引いたスクロール四角形を現在のバック バッファーにコピーします。
  4. ランタイムは最終的に、フロント バッファーとバック バッファーを入れ替えます。

スクロールとダーティ四角形を含むフリップ モデル スワップ チェーンの例

四角形ダーティ追跡し、複数のフレームにわたって四角形をスクロールする

アプリでダーティ四角形を使用する場合は、インクリメンタル レンダリングをサポートするためにダーティ四角形を追跡する必要があります。 アプリで IDXGISwapChain1::P resent1 をダーティ四角形で呼び出す場合は、ダーティ四角形内のすべてのピクセルが最新であることを確認する必要があります。 ダーティ四角形の領域全体を完全に再レンダリングしない場合、または汚れている領域が特定できない場合は、レンダリングを開始する前に、以前の完全に一貫性のあるバック バッファーから現在の古いバック バッファーにデータをコピーする必要があります。

ランタイムは、前のフレームの更新された領域と現在のフレームの更新された領域の違いのみを現在のバック バッファーにコピーします。 これらの領域が交差する場合、ランタイムはそれらの間の差のみをコピーします。 次の図とシーケンスでわかるように、フレーム 1 のダーティ四角形と、フレーム 2 のダーティ四角形の間の交差部分を、フレーム 2 のダーティ四角形にコピーする必要があります。

  1. フレーム 1ダーティ四角形を表示します。
  2. フレーム 1 のダーティ四角形と、フレーム 2 のダーティ四角形の間の交差部分を、フレーム 2 のダーティ四角形にコピーします。
  3. フレーム 2 内ダーティ四角形を表示します。

複数のフレームにわたってスクロールとダーティ四角形を追跡する

一般化するために、N バッファーを含むスワップ チェーンの場合、ランタイムが最後のフレームから現在のフレームの現在のフレームにコピーする領域は次のとおりです。

ランタイムがコピーする領域を計算する数式

ここで、buffer はスワップ チェーン内のバッファー インデックスを示し、現在のバッファー インデックスは 0 から始まります。

前のフレームと現在のフレームのダーティ四角形の間の交差部分を追跡するには、前のフレームのダーティ四角形のコピーを保持するか、前のフレームの適切なコンテンツを使用して新しいフレームのダーティ四角形を再レンダリングします。

同様に、スワップ チェーンに 2 つ以上のバック バッファーがある場合は、現在のバッファーのダーティの四角形と、前のすべてのフレームのダーティ四角形の間で重複する領域がコピーまたは再レンダリングされるようにする必要があります。

2 ダーティ四角形間の単一の交差を追跡する

最も単純なケースでは、フレームごとに 1 つのダーティ四角形を更新すると、2 つのフレームのダーティ四角形が交差する可能性があります。 前のフレームのダーティ四角形と現在のフレームのダーティ四角形が重なっているかどうかを確認するには、前のフレームのダーティ四角形が現在のフレームのダーティ四角形と交差しているかどうかを確認する必要があります。 GDI IntersectRect 関数を呼び出して、2 つのダーティ四角形を表す 2 つの RECT 構造体が交差するかどうかを判断できます。

このコード スニペットでは、IntersectRect を呼び出すと、dirtyRectCopy と呼ばれる別の RECT 内の 2 つのダーティ四角形の積集合が返されます。 コード スニペットは、2 つのダーティ四角形が交差することを判断した後、ID3D11DeviceContext1::CopySubresourceRegion1 メソッドを呼び出して、交差領域を現在のフレームにコピーします。

RECT dirtyRectPrev, dirtyRectCurrent, dirtyRectCopy;
 
if (IntersectRect( &dirtyRectCopy, &dirtyRectPrev, &dirtyRectCurrent ))
{
       D3D11_BOX intersectBox;
       intersectBox.left    = dirtyRectCopy.left;
       intersectBox.top     = dirtyRectCopy.top;
       intersectBox.front   = 0;
       intersectBox.right   = dirtyRectCopy.right;
       intersectBox.bottom  = dirtyRectCopy.bottom;
       intersectBox.back    = 1;
 
       d3dContext->CopySubresourceRegion1(pBackbuffer,
                                    0,
                                    0,
                                    0,
                                    0,
                                    pPrevBackbuffer,
                                    0,
                                    &intersectBox,
                                    0
                                    );
}

// Render additional content to the current pBackbuffer and call Present1.

アプリケーションでこのコード スニペットを使用すると、アプリは IDXGISwapChain1::P resent1 を呼び出して、現在のフレームを現在のダーティ四角形で更新する準備が整います。

N ダーティ四角形間の交差を追跡する

複数のダーティ四角形 (新しく表示されたスクロールラインの四角形をフレームごとにダーティ含めることができる) を指定する場合は、前のフレームのすべてのダーティ四角形と現在のフレームのすべてのダーティ四角形の間で発生する可能性のある重複を確認して追跡する必要があります。 前のフレームのダーティ四角形と現在のフレームのダーティ四角形の間の交差部分を計算するには、ダーティの四角形を領域にグループ化します。

このコード スニペットでは、GDI SetRectRgn 関数を呼び出して、各ダーティ四角形を四角形の領域に変換し、GDI CombineRgn 関数を呼び出して、ダーティのすべての四角形領域をグループに結合します。

HRGN hDirtyRgnPrev, hDirtyRgnCurrent, hRectRgn; // Handles to regions 
// Save all the dirty rectangles from the previous frame.
 
RECT dirtyRect[N]; // N is the number of dirty rectangles in current frame, which includes newly scrolled area.
 
int iReturn;
SetRectRgn(hDirtyRgnCurrent, 
       dirtyRect[0].left, 
       dirtyRect[0].top, 
       dirtyRect[0].right, 
       dirtyRect[0].bottom 
       );

for (int i = 1; i<N; i++)
{
   SetRectRgn(hRectRgn, 
          dirtyRect[0].left, 
          dirtyRect[0].top, 
          dirtyRect[0].right, 
          dirtyRect[0].bottom 
          );

   iReturn = CombineRgn(hDirtyRgnCurrent,
                        hDirtyRgnCurrent,
                        hRectRgn,
                        RGN_OR
                        );
   // Handle the error that CombineRgn returns for iReturn.
}

GDI CombineRgn 関数を使用して、前のフレームのダーティ領域と現在のフレームのダーティ領域の交差部分を決定できるようになりました。 交差する領域を取得した後、GDI GetRegionData 関数を呼び出して交差する領域から個々の四角形を取得し 、ID3D11DeviceContext1::CopySubresourceRegion1 メソッドを呼び出して、交差する各四角形を現在のバック バッファーにコピーします。 次のコード スニペットは、これらの GDI 関数と Direct3D 関数の使用方法を示しています。

HRGN hIntersectRgn;
bool bRegionsIntersect;
iReturn = CombineRgn(hIntersectRgn, hDirtyRgnCurrent, hDirtyRgnPrev, RGN_AND);
if (iReturn == ERROR)
{
       // Handle error.
}
else if(iReturn == NULLREGION)
{
       bRegionsIntersect = false;
}
else
{
       bRegionsIntersect = true;
}
 
if (bRegionsIntersect)
{
       int rgnDataSize = GetRegionData(hIntersectRgn, 0, NULL);
       if (rgnDataSize)
       {
              char pMem[] = new char[size];
              RGNDATA* pRgnData = reinterpret_cast<RGNDATA*>(pMem);
              iReturn = GetRegionData(hIntersectRgn, rgnDataSize, pRgnData);
              // Handle iReturn failure.
 
              for (int rectcount = 0; rectcount < pRgnData->rdh.nCount; ++r)
              {
                     const RECT* pIntersectRect = reinterpret_cast<RECT*>(pRgnData->Buffer) +                                            
                                                  rectcount;                
                     D3D11_BOX intersectBox;
                     intersectBox.left    = pIntersectRect->left;
                     intersectBox.top     = pIntersectRect->top;
                     intersectBox.front   = 0;
                     intersectBox.right   = pIntersectRect->right;
                     intersectBox.bottom  = pIntersectRect->bottom;
                     intersectBox.back    = 1;
 
                     d3dContext->CopySubresourceRegion1(pBackbuffer,
                                                      0,
                                                      0,
                                                      0,
                                                      0,
                                                      pPrevBackbuffer,
                                                      0,
                                                      &intersectBox,
                                                      0
                                                      );
              }

              delete [] pMem;
       }
}

ダーティ四角形を使用したビットblt モデルスワップ チェーン

ビットブル モデル (DXGI_SWAP_EFFECT_SEQUENTIAL で設定) で実行される DXGI スワップ チェーンでダーティ四角形を使用できます。 複数のバッファーを使用するビットblt モデル スワップ チェーンでは、「モデル スワップ チェーンを反転するには、複数のフレームで四角形ダーティ追跡し、四角形をスクロールする」で説明されているのと同じ方法で、フレーム間で重複するダーティの四角形も追跡する必要があります。 バッファーが 1 つだけの Bitblt モデル スワップ チェーンでは、バッファー全体がフレームごとに再描画されるため、重複ダーティ四角形を追跡する必要はありません。

DXGI 1.2 の機能強化