スワップ チェーン (Swap Chain) を用いた複数のビューによる表示

スワップ チェーンを利用することで、1つのデバイスから複数のビューを表示できます。スワップ チェーンとは本質的には、レンダリングを制御するための連続したバッファです。

スワップ チェーンを用いたレンダリング手順

  1. スワップ チェーンの作成
    1. プレゼンテーション パラメータを作成する。
    2. それを使用してスワップ チェーンを作成する。
  2. スワップ チェーンからレンダリング
    1. スワップ チェーンからバックバッファを取得する。
    2. それをデバイスのレンダリングターゲットにする。
    3. 通常のレンダリング処理を行う。
    4. スワップ チェーンのバックバッファから表示する。
SwapChainのプロパティ
プロパティ 内容
Device Device スワップ チェーンに関連付けられているデバイス
DisplayMode DisplayMode ディスプレイ モードの空間解像度、色解像度、リフレッシュ周波数
Disposed bool オブジェクトが解放されているかどうか
PresentParameters PresentParameters スワップ チェーンに関連付けられているプレゼンテーション パラメータ
RasterStatus RasterStatus スワップ チェーンが表示されているモニタのラスタを記述する情報
UnmanagedComPointer    

スワップ チェーンの作成

プレゼンテーション パラメータの作成

デバイスの作成時と同様に、プレゼンテーション パラメータを作成します。

このときBackBufferWidthかBackBufferHeightに0を設定すると、スワップ チェーンの作成時にそれらはDeviceWindowのクライアント領域のサイズに設定され直されます。

スワップ チェーンの作成

SwapChainクラスのコンストラクタから作成します。

public SwapChain(
    Device device,   // スワップ チェーンを関連付けるデバイス
    PresentParameters presentationParameters    // プレゼンテーション パラメータ
);
※Unmanagedでは、DeviceのインスタンスからIDirect3DDevice9::CreateAdditionalSwapChain()メソッドで作成します。

なおデバイスの作成時、既定で1つのスワップ チェーン (the implicit swap chain) が作成されます。このスワップ チェーンはDevice.GetSwapChain()メソッドで取得できます。

public SwapChain GetSwapChain(
    int swapChain  // スワップ チェーンのインデックス
);

スワップ チェーンからレンダリング

スワップ チェーンからバックバッファを取得

SwapChain.GetBackBuffer()メソッドで、スワップ チェーンからバックバッファを取得します。バックバッファはサーフェスの照会を行うためのクラスであるSurfaceクラスで返されます。

DirectX 9ではステレオビューがサポートされないため、typeBufferにはつねにMonoを指定します。

public Surface GetBackBuffer(
    int backBuffer,           // 取得するバックバッファのインデックス
    BackBufferType typeBuffer // バックバッファの種類
);
BackBufferType 列挙型
列挙子 説明
Mono ステレオではないスワップ チェーン
Right サポートされない
Left サポートされない

デバイスのレンダリングターゲットの設定

レンダリングがスワップ チェーンに対して行われるように、Device.SetRenderTargetで先に取得したスワップ チェーンのバックバッファをデバイスに設定します。

public void SetRenderTarget(
    int renderTargetIndex, // レンダリング対象のインデックス
    Surface renderTarget   // レンダリング対象のバックバッファ
);
Device.SetRenderTarget(Int32,Surface) Method (Microsoft.DirectX.Direct3D) | MSDN

この後は通常のレンダリングと同様に、Device.BeginSceneからDevice.EndSceneまで処理します。

アスペクト比の問題

複数のコントロールに描画するとき、それらのコントロールのクライアント領域のアスペクト比が異なるならば、視野錐台を設定し直してアスペクト比を修正します。

なおレンダリングターゲットに設定されているコントロールのクライアント領域のサイズは、DeviceインスタンスのViewportプロパティから取得できます。

スワップ チェーンをバックバッファから表示

既定で作成されるスワップ チェーンの表示はDevice.Presentメソッドを使用しますが、明示的に作成したそれはSwapChain.Presentにより行います。

public void Present(
    Control overrideWindow  //
);

サンプルコード

// スワップ チェーンからバックバッファを取得
using( Surface surface = this.swapChain.GetBackBuffer( 0, BackBufferType.Mono ) )
{
    // デバイスのレンダリングターゲットの設定
    this.device.SetRenderTarget( 0, surface );
}


// (レンダリング対象のコントロールによってアスペクト比が
//  異なるならば、Transform.Projectionを設定し直す)

// 通常の描画処理


// 表示
this.swapChain.Present( targetControl );

ウィンドウのリサイズへの対処

デバイスに関連付けられたウィンドウがリサイズされると、スワップ チェーンは無効な状態となります。よってそのときには、スワップ チェーンを再生成する必要があります。

ウィンドウのリサイズはDevice.DeviceResizingイベントでハンドルできるので、そこでスワップ チェーンを作成します。またはスワップ チェーンが無効にされるとSwapChain.Disposedがtrueに設定されるので、それを確認することでも行えます。

深度ステンシルの作成

作成したスワップ チェーンのバックバッファの大きさが、既定のスワップ チェーンのそれを超えると超えると、レンダリングを正しく行えなくなります。

既定のスワップ チェーンの大きさは、Device.DepthStencilSurface.DescriptionのSurfaceDescription構造体から取得できます。

また深度ステンシルは、Device.CreateDepthStencilSurfaceで作成できます。

public Surface CreateDepthStencilSurface(
    int width,                   // 深度ステンシルの幅
    int height,                  // 深度ステンシルの高さ
    DepthFormat format,          // 深度ステンシルのフォーマット
    MultiSampleType multiSample, // マルチサンプリングの種類
    int multiSampleQuality,      // マルチサンプリングの品質レベル
    bool discard                 // バッファの自動破棄を有効にするかどうか
);
Device.CreateDepthStencilSurface | MSDN