You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2944 lines
96KB

  1. /*
  2. * This file is part of FFmpeg.
  3. *
  4. * FFmpeg is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * FFmpeg is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with FFmpeg; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include <string.h>
  19. #include "config.h"
  20. #include "avassert.h"
  21. #include "avstring.h"
  22. #include "common.h"
  23. #include "hwcontext.h"
  24. #include "hwcontext_internal.h"
  25. #include "hwcontext_opencl.h"
  26. #include "mem.h"
  27. #include "pixdesc.h"
  28. #if HAVE_OPENCL_VAAPI_BEIGNET
  29. #include <unistd.h>
  30. #include <va/va.h>
  31. #include <va/va_drmcommon.h>
  32. #include <CL/cl_intel.h>
  33. #include "hwcontext_vaapi.h"
  34. #endif
  35. #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
  36. #include <mfx/mfxstructures.h>
  37. #include <va/va.h>
  38. #include <CL/va_ext.h>
  39. #include "hwcontext_vaapi.h"
  40. #endif
  41. #if HAVE_OPENCL_DXVA2
  42. #define COBJMACROS
  43. #include <CL/cl_dx9_media_sharing.h>
  44. #include <dxva2api.h>
  45. #include "hwcontext_dxva2.h"
  46. #endif
  47. #if HAVE_OPENCL_D3D11
  48. #include <CL/cl_d3d11.h>
  49. #include "hwcontext_d3d11va.h"
  50. #endif
  51. #if HAVE_OPENCL_DRM_ARM
  52. #include <CL/cl_ext.h>
  53. #include <drm_fourcc.h>
  54. #include "hwcontext_drm.h"
  55. #endif
  56. typedef struct OpenCLDeviceContext {
  57. // Default command queue to use for transfer/mapping operations on
  58. // the device. If the user supplies one, this is a reference to it.
  59. // Otherwise, it is newly-created.
  60. cl_command_queue command_queue;
  61. // The platform the context exists on. This is needed to query and
  62. // retrieve extension functions.
  63. cl_platform_id platform_id;
  64. // Platform/device-specific functions.
  65. #if HAVE_OPENCL_VAAPI_BEIGNET
  66. int vaapi_mapping_usable;
  67. clCreateImageFromFdINTEL_fn clCreateImageFromFdINTEL;
  68. #endif
  69. #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
  70. int qsv_mapping_usable;
  71. clCreateFromVA_APIMediaSurfaceINTEL_fn
  72. clCreateFromVA_APIMediaSurfaceINTEL;
  73. clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn
  74. clEnqueueAcquireVA_APIMediaSurfacesINTEL;
  75. clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn
  76. clEnqueueReleaseVA_APIMediaSurfacesINTEL;
  77. #endif
  78. #if HAVE_OPENCL_DXVA2
  79. int dxva2_mapping_usable;
  80. cl_dx9_media_adapter_type_khr dx9_media_adapter_type;
  81. clCreateFromDX9MediaSurfaceKHR_fn
  82. clCreateFromDX9MediaSurfaceKHR;
  83. clEnqueueAcquireDX9MediaSurfacesKHR_fn
  84. clEnqueueAcquireDX9MediaSurfacesKHR;
  85. clEnqueueReleaseDX9MediaSurfacesKHR_fn
  86. clEnqueueReleaseDX9MediaSurfacesKHR;
  87. #endif
  88. #if HAVE_OPENCL_D3D11
  89. int d3d11_mapping_usable;
  90. clCreateFromD3D11Texture2DKHR_fn
  91. clCreateFromD3D11Texture2DKHR;
  92. clEnqueueAcquireD3D11ObjectsKHR_fn
  93. clEnqueueAcquireD3D11ObjectsKHR;
  94. clEnqueueReleaseD3D11ObjectsKHR_fn
  95. clEnqueueReleaseD3D11ObjectsKHR;
  96. #endif
  97. #if HAVE_OPENCL_DRM_ARM
  98. int drm_arm_mapping_usable;
  99. #endif
  100. } OpenCLDeviceContext;
  101. typedef struct OpenCLFramesContext {
  102. // Command queue used for transfer/mapping operations on this frames
  103. // context. If the user supplies one, this is a reference to it.
  104. // Otherwise, it is a reference to the default command queue for the
  105. // device.
  106. cl_command_queue command_queue;
  107. #if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11
  108. // For mapping APIs which have separate creation and acquire/release
  109. // steps, this stores the OpenCL memory objects corresponding to each
  110. // frame.
  111. int nb_mapped_frames;
  112. AVOpenCLFrameDescriptor *mapped_frames;
  113. #endif
  114. } OpenCLFramesContext;
  115. static void opencl_error_callback(const char *errinfo,
  116. const void *private_info, size_t cb,
  117. void *user_data)
  118. {
  119. AVHWDeviceContext *ctx = user_data;
  120. av_log(ctx, AV_LOG_ERROR, "OpenCL error: %s\n", errinfo);
  121. }
  122. static void opencl_device_free(AVHWDeviceContext *hwdev)
  123. {
  124. AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
  125. cl_int cle;
  126. cle = clReleaseContext(hwctx->context);
  127. if (cle != CL_SUCCESS) {
  128. av_log(hwdev, AV_LOG_ERROR, "Failed to release OpenCL "
  129. "context: %d.\n", cle);
  130. }
  131. }
  132. static struct {
  133. const char *key;
  134. cl_platform_info name;
  135. } opencl_platform_params[] = {
  136. { "platform_profile", CL_PLATFORM_PROFILE },
  137. { "platform_version", CL_PLATFORM_VERSION },
  138. { "platform_name", CL_PLATFORM_NAME },
  139. { "platform_vendor", CL_PLATFORM_VENDOR },
  140. { "platform_extensions", CL_PLATFORM_EXTENSIONS },
  141. };
  142. static struct {
  143. const char *key;
  144. cl_device_info name;
  145. } opencl_device_params[] = {
  146. { "device_name", CL_DEVICE_NAME },
  147. { "device_vendor", CL_DEVICE_VENDOR },
  148. { "driver_version", CL_DRIVER_VERSION },
  149. { "device_version", CL_DEVICE_VERSION },
  150. { "device_profile", CL_DEVICE_PROFILE },
  151. { "device_extensions", CL_DEVICE_EXTENSIONS },
  152. };
  153. static struct {
  154. const char *key;
  155. cl_device_type type;
  156. } opencl_device_types[] = {
  157. { "cpu", CL_DEVICE_TYPE_CPU },
  158. { "gpu", CL_DEVICE_TYPE_GPU },
  159. { "accelerator", CL_DEVICE_TYPE_ACCELERATOR },
  160. { "custom", CL_DEVICE_TYPE_CUSTOM },
  161. { "default", CL_DEVICE_TYPE_DEFAULT },
  162. { "all", CL_DEVICE_TYPE_ALL },
  163. };
  164. static char *opencl_get_platform_string(cl_platform_id platform_id,
  165. cl_platform_info key)
  166. {
  167. char *str;
  168. size_t size;
  169. cl_int cle;
  170. cle = clGetPlatformInfo(platform_id, key, 0, NULL, &size);
  171. if (cle != CL_SUCCESS)
  172. return NULL;
  173. str = av_malloc(size);
  174. if (!str)
  175. return NULL;
  176. cle = clGetPlatformInfo(platform_id, key, size, str, &size);
  177. if (cle != CL_SUCCESS) {
  178. av_free(str);
  179. return NULL;
  180. }
  181. av_assert0(strlen(str) + 1 == size);
  182. return str;
  183. }
  184. static char *opencl_get_device_string(cl_device_id device_id,
  185. cl_device_info key)
  186. {
  187. char *str;
  188. size_t size;
  189. cl_int cle;
  190. cle = clGetDeviceInfo(device_id, key, 0, NULL, &size);
  191. if (cle != CL_SUCCESS)
  192. return NULL;
  193. str = av_malloc(size);
  194. if (!str)
  195. return NULL;
  196. cle = clGetDeviceInfo(device_id, key, size, str, &size);
  197. if (cle != CL_SUCCESS) {
  198. av_free(str);
  199. return NULL;
  200. }
  201. av_assert0(strlen(str) + 1== size);
  202. return str;
  203. }
  204. static int opencl_check_platform_extension(cl_platform_id platform_id,
  205. const char *name)
  206. {
  207. char *str;
  208. int found = 0;
  209. str = opencl_get_platform_string(platform_id,
  210. CL_PLATFORM_EXTENSIONS);
  211. if (str && strstr(str, name))
  212. found = 1;
  213. av_free(str);
  214. return found;
  215. }
  216. static int opencl_check_device_extension(cl_device_id device_id,
  217. const char *name)
  218. {
  219. char *str;
  220. int found = 0;
  221. str = opencl_get_device_string(device_id,
  222. CL_DEVICE_EXTENSIONS);
  223. if (str && strstr(str, name))
  224. found = 1;
  225. av_free(str);
  226. return found;
  227. }
  228. static av_unused int opencl_check_extension(AVHWDeviceContext *hwdev,
  229. const char *name)
  230. {
  231. AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
  232. OpenCLDeviceContext *priv = hwdev->internal->priv;
  233. if (opencl_check_platform_extension(priv->platform_id, name)) {
  234. av_log(hwdev, AV_LOG_DEBUG,
  235. "%s found as platform extension.\n", name);
  236. return 1;
  237. }
  238. if (opencl_check_device_extension(hwctx->device_id, name)) {
  239. av_log(hwdev, AV_LOG_DEBUG,
  240. "%s found as device extension.\n", name);
  241. return 1;
  242. }
  243. return 0;
  244. }
  245. static int opencl_enumerate_platforms(AVHWDeviceContext *hwdev,
  246. cl_uint *nb_platforms,
  247. cl_platform_id **platforms,
  248. void *context)
  249. {
  250. cl_int cle;
  251. cle = clGetPlatformIDs(0, NULL, nb_platforms);
  252. if (cle != CL_SUCCESS) {
  253. av_log(hwdev, AV_LOG_ERROR, "Failed to get number of "
  254. "OpenCL platforms: %d.\n", cle);
  255. return AVERROR(ENODEV);
  256. }
  257. av_log(hwdev, AV_LOG_DEBUG, "%u OpenCL platforms found.\n",
  258. *nb_platforms);
  259. *platforms = av_malloc_array(*nb_platforms, sizeof(**platforms));
  260. if (!*platforms)
  261. return AVERROR(ENOMEM);
  262. cle = clGetPlatformIDs(*nb_platforms, *platforms, NULL);
  263. if (cle != CL_SUCCESS) {
  264. av_log(hwdev, AV_LOG_ERROR, "Failed to get list of OpenCL "
  265. "platforms: %d.\n", cle);
  266. av_freep(platforms);
  267. return AVERROR(ENODEV);
  268. }
  269. return 0;
  270. }
  271. static int opencl_filter_platform(AVHWDeviceContext *hwdev,
  272. cl_platform_id platform_id,
  273. const char *platform_name,
  274. void *context)
  275. {
  276. AVDictionary *opts = context;
  277. const AVDictionaryEntry *param;
  278. char *str;
  279. int i, ret = 0;
  280. for (i = 0; i < FF_ARRAY_ELEMS(opencl_platform_params); i++) {
  281. param = av_dict_get(opts, opencl_platform_params[i].key,
  282. NULL, 0);
  283. if (!param)
  284. continue;
  285. str = opencl_get_platform_string(platform_id,
  286. opencl_platform_params[i].name);
  287. if (!str) {
  288. av_log(hwdev, AV_LOG_ERROR, "Failed to query %s "
  289. "of platform \"%s\".\n",
  290. opencl_platform_params[i].key, platform_name);
  291. return AVERROR_UNKNOWN;
  292. }
  293. if (!av_stristr(str, param->value)) {
  294. av_log(hwdev, AV_LOG_DEBUG, "%s does not match (\"%s\").\n",
  295. param->key, str);
  296. ret = 1;
  297. }
  298. av_free(str);
  299. }
  300. return ret;
  301. }
  302. static int opencl_enumerate_devices(AVHWDeviceContext *hwdev,
  303. cl_platform_id platform_id,
  304. const char *platform_name,
  305. cl_uint *nb_devices,
  306. cl_device_id **devices,
  307. void *context)
  308. {
  309. cl_int cle;
  310. cle = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL,
  311. 0, NULL, nb_devices);
  312. if (cle == CL_DEVICE_NOT_FOUND) {
  313. av_log(hwdev, AV_LOG_DEBUG, "No devices found "
  314. "on platform \"%s\".\n", platform_name);
  315. *nb_devices = 0;
  316. return 0;
  317. } else if (cle != CL_SUCCESS) {
  318. av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
  319. "on platform \"%s\": %d.\n", platform_name, cle);
  320. return AVERROR(ENODEV);
  321. }
  322. av_log(hwdev, AV_LOG_DEBUG, "%u OpenCL devices found on "
  323. "platform \"%s\".\n", *nb_devices, platform_name);
  324. *devices = av_malloc_array(*nb_devices, sizeof(**devices));
  325. if (!*devices)
  326. return AVERROR(ENOMEM);
  327. cle = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL,
  328. *nb_devices, *devices, NULL);
  329. if (cle != CL_SUCCESS) {
  330. av_log(hwdev, AV_LOG_ERROR, "Failed to get list of devices "
  331. "on platform \"%s\": %d.\n", platform_name, cle);
  332. av_freep(devices);
  333. return AVERROR(ENODEV);
  334. }
  335. return 0;
  336. }
  337. static int opencl_filter_device(AVHWDeviceContext *hwdev,
  338. cl_device_id device_id,
  339. const char *device_name,
  340. void *context)
  341. {
  342. AVDictionary *opts = context;
  343. const AVDictionaryEntry *param;
  344. char *str;
  345. int i, ret = 0;
  346. param = av_dict_get(opts, "device_type", NULL, 0);
  347. if (param) {
  348. cl_device_type match_type = 0, device_type;
  349. cl_int cle;
  350. for (i = 0; i < FF_ARRAY_ELEMS(opencl_device_types); i++) {
  351. if (!strcmp(opencl_device_types[i].key, param->value)) {
  352. match_type = opencl_device_types[i].type;
  353. break;
  354. }
  355. }
  356. if (!match_type) {
  357. av_log(hwdev, AV_LOG_ERROR, "Unknown device type %s.\n",
  358. param->value);
  359. return AVERROR(EINVAL);
  360. }
  361. cle = clGetDeviceInfo(device_id, CL_DEVICE_TYPE,
  362. sizeof(device_type), &device_type, NULL);
  363. if (cle != CL_SUCCESS) {
  364. av_log(hwdev, AV_LOG_ERROR, "Failed to query device type "
  365. "of device \"%s\".\n", device_name);
  366. return AVERROR_UNKNOWN;
  367. }
  368. if (!(device_type & match_type)) {
  369. av_log(hwdev, AV_LOG_DEBUG, "device_type does not match.\n");
  370. return 1;
  371. }
  372. }
  373. for (i = 0; i < FF_ARRAY_ELEMS(opencl_device_params); i++) {
  374. param = av_dict_get(opts, opencl_device_params[i].key,
  375. NULL, 0);
  376. if (!param)
  377. continue;
  378. str = opencl_get_device_string(device_id,
  379. opencl_device_params[i].name);
  380. if (!str) {
  381. av_log(hwdev, AV_LOG_ERROR, "Failed to query %s "
  382. "of device \"%s\".\n",
  383. opencl_device_params[i].key, device_name);
  384. return AVERROR_UNKNOWN;
  385. }
  386. if (!av_stristr(str, param->value)) {
  387. av_log(hwdev, AV_LOG_DEBUG, "%s does not match (\"%s\").\n",
  388. param->key, str);
  389. ret = 1;
  390. }
  391. av_free(str);
  392. }
  393. return ret;
  394. }
  395. typedef struct OpenCLDeviceSelector {
  396. int platform_index;
  397. int device_index;
  398. void *context;
  399. int (*enumerate_platforms)(AVHWDeviceContext *hwdev,
  400. cl_uint *nb_platforms,
  401. cl_platform_id **platforms,
  402. void *context);
  403. int (*filter_platform) (AVHWDeviceContext *hwdev,
  404. cl_platform_id platform_id,
  405. const char *platform_name,
  406. void *context);
  407. int (*enumerate_devices) (AVHWDeviceContext *hwdev,
  408. cl_platform_id platform_id,
  409. const char *platform_name,
  410. cl_uint *nb_devices,
  411. cl_device_id **devices,
  412. void *context);
  413. int (*filter_device) (AVHWDeviceContext *hwdev,
  414. cl_device_id device_id,
  415. const char *device_name,
  416. void *context);
  417. } OpenCLDeviceSelector;
  418. static int opencl_device_create_internal(AVHWDeviceContext *hwdev,
  419. const OpenCLDeviceSelector *selector,
  420. cl_context_properties *props)
  421. {
  422. cl_uint nb_platforms;
  423. cl_platform_id *platforms = NULL;
  424. cl_platform_id platform_id;
  425. cl_uint nb_devices;
  426. cl_device_id *devices = NULL;
  427. AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
  428. cl_int cle;
  429. cl_context_properties default_props[3];
  430. char *platform_name_src = NULL,
  431. *device_name_src = NULL;
  432. int err, found, p, d;
  433. err = selector->enumerate_platforms(hwdev, &nb_platforms, &platforms,
  434. selector->context);
  435. if (err)
  436. return err;
  437. found = 0;
  438. for (p = 0; p < nb_platforms; p++) {
  439. const char *platform_name;
  440. if (selector->platform_index >= 0 &&
  441. selector->platform_index != p)
  442. continue;
  443. av_freep(&platform_name_src);
  444. platform_name_src = opencl_get_platform_string(platforms[p],
  445. CL_PLATFORM_NAME);
  446. if (platform_name_src)
  447. platform_name = platform_name_src;
  448. else
  449. platform_name = "Unknown Platform";
  450. if (selector->filter_platform) {
  451. err = selector->filter_platform(hwdev, platforms[p],
  452. platform_name,
  453. selector->context);
  454. if (err < 0)
  455. goto fail;
  456. if (err > 0)
  457. continue;
  458. }
  459. err = opencl_enumerate_devices(hwdev, platforms[p], platform_name,
  460. &nb_devices, &devices,
  461. selector->context);
  462. if (err < 0)
  463. continue;
  464. for (d = 0; d < nb_devices; d++) {
  465. const char *device_name;
  466. if (selector->device_index >= 0 &&
  467. selector->device_index != d)
  468. continue;
  469. av_freep(&device_name_src);
  470. device_name_src = opencl_get_device_string(devices[d],
  471. CL_DEVICE_NAME);
  472. if (device_name_src)
  473. device_name = device_name_src;
  474. else
  475. device_name = "Unknown Device";
  476. if (selector->filter_device) {
  477. err = selector->filter_device(hwdev, devices[d],
  478. device_name,
  479. selector->context);
  480. if (err < 0)
  481. goto fail;
  482. if (err > 0)
  483. continue;
  484. }
  485. av_log(hwdev, AV_LOG_VERBOSE, "%d.%d: %s / %s\n", p, d,
  486. platform_name, device_name);
  487. ++found;
  488. platform_id = platforms[p];
  489. hwctx->device_id = devices[d];
  490. }
  491. av_freep(&devices);
  492. }
  493. if (found == 0) {
  494. av_log(hwdev, AV_LOG_ERROR, "No matching devices found.\n");
  495. err = AVERROR(ENODEV);
  496. goto fail;
  497. }
  498. if (found > 1) {
  499. av_log(hwdev, AV_LOG_ERROR, "More than one matching device found.\n");
  500. err = AVERROR(ENODEV);
  501. goto fail;
  502. }
  503. if (!props) {
  504. props = default_props;
  505. default_props[0] = CL_CONTEXT_PLATFORM;
  506. default_props[1] = (intptr_t)platform_id;
  507. default_props[2] = 0;
  508. } else {
  509. if (props[0] == CL_CONTEXT_PLATFORM && props[1] == 0)
  510. props[1] = (intptr_t)platform_id;
  511. }
  512. hwctx->context = clCreateContext(props, 1, &hwctx->device_id,
  513. &opencl_error_callback, hwdev, &cle);
  514. if (!hwctx->context) {
  515. av_log(hwdev, AV_LOG_ERROR, "Failed to create OpenCL context: "
  516. "%d.\n", cle);
  517. err = AVERROR(ENODEV);
  518. goto fail;
  519. }
  520. hwdev->free = &opencl_device_free;
  521. err = 0;
  522. fail:
  523. av_freep(&platform_name_src);
  524. av_freep(&device_name_src);
  525. av_freep(&platforms);
  526. av_freep(&devices);
  527. return err;
  528. }
  529. static int opencl_device_create(AVHWDeviceContext *hwdev, const char *device,
  530. AVDictionary *opts, int flags)
  531. {
  532. OpenCLDeviceSelector selector = {
  533. .context = opts,
  534. .enumerate_platforms = &opencl_enumerate_platforms,
  535. .filter_platform = &opencl_filter_platform,
  536. .enumerate_devices = &opencl_enumerate_devices,
  537. .filter_device = &opencl_filter_device,
  538. };
  539. if (device && device[0]) {
  540. // Match one or both indices for platform and device.
  541. int d = -1, p = -1, ret;
  542. if (device[0] == '.')
  543. ret = sscanf(device, ".%d", &d);
  544. else
  545. ret = sscanf(device, "%d.%d", &p, &d);
  546. if (ret < 1) {
  547. av_log(hwdev, AV_LOG_ERROR, "Invalid OpenCL platform/device "
  548. "index specification \"%s\".\n", device);
  549. return AVERROR(EINVAL);
  550. }
  551. selector.platform_index = p;
  552. selector.device_index = d;
  553. } else {
  554. selector.platform_index = -1;
  555. selector.device_index = -1;
  556. }
  557. return opencl_device_create_internal(hwdev, &selector, NULL);
  558. }
  559. static int opencl_device_init(AVHWDeviceContext *hwdev)
  560. {
  561. AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
  562. OpenCLDeviceContext *priv = hwdev->internal->priv;
  563. cl_int cle;
  564. if (hwctx->command_queue) {
  565. cle = clRetainCommandQueue(hwctx->command_queue);
  566. if (cle != CL_SUCCESS) {
  567. av_log(hwdev, AV_LOG_ERROR, "Failed to retain external "
  568. "command queue: %d.\n", cle);
  569. return AVERROR(EIO);
  570. }
  571. priv->command_queue = hwctx->command_queue;
  572. } else {
  573. priv->command_queue = clCreateCommandQueue(hwctx->context,
  574. hwctx->device_id,
  575. 0, &cle);
  576. if (!priv->command_queue) {
  577. av_log(hwdev, AV_LOG_ERROR, "Failed to create internal "
  578. "command queue: %d.\n", cle);
  579. return AVERROR(EIO);
  580. }
  581. }
  582. cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_PLATFORM,
  583. sizeof(priv->platform_id), &priv->platform_id,
  584. NULL);
  585. if (cle != CL_SUCCESS) {
  586. av_log(hwdev, AV_LOG_ERROR, "Failed to determine the OpenCL "
  587. "platform containing the device.\n");
  588. return AVERROR(EIO);
  589. }
  590. #define CL_FUNC(name, desc) do { \
  591. if (fail) \
  592. break; \
  593. priv->name = clGetExtensionFunctionAddressForPlatform( \
  594. priv->platform_id, #name); \
  595. if (!priv->name) { \
  596. av_log(hwdev, AV_LOG_VERBOSE, \
  597. desc " function not found (%s).\n", #name); \
  598. fail = 1; \
  599. } else { \
  600. av_log(hwdev, AV_LOG_VERBOSE, \
  601. desc " function found (%s).\n", #name); \
  602. } \
  603. } while (0)
  604. #if HAVE_OPENCL_VAAPI_BEIGNET
  605. {
  606. int fail = 0;
  607. CL_FUNC(clCreateImageFromFdINTEL,
  608. "Intel DRM to OpenCL image mapping");
  609. if (fail) {
  610. av_log(hwdev, AV_LOG_WARNING, "VAAPI to OpenCL mapping "
  611. "not usable.\n");
  612. priv->vaapi_mapping_usable = 0;
  613. } else {
  614. priv->vaapi_mapping_usable = 1;
  615. }
  616. }
  617. #endif
  618. #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
  619. {
  620. size_t props_size;
  621. cl_context_properties *props = NULL;
  622. VADisplay va_display;
  623. const char *va_ext = "cl_intel_va_api_media_sharing";
  624. int i, fail = 0;
  625. if (!opencl_check_extension(hwdev, va_ext)) {
  626. av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is "
  627. "required for QSV to OpenCL mapping.\n", va_ext);
  628. goto no_qsv;
  629. }
  630. cle = clGetContextInfo(hwctx->context, CL_CONTEXT_PROPERTIES,
  631. 0, NULL, &props_size);
  632. if (cle != CL_SUCCESS) {
  633. av_log(hwdev, AV_LOG_VERBOSE, "Failed to get context "
  634. "properties: %d.\n", cle);
  635. goto no_qsv;
  636. }
  637. if (props_size == 0) {
  638. av_log(hwdev, AV_LOG_VERBOSE, "Media sharing must be "
  639. "enabled on context creation to use QSV to "
  640. "OpenCL mapping.\n");
  641. goto no_qsv;
  642. }
  643. props = av_malloc(props_size);
  644. if (!props)
  645. return AVERROR(ENOMEM);
  646. cle = clGetContextInfo(hwctx->context, CL_CONTEXT_PROPERTIES,
  647. props_size, props, NULL);
  648. if (cle != CL_SUCCESS) {
  649. av_log(hwdev, AV_LOG_VERBOSE, "Failed to get context "
  650. "properties: %d.\n", cle);
  651. goto no_qsv;
  652. }
  653. va_display = NULL;
  654. for (i = 0; i < (props_size / sizeof(*props) - 1); i++) {
  655. if (props[i] == CL_CONTEXT_VA_API_DISPLAY_INTEL) {
  656. va_display = (VADisplay)(intptr_t)props[i+1];
  657. break;
  658. }
  659. }
  660. if (!va_display) {
  661. av_log(hwdev, AV_LOG_VERBOSE, "Media sharing must be "
  662. "enabled on context creation to use QSV to "
  663. "OpenCL mapping.\n");
  664. goto no_qsv;
  665. }
  666. if (!vaDisplayIsValid(va_display)) {
  667. av_log(hwdev, AV_LOG_VERBOSE, "A valid VADisplay is "
  668. "required on context creation to use QSV to "
  669. "OpenCL mapping.\n");
  670. goto no_qsv;
  671. }
  672. CL_FUNC(clCreateFromVA_APIMediaSurfaceINTEL,
  673. "Intel QSV to OpenCL mapping");
  674. CL_FUNC(clEnqueueAcquireVA_APIMediaSurfacesINTEL,
  675. "Intel QSV in OpenCL acquire");
  676. CL_FUNC(clEnqueueReleaseVA_APIMediaSurfacesINTEL,
  677. "Intel QSV in OpenCL release");
  678. if (fail) {
  679. no_qsv:
  680. av_log(hwdev, AV_LOG_WARNING, "QSV to OpenCL mapping "
  681. "not usable.\n");
  682. priv->qsv_mapping_usable = 0;
  683. } else {
  684. priv->qsv_mapping_usable = 1;
  685. }
  686. av_free(props);
  687. }
  688. #endif
  689. #if HAVE_OPENCL_DXVA2
  690. {
  691. int fail = 0;
  692. CL_FUNC(clCreateFromDX9MediaSurfaceKHR,
  693. "DXVA2 to OpenCL mapping");
  694. CL_FUNC(clEnqueueAcquireDX9MediaSurfacesKHR,
  695. "DXVA2 in OpenCL acquire");
  696. CL_FUNC(clEnqueueReleaseDX9MediaSurfacesKHR,
  697. "DXVA2 in OpenCL release");
  698. if (fail) {
  699. av_log(hwdev, AV_LOG_WARNING, "DXVA2 to OpenCL mapping "
  700. "not usable.\n");
  701. priv->dxva2_mapping_usable = 0;
  702. } else {
  703. priv->dx9_media_adapter_type = CL_ADAPTER_D3D9EX_KHR;
  704. priv->dxva2_mapping_usable = 1;
  705. }
  706. }
  707. #endif
  708. #if HAVE_OPENCL_D3D11
  709. {
  710. const char *d3d11_ext = "cl_khr_d3d11_sharing";
  711. const char *nv12_ext = "cl_intel_d3d11_nv12_media_sharing";
  712. int fail = 0;
  713. if (!opencl_check_extension(hwdev, d3d11_ext)) {
  714. av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is "
  715. "required for D3D11 to OpenCL mapping.\n", d3d11_ext);
  716. fail = 1;
  717. } else if (!opencl_check_extension(hwdev, nv12_ext)) {
  718. av_log(hwdev, AV_LOG_VERBOSE, "The %s extension may be "
  719. "required for D3D11 to OpenCL mapping.\n", nv12_ext);
  720. // Not fatal.
  721. }
  722. CL_FUNC(clCreateFromD3D11Texture2DKHR,
  723. "D3D11 to OpenCL mapping");
  724. CL_FUNC(clEnqueueAcquireD3D11ObjectsKHR,
  725. "D3D11 in OpenCL acquire");
  726. CL_FUNC(clEnqueueReleaseD3D11ObjectsKHR,
  727. "D3D11 in OpenCL release");
  728. if (fail) {
  729. av_log(hwdev, AV_LOG_WARNING, "D3D11 to OpenCL mapping "
  730. "not usable.\n");
  731. priv->d3d11_mapping_usable = 0;
  732. } else {
  733. priv->d3d11_mapping_usable = 1;
  734. }
  735. }
  736. #endif
  737. #if HAVE_OPENCL_DRM_ARM
  738. {
  739. const char *drm_arm_ext = "cl_arm_import_memory";
  740. const char *image_ext = "cl_khr_image2d_from_buffer";
  741. int fail = 0;
  742. if (!opencl_check_extension(hwdev, drm_arm_ext)) {
  743. av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is "
  744. "required for DRM to OpenCL mapping on ARM.\n",
  745. drm_arm_ext);
  746. fail = 1;
  747. }
  748. if (!opencl_check_extension(hwdev, image_ext)) {
  749. av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is "
  750. "required for DRM to OpenCL mapping on ARM.\n",
  751. image_ext);
  752. fail = 1;
  753. }
  754. // clImportMemoryARM() is linked statically.
  755. if (fail) {
  756. av_log(hwdev, AV_LOG_WARNING, "DRM to OpenCL mapping on ARM "
  757. "not usable.\n");
  758. priv->drm_arm_mapping_usable = 0;
  759. } else {
  760. priv->drm_arm_mapping_usable = 1;
  761. }
  762. }
  763. #endif
  764. #undef CL_FUNC
  765. return 0;
  766. }
  767. static void opencl_device_uninit(AVHWDeviceContext *hwdev)
  768. {
  769. OpenCLDeviceContext *priv = hwdev->internal->priv;
  770. cl_int cle;
  771. if (priv->command_queue) {
  772. cle = clReleaseCommandQueue(priv->command_queue);
  773. if (cle != CL_SUCCESS) {
  774. av_log(hwdev, AV_LOG_ERROR, "Failed to release internal "
  775. "command queue reference: %d.\n", cle);
  776. }
  777. }
  778. }
  779. #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
  780. static int opencl_filter_intel_media_vaapi_platform(AVHWDeviceContext *hwdev,
  781. cl_platform_id platform_id,
  782. const char *platform_name,
  783. void *context)
  784. {
  785. // This doesn't exist as a platform extension, so just test whether
  786. // the function we will use for device enumeration exists.
  787. if (!clGetExtensionFunctionAddressForPlatform(platform_id,
  788. "clGetDeviceIDsFromVA_APIMediaAdapterINTEL")) {
  789. av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not export the "
  790. "VAAPI device enumeration function.\n", platform_name);
  791. return 1;
  792. } else {
  793. return 0;
  794. }
  795. }
  796. static int opencl_enumerate_intel_media_vaapi_devices(AVHWDeviceContext *hwdev,
  797. cl_platform_id platform_id,
  798. const char *platform_name,
  799. cl_uint *nb_devices,
  800. cl_device_id **devices,
  801. void *context)
  802. {
  803. VADisplay va_display = context;
  804. clGetDeviceIDsFromVA_APIMediaAdapterINTEL_fn
  805. clGetDeviceIDsFromVA_APIMediaAdapterINTEL;
  806. cl_int cle;
  807. int err;
  808. clGetDeviceIDsFromVA_APIMediaAdapterINTEL =
  809. clGetExtensionFunctionAddressForPlatform(platform_id,
  810. "clGetDeviceIDsFromVA_APIMediaAdapterINTEL");
  811. if (!clGetDeviceIDsFromVA_APIMediaAdapterINTEL) {
  812. av_log(hwdev, AV_LOG_ERROR, "Failed to get address of "
  813. "clGetDeviceIDsFromVA_APIMediaAdapterINTEL().\n");
  814. return AVERROR_UNKNOWN;
  815. }
  816. cle = clGetDeviceIDsFromVA_APIMediaAdapterINTEL(
  817. platform_id, CL_VA_API_DISPLAY_INTEL, va_display,
  818. CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, 0, NULL, nb_devices);
  819. if (cle == CL_DEVICE_NOT_FOUND) {
  820. av_log(hwdev, AV_LOG_DEBUG, "No VAAPI-supporting devices found "
  821. "on platform \"%s\".\n", platform_name);
  822. *nb_devices = 0;
  823. return 0;
  824. } else if (cle != CL_SUCCESS) {
  825. av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
  826. "on platform \"%s\": %d.\n", platform_name, cle);
  827. return AVERROR_UNKNOWN;
  828. }
  829. *devices = av_malloc_array(*nb_devices, sizeof(**devices));
  830. if (!*devices)
  831. return AVERROR(ENOMEM);
  832. cle = clGetDeviceIDsFromVA_APIMediaAdapterINTEL(
  833. platform_id, CL_VA_API_DISPLAY_INTEL, va_display,
  834. CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, *nb_devices, *devices, NULL);
  835. if (cle != CL_SUCCESS) {
  836. av_log(hwdev, AV_LOG_ERROR, "Failed to get list of VAAPI-supporting "
  837. "devices on platform \"%s\": %d.\n", platform_name, cle);
  838. av_freep(devices);
  839. return AVERROR_UNKNOWN;
  840. }
  841. return 0;
  842. }
  843. static int opencl_filter_intel_media_vaapi_device(AVHWDeviceContext *hwdev,
  844. cl_device_id device_id,
  845. const char *device_name,
  846. void *context)
  847. {
  848. const char *va_ext = "cl_intel_va_api_media_sharing";
  849. if (opencl_check_device_extension(device_id, va_ext)) {
  850. return 0;
  851. } else {
  852. av_log(hwdev, AV_LOG_DEBUG, "Device %s does not support the "
  853. "%s extension.\n", device_name, va_ext);
  854. return 1;
  855. }
  856. }
  857. #endif
  858. #if HAVE_OPENCL_DXVA2
  859. static int opencl_filter_dxva2_platform(AVHWDeviceContext *hwdev,
  860. cl_platform_id platform_id,
  861. const char *platform_name,
  862. void *context)
  863. {
  864. const char *dx9_ext = "cl_khr_dx9_media_sharing";
  865. if (opencl_check_platform_extension(platform_id, dx9_ext)) {
  866. return 0;
  867. } else {
  868. av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the "
  869. "%s extension.\n", platform_name, dx9_ext);
  870. return 1;
  871. }
  872. }
  873. static int opencl_enumerate_dxva2_devices(AVHWDeviceContext *hwdev,
  874. cl_platform_id platform_id,
  875. const char *platform_name,
  876. cl_uint *nb_devices,
  877. cl_device_id **devices,
  878. void *context)
  879. {
  880. IDirect3DDevice9 *device = context;
  881. clGetDeviceIDsFromDX9MediaAdapterKHR_fn
  882. clGetDeviceIDsFromDX9MediaAdapterKHR;
  883. cl_dx9_media_adapter_type_khr media_adapter_type = CL_ADAPTER_D3D9EX_KHR;
  884. cl_int cle;
  885. clGetDeviceIDsFromDX9MediaAdapterKHR =
  886. clGetExtensionFunctionAddressForPlatform(platform_id,
  887. "clGetDeviceIDsFromDX9MediaAdapterKHR");
  888. if (!clGetDeviceIDsFromDX9MediaAdapterKHR) {
  889. av_log(hwdev, AV_LOG_ERROR, "Failed to get address of "
  890. "clGetDeviceIDsFromDX9MediaAdapterKHR().\n");
  891. return AVERROR_UNKNOWN;
  892. }
  893. cle = clGetDeviceIDsFromDX9MediaAdapterKHR(
  894. platform_id, 1, &media_adapter_type, (void**)&device,
  895. CL_PREFERRED_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR,
  896. 0, NULL, nb_devices);
  897. if (cle == CL_DEVICE_NOT_FOUND) {
  898. av_log(hwdev, AV_LOG_DEBUG, "No DXVA2-supporting devices found "
  899. "on platform \"%s\".\n", platform_name);
  900. *nb_devices = 0;
  901. return 0;
  902. } else if (cle != CL_SUCCESS) {
  903. av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
  904. "on platform \"%s\": %d.\n", platform_name, cle);
  905. return AVERROR_UNKNOWN;
  906. }
  907. *devices = av_malloc_array(*nb_devices, sizeof(**devices));
  908. if (!*devices)
  909. return AVERROR(ENOMEM);
  910. cle = clGetDeviceIDsFromDX9MediaAdapterKHR(
  911. platform_id, 1, &media_adapter_type, (void**)&device,
  912. CL_PREFERRED_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR,
  913. *nb_devices, *devices, NULL);
  914. if (cle != CL_SUCCESS) {
  915. av_log(hwdev, AV_LOG_ERROR, "Failed to get list of DXVA2-supporting "
  916. "devices on platform \"%s\": %d.\n", platform_name, cle);
  917. av_freep(devices);
  918. return AVERROR_UNKNOWN;
  919. }
  920. return 0;
  921. }
  922. #endif
  923. #if HAVE_OPENCL_D3D11
  924. static int opencl_filter_d3d11_platform(AVHWDeviceContext *hwdev,
  925. cl_platform_id platform_id,
  926. const char *platform_name,
  927. void *context)
  928. {
  929. const char *d3d11_ext = "cl_khr_d3d11_sharing";
  930. if (opencl_check_platform_extension(platform_id, d3d11_ext)) {
  931. return 0;
  932. } else {
  933. av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the "
  934. "%s extension.\n", platform_name, d3d11_ext);
  935. return 1;
  936. }
  937. }
  938. static int opencl_enumerate_d3d11_devices(AVHWDeviceContext *hwdev,
  939. cl_platform_id platform_id,
  940. const char *platform_name,
  941. cl_uint *nb_devices,
  942. cl_device_id **devices,
  943. void *context)
  944. {
  945. ID3D11Device *device = context;
  946. clGetDeviceIDsFromD3D11KHR_fn clGetDeviceIDsFromD3D11KHR;
  947. cl_int cle;
  948. clGetDeviceIDsFromD3D11KHR =
  949. clGetExtensionFunctionAddressForPlatform(platform_id,
  950. "clGetDeviceIDsFromD3D11KHR");
  951. if (!clGetDeviceIDsFromD3D11KHR) {
  952. av_log(hwdev, AV_LOG_ERROR, "Failed to get address of "
  953. "clGetDeviceIDsFromD3D11KHR().\n");
  954. return AVERROR_UNKNOWN;
  955. }
  956. cle = clGetDeviceIDsFromD3D11KHR(platform_id,
  957. CL_D3D11_DEVICE_KHR, device,
  958. CL_PREFERRED_DEVICES_FOR_D3D11_KHR,
  959. 0, NULL, nb_devices);
  960. if (cle == CL_DEVICE_NOT_FOUND) {
  961. av_log(hwdev, AV_LOG_DEBUG, "No D3D11-supporting devices found "
  962. "on platform \"%s\".\n", platform_name);
  963. *nb_devices = 0;
  964. return 0;
  965. } else if (cle != CL_SUCCESS) {
  966. av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
  967. "on platform \"%s\": %d.\n", platform_name, cle);
  968. return AVERROR_UNKNOWN;
  969. }
  970. *devices = av_malloc_array(*nb_devices, sizeof(**devices));
  971. if (!*devices)
  972. return AVERROR(ENOMEM);
  973. cle = clGetDeviceIDsFromD3D11KHR(platform_id,
  974. CL_D3D11_DEVICE_KHR, device,
  975. CL_PREFERRED_DEVICES_FOR_D3D11_KHR,
  976. *nb_devices, *devices, NULL);
  977. if (cle != CL_SUCCESS) {
  978. av_log(hwdev, AV_LOG_ERROR, "Failed to get list of D3D11-supporting "
  979. "devices on platform \"%s\": %d.\n", platform_name, cle);
  980. av_freep(devices);
  981. return AVERROR_UNKNOWN;
  982. }
  983. return 0;
  984. }
  985. #endif
  986. #if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11
  987. static int opencl_filter_gpu_device(AVHWDeviceContext *hwdev,
  988. cl_device_id device_id,
  989. const char *device_name,
  990. void *context)
  991. {
  992. cl_device_type device_type;
  993. cl_int cle;
  994. cle = clGetDeviceInfo(device_id, CL_DEVICE_TYPE,
  995. sizeof(device_type), &device_type, NULL);
  996. if (cle != CL_SUCCESS) {
  997. av_log(hwdev, AV_LOG_ERROR, "Failed to query device type "
  998. "of device \"%s\".\n", device_name);
  999. return AVERROR_UNKNOWN;
  1000. }
  1001. if (!(device_type & CL_DEVICE_TYPE_GPU)) {
  1002. av_log(hwdev, AV_LOG_DEBUG, "Device %s skipped (not GPU).\n",
  1003. device_name);
  1004. return 1;
  1005. }
  1006. return 0;
  1007. }
  1008. #endif
  1009. #if HAVE_OPENCL_DRM_ARM
  1010. static int opencl_filter_drm_arm_platform(AVHWDeviceContext *hwdev,
  1011. cl_platform_id platform_id,
  1012. const char *platform_name,
  1013. void *context)
  1014. {
  1015. const char *drm_arm_ext = "cl_arm_import_memory";
  1016. if (opencl_check_platform_extension(platform_id, drm_arm_ext)) {
  1017. return 0;
  1018. } else {
  1019. av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the "
  1020. "%s extension.\n", platform_name, drm_arm_ext);
  1021. return 1;
  1022. }
  1023. }
  1024. static int opencl_filter_drm_arm_device(AVHWDeviceContext *hwdev,
  1025. cl_device_id device_id,
  1026. const char *device_name,
  1027. void *context)
  1028. {
  1029. const char *drm_arm_ext = "cl_arm_import_memory";
  1030. if (opencl_check_device_extension(device_id, drm_arm_ext)) {
  1031. return 0;
  1032. } else {
  1033. av_log(hwdev, AV_LOG_DEBUG, "Device %s does not support the "
  1034. "%s extension.\n", device_name, drm_arm_ext);
  1035. return 1;
  1036. }
  1037. }
  1038. #endif
  1039. static int opencl_device_derive(AVHWDeviceContext *hwdev,
  1040. AVHWDeviceContext *src_ctx,
  1041. int flags)
  1042. {
  1043. int err;
  1044. switch (src_ctx->type) {
  1045. #if HAVE_OPENCL_VAAPI_BEIGNET
  1046. case AV_HWDEVICE_TYPE_VAAPI:
  1047. {
  1048. // Surface mapping works via DRM PRIME fds with no special
  1049. // initialisation required in advance. This just finds the
  1050. // Beignet ICD by name.
  1051. AVDictionary *opts = NULL;
  1052. err = av_dict_set(&opts, "platform_vendor", "Intel", 0);
  1053. if (err >= 0)
  1054. err = av_dict_set(&opts, "platform_version", "beignet", 0);
  1055. if (err >= 0) {
  1056. OpenCLDeviceSelector selector = {
  1057. .platform_index = -1,
  1058. .device_index = 0,
  1059. .context = opts,
  1060. .enumerate_platforms = &opencl_enumerate_platforms,
  1061. .filter_platform = &opencl_filter_platform,
  1062. .enumerate_devices = &opencl_enumerate_devices,
  1063. .filter_device = NULL,
  1064. };
  1065. err = opencl_device_create_internal(hwdev, &selector, NULL);
  1066. }
  1067. av_dict_free(&opts);
  1068. }
  1069. break;
  1070. #endif
  1071. #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
  1072. // The generic code automatically attempts to derive from all
  1073. // ancestors of the given device, so we can ignore QSV devices here
  1074. // and just consider the inner VAAPI device it was derived from.
  1075. case AV_HWDEVICE_TYPE_VAAPI:
  1076. {
  1077. AVVAAPIDeviceContext *src_hwctx = src_ctx->hwctx;
  1078. cl_context_properties props[7] = {
  1079. CL_CONTEXT_PLATFORM,
  1080. 0,
  1081. CL_CONTEXT_VA_API_DISPLAY_INTEL,
  1082. (intptr_t)src_hwctx->display,
  1083. CL_CONTEXT_INTEROP_USER_SYNC,
  1084. CL_FALSE,
  1085. 0,
  1086. };
  1087. OpenCLDeviceSelector selector = {
  1088. .platform_index = -1,
  1089. .device_index = -1,
  1090. .context = src_hwctx->display,
  1091. .enumerate_platforms = &opencl_enumerate_platforms,
  1092. .filter_platform = &opencl_filter_intel_media_vaapi_platform,
  1093. .enumerate_devices = &opencl_enumerate_intel_media_vaapi_devices,
  1094. .filter_device = &opencl_filter_intel_media_vaapi_device,
  1095. };
  1096. err = opencl_device_create_internal(hwdev, &selector, props);
  1097. }
  1098. break;
  1099. #endif
  1100. #if HAVE_OPENCL_DXVA2
  1101. case AV_HWDEVICE_TYPE_DXVA2:
  1102. {
  1103. AVDXVA2DeviceContext *src_hwctx = src_ctx->hwctx;
  1104. IDirect3DDevice9 *device;
  1105. HANDLE device_handle;
  1106. HRESULT hr;
  1107. hr = IDirect3DDeviceManager9_OpenDeviceHandle(src_hwctx->devmgr,
  1108. &device_handle);
  1109. if (FAILED(hr)) {
  1110. av_log(hwdev, AV_LOG_ERROR, "Failed to open device handle "
  1111. "for Direct3D9 device: %lx.\n", (unsigned long)hr);
  1112. err = AVERROR_UNKNOWN;
  1113. break;
  1114. }
  1115. hr = IDirect3DDeviceManager9_LockDevice(src_hwctx->devmgr,
  1116. device_handle,
  1117. &device, FALSE);
  1118. if (SUCCEEDED(hr)) {
  1119. cl_context_properties props[5] = {
  1120. CL_CONTEXT_PLATFORM,
  1121. 0,
  1122. CL_CONTEXT_ADAPTER_D3D9EX_KHR,
  1123. (intptr_t)device,
  1124. 0,
  1125. };
  1126. OpenCLDeviceSelector selector = {
  1127. .platform_index = -1,
  1128. .device_index = -1,
  1129. .context = device,
  1130. .enumerate_platforms = &opencl_enumerate_platforms,
  1131. .filter_platform = &opencl_filter_dxva2_platform,
  1132. .enumerate_devices = &opencl_enumerate_dxva2_devices,
  1133. .filter_device = &opencl_filter_gpu_device,
  1134. };
  1135. err = opencl_device_create_internal(hwdev, &selector, props);
  1136. IDirect3DDeviceManager9_UnlockDevice(src_hwctx->devmgr,
  1137. device_handle, FALSE);
  1138. } else {
  1139. av_log(hwdev, AV_LOG_ERROR, "Failed to lock device handle "
  1140. "for Direct3D9 device: %lx.\n", (unsigned long)hr);
  1141. err = AVERROR_UNKNOWN;
  1142. }
  1143. IDirect3DDeviceManager9_CloseDeviceHandle(src_hwctx->devmgr,
  1144. device_handle);
  1145. }
  1146. break;
  1147. #endif
  1148. #if HAVE_OPENCL_D3D11
  1149. case AV_HWDEVICE_TYPE_D3D11VA:
  1150. {
  1151. AVD3D11VADeviceContext *src_hwctx = src_ctx->hwctx;
  1152. cl_context_properties props[5] = {
  1153. CL_CONTEXT_PLATFORM,
  1154. 0,
  1155. CL_CONTEXT_D3D11_DEVICE_KHR,
  1156. (intptr_t)src_hwctx->device,
  1157. 0,
  1158. };
  1159. OpenCLDeviceSelector selector = {
  1160. .platform_index = -1,
  1161. .device_index = -1,
  1162. .context = src_hwctx->device,
  1163. .enumerate_platforms = &opencl_enumerate_platforms,
  1164. .filter_platform = &opencl_filter_d3d11_platform,
  1165. .enumerate_devices = &opencl_enumerate_d3d11_devices,
  1166. .filter_device = &opencl_filter_gpu_device,
  1167. };
  1168. err = opencl_device_create_internal(hwdev, &selector, props);
  1169. }
  1170. break;
  1171. #endif
  1172. #if HAVE_OPENCL_DRM_ARM
  1173. case AV_HWDEVICE_TYPE_DRM:
  1174. {
  1175. OpenCLDeviceSelector selector = {
  1176. .platform_index = -1,
  1177. .device_index = -1,
  1178. .context = NULL,
  1179. .enumerate_platforms = &opencl_enumerate_platforms,
  1180. .filter_platform = &opencl_filter_drm_arm_platform,
  1181. .enumerate_devices = &opencl_enumerate_devices,
  1182. .filter_device = &opencl_filter_drm_arm_device,
  1183. };
  1184. err = opencl_device_create_internal(hwdev, &selector, NULL);
  1185. }
  1186. break;
  1187. #endif
  1188. default:
  1189. err = AVERROR(ENOSYS);
  1190. break;
  1191. }
  1192. if (err < 0)
  1193. return err;
  1194. return opencl_device_init(hwdev);
  1195. }
  1196. static int opencl_get_plane_format(enum AVPixelFormat pixfmt,
  1197. int plane, int width, int height,
  1198. cl_image_format *image_format,
  1199. cl_image_desc *image_desc)
  1200. {
  1201. const AVPixFmtDescriptor *desc;
  1202. const AVComponentDescriptor *comp;
  1203. int channels = 0, order = 0, depth = 0, step = 0;
  1204. int wsub, hsub, alpha;
  1205. int c;
  1206. if (plane >= AV_NUM_DATA_POINTERS)
  1207. return AVERROR(ENOENT);
  1208. desc = av_pix_fmt_desc_get(pixfmt);
  1209. // Only normal images are allowed.
  1210. if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM |
  1211. AV_PIX_FMT_FLAG_HWACCEL |
  1212. AV_PIX_FMT_FLAG_PAL))
  1213. return AVERROR(EINVAL);
  1214. wsub = 1 << desc->log2_chroma_w;
  1215. hsub = 1 << desc->log2_chroma_h;
  1216. // Subsampled components must be exact.
  1217. if (width & wsub - 1 || height & hsub - 1)
  1218. return AVERROR(EINVAL);
  1219. for (c = 0; c < desc->nb_components; c++) {
  1220. comp = &desc->comp[c];
  1221. if (comp->plane != plane)
  1222. continue;
  1223. // The step size must be a power of two.
  1224. if (comp->step != 1 && comp->step != 2 &&
  1225. comp->step != 4 && comp->step != 8)
  1226. return AVERROR(EINVAL);
  1227. // The bits in each component must be packed in the
  1228. // most-significant-bits of the relevant bytes.
  1229. if (comp->shift + comp->depth != 8 &&
  1230. comp->shift + comp->depth != 16)
  1231. return AVERROR(EINVAL);
  1232. // The depth must not vary between components.
  1233. if (depth && comp->depth != depth)
  1234. return AVERROR(EINVAL);
  1235. // If a single data element crosses multiple bytes then
  1236. // it must match the native endianness.
  1237. if (comp->depth > 8 &&
  1238. HAVE_BIGENDIAN == !(desc->flags & AV_PIX_FMT_FLAG_BE))
  1239. return AVERROR(EINVAL);
  1240. // A single data element must not contain multiple samples
  1241. // from the same component.
  1242. if (step && comp->step != step)
  1243. return AVERROR(EINVAL);
  1244. order = order * 10 + c + 1;
  1245. depth = comp->depth;
  1246. step = comp->step;
  1247. alpha = (desc->flags & AV_PIX_FMT_FLAG_ALPHA &&
  1248. c == desc->nb_components - 1);
  1249. ++channels;
  1250. }
  1251. if (channels == 0)
  1252. return AVERROR(ENOENT);
  1253. memset(image_format, 0, sizeof(*image_format));
  1254. memset(image_desc, 0, sizeof(*image_desc));
  1255. image_desc->image_type = CL_MEM_OBJECT_IMAGE2D;
  1256. if (plane == 0 || alpha) {
  1257. image_desc->image_width = width;
  1258. image_desc->image_height = height;
  1259. image_desc->image_row_pitch = step * width;
  1260. } else {
  1261. image_desc->image_width = width / wsub;
  1262. image_desc->image_height = height / hsub;
  1263. image_desc->image_row_pitch = step * width / wsub;
  1264. }
  1265. if (depth <= 8) {
  1266. image_format->image_channel_data_type = CL_UNORM_INT8;
  1267. } else {
  1268. if (depth <= 16)
  1269. image_format->image_channel_data_type = CL_UNORM_INT16;
  1270. else
  1271. return AVERROR(EINVAL);
  1272. }
  1273. #define CHANNEL_ORDER(order, type) \
  1274. case order: image_format->image_channel_order = type; break;
  1275. switch (order) {
  1276. CHANNEL_ORDER(1, CL_R);
  1277. CHANNEL_ORDER(2, CL_R);
  1278. CHANNEL_ORDER(3, CL_R);
  1279. CHANNEL_ORDER(4, CL_R);
  1280. CHANNEL_ORDER(12, CL_RG);
  1281. CHANNEL_ORDER(23, CL_RG);
  1282. CHANNEL_ORDER(1234, CL_RGBA);
  1283. CHANNEL_ORDER(3214, CL_BGRA);
  1284. CHANNEL_ORDER(4123, CL_ARGB);
  1285. #ifdef CL_ABGR
  1286. CHANNEL_ORDER(4321, CL_ABGR);
  1287. #endif
  1288. default:
  1289. return AVERROR(EINVAL);
  1290. }
  1291. #undef CHANNEL_ORDER
  1292. return 0;
  1293. }
  1294. static int opencl_frames_get_constraints(AVHWDeviceContext *hwdev,
  1295. const void *hwconfig,
  1296. AVHWFramesConstraints *constraints)
  1297. {
  1298. AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
  1299. cl_uint nb_image_formats;
  1300. cl_image_format *image_formats = NULL;
  1301. cl_int cle;
  1302. enum AVPixelFormat pix_fmt;
  1303. int err, pix_fmts_found;
  1304. size_t max_width, max_height;
  1305. cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_IMAGE2D_MAX_WIDTH,
  1306. sizeof(max_width), &max_width, NULL);
  1307. if (cle != CL_SUCCESS) {
  1308. av_log(hwdev, AV_LOG_ERROR, "Failed to query maximum "
  1309. "supported image width: %d.\n", cle);
  1310. } else {
  1311. constraints->max_width = max_width;
  1312. }
  1313. cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_IMAGE2D_MAX_HEIGHT,
  1314. sizeof(max_height), &max_height, NULL);
  1315. if (cle != CL_SUCCESS) {
  1316. av_log(hwdev, AV_LOG_ERROR, "Failed to query maximum "
  1317. "supported image height: %d.\n", cle);
  1318. } else {
  1319. constraints->max_height = max_height;
  1320. }
  1321. av_log(hwdev, AV_LOG_DEBUG, "Maximum supported image size %dx%d.\n",
  1322. constraints->max_width, constraints->max_height);
  1323. cle = clGetSupportedImageFormats(hwctx->context,
  1324. CL_MEM_READ_WRITE,
  1325. CL_MEM_OBJECT_IMAGE2D,
  1326. 0, NULL, &nb_image_formats);
  1327. if (cle != CL_SUCCESS) {
  1328. av_log(hwdev, AV_LOG_ERROR, "Failed to query supported "
  1329. "image formats: %d.\n", cle);
  1330. err = AVERROR(ENOSYS);
  1331. goto fail;
  1332. }
  1333. if (nb_image_formats == 0) {
  1334. av_log(hwdev, AV_LOG_ERROR, "No image support in OpenCL "
  1335. "driver (zero supported image formats).\n");
  1336. err = AVERROR(ENOSYS);
  1337. goto fail;
  1338. }
  1339. image_formats =
  1340. av_malloc_array(nb_image_formats, sizeof(*image_formats));
  1341. if (!image_formats) {
  1342. err = AVERROR(ENOMEM);
  1343. goto fail;
  1344. }
  1345. cle = clGetSupportedImageFormats(hwctx->context,
  1346. CL_MEM_READ_WRITE,
  1347. CL_MEM_OBJECT_IMAGE2D,
  1348. nb_image_formats,
  1349. image_formats, NULL);
  1350. if (cle != CL_SUCCESS) {
  1351. av_log(hwdev, AV_LOG_ERROR, "Failed to query supported "
  1352. "image formats: %d.\n", cle);
  1353. err = AVERROR(ENOSYS);
  1354. goto fail;
  1355. }
  1356. pix_fmts_found = 0;
  1357. for (pix_fmt = 0; pix_fmt < AV_PIX_FMT_NB; pix_fmt++) {
  1358. cl_image_format image_format;
  1359. cl_image_desc image_desc;
  1360. int plane, i;
  1361. for (plane = 0;; plane++) {
  1362. err = opencl_get_plane_format(pix_fmt, plane, 0, 0,
  1363. &image_format,
  1364. &image_desc);
  1365. if (err < 0)
  1366. break;
  1367. for (i = 0; i < nb_image_formats; i++) {
  1368. if (image_formats[i].image_channel_order ==
  1369. image_format.image_channel_order &&
  1370. image_formats[i].image_channel_data_type ==
  1371. image_format.image_channel_data_type)
  1372. break;
  1373. }
  1374. if (i == nb_image_formats) {
  1375. err = AVERROR(EINVAL);
  1376. break;
  1377. }
  1378. }
  1379. if (err != AVERROR(ENOENT))
  1380. continue;
  1381. av_log(hwdev, AV_LOG_DEBUG, "Format %s supported.\n",
  1382. av_get_pix_fmt_name(pix_fmt));
  1383. err = av_reallocp_array(&constraints->valid_sw_formats,
  1384. pix_fmts_found + 2,
  1385. sizeof(*constraints->valid_sw_formats));
  1386. if (err < 0)
  1387. goto fail;
  1388. constraints->valid_sw_formats[pix_fmts_found] = pix_fmt;
  1389. constraints->valid_sw_formats[pix_fmts_found + 1] =
  1390. AV_PIX_FMT_NONE;
  1391. ++pix_fmts_found;
  1392. }
  1393. av_freep(&image_formats);
  1394. constraints->valid_hw_formats =
  1395. av_malloc_array(2, sizeof(*constraints->valid_hw_formats));
  1396. if (!constraints->valid_hw_formats) {
  1397. err = AVERROR(ENOMEM);
  1398. goto fail;
  1399. }
  1400. constraints->valid_hw_formats[0] = AV_PIX_FMT_OPENCL;
  1401. constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
  1402. return 0;
  1403. fail:
  1404. av_freep(&image_formats);
  1405. return err;
  1406. }
  1407. static void opencl_pool_free(void *opaque, uint8_t *data)
  1408. {
  1409. AVHWFramesContext *hwfc = opaque;
  1410. AVOpenCLFrameDescriptor *desc = (AVOpenCLFrameDescriptor*)data;
  1411. cl_int cle;
  1412. int p;
  1413. for (p = 0; p < desc->nb_planes; p++) {
  1414. cle = clReleaseMemObject(desc->planes[p]);
  1415. if (cle != CL_SUCCESS) {
  1416. av_log(hwfc, AV_LOG_ERROR, "Failed to release plane %d: "
  1417. "%d.\n", p, cle);
  1418. }
  1419. }
  1420. av_free(desc);
  1421. }
  1422. static AVBufferRef *opencl_pool_alloc(void *opaque, int size)
  1423. {
  1424. AVHWFramesContext *hwfc = opaque;
  1425. AVOpenCLDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  1426. AVOpenCLFrameDescriptor *desc;
  1427. cl_int cle;
  1428. cl_mem image;
  1429. cl_image_format image_format;
  1430. cl_image_desc image_desc;
  1431. int err, p;
  1432. AVBufferRef *ref;
  1433. desc = av_mallocz(sizeof(*desc));
  1434. if (!desc)
  1435. return NULL;
  1436. for (p = 0;; p++) {
  1437. err = opencl_get_plane_format(hwfc->sw_format, p,
  1438. hwfc->width, hwfc->height,
  1439. &image_format, &image_desc);
  1440. if (err == AVERROR(ENOENT))
  1441. break;
  1442. if (err < 0)
  1443. goto fail;
  1444. // For generic image objects, the pitch is determined by the
  1445. // implementation.
  1446. image_desc.image_row_pitch = 0;
  1447. image = clCreateImage(hwctx->context, CL_MEM_READ_WRITE,
  1448. &image_format, &image_desc, NULL, &cle);
  1449. if (!image) {
  1450. av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
  1451. "plane %d: %d.\n", p, cle);
  1452. goto fail;
  1453. }
  1454. desc->planes[p] = image;
  1455. }
  1456. desc->nb_planes = p;
  1457. ref = av_buffer_create((uint8_t*)desc, sizeof(*desc),
  1458. &opencl_pool_free, hwfc, 0);
  1459. if (!ref)
  1460. goto fail;
  1461. return ref;
  1462. fail:
  1463. for (p = 0; desc->planes[p]; p++)
  1464. clReleaseMemObject(desc->planes[p]);
  1465. av_free(desc);
  1466. return NULL;
  1467. }
  1468. static int opencl_frames_init_command_queue(AVHWFramesContext *hwfc)
  1469. {
  1470. AVOpenCLFramesContext *hwctx = hwfc->hwctx;
  1471. OpenCLDeviceContext *devpriv = hwfc->device_ctx->internal->priv;
  1472. OpenCLFramesContext *priv = hwfc->internal->priv;
  1473. cl_int cle;
  1474. priv->command_queue = hwctx->command_queue ? hwctx->command_queue
  1475. : devpriv->command_queue;
  1476. cle = clRetainCommandQueue(priv->command_queue);
  1477. if (cle != CL_SUCCESS) {
  1478. av_log(hwfc, AV_LOG_ERROR, "Failed to retain frame "
  1479. "command queue: %d.\n", cle);
  1480. return AVERROR(EIO);
  1481. }
  1482. return 0;
  1483. }
  1484. static int opencl_frames_init(AVHWFramesContext *hwfc)
  1485. {
  1486. if (!hwfc->pool) {
  1487. hwfc->internal->pool_internal =
  1488. av_buffer_pool_init2(sizeof(cl_mem), hwfc,
  1489. &opencl_pool_alloc, NULL);
  1490. if (!hwfc->internal->pool_internal)
  1491. return AVERROR(ENOMEM);
  1492. }
  1493. return opencl_frames_init_command_queue(hwfc);
  1494. }
  1495. static void opencl_frames_uninit(AVHWFramesContext *hwfc)
  1496. {
  1497. OpenCLFramesContext *priv = hwfc->internal->priv;
  1498. cl_int cle;
  1499. #if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11
  1500. int i, p;
  1501. for (i = 0; i < priv->nb_mapped_frames; i++) {
  1502. AVOpenCLFrameDescriptor *desc = &priv->mapped_frames[i];
  1503. for (p = 0; p < desc->nb_planes; p++) {
  1504. cle = clReleaseMemObject(desc->planes[p]);
  1505. if (cle != CL_SUCCESS) {
  1506. av_log(hwfc, AV_LOG_ERROR, "Failed to release mapped "
  1507. "frame object (frame %d plane %d): %d.\n",
  1508. i, p, cle);
  1509. }
  1510. }
  1511. }
  1512. av_freep(&priv->mapped_frames);
  1513. #endif
  1514. cle = clReleaseCommandQueue(priv->command_queue);
  1515. if (cle != CL_SUCCESS) {
  1516. av_log(hwfc, AV_LOG_ERROR, "Failed to release frame "
  1517. "command queue: %d.\n", cle);
  1518. }
  1519. }
  1520. static int opencl_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
  1521. {
  1522. AVOpenCLFrameDescriptor *desc;
  1523. int p;
  1524. frame->buf[0] = av_buffer_pool_get(hwfc->pool);
  1525. if (!frame->buf[0])
  1526. return AVERROR(ENOMEM);
  1527. desc = (AVOpenCLFrameDescriptor*)frame->buf[0]->data;
  1528. for (p = 0; p < desc->nb_planes; p++)
  1529. frame->data[p] = (uint8_t*)desc->planes[p];
  1530. frame->format = AV_PIX_FMT_OPENCL;
  1531. frame->width = hwfc->width;
  1532. frame->height = hwfc->height;
  1533. return 0;
  1534. }
  1535. static int opencl_transfer_get_formats(AVHWFramesContext *hwfc,
  1536. enum AVHWFrameTransferDirection dir,
  1537. enum AVPixelFormat **formats)
  1538. {
  1539. enum AVPixelFormat *fmts;
  1540. fmts = av_malloc_array(2, sizeof(*fmts));
  1541. if (!fmts)
  1542. return AVERROR(ENOMEM);
  1543. fmts[0] = hwfc->sw_format;
  1544. fmts[1] = AV_PIX_FMT_NONE;
  1545. *formats = fmts;
  1546. return 0;
  1547. }
  1548. static int opencl_wait_events(AVHWFramesContext *hwfc,
  1549. cl_event *events, int nb_events)
  1550. {
  1551. cl_int cle;
  1552. int i;
  1553. cle = clWaitForEvents(nb_events, events);
  1554. if (cle != CL_SUCCESS) {
  1555. av_log(hwfc, AV_LOG_ERROR, "Failed to wait for event "
  1556. "completion: %d.\n", cle);
  1557. return AVERROR(EIO);
  1558. }
  1559. for (i = 0; i < nb_events; i++) {
  1560. cle = clReleaseEvent(events[i]);
  1561. if (cle != CL_SUCCESS) {
  1562. av_log(hwfc, AV_LOG_ERROR, "Failed to release "
  1563. "event: %d.\n", cle);
  1564. }
  1565. }
  1566. return 0;
  1567. }
  1568. static int opencl_transfer_data_from(AVHWFramesContext *hwfc,
  1569. AVFrame *dst, const AVFrame *src)
  1570. {
  1571. OpenCLFramesContext *priv = hwfc->internal->priv;
  1572. cl_image_format image_format;
  1573. cl_image_desc image_desc;
  1574. cl_int cle;
  1575. size_t origin[3] = { 0, 0, 0 };
  1576. size_t region[3];
  1577. cl_event events[AV_NUM_DATA_POINTERS];
  1578. int err, p;
  1579. if (dst->format != hwfc->sw_format)
  1580. return AVERROR(EINVAL);
  1581. for (p = 0;; p++) {
  1582. err = opencl_get_plane_format(hwfc->sw_format, p,
  1583. src->width, src->height,
  1584. &image_format, &image_desc);
  1585. if (err < 0) {
  1586. if (err == AVERROR(ENOENT))
  1587. err = 0;
  1588. break;
  1589. }
  1590. if (!dst->data[p]) {
  1591. av_log(hwfc, AV_LOG_ERROR, "Plane %d missing on "
  1592. "destination frame for transfer.\n", p);
  1593. err = AVERROR(EINVAL);
  1594. break;
  1595. }
  1596. region[0] = image_desc.image_width;
  1597. region[1] = image_desc.image_height;
  1598. region[2] = 1;
  1599. cle = clEnqueueReadImage(priv->command_queue,
  1600. (cl_mem)src->data[p],
  1601. CL_FALSE, origin, region,
  1602. dst->linesize[p], 0,
  1603. dst->data[p],
  1604. 0, NULL, &events[p]);
  1605. if (cle != CL_SUCCESS) {
  1606. av_log(hwfc, AV_LOG_ERROR, "Failed to enqueue read of "
  1607. "OpenCL image plane %d: %d.\n", p, cle);
  1608. err = AVERROR(EIO);
  1609. break;
  1610. }
  1611. }
  1612. opencl_wait_events(hwfc, events, p);
  1613. return err;
  1614. }
  1615. static int opencl_transfer_data_to(AVHWFramesContext *hwfc,
  1616. AVFrame *dst, const AVFrame *src)
  1617. {
  1618. OpenCLFramesContext *priv = hwfc->internal->priv;
  1619. cl_image_format image_format;
  1620. cl_image_desc image_desc;
  1621. cl_int cle;
  1622. size_t origin[3] = { 0, 0, 0 };
  1623. size_t region[3];
  1624. cl_event events[AV_NUM_DATA_POINTERS];
  1625. int err, p;
  1626. if (src->format != hwfc->sw_format)
  1627. return AVERROR(EINVAL);
  1628. for (p = 0;; p++) {
  1629. err = opencl_get_plane_format(hwfc->sw_format, p,
  1630. src->width, src->height,
  1631. &image_format, &image_desc);
  1632. if (err < 0) {
  1633. if (err == AVERROR(ENOENT))
  1634. err = 0;
  1635. break;
  1636. }
  1637. if (!src->data[p]) {
  1638. av_log(hwfc, AV_LOG_ERROR, "Plane %d missing on "
  1639. "source frame for transfer.\n", p);
  1640. err = AVERROR(EINVAL);
  1641. break;
  1642. }
  1643. region[0] = image_desc.image_width;
  1644. region[1] = image_desc.image_height;
  1645. region[2] = 1;
  1646. cle = clEnqueueWriteImage(priv->command_queue,
  1647. (cl_mem)dst->data[p],
  1648. CL_FALSE, origin, region,
  1649. src->linesize[p], 0,
  1650. src->data[p],
  1651. 0, NULL, &events[p]);
  1652. if (cle != CL_SUCCESS) {
  1653. av_log(hwfc, AV_LOG_ERROR, "Failed to enqueue write of "
  1654. "OpenCL image plane %d: %d.\n", p, cle);
  1655. err = AVERROR(EIO);
  1656. break;
  1657. }
  1658. }
  1659. opencl_wait_events(hwfc, events, p);
  1660. return err;
  1661. }
  1662. typedef struct OpenCLMapping {
  1663. // The mapped addresses for each plane.
  1664. // The destination frame is not available when we unmap, so these
  1665. // need to be stored separately.
  1666. void *address[AV_NUM_DATA_POINTERS];
  1667. } OpenCLMapping;
  1668. static void opencl_unmap_frame(AVHWFramesContext *hwfc,
  1669. HWMapDescriptor *hwmap)
  1670. {
  1671. OpenCLFramesContext *priv = hwfc->internal->priv;
  1672. OpenCLMapping *map = hwmap->priv;
  1673. cl_event events[AV_NUM_DATA_POINTERS];
  1674. int p, e;
  1675. cl_int cle;
  1676. for (p = e = 0; p < FF_ARRAY_ELEMS(map->address); p++) {
  1677. if (!map->address[p])
  1678. break;
  1679. cle = clEnqueueUnmapMemObject(priv->command_queue,
  1680. (cl_mem)hwmap->source->data[p],
  1681. map->address[p],
  1682. 0, NULL, &events[e]);
  1683. if (cle != CL_SUCCESS) {
  1684. av_log(hwfc, AV_LOG_ERROR, "Failed to unmap OpenCL "
  1685. "image plane %d: %d.\n", p, cle);
  1686. }
  1687. ++e;
  1688. }
  1689. opencl_wait_events(hwfc, events, e);
  1690. av_free(map);
  1691. }
  1692. static int opencl_map_frame(AVHWFramesContext *hwfc, AVFrame *dst,
  1693. const AVFrame *src, int flags)
  1694. {
  1695. OpenCLFramesContext *priv = hwfc->internal->priv;
  1696. cl_map_flags map_flags;
  1697. cl_image_format image_format;
  1698. cl_image_desc image_desc;
  1699. cl_int cle;
  1700. OpenCLMapping *map;
  1701. size_t origin[3] = { 0, 0, 0 };
  1702. size_t region[3];
  1703. size_t row_pitch;
  1704. cl_event events[AV_NUM_DATA_POINTERS];
  1705. int err, p;
  1706. av_assert0(hwfc->sw_format == dst->format);
  1707. if (flags & AV_HWFRAME_MAP_OVERWRITE &&
  1708. !(flags & AV_HWFRAME_MAP_READ)) {
  1709. // This is mutually exclusive with the read/write flags, so
  1710. // there is no way to map with read here.
  1711. map_flags = CL_MAP_WRITE_INVALIDATE_REGION;
  1712. } else {
  1713. map_flags = 0;
  1714. if (flags & AV_HWFRAME_MAP_READ)
  1715. map_flags |= CL_MAP_READ;
  1716. if (flags & AV_HWFRAME_MAP_WRITE)
  1717. map_flags |= CL_MAP_WRITE;
  1718. }
  1719. map = av_mallocz(sizeof(*map));
  1720. if (!map)
  1721. return AVERROR(ENOMEM);
  1722. for (p = 0;; p++) {
  1723. err = opencl_get_plane_format(hwfc->sw_format, p,
  1724. src->width, src->height,
  1725. &image_format, &image_desc);
  1726. if (err == AVERROR(ENOENT))
  1727. break;
  1728. if (err < 0)
  1729. goto fail;
  1730. region[0] = image_desc.image_width;
  1731. region[1] = image_desc.image_height;
  1732. region[2] = 1;
  1733. map->address[p] =
  1734. clEnqueueMapImage(priv->command_queue,
  1735. (cl_mem)src->data[p],
  1736. CL_FALSE, map_flags, origin, region,
  1737. &row_pitch, NULL, 0, NULL,
  1738. &events[p], &cle);
  1739. if (!map->address[p]) {
  1740. av_log(hwfc, AV_LOG_ERROR, "Failed to map OpenCL "
  1741. "image plane %d: %d.\n", p, cle);
  1742. err = AVERROR(EIO);
  1743. goto fail;
  1744. }
  1745. dst->data[p] = map->address[p];
  1746. av_log(hwfc, AV_LOG_DEBUG, "Map plane %d (%p -> %p).\n",
  1747. p, src->data[p], dst->data[p]);
  1748. }
  1749. err = opencl_wait_events(hwfc, events, p);
  1750. if (err < 0)
  1751. goto fail;
  1752. err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
  1753. &opencl_unmap_frame, map);
  1754. if (err < 0)
  1755. goto fail;
  1756. dst->width = src->width;
  1757. dst->height = src->height;
  1758. return 0;
  1759. fail:
  1760. for (p = 0; p < AV_NUM_DATA_POINTERS; p++) {
  1761. if (!map->address[p])
  1762. break;
  1763. clEnqueueUnmapMemObject(priv->command_queue,
  1764. (cl_mem)src->data[p],
  1765. map->address[p],
  1766. 0, NULL, &events[p]);
  1767. }
  1768. if (p > 0)
  1769. opencl_wait_events(hwfc, events, p);
  1770. av_freep(&map);
  1771. return err;
  1772. }
  1773. #if HAVE_OPENCL_VAAPI_BEIGNET
  1774. typedef struct VAAPItoOpenCLMapping {
  1775. VAImage va_image;
  1776. VABufferInfo va_buffer_info;
  1777. AVOpenCLFrameDescriptor frame;
  1778. } VAAPItoOpenCLMapping;
  1779. static void opencl_unmap_from_vaapi(AVHWFramesContext *src_fc,
  1780. HWMapDescriptor *hwmap)
  1781. {
  1782. VAAPItoOpenCLMapping *mapping = hwmap->priv;
  1783. AVVAAPIDeviceContext *src_dev = src_fc->device_ctx->hwctx;
  1784. VASurfaceID surface_id;
  1785. VAStatus vas;
  1786. cl_int cle;
  1787. int i;
  1788. surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
  1789. av_log(src_fc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from OpenCL.\n",
  1790. surface_id);
  1791. for (i = 0; i < mapping->frame.nb_planes; i++) {
  1792. cle = clReleaseMemObject(mapping->frame.planes[i]);
  1793. if (cle != CL_SUCCESS) {
  1794. av_log(src_fc, AV_LOG_ERROR, "Failed to release CL "
  1795. "buffer of plane %d of VA image %#x (derived "
  1796. "from surface %#x): %d.\n", i,
  1797. mapping->va_image.buf, surface_id, cle);
  1798. }
  1799. }
  1800. vas = vaReleaseBufferHandle(src_dev->display,
  1801. mapping->va_image.buf);
  1802. if (vas != VA_STATUS_SUCCESS) {
  1803. av_log(src_fc, AV_LOG_ERROR, "Failed to release buffer "
  1804. "handle of image %#x (derived from surface %#x): "
  1805. "%d (%s).\n", mapping->va_image.buf, surface_id,
  1806. vas, vaErrorStr(vas));
  1807. }
  1808. vas = vaDestroyImage(src_dev->display,
  1809. mapping->va_image.image_id);
  1810. if (vas != VA_STATUS_SUCCESS) {
  1811. av_log(src_fc, AV_LOG_ERROR, "Failed to destroy image "
  1812. "derived from surface %#x: %d (%s).\n",
  1813. surface_id, vas, vaErrorStr(vas));
  1814. }
  1815. av_free(mapping);
  1816. }
  1817. static int opencl_map_from_vaapi(AVHWFramesContext *dst_fc, AVFrame *dst,
  1818. const AVFrame *src, int flags)
  1819. {
  1820. AVHWFramesContext *src_fc =
  1821. (AVHWFramesContext*)src->hw_frames_ctx->data;
  1822. AVVAAPIDeviceContext *src_dev = src_fc->device_ctx->hwctx;
  1823. AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
  1824. OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv;
  1825. VAAPItoOpenCLMapping *mapping = NULL;
  1826. VASurfaceID surface_id;
  1827. VAStatus vas;
  1828. cl_int cle;
  1829. int err, p;
  1830. surface_id = (VASurfaceID)(uintptr_t)src->data[3];
  1831. av_log(src_fc, AV_LOG_DEBUG, "Map VAAPI surface %#x to OpenCL.\n",
  1832. surface_id);
  1833. mapping = av_mallocz(sizeof(*mapping));
  1834. if (!mapping)
  1835. return AVERROR(ENOMEM);
  1836. vas = vaDeriveImage(src_dev->display, surface_id,
  1837. &mapping->va_image);
  1838. if (vas != VA_STATUS_SUCCESS) {
  1839. av_log(src_fc, AV_LOG_ERROR, "Failed to derive image from "
  1840. "surface %#x: %d (%s).\n",
  1841. surface_id, vas, vaErrorStr(vas));
  1842. err = AVERROR(EIO);
  1843. goto fail;
  1844. }
  1845. mapping->va_buffer_info.mem_type =
  1846. VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
  1847. vas = vaAcquireBufferHandle(src_dev->display,
  1848. mapping->va_image.buf,
  1849. &mapping->va_buffer_info);
  1850. if (vas != VA_STATUS_SUCCESS) {
  1851. av_log(src_fc, AV_LOG_ERROR, "Failed to get buffer "
  1852. "handle from image %#x (derived from surface %#x): "
  1853. "%d (%s).\n", mapping->va_image.buf, surface_id,
  1854. vas, vaErrorStr(vas));
  1855. vaDestroyImage(src_dev->display, mapping->va_image.buf);
  1856. err = AVERROR(EIO);
  1857. goto fail_derived;
  1858. }
  1859. av_log(dst_fc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
  1860. mapping->va_buffer_info.handle);
  1861. mapping->frame.nb_planes = mapping->va_image.num_planes;
  1862. for (p = 0; p < mapping->frame.nb_planes; p++) {
  1863. cl_import_image_info_intel image_info = {
  1864. .fd = mapping->va_buffer_info.handle,
  1865. .size = mapping->va_buffer_info.mem_size,
  1866. .type = CL_MEM_OBJECT_IMAGE2D,
  1867. .offset = mapping->va_image.offsets[p],
  1868. .row_pitch = mapping->va_image.pitches[p],
  1869. };
  1870. cl_image_desc image_desc;
  1871. err = opencl_get_plane_format(src_fc->sw_format, p,
  1872. mapping->va_image.width,
  1873. mapping->va_image.height,
  1874. &image_info.fmt,
  1875. &image_desc);
  1876. if (err < 0) {
  1877. av_log(dst_fc, AV_LOG_ERROR, "VA %#x (derived from "
  1878. "surface %#x) has invalid parameters: %d.\n",
  1879. mapping->va_image.buf, surface_id, err);
  1880. goto fail_mapped;
  1881. }
  1882. image_info.width = image_desc.image_width;
  1883. image_info.height = image_desc.image_height;
  1884. mapping->frame.planes[p] =
  1885. priv->clCreateImageFromFdINTEL(dst_dev->context,
  1886. &image_info, &cle);
  1887. if (!mapping->frame.planes[p]) {
  1888. av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL image "
  1889. "from plane %d of VA image %#x (derived from "
  1890. "surface %#x): %d.\n", p,
  1891. mapping->va_image.buf, surface_id, cle);
  1892. err = AVERROR(EIO);
  1893. goto fail_mapped;
  1894. }
  1895. dst->data[p] = (uint8_t*)mapping->frame.planes[p];
  1896. }
  1897. err = ff_hwframe_map_create(src->hw_frames_ctx,
  1898. dst, src, &opencl_unmap_from_vaapi,
  1899. mapping);
  1900. if (err < 0)
  1901. goto fail_mapped;
  1902. dst->width = src->width;
  1903. dst->height = src->height;
  1904. return 0;
  1905. fail_mapped:
  1906. for (p = 0; p < mapping->frame.nb_planes; p++) {
  1907. if (mapping->frame.planes[p])
  1908. clReleaseMemObject(mapping->frame.planes[p]);
  1909. }
  1910. vaReleaseBufferHandle(src_dev->display, mapping->va_image.buf);
  1911. fail_derived:
  1912. vaDestroyImage(src_dev->display, mapping->va_image.image_id);
  1913. fail:
  1914. av_freep(&mapping);
  1915. return err;
  1916. }
  1917. #endif
  1918. static inline cl_mem_flags opencl_mem_flags_for_mapping(int map_flags)
  1919. {
  1920. if ((map_flags & AV_HWFRAME_MAP_READ) &&
  1921. (map_flags & AV_HWFRAME_MAP_WRITE))
  1922. return CL_MEM_READ_WRITE;
  1923. else if (map_flags & AV_HWFRAME_MAP_READ)
  1924. return CL_MEM_READ_ONLY;
  1925. else if (map_flags & AV_HWFRAME_MAP_WRITE)
  1926. return CL_MEM_WRITE_ONLY;
  1927. else
  1928. return 0;
  1929. }
  1930. #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
  1931. static void opencl_unmap_from_qsv(AVHWFramesContext *dst_fc,
  1932. HWMapDescriptor *hwmap)
  1933. {
  1934. AVOpenCLFrameDescriptor *desc = hwmap->priv;
  1935. OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
  1936. OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
  1937. cl_event event;
  1938. cl_int cle;
  1939. int p;
  1940. av_log(dst_fc, AV_LOG_DEBUG, "Unmap QSV/VAAPI surface from OpenCL.\n");
  1941. cle = device_priv->clEnqueueReleaseVA_APIMediaSurfacesINTEL(
  1942. frames_priv->command_queue, desc->nb_planes, desc->planes,
  1943. 0, NULL, &event);
  1944. if (cle != CL_SUCCESS) {
  1945. av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface "
  1946. "handles: %d.\n", cle);
  1947. }
  1948. opencl_wait_events(dst_fc, &event, 1);
  1949. for (p = 0; p < desc->nb_planes; p++) {
  1950. cle = clReleaseMemObject(desc->planes[p]);
  1951. if (cle != CL_SUCCESS) {
  1952. av_log(dst_fc, AV_LOG_ERROR, "Failed to release CL "
  1953. "image of plane %d of QSV/VAAPI surface: %d\n",
  1954. p, cle);
  1955. }
  1956. }
  1957. av_free(desc);
  1958. }
  1959. static int opencl_map_from_qsv(AVHWFramesContext *dst_fc, AVFrame *dst,
  1960. const AVFrame *src, int flags)
  1961. {
  1962. AVHWFramesContext *src_fc =
  1963. (AVHWFramesContext*)src->hw_frames_ctx->data;
  1964. AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
  1965. OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
  1966. OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
  1967. AVOpenCLFrameDescriptor *desc;
  1968. VASurfaceID va_surface;
  1969. cl_mem_flags cl_flags;
  1970. cl_event event;
  1971. cl_int cle;
  1972. int err, p;
  1973. if (src->format == AV_PIX_FMT_QSV) {
  1974. mfxFrameSurface1 *mfx_surface = (mfxFrameSurface1*)src->data[3];
  1975. va_surface = *(VASurfaceID*)mfx_surface->Data.MemId;
  1976. } else if (src->format == AV_PIX_FMT_VAAPI) {
  1977. va_surface = (VASurfaceID)(uintptr_t)src->data[3];
  1978. } else {
  1979. return AVERROR(ENOSYS);
  1980. }
  1981. cl_flags = opencl_mem_flags_for_mapping(flags);
  1982. if (!cl_flags)
  1983. return AVERROR(EINVAL);
  1984. av_log(src_fc, AV_LOG_DEBUG, "Map QSV/VAAPI surface %#x to "
  1985. "OpenCL.\n", va_surface);
  1986. desc = av_mallocz(sizeof(*desc));
  1987. if (!desc)
  1988. return AVERROR(ENOMEM);
  1989. // The cl_intel_va_api_media_sharing extension only supports NV12
  1990. // surfaces, so for now there are always exactly two planes.
  1991. desc->nb_planes = 2;
  1992. for (p = 0; p < desc->nb_planes; p++) {
  1993. desc->planes[p] =
  1994. device_priv->clCreateFromVA_APIMediaSurfaceINTEL(
  1995. dst_dev->context, cl_flags, &va_surface, p, &cle);
  1996. if (!desc->planes[p]) {
  1997. av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL "
  1998. "image from plane %d of QSV/VAAPI surface "
  1999. "%#x: %d.\n", p, va_surface, cle);
  2000. err = AVERROR(EIO);
  2001. goto fail;
  2002. }
  2003. dst->data[p] = (uint8_t*)desc->planes[p];
  2004. }
  2005. cle = device_priv->clEnqueueAcquireVA_APIMediaSurfacesINTEL(
  2006. frames_priv->command_queue, desc->nb_planes, desc->planes,
  2007. 0, NULL, &event);
  2008. if (cle != CL_SUCCESS) {
  2009. av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface "
  2010. "handles: %d.\n", cle);
  2011. err = AVERROR(EIO);
  2012. goto fail;
  2013. }
  2014. err = opencl_wait_events(dst_fc, &event, 1);
  2015. if (err < 0)
  2016. goto fail;
  2017. err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
  2018. &opencl_unmap_from_qsv, desc);
  2019. if (err < 0)
  2020. goto fail;
  2021. dst->width = src->width;
  2022. dst->height = src->height;
  2023. return 0;
  2024. fail:
  2025. for (p = 0; p < desc->nb_planes; p++)
  2026. if (desc->planes[p])
  2027. clReleaseMemObject(desc->planes[p]);
  2028. av_freep(&desc);
  2029. return err;
  2030. }
  2031. #endif
  2032. #if HAVE_OPENCL_DXVA2
  2033. static void opencl_unmap_from_dxva2(AVHWFramesContext *dst_fc,
  2034. HWMapDescriptor *hwmap)
  2035. {
  2036. AVOpenCLFrameDescriptor *desc = hwmap->priv;
  2037. OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
  2038. OpenCLFramesContext *frames_priv = dst_fc->device_ctx->internal->priv;
  2039. cl_event event;
  2040. cl_int cle;
  2041. av_log(dst_fc, AV_LOG_DEBUG, "Unmap DXVA2 surface from OpenCL.\n");
  2042. cle = device_priv->clEnqueueReleaseDX9MediaSurfacesKHR(
  2043. frames_priv->command_queue, desc->nb_planes, desc->planes,
  2044. 0, NULL, &event);
  2045. if (cle != CL_SUCCESS) {
  2046. av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface "
  2047. "handle: %d.\n", cle);
  2048. return;
  2049. }
  2050. opencl_wait_events(dst_fc, &event, 1);
  2051. }
  2052. static int opencl_map_from_dxva2(AVHWFramesContext *dst_fc, AVFrame *dst,
  2053. const AVFrame *src, int flags)
  2054. {
  2055. AVHWFramesContext *src_fc =
  2056. (AVHWFramesContext*)src->hw_frames_ctx->data;
  2057. AVDXVA2FramesContext *src_hwctx = src_fc->hwctx;
  2058. OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
  2059. OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
  2060. AVOpenCLFrameDescriptor *desc;
  2061. cl_event event;
  2062. cl_int cle;
  2063. int err, i;
  2064. av_log(dst_fc, AV_LOG_DEBUG, "Map DXVA2 surface %p to "
  2065. "OpenCL.\n", src->data[3]);
  2066. for (i = 0; i < src_hwctx->nb_surfaces; i++) {
  2067. if (src_hwctx->surfaces[i] == (IDirect3DSurface9*)src->data[3])
  2068. break;
  2069. }
  2070. if (i >= src_hwctx->nb_surfaces) {
  2071. av_log(dst_fc, AV_LOG_ERROR, "Trying to map from a surface which "
  2072. "is not in the mapped frames context.\n");
  2073. return AVERROR(EINVAL);
  2074. }
  2075. desc = &frames_priv->mapped_frames[i];
  2076. cle = device_priv->clEnqueueAcquireDX9MediaSurfacesKHR(
  2077. frames_priv->command_queue, desc->nb_planes, desc->planes,
  2078. 0, NULL, &event);
  2079. if (cle != CL_SUCCESS) {
  2080. av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface "
  2081. "handle: %d.\n", cle);
  2082. return AVERROR(EIO);
  2083. }
  2084. err = opencl_wait_events(dst_fc, &event, 1);
  2085. if (err < 0)
  2086. goto fail;
  2087. for (i = 0; i < desc->nb_planes; i++)
  2088. dst->data[i] = (uint8_t*)desc->planes[i];
  2089. err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
  2090. &opencl_unmap_from_dxva2, desc);
  2091. if (err < 0)
  2092. goto fail;
  2093. dst->width = src->width;
  2094. dst->height = src->height;
  2095. return 0;
  2096. fail:
  2097. cle = device_priv->clEnqueueReleaseDX9MediaSurfacesKHR(
  2098. frames_priv->command_queue, desc->nb_planes, desc->planes,
  2099. 0, NULL, &event);
  2100. if (cle == CL_SUCCESS)
  2101. opencl_wait_events(dst_fc, &event, 1);
  2102. return err;
  2103. }
  2104. static int opencl_frames_derive_from_dxva2(AVHWFramesContext *dst_fc,
  2105. AVHWFramesContext *src_fc, int flags)
  2106. {
  2107. AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
  2108. AVDXVA2FramesContext *src_hwctx = src_fc->hwctx;
  2109. OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
  2110. OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
  2111. cl_mem_flags cl_flags;
  2112. cl_int cle;
  2113. int err, i, p, nb_planes;
  2114. if (src_fc->sw_format != AV_PIX_FMT_NV12) {
  2115. av_log(dst_fc, AV_LOG_ERROR, "Only NV12 textures are supported "
  2116. "for DXVA2 to OpenCL mapping.\n");
  2117. return AVERROR(EINVAL);
  2118. }
  2119. nb_planes = 2;
  2120. if (src_fc->initial_pool_size == 0) {
  2121. av_log(dst_fc, AV_LOG_ERROR, "Only fixed-size pools are supported "
  2122. "for DXVA2 to OpenCL mapping.\n");
  2123. return AVERROR(EINVAL);
  2124. }
  2125. cl_flags = opencl_mem_flags_for_mapping(flags);
  2126. if (!cl_flags)
  2127. return AVERROR(EINVAL);
  2128. frames_priv->nb_mapped_frames = src_hwctx->nb_surfaces;
  2129. frames_priv->mapped_frames =
  2130. av_mallocz_array(frames_priv->nb_mapped_frames,
  2131. sizeof(*frames_priv->mapped_frames));
  2132. if (!frames_priv->mapped_frames)
  2133. return AVERROR(ENOMEM);
  2134. for (i = 0; i < frames_priv->nb_mapped_frames; i++) {
  2135. AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i];
  2136. cl_dx9_surface_info_khr surface_info = {
  2137. .resource = src_hwctx->surfaces[i],
  2138. .shared_handle = NULL,
  2139. };
  2140. desc->nb_planes = nb_planes;
  2141. for (p = 0; p < nb_planes; p++) {
  2142. desc->planes[p] =
  2143. device_priv->clCreateFromDX9MediaSurfaceKHR(
  2144. dst_dev->context, cl_flags,
  2145. device_priv->dx9_media_adapter_type,
  2146. &surface_info, p, &cle);
  2147. if (!desc->planes[p]) {
  2148. av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL "
  2149. "image from plane %d of DXVA2 surface %d: %d.\n",
  2150. p, i, cle);
  2151. err = AVERROR(EIO);
  2152. goto fail;
  2153. }
  2154. }
  2155. }
  2156. return 0;
  2157. fail:
  2158. for (i = 0; i < frames_priv->nb_mapped_frames; i++) {
  2159. AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i];
  2160. for (p = 0; p < desc->nb_planes; p++) {
  2161. if (desc->planes[p])
  2162. clReleaseMemObject(desc->planes[p]);
  2163. }
  2164. }
  2165. av_freep(&frames_priv->mapped_frames);
  2166. frames_priv->nb_mapped_frames = 0;
  2167. return err;
  2168. }
  2169. #endif
  2170. #if HAVE_OPENCL_D3D11
  2171. static void opencl_unmap_from_d3d11(AVHWFramesContext *dst_fc,
  2172. HWMapDescriptor *hwmap)
  2173. {
  2174. AVOpenCLFrameDescriptor *desc = hwmap->priv;
  2175. OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
  2176. OpenCLFramesContext *frames_priv = dst_fc->device_ctx->internal->priv;
  2177. cl_event event;
  2178. cl_int cle;
  2179. cle = device_priv->clEnqueueReleaseD3D11ObjectsKHR(
  2180. frames_priv->command_queue, desc->nb_planes, desc->planes,
  2181. 0, NULL, &event);
  2182. if (cle != CL_SUCCESS) {
  2183. av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface "
  2184. "handle: %d.\n", cle);
  2185. }
  2186. opencl_wait_events(dst_fc, &event, 1);
  2187. }
  2188. static int opencl_map_from_d3d11(AVHWFramesContext *dst_fc, AVFrame *dst,
  2189. const AVFrame *src, int flags)
  2190. {
  2191. OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
  2192. OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
  2193. AVOpenCLFrameDescriptor *desc;
  2194. cl_event event;
  2195. cl_int cle;
  2196. int err, index, i;
  2197. index = (intptr_t)src->data[1];
  2198. if (index >= frames_priv->nb_mapped_frames) {
  2199. av_log(dst_fc, AV_LOG_ERROR, "Texture array index out of range for "
  2200. "mapping: %d >= %d.\n", index, frames_priv->nb_mapped_frames);
  2201. return AVERROR(EINVAL);
  2202. }
  2203. av_log(dst_fc, AV_LOG_DEBUG, "Map D3D11 texture %d to OpenCL.\n",
  2204. index);
  2205. desc = &frames_priv->mapped_frames[index];
  2206. cle = device_priv->clEnqueueAcquireD3D11ObjectsKHR(
  2207. frames_priv->command_queue, desc->nb_planes, desc->planes,
  2208. 0, NULL, &event);
  2209. if (cle != CL_SUCCESS) {
  2210. av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface "
  2211. "handle: %d.\n", cle);
  2212. return AVERROR(EIO);
  2213. }
  2214. err = opencl_wait_events(dst_fc, &event, 1);
  2215. if (err < 0)
  2216. goto fail;
  2217. for (i = 0; i < desc->nb_planes; i++)
  2218. dst->data[i] = (uint8_t*)desc->planes[i];
  2219. err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
  2220. &opencl_unmap_from_d3d11, desc);
  2221. if (err < 0)
  2222. goto fail;
  2223. dst->width = src->width;
  2224. dst->height = src->height;
  2225. return 0;
  2226. fail:
  2227. cle = device_priv->clEnqueueReleaseD3D11ObjectsKHR(
  2228. frames_priv->command_queue, desc->nb_planes, desc->planes,
  2229. 0, NULL, &event);
  2230. if (cle == CL_SUCCESS)
  2231. opencl_wait_events(dst_fc, &event, 1);
  2232. return err;
  2233. }
  2234. static int opencl_frames_derive_from_d3d11(AVHWFramesContext *dst_fc,
  2235. AVHWFramesContext *src_fc, int flags)
  2236. {
  2237. AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
  2238. AVD3D11VAFramesContext *src_hwctx = src_fc->hwctx;
  2239. OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
  2240. OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
  2241. cl_mem_flags cl_flags;
  2242. cl_int cle;
  2243. int err, i, p, nb_planes;
  2244. if (src_fc->sw_format != AV_PIX_FMT_NV12) {
  2245. av_log(dst_fc, AV_LOG_ERROR, "Only NV12 textures are supported "
  2246. "for D3D11 to OpenCL mapping.\n");
  2247. return AVERROR(EINVAL);
  2248. }
  2249. nb_planes = 2;
  2250. if (src_fc->initial_pool_size == 0) {
  2251. av_log(dst_fc, AV_LOG_ERROR, "Only fixed-size pools are supported "
  2252. "for D3D11 to OpenCL mapping.\n");
  2253. return AVERROR(EINVAL);
  2254. }
  2255. cl_flags = opencl_mem_flags_for_mapping(flags);
  2256. if (!cl_flags)
  2257. return AVERROR(EINVAL);
  2258. frames_priv->nb_mapped_frames = src_fc->initial_pool_size;
  2259. frames_priv->mapped_frames =
  2260. av_mallocz_array(frames_priv->nb_mapped_frames,
  2261. sizeof(*frames_priv->mapped_frames));
  2262. if (!frames_priv->mapped_frames)
  2263. return AVERROR(ENOMEM);
  2264. for (i = 0; i < frames_priv->nb_mapped_frames; i++) {
  2265. AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i];
  2266. desc->nb_planes = nb_planes;
  2267. for (p = 0; p < nb_planes; p++) {
  2268. UINT subresource = 2 * i + p;
  2269. desc->planes[p] =
  2270. device_priv->clCreateFromD3D11Texture2DKHR(
  2271. dst_dev->context, cl_flags, src_hwctx->texture,
  2272. subresource, &cle);
  2273. if (!desc->planes[p]) {
  2274. av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL "
  2275. "image from plane %d of D3D texture "
  2276. "index %d (subresource %u): %d.\n",
  2277. p, i, (unsigned int)subresource, cle);
  2278. err = AVERROR(EIO);
  2279. goto fail;
  2280. }
  2281. }
  2282. }
  2283. return 0;
  2284. fail:
  2285. for (i = 0; i < frames_priv->nb_mapped_frames; i++) {
  2286. AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i];
  2287. for (p = 0; p < desc->nb_planes; p++) {
  2288. if (desc->planes[p])
  2289. clReleaseMemObject(desc->planes[p]);
  2290. }
  2291. }
  2292. av_freep(&frames_priv->mapped_frames);
  2293. frames_priv->nb_mapped_frames = 0;
  2294. return err;
  2295. }
  2296. #endif
  2297. #if HAVE_OPENCL_DRM_ARM
  2298. typedef struct DRMARMtoOpenCLMapping {
  2299. int nb_objects;
  2300. cl_mem object_buffers[AV_DRM_MAX_PLANES];
  2301. int nb_planes;
  2302. cl_mem plane_images[AV_DRM_MAX_PLANES];
  2303. } DRMARMtoOpenCLMapping;
  2304. static void opencl_unmap_from_drm_arm(AVHWFramesContext *dst_fc,
  2305. HWMapDescriptor *hwmap)
  2306. {
  2307. DRMARMtoOpenCLMapping *mapping = hwmap->priv;
  2308. int i;
  2309. for (i = 0; i < mapping->nb_planes; i++)
  2310. clReleaseMemObject(mapping->plane_images[i]);
  2311. for (i = 0; i < mapping->nb_objects; i++)
  2312. clReleaseMemObject(mapping->object_buffers[i]);
  2313. av_free(mapping);
  2314. }
  2315. static int opencl_map_from_drm_arm(AVHWFramesContext *dst_fc, AVFrame *dst,
  2316. const AVFrame *src, int flags)
  2317. {
  2318. AVHWFramesContext *src_fc =
  2319. (AVHWFramesContext*)src->hw_frames_ctx->data;
  2320. AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
  2321. const AVDRMFrameDescriptor *desc;
  2322. DRMARMtoOpenCLMapping *mapping = NULL;
  2323. cl_mem_flags cl_flags;
  2324. const cl_import_properties_arm props[3] = {
  2325. CL_IMPORT_TYPE_ARM, CL_IMPORT_TYPE_DMA_BUF_ARM, 0,
  2326. };
  2327. cl_int cle;
  2328. int err, i, j;
  2329. desc = (const AVDRMFrameDescriptor*)src->data[0];
  2330. cl_flags = opencl_mem_flags_for_mapping(flags);
  2331. if (!cl_flags)
  2332. return AVERROR(EINVAL);
  2333. mapping = av_mallocz(sizeof(*mapping));
  2334. if (!mapping)
  2335. return AVERROR(ENOMEM);
  2336. mapping->nb_objects = desc->nb_objects;
  2337. for (i = 0; i < desc->nb_objects; i++) {
  2338. int fd = desc->objects[i].fd;
  2339. av_log(dst_fc, AV_LOG_DEBUG, "Map DRM PRIME fd %d to OpenCL.\n", fd);
  2340. if (desc->objects[i].format_modifier) {
  2341. av_log(dst_fc, AV_LOG_DEBUG, "Warning: object %d fd %d has "
  2342. "nonzero format modifier %"PRId64", result may not "
  2343. "be as expected.\n", i, fd,
  2344. desc->objects[i].format_modifier);
  2345. }
  2346. mapping->object_buffers[i] =
  2347. clImportMemoryARM(dst_dev->context, cl_flags, props,
  2348. &fd, desc->objects[i].size, &cle);
  2349. if (!mapping->object_buffers[i]) {
  2350. av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL buffer "
  2351. "from object %d (fd %d, size %zu) of DRM frame: %d.\n",
  2352. i, fd, desc->objects[i].size, cle);
  2353. err = AVERROR(EIO);
  2354. goto fail;
  2355. }
  2356. }
  2357. mapping->nb_planes = 0;
  2358. for (i = 0; i < desc->nb_layers; i++) {
  2359. const AVDRMLayerDescriptor *layer = &desc->layers[i];
  2360. for (j = 0; j < layer->nb_planes; j++) {
  2361. const AVDRMPlaneDescriptor *plane = &layer->planes[j];
  2362. cl_mem plane_buffer;
  2363. cl_image_format image_format;
  2364. cl_image_desc image_desc;
  2365. cl_buffer_region region;
  2366. int p = mapping->nb_planes;
  2367. err = opencl_get_plane_format(src_fc->sw_format, p,
  2368. src_fc->width, src_fc->height,
  2369. &image_format, &image_desc);
  2370. if (err < 0) {
  2371. av_log(dst_fc, AV_LOG_ERROR, "Invalid plane %d (DRM "
  2372. "layer %d plane %d): %d.\n", p, i, j, err);
  2373. goto fail;
  2374. }
  2375. region.origin = plane->offset;
  2376. region.size = image_desc.image_row_pitch *
  2377. image_desc.image_height;
  2378. plane_buffer =
  2379. clCreateSubBuffer(mapping->object_buffers[plane->object_index],
  2380. cl_flags,
  2381. CL_BUFFER_CREATE_TYPE_REGION,
  2382. &region, &cle);
  2383. if (!plane_buffer) {
  2384. av_log(dst_fc, AV_LOG_ERROR, "Failed to create sub-buffer "
  2385. "for plane %d: %d.\n", p, cle);
  2386. err = AVERROR(EIO);
  2387. goto fail;
  2388. }
  2389. image_desc.buffer = plane_buffer;
  2390. mapping->plane_images[p] =
  2391. clCreateImage(dst_dev->context, cl_flags,
  2392. &image_format, &image_desc, NULL, &cle);
  2393. // Unreference the sub-buffer immediately - we don't need it
  2394. // directly and a reference is held by the image.
  2395. clReleaseMemObject(plane_buffer);
  2396. if (!mapping->plane_images[p]) {
  2397. av_log(dst_fc, AV_LOG_ERROR, "Failed to create image "
  2398. "for plane %d: %d.\n", p, cle);
  2399. err = AVERROR(EIO);
  2400. goto fail;
  2401. }
  2402. ++mapping->nb_planes;
  2403. }
  2404. }
  2405. for (i = 0; i < mapping->nb_planes; i++)
  2406. dst->data[i] = (uint8_t*)mapping->plane_images[i];
  2407. err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
  2408. &opencl_unmap_from_drm_arm, mapping);
  2409. if (err < 0)
  2410. goto fail;
  2411. dst->width = src->width;
  2412. dst->height = src->height;
  2413. return 0;
  2414. fail:
  2415. for (i = 0; i < mapping->nb_planes; i++) {
  2416. clReleaseMemObject(mapping->plane_images[i]);
  2417. }
  2418. for (i = 0; i < mapping->nb_objects; i++) {
  2419. if (mapping->object_buffers[i])
  2420. clReleaseMemObject(mapping->object_buffers[i]);
  2421. }
  2422. av_free(mapping);
  2423. return err;
  2424. }
  2425. #endif
  2426. static int opencl_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
  2427. const AVFrame *src, int flags)
  2428. {
  2429. av_assert0(src->format == AV_PIX_FMT_OPENCL);
  2430. if (hwfc->sw_format != dst->format)
  2431. return AVERROR(ENOSYS);
  2432. return opencl_map_frame(hwfc, dst, src, flags);
  2433. }
  2434. static int opencl_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
  2435. const AVFrame *src, int flags)
  2436. {
  2437. OpenCLDeviceContext *priv = hwfc->device_ctx->internal->priv;
  2438. av_assert0(dst->format == AV_PIX_FMT_OPENCL);
  2439. switch (src->format) {
  2440. #if HAVE_OPENCL_VAAPI_BEIGNET
  2441. case AV_PIX_FMT_VAAPI:
  2442. if (priv->vaapi_mapping_usable)
  2443. return opencl_map_from_vaapi(hwfc, dst, src, flags);
  2444. #endif
  2445. #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
  2446. case AV_PIX_FMT_QSV:
  2447. case AV_PIX_FMT_VAAPI:
  2448. if (priv->qsv_mapping_usable)
  2449. return opencl_map_from_qsv(hwfc, dst, src, flags);
  2450. #endif
  2451. #if HAVE_OPENCL_DXVA2
  2452. case AV_PIX_FMT_DXVA2_VLD:
  2453. if (priv->dxva2_mapping_usable)
  2454. return opencl_map_from_dxva2(hwfc, dst, src, flags);
  2455. #endif
  2456. #if HAVE_OPENCL_D3D11
  2457. case AV_PIX_FMT_D3D11:
  2458. if (priv->d3d11_mapping_usable)
  2459. return opencl_map_from_d3d11(hwfc, dst, src, flags);
  2460. #endif
  2461. #if HAVE_OPENCL_DRM_ARM
  2462. case AV_PIX_FMT_DRM_PRIME:
  2463. if (priv->drm_arm_mapping_usable)
  2464. return opencl_map_from_drm_arm(hwfc, dst, src, flags);
  2465. #endif
  2466. }
  2467. return AVERROR(ENOSYS);
  2468. }
  2469. static int opencl_frames_derive_to(AVHWFramesContext *dst_fc,
  2470. AVHWFramesContext *src_fc, int flags)
  2471. {
  2472. OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv;
  2473. switch (src_fc->device_ctx->type) {
  2474. #if HAVE_OPENCL_VAAPI_BEIGNET
  2475. case AV_HWDEVICE_TYPE_VAAPI:
  2476. if (!priv->vaapi_mapping_usable)
  2477. return AVERROR(ENOSYS);
  2478. break;
  2479. #endif
  2480. #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
  2481. case AV_HWDEVICE_TYPE_QSV:
  2482. case AV_HWDEVICE_TYPE_VAAPI:
  2483. if (!priv->qsv_mapping_usable)
  2484. return AVERROR(ENOSYS);
  2485. break;
  2486. #endif
  2487. #if HAVE_OPENCL_DXVA2
  2488. case AV_HWDEVICE_TYPE_DXVA2:
  2489. if (!priv->dxva2_mapping_usable)
  2490. return AVERROR(ENOSYS);
  2491. {
  2492. int err;
  2493. err = opencl_frames_derive_from_dxva2(dst_fc, src_fc, flags);
  2494. if (err < 0)
  2495. return err;
  2496. }
  2497. break;
  2498. #endif
  2499. #if HAVE_OPENCL_D3D11
  2500. case AV_HWDEVICE_TYPE_D3D11VA:
  2501. if (!priv->d3d11_mapping_usable)
  2502. return AVERROR(ENOSYS);
  2503. {
  2504. int err;
  2505. err = opencl_frames_derive_from_d3d11(dst_fc, src_fc, flags);
  2506. if (err < 0)
  2507. return err;
  2508. }
  2509. break;
  2510. #endif
  2511. #if HAVE_OPENCL_DRM_ARM
  2512. case AV_HWDEVICE_TYPE_DRM:
  2513. if (!priv->drm_arm_mapping_usable)
  2514. return AVERROR(ENOSYS);
  2515. break;
  2516. #endif
  2517. default:
  2518. return AVERROR(ENOSYS);
  2519. }
  2520. return opencl_frames_init_command_queue(dst_fc);
  2521. }
  2522. const HWContextType ff_hwcontext_type_opencl = {
  2523. .type = AV_HWDEVICE_TYPE_OPENCL,
  2524. .name = "OpenCL",
  2525. .device_hwctx_size = sizeof(AVOpenCLDeviceContext),
  2526. .device_priv_size = sizeof(OpenCLDeviceContext),
  2527. .frames_hwctx_size = sizeof(AVOpenCLFramesContext),
  2528. .frames_priv_size = sizeof(OpenCLFramesContext),
  2529. .device_create = &opencl_device_create,
  2530. .device_derive = &opencl_device_derive,
  2531. .device_init = &opencl_device_init,
  2532. .device_uninit = &opencl_device_uninit,
  2533. .frames_get_constraints = &opencl_frames_get_constraints,
  2534. .frames_init = &opencl_frames_init,
  2535. .frames_uninit = &opencl_frames_uninit,
  2536. .frames_get_buffer = &opencl_get_buffer,
  2537. .transfer_get_formats = &opencl_transfer_get_formats,
  2538. .transfer_data_to = &opencl_transfer_data_to,
  2539. .transfer_data_from = &opencl_transfer_data_from,
  2540. .map_from = &opencl_map_from,
  2541. .map_to = &opencl_map_to,
  2542. .frames_derive_to = &opencl_frames_derive_to,
  2543. .pix_fmts = (const enum AVPixelFormat[]) {
  2544. AV_PIX_FMT_OPENCL,
  2545. AV_PIX_FMT_NONE
  2546. },
  2547. };