common_directx11.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. #include "common_directx11.h"
  2. #include <map>
  3. ID3D11Device *g_pD3D11Device;
  4. ID3D11DeviceContext *g_pD3D11Ctx;
  5. IDXGIFactory2 *g_pDXGIFactory;
  6. IDXGIAdapter *g_pAdapter;
  7. std::map<mfxMemId *, mfxHDL> allocResponses;
  8. std::map<mfxHDL, mfxFrameAllocResponse> allocDecodeResponses;
  9. std::map<mfxHDL, int> allocDecodeRefCount;
  10. typedef struct {
  11. mfxMemId memId;
  12. mfxMemId memIdStage;
  13. mfxU16 rw;
  14. } CustomMemId;
  15. const struct {
  16. mfxIMPL impl; // actual implementation
  17. mfxU32 adapterID; // device adapter number
  18. } implTypes[] = {{MFX_IMPL_HARDWARE, 0},
  19. {MFX_IMPL_HARDWARE2, 1},
  20. {MFX_IMPL_HARDWARE3, 2},
  21. {MFX_IMPL_HARDWARE4, 3}};
  22. // =================================================================
  23. // DirectX functionality required to manage DX11 device and surfaces
  24. //
  25. IDXGIAdapter *GetIntelDeviceAdapterHandle(mfxSession session)
  26. {
  27. mfxU32 adapterNum = 0;
  28. mfxIMPL impl;
  29. MFXQueryIMPL(session, &impl);
  30. mfxIMPL baseImpl = MFX_IMPL_BASETYPE(
  31. impl); // Extract Media SDK base implementation type
  32. // get corresponding adapter number
  33. for (mfxU8 i = 0; i < sizeof(implTypes) / sizeof(implTypes[0]); i++) {
  34. if (implTypes[i].impl == baseImpl) {
  35. adapterNum = implTypes[i].adapterID;
  36. break;
  37. }
  38. }
  39. HRESULT hres = CreateDXGIFactory1(__uuidof(IDXGIFactory2),
  40. (void **)(&g_pDXGIFactory));
  41. if (FAILED(hres))
  42. return NULL;
  43. IDXGIAdapter *adapter;
  44. hres = g_pDXGIFactory->EnumAdapters(adapterNum, &adapter);
  45. if (FAILED(hres))
  46. return NULL;
  47. return adapter;
  48. }
  49. // Create HW device context
  50. mfxStatus CreateHWDevice(mfxSession session, mfxHDL *deviceHandle, HWND hWnd,
  51. bool bCreateSharedHandles)
  52. {
  53. //Note: not using bCreateSharedHandles for DX11 -- for API consistency only
  54. hWnd; // Window handle not required by DX11 since we do not showcase rendering.
  55. bCreateSharedHandles; // For rendering, not used here. Just for consistencies sake.
  56. HRESULT hres = S_OK;
  57. static D3D_FEATURE_LEVEL FeatureLevels[] = {D3D_FEATURE_LEVEL_11_1,
  58. D3D_FEATURE_LEVEL_11_0,
  59. D3D_FEATURE_LEVEL_10_1,
  60. D3D_FEATURE_LEVEL_10_0};
  61. D3D_FEATURE_LEVEL pFeatureLevelsOut;
  62. g_pAdapter = GetIntelDeviceAdapterHandle(session);
  63. if (NULL == g_pAdapter)
  64. return MFX_ERR_DEVICE_FAILED;
  65. UINT dxFlags = 0;
  66. //UINT dxFlags = D3D11_CREATE_DEVICE_DEBUG;
  67. hres = D3D11CreateDevice(
  68. g_pAdapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, dxFlags,
  69. FeatureLevels,
  70. (sizeof(FeatureLevels) / sizeof(FeatureLevels[0])),
  71. D3D11_SDK_VERSION, &g_pD3D11Device, &pFeatureLevelsOut,
  72. &g_pD3D11Ctx);
  73. if (FAILED(hres))
  74. return MFX_ERR_DEVICE_FAILED;
  75. // turn on multithreading for the DX11 context
  76. CComQIPtr<ID3D10Multithread> p_mt(g_pD3D11Ctx);
  77. if (p_mt)
  78. p_mt->SetMultithreadProtected(true);
  79. else
  80. return MFX_ERR_DEVICE_FAILED;
  81. *deviceHandle = (mfxHDL)g_pD3D11Device;
  82. return MFX_ERR_NONE;
  83. }
  84. void SetHWDeviceContext(CComPtr<ID3D11DeviceContext> devCtx)
  85. {
  86. g_pD3D11Ctx = devCtx;
  87. devCtx->GetDevice(&g_pD3D11Device);
  88. }
  89. // Free HW device context
  90. void CleanupHWDevice()
  91. {
  92. if (g_pAdapter) {
  93. g_pAdapter->Release();
  94. g_pAdapter = NULL;
  95. }
  96. if (g_pD3D11Device) {
  97. g_pD3D11Device->Release();
  98. g_pD3D11Device = NULL;
  99. }
  100. if (g_pD3D11Ctx) {
  101. g_pD3D11Ctx->Release();
  102. g_pD3D11Ctx = NULL;
  103. }
  104. if (g_pDXGIFactory) {
  105. g_pDXGIFactory->Release();
  106. g_pDXGIFactory = NULL;
  107. }
  108. }
  109. CComPtr<ID3D11DeviceContext> GetHWDeviceContext()
  110. {
  111. return g_pD3D11Ctx;
  112. }
  113. /* (Hugh) Functions currently unused */
  114. #if 0
  115. void ClearYUVSurfaceD3D(mfxMemId memId)
  116. {
  117. // TBD
  118. }
  119. void ClearRGBSurfaceD3D(mfxMemId memId)
  120. {
  121. // TBD
  122. }
  123. #endif
  124. //
  125. // Intel Media SDK memory allocator entrypoints....
  126. //
  127. mfxStatus _simple_alloc(mfxFrameAllocRequest *request,
  128. mfxFrameAllocResponse *response)
  129. {
  130. HRESULT hRes;
  131. // Determine surface format
  132. DXGI_FORMAT format;
  133. if (MFX_FOURCC_NV12 == request->Info.FourCC)
  134. format = DXGI_FORMAT_NV12;
  135. else if (MFX_FOURCC_RGB4 == request->Info.FourCC)
  136. format = DXGI_FORMAT_B8G8R8A8_UNORM;
  137. else if (MFX_FOURCC_YUY2 == request->Info.FourCC)
  138. format = DXGI_FORMAT_YUY2;
  139. else if (MFX_FOURCC_P8 ==
  140. request->Info
  141. .FourCC) //|| MFX_FOURCC_P8_TEXTURE == request->Info.FourCC
  142. format = DXGI_FORMAT_P8;
  143. else
  144. format = DXGI_FORMAT_UNKNOWN;
  145. if (DXGI_FORMAT_UNKNOWN == format)
  146. return MFX_ERR_UNSUPPORTED;
  147. // Allocate custom container to keep texture and stage buffers for each surface
  148. // Container also stores the intended read and/or write operation.
  149. CustomMemId **mids = (CustomMemId **)calloc(request->NumFrameSuggested,
  150. sizeof(CustomMemId *));
  151. if (!mids)
  152. return MFX_ERR_MEMORY_ALLOC;
  153. for (int i = 0; i < request->NumFrameSuggested; i++) {
  154. mids[i] = (CustomMemId *)calloc(1, sizeof(CustomMemId));
  155. if (!mids[i]) {
  156. return MFX_ERR_MEMORY_ALLOC;
  157. }
  158. mids[i]->rw = request->Type &
  159. 0xF000; // Set intended read/write operation
  160. }
  161. request->Type = request->Type & 0x0FFF;
  162. // because P8 data (bitstream) for h264 encoder should be allocated by CreateBuffer()
  163. // but P8 data (MBData) for MPEG2 encoder should be allocated by CreateTexture2D()
  164. if (request->Info.FourCC == MFX_FOURCC_P8) {
  165. D3D11_BUFFER_DESC desc = {0};
  166. if (!request->NumFrameSuggested)
  167. return MFX_ERR_MEMORY_ALLOC;
  168. desc.ByteWidth = request->Info.Width * request->Info.Height;
  169. desc.Usage = D3D11_USAGE_STAGING;
  170. desc.BindFlags = 0;
  171. desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
  172. desc.MiscFlags = 0;
  173. desc.StructureByteStride = 0;
  174. ID3D11Buffer *buffer = 0;
  175. hRes = g_pD3D11Device->CreateBuffer(&desc, 0, &buffer);
  176. if (FAILED(hRes))
  177. return MFX_ERR_MEMORY_ALLOC;
  178. mids[0]->memId = reinterpret_cast<ID3D11Texture2D *>(buffer);
  179. } else {
  180. D3D11_TEXTURE2D_DESC desc = {0};
  181. desc.Width = request->Info.Width;
  182. desc.Height = request->Info.Height;
  183. desc.MipLevels = 1;
  184. desc.ArraySize = 1; // number of subresources is 1 in this case
  185. desc.Format = format;
  186. desc.SampleDesc.Count = 1;
  187. desc.Usage = D3D11_USAGE_DEFAULT;
  188. desc.BindFlags = D3D11_BIND_DECODER;
  189. desc.MiscFlags = 0;
  190. //desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
  191. if ((MFX_MEMTYPE_FROM_VPPIN & request->Type) &&
  192. (DXGI_FORMAT_B8G8R8A8_UNORM == desc.Format)) {
  193. desc.BindFlags = D3D11_BIND_RENDER_TARGET;
  194. if (desc.ArraySize > 2)
  195. return MFX_ERR_MEMORY_ALLOC;
  196. }
  197. if ((MFX_MEMTYPE_FROM_VPPOUT & request->Type) ||
  198. (MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET &
  199. request->Type)) {
  200. desc.BindFlags = D3D11_BIND_RENDER_TARGET;
  201. if (desc.ArraySize > 2)
  202. return MFX_ERR_MEMORY_ALLOC;
  203. }
  204. if (DXGI_FORMAT_P8 == desc.Format)
  205. desc.BindFlags = 0;
  206. ID3D11Texture2D *pTexture2D;
  207. // Create surface textures
  208. for (size_t i = 0;
  209. i < request->NumFrameSuggested / desc.ArraySize; i++) {
  210. hRes = g_pD3D11Device->CreateTexture2D(&desc, NULL,
  211. &pTexture2D);
  212. if (FAILED(hRes))
  213. return MFX_ERR_MEMORY_ALLOC;
  214. mids[i]->memId = pTexture2D;
  215. }
  216. desc.ArraySize = 1;
  217. desc.Usage = D3D11_USAGE_STAGING;
  218. desc.CPUAccessFlags =
  219. D3D11_CPU_ACCESS_READ; // | D3D11_CPU_ACCESS_WRITE;
  220. desc.BindFlags = 0;
  221. desc.MiscFlags = 0;
  222. //desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
  223. // Create surface staging textures
  224. for (size_t i = 0; i < request->NumFrameSuggested; i++) {
  225. hRes = g_pD3D11Device->CreateTexture2D(&desc, NULL,
  226. &pTexture2D);
  227. if (FAILED(hRes))
  228. return MFX_ERR_MEMORY_ALLOC;
  229. mids[i]->memIdStage = pTexture2D;
  230. }
  231. }
  232. response->mids = (mfxMemId *)mids;
  233. response->NumFrameActual = request->NumFrameSuggested;
  234. return MFX_ERR_NONE;
  235. }
  236. mfxStatus simple_alloc(mfxHDL pthis, mfxFrameAllocRequest *request,
  237. mfxFrameAllocResponse *response)
  238. {
  239. mfxStatus sts = MFX_ERR_NONE;
  240. if (request->Type & MFX_MEMTYPE_SYSTEM_MEMORY)
  241. return MFX_ERR_UNSUPPORTED;
  242. if (allocDecodeResponses.find(pthis) != allocDecodeResponses.end() &&
  243. MFX_MEMTYPE_EXTERNAL_FRAME & request->Type &&
  244. MFX_MEMTYPE_FROM_DECODE & request->Type) {
  245. // Memory for this request was already allocated during manual allocation stage. Return saved response
  246. // When decode acceleration device (DXVA) is created it requires a list of d3d surfaces to be passed.
  247. // Therefore Media SDK will ask for the surface info/mids again at Init() stage, thus requiring us to return the saved response
  248. // (No such restriction applies to Encode or VPP)
  249. *response = allocDecodeResponses[pthis];
  250. allocDecodeRefCount[pthis]++;
  251. } else {
  252. sts = _simple_alloc(request, response);
  253. if (MFX_ERR_NONE == sts) {
  254. if (MFX_MEMTYPE_EXTERNAL_FRAME & request->Type &&
  255. MFX_MEMTYPE_FROM_DECODE & request->Type) {
  256. // Decode alloc response handling
  257. allocDecodeResponses[pthis] = *response;
  258. allocDecodeRefCount[pthis]++;
  259. } else {
  260. // Encode and VPP alloc response handling
  261. allocResponses[response->mids] = pthis;
  262. }
  263. }
  264. }
  265. return sts;
  266. }
  267. mfxStatus simple_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
  268. {
  269. pthis; // To suppress warning for this unused parameter
  270. HRESULT hRes = S_OK;
  271. D3D11_TEXTURE2D_DESC desc = {0};
  272. D3D11_MAPPED_SUBRESOURCE lockedRect = {0};
  273. CustomMemId *memId = (CustomMemId *)mid;
  274. ID3D11Texture2D *pSurface = (ID3D11Texture2D *)memId->memId;
  275. ID3D11Texture2D *pStage = (ID3D11Texture2D *)memId->memIdStage;
  276. D3D11_MAP mapType = D3D11_MAP_READ;
  277. UINT mapFlags = D3D11_MAP_FLAG_DO_NOT_WAIT;
  278. if (NULL == pStage) {
  279. hRes = g_pD3D11Ctx->Map(pSurface, 0, mapType, mapFlags,
  280. &lockedRect);
  281. desc.Format = DXGI_FORMAT_P8;
  282. } else {
  283. pSurface->GetDesc(&desc);
  284. // copy data only in case of user wants to read from stored surface
  285. if (memId->rw & WILL_READ)
  286. g_pD3D11Ctx->CopySubresourceRegion(pStage, 0, 0, 0, 0,
  287. pSurface, 0, NULL);
  288. do {
  289. hRes = g_pD3D11Ctx->Map(pStage, 0, mapType, mapFlags,
  290. &lockedRect);
  291. if (S_OK != hRes &&
  292. DXGI_ERROR_WAS_STILL_DRAWING != hRes)
  293. return MFX_ERR_LOCK_MEMORY;
  294. } while (DXGI_ERROR_WAS_STILL_DRAWING == hRes);
  295. }
  296. if (FAILED(hRes))
  297. return MFX_ERR_LOCK_MEMORY;
  298. switch (desc.Format) {
  299. case DXGI_FORMAT_NV12:
  300. ptr->Pitch = (mfxU16)lockedRect.RowPitch;
  301. ptr->Y = (mfxU8 *)lockedRect.pData;
  302. ptr->U = (mfxU8 *)lockedRect.pData +
  303. desc.Height * lockedRect.RowPitch;
  304. ptr->V = ptr->U + 1;
  305. break;
  306. case DXGI_FORMAT_B8G8R8A8_UNORM:
  307. ptr->Pitch = (mfxU16)lockedRect.RowPitch;
  308. ptr->B = (mfxU8 *)lockedRect.pData;
  309. ptr->G = ptr->B + 1;
  310. ptr->R = ptr->B + 2;
  311. ptr->A = ptr->B + 3;
  312. break;
  313. case DXGI_FORMAT_YUY2:
  314. ptr->Pitch = (mfxU16)lockedRect.RowPitch;
  315. ptr->Y = (mfxU8 *)lockedRect.pData;
  316. ptr->U = ptr->Y + 1;
  317. ptr->V = ptr->Y + 3;
  318. break;
  319. case DXGI_FORMAT_P8:
  320. ptr->Pitch = (mfxU16)lockedRect.RowPitch;
  321. ptr->Y = (mfxU8 *)lockedRect.pData;
  322. ptr->U = 0;
  323. ptr->V = 0;
  324. break;
  325. default:
  326. return MFX_ERR_LOCK_MEMORY;
  327. }
  328. return MFX_ERR_NONE;
  329. }
  330. mfxStatus simple_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
  331. {
  332. pthis; // To suppress warning for this unused parameter
  333. CustomMemId *memId = (CustomMemId *)mid;
  334. ID3D11Texture2D *pSurface = (ID3D11Texture2D *)memId->memId;
  335. ID3D11Texture2D *pStage = (ID3D11Texture2D *)memId->memIdStage;
  336. if (NULL == pStage) {
  337. g_pD3D11Ctx->Unmap(pSurface, 0);
  338. } else {
  339. g_pD3D11Ctx->Unmap(pStage, 0);
  340. // copy data only in case of user wants to write to stored surface
  341. if (memId->rw & WILL_WRITE)
  342. g_pD3D11Ctx->CopySubresourceRegion(pSurface, 0, 0, 0, 0,
  343. pStage, 0, NULL);
  344. }
  345. if (ptr) {
  346. ptr->Pitch = 0;
  347. ptr->U = ptr->V = ptr->Y = 0;
  348. ptr->A = ptr->R = ptr->G = ptr->B = 0;
  349. }
  350. return MFX_ERR_NONE;
  351. }
  352. mfxStatus simple_copytex(mfxHDL pthis, mfxMemId mid, mfxU32 tex_handle,
  353. mfxU64 lock_key, mfxU64 *next_key)
  354. {
  355. pthis; // To suppress warning for this unused parameter
  356. CustomMemId *memId = (CustomMemId *)mid;
  357. ID3D11Texture2D *pSurface = (ID3D11Texture2D *)memId->memId;
  358. IDXGIKeyedMutex *km;
  359. ID3D11Texture2D *input_tex;
  360. HRESULT hr;
  361. hr = g_pD3D11Device->OpenSharedResource((HANDLE)(uintptr_t)tex_handle,
  362. IID_ID3D11Texture2D,
  363. (void **)&input_tex);
  364. if (FAILED(hr)) {
  365. return MFX_ERR_INVALID_HANDLE;
  366. }
  367. hr = input_tex->QueryInterface(IID_IDXGIKeyedMutex, (void **)&km);
  368. if (FAILED(hr)) {
  369. input_tex->Release();
  370. return MFX_ERR_INVALID_HANDLE;
  371. }
  372. input_tex->SetEvictionPriority(DXGI_RESOURCE_PRIORITY_MAXIMUM);
  373. km->AcquireSync(lock_key, INFINITE);
  374. D3D11_TEXTURE2D_DESC desc = {0};
  375. input_tex->GetDesc(&desc);
  376. D3D11_BOX SrcBox = {0, 0, 0, desc.Width, desc.Height, 1};
  377. g_pD3D11Ctx->CopySubresourceRegion(pSurface, 0, 0, 0, 0, input_tex, 0,
  378. &SrcBox);
  379. km->ReleaseSync(*next_key);
  380. return MFX_ERR_NONE;
  381. }
  382. mfxStatus simple_gethdl(mfxHDL pthis, mfxMemId mid, mfxHDL *handle)
  383. {
  384. pthis; // To suppress warning for this unused parameter
  385. if (NULL == handle)
  386. return MFX_ERR_INVALID_HANDLE;
  387. mfxHDLPair *pPair = (mfxHDLPair *)handle;
  388. CustomMemId *memId = (CustomMemId *)mid;
  389. pPair->first = memId->memId; // surface texture
  390. pPair->second = 0;
  391. return MFX_ERR_NONE;
  392. }
  393. mfxStatus _simple_free(mfxFrameAllocResponse *response)
  394. {
  395. if (response->mids) {
  396. for (mfxU32 i = 0; i < response->NumFrameActual; i++) {
  397. if (response->mids[i]) {
  398. CustomMemId *mid =
  399. (CustomMemId *)response->mids[i];
  400. ID3D11Texture2D *pSurface =
  401. (ID3D11Texture2D *)mid->memId;
  402. ID3D11Texture2D *pStage =
  403. (ID3D11Texture2D *)mid->memIdStage;
  404. if (pSurface)
  405. pSurface->Release();
  406. if (pStage)
  407. pStage->Release();
  408. free(mid);
  409. }
  410. }
  411. free(response->mids);
  412. response->mids = NULL;
  413. }
  414. return MFX_ERR_NONE;
  415. }
  416. mfxStatus simple_free(mfxHDL pthis, mfxFrameAllocResponse *response)
  417. {
  418. if (NULL == response)
  419. return MFX_ERR_NULL_PTR;
  420. if (allocResponses.find(response->mids) == allocResponses.end()) {
  421. // Decode free response handling
  422. if (--allocDecodeRefCount[pthis] == 0) {
  423. _simple_free(response);
  424. allocDecodeResponses.erase(pthis);
  425. allocDecodeRefCount.erase(pthis);
  426. }
  427. } else {
  428. // Encode and VPP free response handling
  429. allocResponses.erase(response->mids);
  430. _simple_free(response);
  431. }
  432. return MFX_ERR_NONE;
  433. }