common_directx11.cpp 13 KB

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