次の方法で共有


Direct2D と Direct3D の相互運用性に関する概要

ハードウェア アクセラレータ付き 2-D および 3-D グラフィックスは、非ゲーム アプリケーションの一部になりつつあります。ほとんどのゲーム アプリケーションでは、メニューやHeads-Upディスプレイ (HUD) の形式で 2-D グラフィックスを使用しています。 従来の 2-D レンダリングを Direct3D レンダリングと効率的に混合できるようにすることで、多くの価値を追加できます。

このトピックでは、Direct2D と Direct3D を使用して 2-D および 3-D グラフィックスを統合する方法について説明します。

前提条件

この概要では、基本的な Direct2D 描画操作について理解していることを前提としています。 チュートリアルについては、「 単純な Direct2D アプリケーションを作成する」を参照してください。 また、 Direct3D 10.1 を使用してプログラミングできることを前提としています。

サポートされている Direct3D バージョン

DirectX 11.0 では、Direct2D では Direct3D 10.1 デバイスとの相互運用性のみがサポートされます。 DirectX 11.1 以降では、Direct2D では Direct3D 11 との相互運用性もサポートされています。

DXGI による相互運用性

Direct3D 10 の時点では、Direct3D ランタイムはリソース管理に DXGI を使用します。 DXGI ランタイム レイヤーは、ビデオ メモリ サーフェスのクロスプロセス共有を提供し、他のビデオ メモリ ベースのランタイム プラットフォームの基盤として機能します。 Direct2D では、DXGI を使用して Direct3D と相互運用します。

Direct2D と Direct3D を一緒に使用するには、主に次の 2 つの方法があります。

  • Direct2D サーフェスに Direct2D コンテンツを書き込むには、 IDXGISurface を取得し、 CreateDxgiSurfaceRenderTarget でそれを使用して ID2D1RenderTarget を作成します。 その後、レンダー ターゲットを使用して、3 次元グラフィックスに 2 次元インターフェイスまたは背景を追加したり、3 次元オブジェクトのテクスチャとして Direct2D 描画を使用したりできます。
  • CreateSharedBitmap を使用して IDXGISurface から ID2D1Bitmap を作成すると、Direct3D シーンをビットマップに書き込み、Direct2D でレンダリングできます。

DXGI サーフェス レンダー ターゲットを使用して Direct3D サーフェスに書き込む

Direct3D サーフェスに書き込むには、 IDXGISurface を取得し、 CreateDxgiSurfaceRenderTarget メソッドに渡して DXGI サーフェス レンダー ターゲットを作成します。 その後、DXGI サーフェス レンダー ターゲットを使用して、DXGI サーフェスに 2-D コンテンツを描画できます。

DXGI サーフェス レンダー ターゲットは、 ID2D1RenderTarget の一種です。 他の Direct2D レンダー ターゲットと同様に、それを使用してリソースを作成し、描画コマンドを発行できます。

DXGI サーフェス レンダー ターゲットと DXGI サーフェスは、同じ DXGI 形式を使用する必要があります。 レンダー ターゲットの作成時に DXGI_FORMAT_UNKOWN 形式を指定すると、サーフェスの形式が自動的に使用されます。

DXGI サーフェス レンダー ターゲットは、DXGI サーフェス同期を実行しません。

DXGI サーフェスの作成

Direct3D 10 では、DXGI サーフェスを取得する方法はいくつかあります。 デバイスの IDXGISwapChain を 作成し、スワップ チェーンの GetBuffer メソッドを使用して DXGI サーフェスを取得できます。 または、デバイスを使用してテクスチャを作成し、そのテクスチャを DXGI サーフェスとして使用することもできます。

DXGI サーフェスの作成方法に関係なく、サーフェスでは DXGI サーフェス レンダー ターゲットでサポートされている DXGI 形式のいずれかを使用する必要があります。 一覧については、「 サポートされているピクセル形式とアルファ モード」を参照してください。

さらに、DXGI サーフェスに関連付けられている ID3D10Device1 は、サーフェスが Direct2D で動作するために BGRA DXGI 形式をサポートする必要があります。 このサポートを確保するには、D3D10CreateDevice1 メソッドを呼び出してデバイスを作成するときに、D3D10_CREATE_DEVICE_BGRA_SUPPORT フラグを使用します。

次のコードでは、 ID3D10Device1 を作成するメソッドを定義します。 使用可能な最適な機能レベルを選択し、ハードウェア レンダリングが使用できない場合は Windows Advanced Rasterization Platform (WARP) にフォールバックします。

HRESULT DXGISampleApp::CreateD3DDevice(
    IDXGIAdapter *pAdapter,
    D3D10_DRIVER_TYPE driverType,
    UINT flags,
    ID3D10Device1 **ppDevice
    )
{
    HRESULT hr = S_OK;

    static const D3D10_FEATURE_LEVEL1 levelAttempts[] =
    {
        D3D10_FEATURE_LEVEL_10_0,
        D3D10_FEATURE_LEVEL_9_3,
        D3D10_FEATURE_LEVEL_9_2,
        D3D10_FEATURE_LEVEL_9_1,
    };

    for (UINT level = 0; level < ARRAYSIZE(levelAttempts); level++)
    {
        ID3D10Device1 *pDevice = NULL;
        hr = D3D10CreateDevice1(
            pAdapter,
            driverType,
            NULL,
            flags,
            levelAttempts[level],
            D3D10_1_SDK_VERSION,
            &pDevice
            );

        if (SUCCEEDED(hr))
        {
            // transfer reference
            *ppDevice = pDevice;
            pDevice = NULL;
            break;
        }
    }

    return hr;
}

次のコード例では、前の例で示した CreateD3DDevice メソッドを使用して、Direct2D で使用する DXGI サーフェスを作成できる Direct3D デバイスを作成します。

// Create device
hr = CreateD3DDevice(
    NULL,
    D3D10_DRIVER_TYPE_HARDWARE,
    nDeviceFlags,
    &pDevice
    );

if (FAILED(hr))
{
    hr = CreateD3DDevice(
        NULL,
        D3D10_DRIVER_TYPE_WARP,
        nDeviceFlags,
        &pDevice
        );
}

スワップ チェーン バッファーへの Direct2D コンテンツの書き込み

Direct2D コンテンツを Direct3D シーンに追加する最も簡単な方法は、IDXGISwapChainGetBuffer メソッドを使用して DXGI サーフェスを取得し、CreateDxgiSurfaceRenderTarget メソッドでサーフェスを使用して、2-D コンテンツを描画する ID2D1RenderTarget を作成することです。

この方法では、コンテンツは 3 次元でレンダリングされません。遠近法や奥行きはありません。 ただし、いくつかの一般的なタスクに役立ちます。

  • 3-D シーンの 2-D 背景を作成する。
  • 3-D シーンの前に 2-D インターフェイスを作成する。
  • Direct2D コンテンツをレンダリングするときに Direct3D マルチサンプリングを使用する。

次のセクションでは、3-D シーンの 2-D 背景を作成する方法を示します。

例: 2-D 背景を描画する

次の手順では、DXGI サーフェス レンダー ターゲットを作成し、それを使用してグラデーションの背景を描画する方法について説明します。

  1. CreateSwapChain メソッドを使用して、ID3D10Device1 (m_pDevice 変数) のスワップ チェーンを作成します。 スワップ チェーンでは、 DXGI_FORMAT_B8G8R8A8_UNORM DXGI 形式が使用されます。これは、Direct2D でサポートされている DXGI 形式の 1 つです。

    if (SUCCEEDED(hr))
    {
        hr = pDevice->QueryInterface(&m_pDevice);
    }
    if (SUCCEEDED(hr))
    {
        hr = pDevice->QueryInterface(&pDXGIDevice);
    }
    if (SUCCEEDED(hr))
    {
        hr = pDXGIDevice->GetAdapter(&pAdapter);
    }
    if (SUCCEEDED(hr))
    {
        hr = pAdapter->GetParent(IID_PPV_ARGS(&pDXGIFactory));
    }
    if (SUCCEEDED(hr))
    {
        DXGI_SWAP_CHAIN_DESC swapDesc;
        ::ZeroMemory(&swapDesc, sizeof(swapDesc));
    
        swapDesc.BufferDesc.Width = nWidth;
        swapDesc.BufferDesc.Height = nHeight;
        swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
        swapDesc.BufferDesc.RefreshRate.Numerator = 60;
        swapDesc.BufferDesc.RefreshRate.Denominator = 1;
        swapDesc.SampleDesc.Count = 1;
        swapDesc.SampleDesc.Quality = 0;
        swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
        swapDesc.BufferCount = 1;
        swapDesc.OutputWindow = m_hwnd;
        swapDesc.Windowed = TRUE;
    
        hr = pDXGIFactory->CreateSwapChain(m_pDevice, &swapDesc, &m_pSwapChain);
    }
    
  2. DXGI サーフェスを取得するには、スワップ チェーンの GetBuffer メソッドを使用します。

    // Get a surface in the swap chain
    hr = m_pSwapChain->GetBuffer(
        0,
        IID_PPV_ARGS(&pBackBuffer)
        );
    
  3. DXGI サーフェスを使用して DXGI レンダー ターゲットを作成します。

    // Initialize *hwnd* with the handle of the window displaying the rendered content.
    HWND hwnd;
    
    // Create the DXGI Surface Render Target.
    float dpi = GetDpiForWindow(hwnd);
    
    D2D1_RENDER_TARGET_PROPERTIES props =
        D2D1::RenderTargetProperties(
            D2D1_RENDER_TARGET_TYPE_DEFAULT,
            D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
            dpiX,
            dpiY);
    
    // Create a Direct2D render target that can draw into the surface in the swap chain
    
    hr = m_pD2DFactory->CreateDxgiSurfaceRenderTarget(
        pBackBuffer,
        &props,
        &m_pBackBufferRT);
    
  4. レンダー ターゲットを使用してグラデーションの背景を描画します。

    // Swap chain will tell us how big the back buffer is
    DXGI_SWAP_CHAIN_DESC swapDesc;
    hr = m_pSwapChain->GetDesc(&swapDesc);
    
    if (SUCCEEDED(hr))
    {
        // Draw a gradient background.
        if (m_pBackBufferRT)
        {
            D2D1_SIZE_F targetSize = m_pBackBufferRT->GetSize();
    
            m_pBackBufferRT->BeginDraw();
    
            m_pBackBufferGradientBrush->SetTransform(
                D2D1::Matrix3x2F::Scale(targetSize)
                );
    
            D2D1_RECT_F rect = D2D1::RectF(
                0.0f,
                0.0f,
                targetSize.width,
                targetSize.height
                );
    
            m_pBackBufferRT->FillRectangle(&rect, m_pBackBufferGradientBrush);
    
            hr = m_pBackBufferRT->EndDraw();
        }
    ...
    

このサンプルではコードを省略します。

Direct2D コンテンツをテクスチャとして使用する

Direct3D で Direct2D コンテンツを使用するもう 1 つの方法は、Direct2D を使用して 2-D テクスチャを生成し、そのテクスチャを 3-D モデルに適用することです。 これを行うには、 ID3D10Texture2D を作成し、テクスチャから DXGI サーフェスを取得し、そのサーフェスを使用して DXGI サーフェス レンダー ターゲットを作成します。 ID3D10Texture2D サーフェスでは、D3D10_BIND_RENDER_TARGETバインド フラグを使用し、DXGI サーフェス レンダー ターゲットでサポートされている DXGI 形式を使用する必要があります。 サポートされている DXGI 形式の一覧については、「 サポートされているピクセル形式とアルファ モード」を参照してください。

例: Direct2D コンテンツをテクスチャとして使用する

次の例では、2-D テクスチャ ( ID3D10Texture2D で表される) にレンダリングする DXGI サーフェス レンダー ターゲットを作成する方法を示します。

  1. まず、Direct3D デバイスを使用して 2-D テクスチャを作成します。 テクスチャでは 、D3D10_BIND_RENDER_TARGETD3D10_BIND_SHADER_RESOURCE バインド フラグが使用され、Direct2D でサポートされている DXGI 形式の 1 つである DXGI_FORMAT_B8G8R8A8_UNORM DXGI 形式が使用されます。

    // Allocate an offscreen D3D surface for D2D to render our 2D content into
    D3D10_TEXTURE2D_DESC texDesc;
    texDesc.ArraySize = 1;
    texDesc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
    texDesc.CPUAccessFlags = 0;
    texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
    texDesc.Height = 512;
    texDesc.Width = 512;
    texDesc.MipLevels = 1;
    texDesc.MiscFlags = 0;
    texDesc.SampleDesc.Count = 1;
    texDesc.SampleDesc.Quality = 0;
    texDesc.Usage = D3D10_USAGE_DEFAULT;
    
    hr = m_pDevice->CreateTexture2D(&texDesc, NULL, &m_pOffscreenTexture);
    
  2. テクスチャを使用して DXGI サーフェスを取得します。

    IDXGISurface *pDxgiSurface = NULL;
    
    hr = m_pOffscreenTexture->QueryInterface(&pDxgiSurface);
    
  3. CreateDxgiSurfaceRenderTarget メソッドでサーフェスを使用して、Direct2D レンダー ターゲットを取得します。

    if (SUCCEEDED(hr))
    {
        // Create a D2D render target that can draw into our offscreen D3D
        // surface. Given that we use a constant size for the texture, we
        // fix the DPI at 96.
        D2D1_RENDER_TARGET_PROPERTIES props =
            D2D1::RenderTargetProperties(
                D2D1_RENDER_TARGET_TYPE_DEFAULT,
                D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
                96,
                96);
    
        hr = m_pD2DFactory->CreateDxgiSurfaceRenderTarget(
                pDxgiSurface,
                &props,
                &m_pRenderTarget);
    }
    

Direct2D レンダー ターゲットを取得し、Direct3D テクスチャに関連付けたので、レンダー ターゲットを使用してそのテクスチャに Direct2D コンテンツを描画し、そのテクスチャを Direct3D プリミティブに適用できます。

このサンプルではコードを省略します。

DXGI サーフェス レンダー ターゲットのサイズ変更

DXGI サーフェス レンダー ターゲットでは 、ID2D1RenderTarget::Resize メソッドはサポートされていません。 DXGI サーフェス レンダー ターゲットのサイズを変更するには、アプリケーションがそれを解放して再作成する必要があります。

この操作によって、パフォーマンスの問題が発生する可能性があります。 レンダー ターゲットは、レンダー ターゲットの DXGI サーフェスに関連付けられている ID3D10Device1 への参照を保持する最後のアクティブな Direct2D リソースである可能性があります。 アプリケーションがレンダー ターゲットを解放し、 ID3D10Device1 参照が破棄された場合は、新しい参照を再作成する必要があります。

レンダリング ターゲットを再作成するときに、レンダー ターゲットによって作成された Direct2D リソースを少なくとも 1 つ保持することで、このコストの高い可能性がある操作を回避できます。 このアプローチに適した Direct2D リソースを次に示します。

この方法に対応するには、サイズ変更メソッドで Direct3D デバイスが使用可能かどうかをテストする必要があります。 使用可能な場合は、DXGI サーフェス レンダー ターゲットを解放して再作成しますが、以前に作成したすべてのリソースを保持し、再利用します。 これは、「 リソースの概要」で説明されているように、両方のレンダー ターゲットが同じ Direct3D デバイスに関連付けられている場合、2 つのレンダー ターゲットによって作成されたリソースに互換性があるためです。

サポートされているピクセル形式とアルファ モード

CreateDxgiSurfaceRenderTarget

Windows DirectX グラフィックス