common_utils_linux.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. #include "common_utils.h"
  2. #include <time.h>
  3. #include <cpuid.h>
  4. #include <util/c99defs.h>
  5. #include <util/dstr.h>
  6. #include <va/va_drm.h>
  7. #include <va/va_x11.h>
  8. #include <va/va_wayland.h>
  9. #include <va/va_str.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <unistd.h>
  13. #include <fcntl.h>
  14. #include <string.h>
  15. #include <dirent.h>
  16. #include <obs.h>
  17. #include <obs-nix-platform.h>
  18. mfxStatus simple_alloc(mfxHDL pthis, mfxFrameAllocRequest *request,
  19. mfxFrameAllocResponse *response)
  20. {
  21. UNUSED_PARAMETER(pthis);
  22. UNUSED_PARAMETER(request);
  23. UNUSED_PARAMETER(response);
  24. return MFX_ERR_UNSUPPORTED;
  25. }
  26. mfxStatus simple_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
  27. {
  28. UNUSED_PARAMETER(pthis);
  29. UNUSED_PARAMETER(mid);
  30. UNUSED_PARAMETER(ptr);
  31. return MFX_ERR_UNSUPPORTED;
  32. }
  33. mfxStatus simple_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
  34. {
  35. UNUSED_PARAMETER(pthis);
  36. UNUSED_PARAMETER(mid);
  37. UNUSED_PARAMETER(ptr);
  38. return MFX_ERR_UNSUPPORTED;
  39. }
  40. mfxStatus simple_gethdl(mfxHDL pthis, mfxMemId mid, mfxHDL *handle)
  41. {
  42. UNUSED_PARAMETER(pthis);
  43. UNUSED_PARAMETER(mid);
  44. UNUSED_PARAMETER(handle);
  45. return MFX_ERR_UNSUPPORTED;
  46. }
  47. mfxStatus simple_free(mfxHDL pthis, mfxFrameAllocResponse *response)
  48. {
  49. UNUSED_PARAMETER(pthis);
  50. UNUSED_PARAMETER(response);
  51. return MFX_ERR_UNSUPPORTED;
  52. }
  53. mfxStatus simple_copytex(mfxHDL pthis, mfxMemId mid, mfxU32 tex_handle,
  54. mfxU64 lock_key, mfxU64 *next_key)
  55. {
  56. UNUSED_PARAMETER(pthis);
  57. UNUSED_PARAMETER(mid);
  58. UNUSED_PARAMETER(tex_handle);
  59. UNUSED_PARAMETER(lock_key);
  60. UNUSED_PARAMETER(next_key);
  61. return MFX_ERR_UNSUPPORTED;
  62. }
  63. #if 0
  64. void ClearYUVSurfaceVMem(mfxMemId memId);
  65. void ClearRGBSurfaceVMem(mfxMemId memId);
  66. #endif
  67. // Initialize Intel VPL Session, device/display and memory manager
  68. mfxStatus Initialize(mfxVersion ver, mfxSession *pSession,
  69. mfxFrameAllocator *pmfxAllocator, mfxHDL *deviceHandle,
  70. bool bCreateSharedHandles, bool dx9hack)
  71. {
  72. UNUSED_PARAMETER(ver);
  73. UNUSED_PARAMETER(pmfxAllocator);
  74. UNUSED_PARAMETER(deviceHandle);
  75. UNUSED_PARAMETER(bCreateSharedHandles);
  76. UNUSED_PARAMETER(dx9hack);
  77. mfxStatus sts = MFX_ERR_NONE;
  78. mfxVariant impl;
  79. // Initialize Intel VPL Session
  80. mfxLoader loader = MFXLoad();
  81. mfxConfig cfg = MFXCreateConfig(loader);
  82. impl.Type = MFX_VARIANT_TYPE_U32;
  83. impl.Data.U32 = MFX_IMPL_TYPE_HARDWARE;
  84. MFXSetConfigFilterProperty(
  85. cfg, (const mfxU8 *)"mfxImplDescription.Impl", impl);
  86. impl.Type = MFX_VARIANT_TYPE_U32;
  87. impl.Data.U32 = INTEL_VENDOR_ID;
  88. MFXSetConfigFilterProperty(
  89. cfg, (const mfxU8 *)"mfxImplDescription.VendorID", impl);
  90. impl.Type = MFX_VARIANT_TYPE_U32;
  91. impl.Data.U32 = MFX_ACCEL_MODE_VIA_VAAPI_DRM_RENDER_NODE;
  92. MFXSetConfigFilterProperty(
  93. cfg, (const mfxU8 *)"mfxImplDescription.AccelerationMode",
  94. impl);
  95. mfxHDL vaDisplay = nullptr;
  96. if (obs_get_nix_platform() == OBS_NIX_PLATFORM_X11_EGL) {
  97. vaDisplay =
  98. vaGetDisplay((Display *)obs_get_nix_platform_display());
  99. } else if (obs_get_nix_platform() == OBS_NIX_PLATFORM_WAYLAND) {
  100. vaDisplay = vaGetDisplayWl(
  101. (wl_display *)obs_get_nix_platform_display());
  102. }
  103. sts = MFXCreateSession(loader, 0, pSession);
  104. MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
  105. // VPL expects the VADisplay to be initialized.
  106. int major;
  107. int minor;
  108. if (vaInitialize(vaDisplay, &major, &minor) != VA_STATUS_SUCCESS) {
  109. vaTerminate(vaDisplay);
  110. return MFX_ERR_DEVICE_FAILED;
  111. }
  112. sts = MFXVideoCORE_SetHandle(*pSession, MFX_HANDLE_VA_DISPLAY,
  113. vaDisplay);
  114. MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
  115. return sts;
  116. }
  117. // Release resources (device/display)
  118. void Release(){};
  119. void mfxGetTime(mfxTime *timestamp)
  120. {
  121. clock_gettime(CLOCK_MONOTONIC, timestamp);
  122. }
  123. double TimeDiffMsec(mfxTime tfinish, mfxTime tstart)
  124. {
  125. UNUSED_PARAMETER(tfinish);
  126. UNUSED_PARAMETER(tstart);
  127. //TODO, unused so far it seems
  128. return 0.0;
  129. }
  130. extern "C" void util_cpuid(int cpuinfo[4], int level)
  131. {
  132. __get_cpuid(level, (unsigned int *)&cpuinfo[0],
  133. (unsigned int *)&cpuinfo[1], (unsigned int *)&cpuinfo[2],
  134. (unsigned int *)&cpuinfo[3]);
  135. }
  136. struct vaapi_device {
  137. int fd;
  138. VADisplay display;
  139. const char *driver;
  140. };
  141. void vaapi_open(char *device_path, struct vaapi_device *device)
  142. {
  143. int fd = open(device_path, O_RDWR);
  144. if (fd < 0) {
  145. return;
  146. }
  147. VADisplay display = vaGetDisplayDRM(fd);
  148. if (!display) {
  149. close(fd);
  150. return;
  151. }
  152. // VA-API is noisy by default.
  153. vaSetInfoCallback(display, nullptr, nullptr);
  154. vaSetErrorCallback(display, nullptr, nullptr);
  155. int major;
  156. int minor;
  157. if (vaInitialize(display, &major, &minor) != VA_STATUS_SUCCESS) {
  158. vaTerminate(display);
  159. close(fd);
  160. return;
  161. }
  162. const char *driver = vaQueryVendorString(display);
  163. if (strstr(driver, "Intel i965 driver") != nullptr) {
  164. blog(LOG_WARNING,
  165. "Legacy intel-vaapi-driver detected, incompatible with QSV");
  166. vaTerminate(display);
  167. close(fd);
  168. return;
  169. }
  170. device->fd = fd;
  171. device->display = display;
  172. device->driver = driver;
  173. }
  174. void vaapi_close(struct vaapi_device *device)
  175. {
  176. vaTerminate(device->display);
  177. close(device->fd);
  178. }
  179. static uint32_t vaapi_check_support(VADisplay display, VAProfile profile,
  180. VAEntrypoint entrypoint)
  181. {
  182. bool ret = false;
  183. VAConfigAttrib attrib[1];
  184. attrib->type = VAConfigAttribRateControl;
  185. VAStatus va_status =
  186. vaGetConfigAttributes(display, profile, entrypoint, attrib, 1);
  187. uint32_t rc = 0;
  188. switch (va_status) {
  189. case VA_STATUS_SUCCESS:
  190. rc = attrib->value;
  191. break;
  192. case VA_STATUS_ERROR_UNSUPPORTED_PROFILE:
  193. case VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT:
  194. default:
  195. break;
  196. }
  197. return (rc & VA_RC_CBR || rc & VA_RC_CQP || rc & VA_RC_VBR);
  198. }
  199. bool vaapi_supports_h264(VADisplay display)
  200. {
  201. bool ret = false;
  202. ret |= vaapi_check_support(display, VAProfileH264ConstrainedBaseline,
  203. VAEntrypointEncSlice);
  204. ret |= vaapi_check_support(display, VAProfileH264Main,
  205. VAEntrypointEncSlice);
  206. ret |= vaapi_check_support(display, VAProfileH264High,
  207. VAEntrypointEncSlice);
  208. if (!ret) {
  209. ret |= vaapi_check_support(display,
  210. VAProfileH264ConstrainedBaseline,
  211. VAEntrypointEncSliceLP);
  212. ret |= vaapi_check_support(display, VAProfileH264Main,
  213. VAEntrypointEncSliceLP);
  214. ret |= vaapi_check_support(display, VAProfileH264High,
  215. VAEntrypointEncSliceLP);
  216. }
  217. return ret;
  218. }
  219. bool vaapi_supports_av1(VADisplay display)
  220. {
  221. bool ret = false;
  222. // Are there any devices with non-LowPower entrypoints?
  223. ret |= vaapi_check_support(display, VAProfileAV1Profile0,
  224. VAEntrypointEncSlice);
  225. ret |= vaapi_check_support(display, VAProfileAV1Profile0,
  226. VAEntrypointEncSliceLP);
  227. return ret;
  228. }
  229. bool vaapi_supports_hevc(VADisplay display)
  230. {
  231. bool ret = false;
  232. ret |= vaapi_check_support(display, VAProfileHEVCMain,
  233. VAEntrypointEncSlice);
  234. ret |= vaapi_check_support(display, VAProfileHEVCMain,
  235. VAEntrypointEncSliceLP);
  236. return ret;
  237. }
  238. void check_adapters(struct adapter_info *adapters, size_t *adapter_count)
  239. {
  240. struct dstr full_path;
  241. struct dirent **namelist;
  242. int no;
  243. int adapter_idx;
  244. const char *base_dir = "/dev/dri/";
  245. dstr_init(&full_path);
  246. if ((no = scandir(base_dir, &namelist, 0, alphasort)) > 0) {
  247. for (int i = 0; i < no; i++) {
  248. struct adapter_info *adapter;
  249. struct dirent *dp;
  250. struct vaapi_device device = {0};
  251. dp = namelist[i];
  252. if (strstr(dp->d_name, "renderD") == nullptr)
  253. goto next_entry;
  254. adapter_idx = atoi(&dp->d_name[7]) - 128;
  255. if (adapter_idx >= (ssize_t)*adapter_count ||
  256. adapter_idx < 0)
  257. goto next_entry;
  258. *adapter_count = adapter_idx + 1;
  259. dstr_copy(&full_path, base_dir);
  260. dstr_cat(&full_path, dp->d_name);
  261. vaapi_open(full_path.array, &device);
  262. if (!device.display)
  263. goto next_entry;
  264. adapter = &adapters[adapter_idx];
  265. adapter->is_intel = strstr(device.driver, "Intel") !=
  266. nullptr;
  267. // This is currently only used for LowPower coding which is busted on VA-API anyway.
  268. adapter->is_dgpu = false;
  269. adapter->supports_av1 =
  270. vaapi_supports_av1(device.display);
  271. adapter->supports_hevc =
  272. vaapi_supports_hevc(device.display);
  273. vaapi_close(&device);
  274. next_entry:
  275. free(dp);
  276. }
  277. free(namelist);
  278. }
  279. dstr_free(&full_path);
  280. }