Browse code

hwcontext_opencl: DRM to OpenCL mapping for ARM

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.

Mark Thompson authored on 2017/09/10 21:37:20
Showing 2 changed files
... ...
@@ -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
+                                  &region, &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
     }