Direct3D 设备管理器

Microsoft Direct3D 设备管理器允许两个或多个对象共享同一个 Microsoft Direct3D 9 设备。 一个对象充当 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