common_directx11.cpp 14 KB

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