Direct3D デバイス マネージャー

Microsoft Direct3D デバイス マネージャーを使用すると、2 つ以上のオブジェクトで同じ Microsoft Direct3D 9 デバイスを共有できます。 1 つのオブジェクトが Direct3D 9 デバイスの所有者として機能します。 デバイスを共有するために、デバイスの所有者が Direct3D デバイス マネージャーを作成します。 他のオブジェクトは、デバイス所有者からデバイス マネージャーへのポインターを取得し、デバイス マネージャーを使用して Direct3D デバイスへのポインターを取得できます。 デバイスを使用するオブジェクトは排他ロックを保持するため、他のオブジェクトが同時にデバイスを使用できなくなります。

注意

Direct3D デバイス マネージャーでは、Direct3D 9 デバイスのみがサポートされます。 DXGI デバイスはサポートされていません。

 

Direct3D デバイス マネージャーを作成するには、 DXVA2CreateDirect3DDeviceManager9 を呼び出します。 この関数は、デバイス マネージャーの IDirect3DDeviceManager9 インターフェイスへのポインターとリセット トークンを返します。 リセット トークンを使用すると、Direct3D デバイスの所有者はデバイス マネージャーでデバイスを設定 (およびリセット) できます。 デバイス マネージャーを初期化するには、 IDirect3DDeviceManager9::ResetDevice を呼び出します。 リセット トークンと共に、Direct3D デバイスへのポインターを渡します。

次のコードは、デバイス マネージャーを作成して初期化する方法を示しています。

HRESULT CreateD3DDeviceManager(
    IDirect3DDevice9 *pDevice, 
    UINT *pReset, 
    IDirect3DDeviceManager9 **ppManager
    )
{
    UINT resetToken = 0;

    IDirect3DDeviceManager9 *pD3DManager = NULL;

    HRESULT hr = DXVA2CreateDirect3DDeviceManager9(&resetToken, &pD3DManager);

    if (FAILED(hr))
    {
        goto done;
    }

    hr = pD3DManager->ResetDevice(pDevice, resetToken);

    if (FAILED(hr))
    {
        goto done;
    }

    *ppManager = pD3DManager;
    (*ppManager)->AddRef();

    *pReset = resetToken;


done:
    SafeRelease(&pD3DManager);
    return hr;
}

デバイス所有者は、他のオブジェクトが IDirect3DDeviceManager9 インターフェイスへのポインターを取得する方法を提供する必要があります。 標準的なメカニズムは、 IMFGetService インターフェイスを実装することです。 サービス GUID がMR_VIDEO_ACCELERATION_SERVICE。

複数のオブジェクト間でデバイスを共有するには、次のように、各オブジェクト (デバイスの所有者を含む) がデバイス マネージャーを介してデバイスにアクセスする必要があります。

  1. IDirect3DDeviceManager9::OpenDeviceHandle を呼び出して、デバイスへのハンドルを取得します。
  2. デバイスを使用するには、 IDirect3DDeviceManager9::LockDevice を呼び出し、デバイス ハンドルを渡します。 メソッドは、 IDirect3DDevice9 インターフェイスへのポインターを返します。 メソッドは、 fBlock パラメーターの値に応じて、ブロッキング モードまたは非ブロッキング モードで呼び出すことができます。
  3. デバイスの使用が完了したら、 IDirect3DDeviceManager9::UnlockDevice を呼び出します。 このメソッドを使用すると、デバイスを他のオブジェクトで使用できるようになります。
  4. 終了する前に、 IDirect3DDeviceManager9::CloseDeviceHandle を呼び出してデバイス ハンドルを閉じます。

デバイス ロックを保持すると、他のオブジェクトがデバイスを使用できなくなるため、デバイスの使用中にのみデバイス ロックを保持する必要があります。

デバイスの所有者は、 ResetDevice を呼び出すことによって、いつでも別のデバイスに切り替えることができます。通常は、元のデバイスが失われたためです。 デバイスの損失は、モニターの解像度の変更、電源管理アクション、コンピューターのロックとロック解除など、さまざまな理由で発生する可能性があります。 詳細については、Direct3D のドキュメントを参照してください。

ResetDevice メソッドは、以前に開いたデバイス ハンドルを無効にします。 デバイス ハンドルが無効な場合、 LockDevice メソッドは DXVA2_E_NEW_VIDEO_DEVICEを返します。 この場合は、次のコードに示すように、ハンドルを閉じて OpenDeviceHandle をもう一度呼び出して、新しいデバイス ハンドルを取得します。

次の例は、デバイス ハンドルを開いてデバイスをロックする方法を示しています。

HRESULT LockDevice(
    IDirect3DDeviceManager9 *pDeviceManager,
    BOOL fBlock,
    IDirect3DDevice9 **ppDevice, // Receives a pointer to the device.
    HANDLE *pHandle              // Receives a device handle.   
    )
{
    *pHandle = NULL;
    *ppDevice = NULL;

    HANDLE hDevice = 0;

    HRESULT hr = pDeviceManager->OpenDeviceHandle(&hDevice);

    if (SUCCEEDED(hr))
    {
        hr = pDeviceManager->LockDevice(hDevice, ppDevice, fBlock);
    }

    if (hr == DXVA2_E_NEW_VIDEO_DEVICE)
    {
        // Invalid device handle. Try to open a new device handle.
        hr = pDeviceManager->CloseDeviceHandle(hDevice);

        if (SUCCEEDED(hr))
        {
            hr = pDeviceManager->OpenDeviceHandle(&hDevice);
        }

        // Try to lock the device again.
        if (SUCCEEDED(hr))
        {
            hr = pDeviceManager->LockDevice(hDevice, ppDevice, TRUE); 
        }
    }

    if (SUCCEEDED(hr))
    {
        *pHandle = hDevice;
    }
    return hr;
}

DirectX ビデオ アクセラレータ 2.0