Direct3D设备管理器(Direct3D device manager)
这几天在做dxva2硬件加速,找不到什么资料,翻译了一下微软的两篇相关文档。并准备记录一下用ffmpeg实现dxva2,将在第三篇写到。这是第一篇,英文原址:https://msdn.microsoft.com/en-us/library/aa965267(v=vs.85).aspx
Direct3D设备管理器(Direct3D device manager)允许两个或多个对象(object)共用同一个Direct3D 9 设备(device)。其中一个对象作为Direct3D 9 设备的拥有者。要能共享设备,拥有设备的对象(the owner)要创建Direct3D设备管理器,其他对象可以获得一个指向这个设备管理器的指针,然后通过设备管理器获得一个指向Direct3D 设备的指针。每个使用这个设备的的对象都有一个互斥锁,防止与其他设备同时使用这个设备。(我的注释:即一次只能有一个对象使用设备,不能两个对象同时使用同一个设备。这就是锁的互斥功能)
注意:Direct3D 设备管理器只支持Direct3D 9 设备。不支持DXGI 设备.
要创建Direct3D 设备管理器, 需要调用DXVA2CreateDirect3DDeviceManager9函数。这个函数返回一个指向这个创建的设备管理器的IDirect3DDeviceManager9接口的指针,以及一个重置标志(reset token)。重置标志使得使用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关闭设备句柄。
你应当只在使用设备的时候才设置设备锁(the device lock),因为设置设备锁会阻止其他对象使用设备。(我的注释:这一点如果有疑惑,百度一下互斥锁的定义就会明白了,就是一个防止多个对象同时使用同一个设备导致混乱的互斥机制)
拥有设备的对象(the ownder)可以通过调用ResetDevice函数在任意时候切换到其他设备,特别地,在原始设备丢失的情况下。设备丢失可以由各种原因造成,包括改变显示器分辨率,电源管理操作,锁定或解锁电脑,等等。更多情况,请转Direct3D文档。
ResetDevice函数会把任何之前打开的设备句柄置为无效。设备无效后,LockDevice函数返回DXVA2_E_NEW_VIDEO_DEVICE。如果发生这种情况,关闭句柄并再次调用OpenDeviceHandle以重新获得新的设备句柄,如以下代码锁展示的。
下面的例子展示了如何打开设备句柄和锁设备(lock the device)。
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; }