Using cl_arm_import_memory. Unfortunately, despite this not being a
standard extension, the function clImportMemoryARM() is not accessible
via clGetExtensionFunctionAddressForPlatform(). This means that it has
to be linked directly to the ARM OpenCL binary, so making a portable
binary is not possible as it is with all other mapping extensions.
... | ... |
@@ -2121,6 +2121,7 @@ HAVE_LIST=" |
2121 | 2121 |
makeinfo |
2122 | 2122 |
makeinfo_html |
2123 | 2123 |
opencl_d3d11 |
2124 |
+ opencl_drm_arm |
|
2124 | 2125 |
opencl_dxva2 |
2125 | 2126 |
opencl_vaapi_beignet |
2126 | 2127 |
opencl_vaapi_intel_media |
... | ... |
@@ -6178,6 +6179,11 @@ if enabled_all opencl d3d11va ; then |
6178 | 6178 |
enable opencl_d3d11 |
6179 | 6179 |
fi |
6180 | 6180 |
|
6181 |
+if enabled_all opencl libdrm ; then |
|
6182 |
+ check_func_headers "CL/cl_ext.h" clImportMemoryARM && |
|
6183 |
+ enable opencl_drm_arm |
|
6184 |
+fi |
|
6185 |
+ |
|
6181 | 6186 |
enabled vdpau && |
6182 | 6187 |
check_cpp_condition vdpau/vdpau.h "defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP" || |
6183 | 6188 |
disable vdpau |
... | ... |
@@ -56,6 +56,12 @@ |
56 | 56 |
#include "hwcontext_d3d11va.h" |
57 | 57 |
#endif |
58 | 58 |
|
59 |
+#if HAVE_OPENCL_DRM_ARM |
|
60 |
+#include <CL/cl_ext.h> |
|
61 |
+#include <drm_fourcc.h> |
|
62 |
+#include "hwcontext_drm.h" |
|
63 |
+#endif |
|
64 |
+ |
|
59 | 65 |
|
60 | 66 |
typedef struct OpenCLDeviceContext { |
61 | 67 |
// Default command queue to use for transfer/mapping operations on |
... | ... |
@@ -104,6 +110,10 @@ typedef struct OpenCLDeviceContext { |
104 | 104 |
clEnqueueReleaseD3D11ObjectsKHR_fn |
105 | 105 |
clEnqueueReleaseD3D11ObjectsKHR; |
106 | 106 |
#endif |
107 |
+ |
|
108 |
+#if HAVE_OPENCL_DRM_ARM |
|
109 |
+ int drm_arm_mapping_usable; |
|
110 |
+#endif |
|
107 | 111 |
} OpenCLDeviceContext; |
108 | 112 |
|
109 | 113 |
typedef struct OpenCLFramesContext { |
... | ... |
@@ -826,6 +836,37 @@ static int opencl_device_init(AVHWDeviceContext *hwdev) |
826 | 826 |
} |
827 | 827 |
#endif |
828 | 828 |
|
829 |
+#if HAVE_OPENCL_DRM_ARM |
|
830 |
+ { |
|
831 |
+ const char *drm_arm_ext = "cl_arm_import_memory"; |
|
832 |
+ const char *image_ext = "cl_khr_image2d_from_buffer"; |
|
833 |
+ int fail = 0; |
|
834 |
+ |
|
835 |
+ if (!opencl_check_extension(hwdev, drm_arm_ext)) { |
|
836 |
+ av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is " |
|
837 |
+ "required for DRM to OpenCL mapping on ARM.\n", |
|
838 |
+ drm_arm_ext); |
|
839 |
+ fail = 1; |
|
840 |
+ } |
|
841 |
+ if (!opencl_check_extension(hwdev, image_ext)) { |
|
842 |
+ av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is " |
|
843 |
+ "required for DRM to OpenCL mapping on ARM.\n", |
|
844 |
+ image_ext); |
|
845 |
+ fail = 1; |
|
846 |
+ } |
|
847 |
+ |
|
848 |
+ // clImportMemoryARM() is linked statically. |
|
849 |
+ |
|
850 |
+ if (fail) { |
|
851 |
+ av_log(hwdev, AV_LOG_WARNING, "DRM to OpenCL mapping on ARM " |
|
852 |
+ "not usable.\n"); |
|
853 |
+ priv->drm_arm_mapping_usable = 0; |
|
854 |
+ } else { |
|
855 |
+ priv->drm_arm_mapping_usable = 1; |
|
856 |
+ } |
|
857 |
+ } |
|
858 |
+#endif |
|
859 |
+ |
|
829 | 860 |
#undef CL_FUNC |
830 | 861 |
|
831 | 862 |
return 0; |
... | ... |
@@ -1104,6 +1145,40 @@ static int opencl_filter_gpu_device(AVHWDeviceContext *hwdev, |
1104 | 1104 |
} |
1105 | 1105 |
#endif |
1106 | 1106 |
|
1107 |
+#if HAVE_OPENCL_DRM_ARM |
|
1108 |
+static int opencl_filter_drm_arm_platform(AVHWDeviceContext *hwdev, |
|
1109 |
+ cl_platform_id platform_id, |
|
1110 |
+ const char *platform_name, |
|
1111 |
+ void *context) |
|
1112 |
+{ |
|
1113 |
+ const char *drm_arm_ext = "cl_arm_import_memory"; |
|
1114 |
+ |
|
1115 |
+ if (opencl_check_platform_extension(platform_id, drm_arm_ext)) { |
|
1116 |
+ return 0; |
|
1117 |
+ } else { |
|
1118 |
+ av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the " |
|
1119 |
+ "%s extension.\n", platform_name, drm_arm_ext); |
|
1120 |
+ return 1; |
|
1121 |
+ } |
|
1122 |
+} |
|
1123 |
+ |
|
1124 |
+static int opencl_filter_drm_arm_device(AVHWDeviceContext *hwdev, |
|
1125 |
+ cl_device_id device_id, |
|
1126 |
+ const char *device_name, |
|
1127 |
+ void *context) |
|
1128 |
+{ |
|
1129 |
+ const char *drm_arm_ext = "cl_arm_import_memory"; |
|
1130 |
+ |
|
1131 |
+ if (opencl_check_device_extension(device_id, drm_arm_ext)) { |
|
1132 |
+ return 0; |
|
1133 |
+ } else { |
|
1134 |
+ av_log(hwdev, AV_LOG_DEBUG, "Device %s does not support the " |
|
1135 |
+ "%s extension.\n", device_name, drm_arm_ext); |
|
1136 |
+ return 1; |
|
1137 |
+ } |
|
1138 |
+} |
|
1139 |
+#endif |
|
1140 |
+ |
|
1107 | 1141 |
static int opencl_device_derive(AVHWDeviceContext *hwdev, |
1108 | 1142 |
AVHWDeviceContext *src_ctx, |
1109 | 1143 |
int flags) |
... | ... |
@@ -1250,6 +1325,24 @@ static int opencl_device_derive(AVHWDeviceContext *hwdev, |
1250 | 1250 |
break; |
1251 | 1251 |
#endif |
1252 | 1252 |
|
1253 |
+#if HAVE_OPENCL_DRM_ARM |
|
1254 |
+ case AV_HWDEVICE_TYPE_DRM: |
|
1255 |
+ { |
|
1256 |
+ OpenCLDeviceSelector selector = { |
|
1257 |
+ .platform_index = -1, |
|
1258 |
+ .device_index = -1, |
|
1259 |
+ .context = NULL, |
|
1260 |
+ .enumerate_platforms = &opencl_enumerate_platforms, |
|
1261 |
+ .filter_platform = &opencl_filter_drm_arm_platform, |
|
1262 |
+ .enumerate_devices = &opencl_enumerate_devices, |
|
1263 |
+ .filter_device = &opencl_filter_drm_arm_device, |
|
1264 |
+ }; |
|
1265 |
+ |
|
1266 |
+ err = opencl_device_create_internal(hwdev, &selector, NULL); |
|
1267 |
+ } |
|
1268 |
+ break; |
|
1269 |
+#endif |
|
1270 |
+ |
|
1253 | 1271 |
default: |
1254 | 1272 |
err = AVERROR(ENOSYS); |
1255 | 1273 |
break; |
... | ... |
@@ -2558,6 +2651,165 @@ fail: |
2558 | 2558 |
|
2559 | 2559 |
#endif |
2560 | 2560 |
|
2561 |
+#if HAVE_OPENCL_DRM_ARM |
|
2562 |
+ |
|
2563 |
+typedef struct DRMARMtoOpenCLMapping { |
|
2564 |
+ int nb_objects; |
|
2565 |
+ cl_mem object_buffers[AV_DRM_MAX_PLANES]; |
|
2566 |
+ int nb_planes; |
|
2567 |
+ cl_mem plane_images[AV_DRM_MAX_PLANES]; |
|
2568 |
+} DRMARMtoOpenCLMapping; |
|
2569 |
+ |
|
2570 |
+static void opencl_unmap_from_drm_arm(AVHWFramesContext *dst_fc, |
|
2571 |
+ HWMapDescriptor *hwmap) |
|
2572 |
+{ |
|
2573 |
+ DRMARMtoOpenCLMapping *mapping = hwmap->priv; |
|
2574 |
+ int i; |
|
2575 |
+ |
|
2576 |
+ for (i = 0; i < mapping->nb_planes; i++) |
|
2577 |
+ clReleaseMemObject(mapping->plane_images[i]); |
|
2578 |
+ |
|
2579 |
+ for (i = 0; i < mapping->nb_objects; i++) |
|
2580 |
+ clReleaseMemObject(mapping->object_buffers[i]); |
|
2581 |
+ |
|
2582 |
+ av_free(mapping); |
|
2583 |
+} |
|
2584 |
+ |
|
2585 |
+static int opencl_map_from_drm_arm(AVHWFramesContext *dst_fc, AVFrame *dst, |
|
2586 |
+ const AVFrame *src, int flags) |
|
2587 |
+{ |
|
2588 |
+ AVHWFramesContext *src_fc = |
|
2589 |
+ (AVHWFramesContext*)src->hw_frames_ctx->data; |
|
2590 |
+ AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; |
|
2591 |
+ const AVDRMFrameDescriptor *desc; |
|
2592 |
+ DRMARMtoOpenCLMapping *mapping = NULL; |
|
2593 |
+ cl_mem_flags cl_flags; |
|
2594 |
+ const cl_import_properties_arm props[3] = { |
|
2595 |
+ CL_IMPORT_TYPE_ARM, CL_IMPORT_TYPE_DMA_BUF_ARM, 0, |
|
2596 |
+ }; |
|
2597 |
+ cl_int cle; |
|
2598 |
+ int err, i, j; |
|
2599 |
+ |
|
2600 |
+ desc = (const AVDRMFrameDescriptor*)src->data[0]; |
|
2601 |
+ |
|
2602 |
+ cl_flags = opencl_mem_flags_for_mapping(flags); |
|
2603 |
+ if (!cl_flags) |
|
2604 |
+ return AVERROR(EINVAL); |
|
2605 |
+ |
|
2606 |
+ mapping = av_mallocz(sizeof(*mapping)); |
|
2607 |
+ if (!mapping) |
|
2608 |
+ return AVERROR(ENOMEM); |
|
2609 |
+ |
|
2610 |
+ mapping->nb_objects = desc->nb_objects; |
|
2611 |
+ for (i = 0; i < desc->nb_objects; i++) { |
|
2612 |
+ int fd = desc->objects[i].fd; |
|
2613 |
+ |
|
2614 |
+ av_log(dst_fc, AV_LOG_DEBUG, "Map DRM PRIME fd %d to OpenCL.\n", fd); |
|
2615 |
+ |
|
2616 |
+ if (desc->objects[i].format_modifier) { |
|
2617 |
+ av_log(dst_fc, AV_LOG_DEBUG, "Warning: object %d fd %d has " |
|
2618 |
+ "nonzero format modifier %"PRId64", result may not " |
|
2619 |
+ "be as expected.\n", i, fd, |
|
2620 |
+ desc->objects[i].format_modifier); |
|
2621 |
+ } |
|
2622 |
+ |
|
2623 |
+ mapping->object_buffers[i] = |
|
2624 |
+ clImportMemoryARM(dst_dev->context, cl_flags, props, |
|
2625 |
+ &fd, desc->objects[i].size, &cle); |
|
2626 |
+ if (!mapping->object_buffers[i]) { |
|
2627 |
+ av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL buffer " |
|
2628 |
+ "from object %d (fd %d, size %zu) of DRM frame: %d.\n", |
|
2629 |
+ i, fd, desc->objects[i].size, cle); |
|
2630 |
+ err = AVERROR(EIO); |
|
2631 |
+ goto fail; |
|
2632 |
+ } |
|
2633 |
+ } |
|
2634 |
+ |
|
2635 |
+ mapping->nb_planes = 0; |
|
2636 |
+ for (i = 0; i < desc->nb_layers; i++) { |
|
2637 |
+ const AVDRMLayerDescriptor *layer = &desc->layers[i]; |
|
2638 |
+ |
|
2639 |
+ for (j = 0; j < layer->nb_planes; j++) { |
|
2640 |
+ const AVDRMPlaneDescriptor *plane = &layer->planes[j]; |
|
2641 |
+ cl_mem plane_buffer; |
|
2642 |
+ cl_image_format image_format; |
|
2643 |
+ cl_image_desc image_desc; |
|
2644 |
+ cl_buffer_region region; |
|
2645 |
+ int p = mapping->nb_planes; |
|
2646 |
+ |
|
2647 |
+ err = opencl_get_plane_format(src_fc->sw_format, p, |
|
2648 |
+ src_fc->width, src_fc->height, |
|
2649 |
+ &image_format, &image_desc); |
|
2650 |
+ if (err < 0) { |
|
2651 |
+ av_log(dst_fc, AV_LOG_ERROR, "Invalid plane %d (DRM " |
|
2652 |
+ "layer %d plane %d): %d.\n", p, i, j, err); |
|
2653 |
+ goto fail; |
|
2654 |
+ } |
|
2655 |
+ |
|
2656 |
+ region.origin = plane->offset; |
|
2657 |
+ region.size = image_desc.image_row_pitch * |
|
2658 |
+ image_desc.image_height; |
|
2659 |
+ |
|
2660 |
+ plane_buffer = |
|
2661 |
+ clCreateSubBuffer(mapping->object_buffers[plane->object_index], |
|
2662 |
+ cl_flags, |
|
2663 |
+ CL_BUFFER_CREATE_TYPE_REGION, |
|
2664 |
+ ®ion, &cle); |
|
2665 |
+ if (!plane_buffer) { |
|
2666 |
+ av_log(dst_fc, AV_LOG_ERROR, "Failed to create sub-buffer " |
|
2667 |
+ "for plane %d: %d.\n", p, cle); |
|
2668 |
+ err = AVERROR(EIO); |
|
2669 |
+ goto fail; |
|
2670 |
+ } |
|
2671 |
+ |
|
2672 |
+ image_desc.buffer = plane_buffer; |
|
2673 |
+ |
|
2674 |
+ mapping->plane_images[p] = |
|
2675 |
+ clCreateImage(dst_dev->context, cl_flags, |
|
2676 |
+ &image_format, &image_desc, NULL, &cle); |
|
2677 |
+ |
|
2678 |
+ // Unreference the sub-buffer immediately - we don't need it |
|
2679 |
+ // directly and a reference is held by the image. |
|
2680 |
+ clReleaseMemObject(plane_buffer); |
|
2681 |
+ |
|
2682 |
+ if (!mapping->plane_images[p]) { |
|
2683 |
+ av_log(dst_fc, AV_LOG_ERROR, "Failed to create image " |
|
2684 |
+ "for plane %d: %d.\n", p, cle); |
|
2685 |
+ err = AVERROR(EIO); |
|
2686 |
+ goto fail; |
|
2687 |
+ } |
|
2688 |
+ |
|
2689 |
+ ++mapping->nb_planes; |
|
2690 |
+ } |
|
2691 |
+ } |
|
2692 |
+ |
|
2693 |
+ for (i = 0; i < mapping->nb_planes; i++) |
|
2694 |
+ dst->data[i] = (uint8_t*)mapping->plane_images[i]; |
|
2695 |
+ |
|
2696 |
+ err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src, |
|
2697 |
+ &opencl_unmap_from_drm_arm, mapping); |
|
2698 |
+ if (err < 0) |
|
2699 |
+ goto fail; |
|
2700 |
+ |
|
2701 |
+ dst->width = src->width; |
|
2702 |
+ dst->height = src->height; |
|
2703 |
+ |
|
2704 |
+ return 0; |
|
2705 |
+ |
|
2706 |
+fail: |
|
2707 |
+ for (i = 0; i < mapping->nb_planes; i++) { |
|
2708 |
+ clReleaseMemObject(mapping->plane_images[i]); |
|
2709 |
+ } |
|
2710 |
+ for (i = 0; i < mapping->nb_objects; i++) { |
|
2711 |
+ if (mapping->object_buffers[i]) |
|
2712 |
+ clReleaseMemObject(mapping->object_buffers[i]); |
|
2713 |
+ } |
|
2714 |
+ av_free(mapping); |
|
2715 |
+ return err; |
|
2716 |
+} |
|
2717 |
+ |
|
2718 |
+#endif |
|
2719 |
+ |
|
2561 | 2720 |
static int opencl_map_from(AVHWFramesContext *hwfc, AVFrame *dst, |
2562 | 2721 |
const AVFrame *src, int flags) |
2563 | 2722 |
{ |
... | ... |
@@ -2594,6 +2846,11 @@ static int opencl_map_to(AVHWFramesContext *hwfc, AVFrame *dst, |
2594 | 2594 |
if (priv->d3d11_mapping_usable) |
2595 | 2595 |
return opencl_map_from_d3d11(hwfc, dst, src, flags); |
2596 | 2596 |
#endif |
2597 |
+#if HAVE_OPENCL_DRM_ARM |
|
2598 |
+ case AV_PIX_FMT_DRM_PRIME: |
|
2599 |
+ if (priv->drm_arm_mapping_usable) |
|
2600 |
+ return opencl_map_from_drm_arm(hwfc, dst, src, flags); |
|
2601 |
+#endif |
|
2597 | 2602 |
} |
2598 | 2603 |
return AVERROR(ENOSYS); |
2599 | 2604 |
} |
... | ... |
@@ -2640,6 +2897,12 @@ static int opencl_frames_derive_to(AVHWFramesContext *dst_fc, |
2640 | 2640 |
} |
2641 | 2641 |
break; |
2642 | 2642 |
#endif |
2643 |
+#if HAVE_OPENCL_DRM_ARM |
|
2644 |
+ case AV_HWDEVICE_TYPE_DRM: |
|
2645 |
+ if (!priv->drm_arm_mapping_usable) |
|
2646 |
+ return AVERROR(ENOSYS); |
|
2647 |
+ break; |
|
2648 |
+#endif |
|
2643 | 2649 |
default: |
2644 | 2650 |
return AVERROR(ENOSYS); |
2645 | 2651 |
} |