這幾天在做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; }