common_utils_linux.cpp 7.2 KB

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