Browse code

hwcontext_opencl: D3D11 to OpenCL mapping

Using cl_khr_d3d11_sharing and cl_intel_d3d11_nv12_media_sharing.

Mark Thompson authored on 2017/06/26 06:34:40
Showing 2 changed files
... ...
@@ -2120,6 +2120,7 @@ HAVE_LIST="
2120 2120
     $TYPES_LIST
2121 2121
     makeinfo
2122 2122
     makeinfo_html
2123
+    opencl_d3d11
2123 2124
     opencl_dxva2
2124 2125
     opencl_vaapi_beignet
2125 2126
     opencl_vaapi_intel_media
... ...
@@ -6172,6 +6173,11 @@ if enabled_all opencl dxva2 ; then
6172 6172
         enable opencl_dxva2
6173 6173
 fi
6174 6174
 
6175
+if enabled_all opencl d3d11va ; then
6176
+    check_type "CL/cl_d3d11.h" clGetDeviceIDsFromD3D11KHR_fn &&
6177
+        enable opencl_d3d11
6178
+fi
6179
+
6175 6180
 enabled vdpau &&
6176 6181
     check_cpp_condition vdpau/vdpau.h "defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP" ||
6177 6182
     disable vdpau
... ...
@@ -51,6 +51,11 @@
51 51
 #include "hwcontext_dxva2.h"
52 52
 #endif
53 53
 
54
+#if HAVE_OPENCL_D3D11
55
+#include <CL/cl_d3d11.h>
56
+#include "hwcontext_d3d11va.h"
57
+#endif
58
+
54 59
 
55 60
 typedef struct OpenCLDeviceContext {
56 61
     // Default command queue to use for transfer/mapping operations on
... ...
@@ -89,6 +94,16 @@ typedef struct OpenCLDeviceContext {
89 89
     clEnqueueReleaseDX9MediaSurfacesKHR_fn
90 90
         clEnqueueReleaseDX9MediaSurfacesKHR;
91 91
 #endif
92
+
93
+#if HAVE_OPENCL_D3D11
94
+    int d3d11_mapping_usable;
95
+    clCreateFromD3D11Texture2DKHR_fn
96
+        clCreateFromD3D11Texture2DKHR;
97
+    clEnqueueAcquireD3D11ObjectsKHR_fn
98
+        clEnqueueAcquireD3D11ObjectsKHR;
99
+    clEnqueueReleaseD3D11ObjectsKHR_fn
100
+        clEnqueueReleaseD3D11ObjectsKHR;
101
+#endif
92 102
 } OpenCLDeviceContext;
93 103
 
94 104
 typedef struct OpenCLFramesContext {
... ...
@@ -98,7 +113,7 @@ typedef struct OpenCLFramesContext {
98 98
     // device.
99 99
     cl_command_queue command_queue;
100 100
 
101
-#if HAVE_OPENCL_DXVA2
101
+#if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11
102 102
     // For mapping APIs which have separate creation and acquire/release
103 103
     // steps, this stores the OpenCL memory objects corresponding to each
104 104
     // frame.
... ...
@@ -778,6 +793,39 @@ static int opencl_device_init(AVHWDeviceContext *hwdev)
778 778
     }
779 779
 #endif
780 780
 
781
+#if HAVE_OPENCL_D3D11
782
+    {
783
+        const char *d3d11_ext = "cl_khr_d3d11_sharing";
784
+        const char *nv12_ext  = "cl_intel_d3d11_nv12_media_sharing";
785
+        int fail = 0;
786
+
787
+        if (!opencl_check_extension(hwdev, d3d11_ext)) {
788
+            av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is "
789
+                   "required for D3D11 to OpenCL mapping.\n", d3d11_ext);
790
+            fail = 1;
791
+        } else if (!opencl_check_extension(hwdev, nv12_ext)) {
792
+            av_log(hwdev, AV_LOG_VERBOSE, "The %s extension may be "
793
+                   "required for D3D11 to OpenCL mapping.\n", nv12_ext);
794
+            // Not fatal.
795
+        }
796
+
797
+        CL_FUNC(clCreateFromD3D11Texture2DKHR,
798
+                "D3D11 to OpenCL mapping");
799
+        CL_FUNC(clEnqueueAcquireD3D11ObjectsKHR,
800
+                "D3D11 in OpenCL acquire");
801
+        CL_FUNC(clEnqueueReleaseD3D11ObjectsKHR,
802
+                "D3D11 in OpenCL release");
803
+
804
+        if (fail) {
805
+            av_log(hwdev, AV_LOG_WARNING, "D3D11 to OpenCL mapping "
806
+                   "not usable.\n");
807
+            priv->d3d11_mapping_usable = 0;
808
+        } else {
809
+            priv->d3d11_mapping_usable = 1;
810
+        }
811
+    }
812
+#endif
813
+
781 814
 #undef CL_FUNC
782 815
 
783 816
     return 0;
... ...
@@ -957,7 +1005,80 @@ static int opencl_enumerate_dxva2_devices(AVHWDeviceContext *hwdev,
957 957
 
958 958
     return 0;
959 959
 }
960
+#endif
961
+
962
+#if HAVE_OPENCL_D3D11
963
+static int opencl_filter_d3d11_platform(AVHWDeviceContext *hwdev,
964
+                                        cl_platform_id platform_id,
965
+                                        const char *platform_name,
966
+                                        void *context)
967
+{
968
+    const char *d3d11_ext = "cl_khr_d3d11_sharing";
969
+
970
+    if (opencl_check_platform_extension(platform_id, d3d11_ext)) {
971
+        return 0;
972
+    } else {
973
+        av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the "
974
+               "%s extension.\n", platform_name, d3d11_ext);
975
+        return 1;
976
+    }
977
+}
978
+
979
+static int opencl_enumerate_d3d11_devices(AVHWDeviceContext *hwdev,
980
+                                          cl_platform_id platform_id,
981
+                                          const char *platform_name,
982
+                                          cl_uint *nb_devices,
983
+                                          cl_device_id **devices,
984
+                                          void *context)
985
+{
986
+    ID3D11Device *device = context;
987
+    clGetDeviceIDsFromD3D11KHR_fn clGetDeviceIDsFromD3D11KHR;
988
+    cl_int cle;
989
+
990
+    clGetDeviceIDsFromD3D11KHR =
991
+        clGetExtensionFunctionAddressForPlatform(platform_id,
992
+            "clGetDeviceIDsFromD3D11KHR");
993
+    if (!clGetDeviceIDsFromD3D11KHR) {
994
+        av_log(hwdev, AV_LOG_ERROR, "Failed to get address of "
995
+               "clGetDeviceIDsFromD3D11KHR().\n");
996
+        return AVERROR_UNKNOWN;
997
+    }
998
+
999
+    cle = clGetDeviceIDsFromD3D11KHR(platform_id,
1000
+                                     CL_D3D11_DEVICE_KHR, device,
1001
+                                     CL_PREFERRED_DEVICES_FOR_D3D11_KHR,
1002
+                                     0, NULL, nb_devices);
1003
+    if (cle == CL_DEVICE_NOT_FOUND) {
1004
+        av_log(hwdev, AV_LOG_DEBUG, "No D3D11-supporting devices found "
1005
+               "on platform \"%s\".\n", platform_name);
1006
+        *nb_devices = 0;
1007
+        return 0;
1008
+    } else if (cle != CL_SUCCESS) {
1009
+        av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
1010
+               "on platform \"%s\": %d.\n", platform_name, cle);
1011
+        return AVERROR_UNKNOWN;
1012
+    }
1013
+
1014
+    *devices = av_malloc_array(*nb_devices, sizeof(**devices));
1015
+    if (!*devices)
1016
+        return AVERROR(ENOMEM);
1017
+
1018
+    cle = clGetDeviceIDsFromD3D11KHR(platform_id,
1019
+                                     CL_D3D11_DEVICE_KHR, device,
1020
+                                     CL_PREFERRED_DEVICES_FOR_D3D11_KHR,
1021
+                                     *nb_devices, *devices, NULL);
1022
+    if (cle != CL_SUCCESS) {
1023
+        av_log(hwdev, AV_LOG_ERROR, "Failed to get list of D3D11-supporting "
1024
+               "devices on platform \"%s\": %d.\n", platform_name, cle);
1025
+        av_freep(devices);
1026
+        return AVERROR_UNKNOWN;
1027
+    }
1028
+
1029
+    return 0;
1030
+}
1031
+#endif
960 1032
 
1033
+#if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11
961 1034
 static int opencl_filter_gpu_device(AVHWDeviceContext *hwdev,
962 1035
                                     cl_device_id device_id,
963 1036
                                     const char *device_name,
... ...
@@ -1103,6 +1224,32 @@ static int opencl_device_derive(AVHWDeviceContext *hwdev,
1103 1103
         break;
1104 1104
 #endif
1105 1105
 
1106
+#if HAVE_OPENCL_D3D11
1107
+    case AV_HWDEVICE_TYPE_D3D11VA:
1108
+        {
1109
+            AVD3D11VADeviceContext *src_hwctx = src_ctx->hwctx;
1110
+            cl_context_properties props[5] = {
1111
+                CL_CONTEXT_PLATFORM,
1112
+                0,
1113
+                CL_CONTEXT_D3D11_DEVICE_KHR,
1114
+                (intptr_t)src_hwctx->device,
1115
+                0,
1116
+            };
1117
+            OpenCLDeviceSelector selector = {
1118
+                .platform_index      = -1,
1119
+                .device_index        = -1,
1120
+                .context             = src_hwctx->device,
1121
+                .enumerate_platforms = &opencl_enumerate_platforms,
1122
+                .filter_platform     = &opencl_filter_d3d11_platform,
1123
+                .enumerate_devices   = &opencl_enumerate_d3d11_devices,
1124
+                .filter_device       = &opencl_filter_gpu_device,
1125
+            };
1126
+
1127
+            err = opencl_device_create_internal(hwdev, &selector, props);
1128
+        }
1129
+        break;
1130
+#endif
1131
+
1106 1132
     default:
1107 1133
         err = AVERROR(ENOSYS);
1108 1134
         break;
... ...
@@ -1461,7 +1608,7 @@ static void opencl_frames_uninit(AVHWFramesContext *hwfc)
1461 1461
     OpenCLFramesContext *priv = hwfc->internal->priv;
1462 1462
     cl_int cle;
1463 1463
 
1464
-#if HAVE_OPENCL_DXVA2
1464
+#if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11
1465 1465
     int i, p;
1466 1466
     for (i = 0; i < priv->nb_mapped_frames; i++) {
1467 1467
         AVOpenCLFrameDescriptor *desc = &priv->mapped_frames[i];
... ...
@@ -2258,6 +2405,159 @@ fail:
2258 2258
 
2259 2259
 #endif
2260 2260
 
2261
+#if HAVE_OPENCL_D3D11
2262
+
2263
+static void opencl_unmap_from_d3d11(AVHWFramesContext *dst_fc,
2264
+                                    HWMapDescriptor *hwmap)
2265
+{
2266
+    AVOpenCLFrameDescriptor    *desc = hwmap->priv;
2267
+    OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2268
+    OpenCLFramesContext *frames_priv = dst_fc->device_ctx->internal->priv;
2269
+    cl_event event;
2270
+    cl_int cle;
2271
+
2272
+    cle = device_priv->clEnqueueReleaseD3D11ObjectsKHR(
2273
+        frames_priv->command_queue, desc->nb_planes, desc->planes,
2274
+        0, NULL, &event);
2275
+    if (cle != CL_SUCCESS) {
2276
+        av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface "
2277
+               "handle: %d.\n", cle);
2278
+    }
2279
+
2280
+    opencl_wait_events(dst_fc, &event, 1);
2281
+}
2282
+
2283
+static int opencl_map_from_d3d11(AVHWFramesContext *dst_fc, AVFrame *dst,
2284
+                                 const AVFrame *src, int flags)
2285
+{
2286
+    OpenCLDeviceContext  *device_priv = dst_fc->device_ctx->internal->priv;
2287
+    OpenCLFramesContext  *frames_priv = dst_fc->internal->priv;
2288
+    AVOpenCLFrameDescriptor *desc;
2289
+    cl_event event;
2290
+    cl_int cle;
2291
+    int err, index, i;
2292
+
2293
+    index = (intptr_t)src->data[1];
2294
+    if (index >= frames_priv->nb_mapped_frames) {
2295
+        av_log(dst_fc, AV_LOG_ERROR, "Texture array index out of range for "
2296
+               "mapping: %d >= %d.\n", index, frames_priv->nb_mapped_frames);
2297
+        return AVERROR(EINVAL);
2298
+    }
2299
+
2300
+    av_log(dst_fc, AV_LOG_DEBUG, "Map D3D11 texture %d to OpenCL.\n",
2301
+           index);
2302
+
2303
+    desc = &frames_priv->mapped_frames[index];
2304
+
2305
+    cle = device_priv->clEnqueueAcquireD3D11ObjectsKHR(
2306
+        frames_priv->command_queue, desc->nb_planes, desc->planes,
2307
+        0, NULL, &event);
2308
+    if (cle != CL_SUCCESS) {
2309
+        av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface "
2310
+               "handle: %d.\n", cle);
2311
+        return AVERROR(EIO);
2312
+    }
2313
+
2314
+    err = opencl_wait_events(dst_fc, &event, 1);
2315
+    if (err < 0)
2316
+        goto fail;
2317
+
2318
+    for (i = 0; i < desc->nb_planes; i++)
2319
+        dst->data[i] = (uint8_t*)desc->planes[i];
2320
+
2321
+    err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
2322
+                                &opencl_unmap_from_d3d11, desc);
2323
+    if (err < 0)
2324
+        goto fail;
2325
+
2326
+    dst->width  = src->width;
2327
+    dst->height = src->height;
2328
+
2329
+    return 0;
2330
+
2331
+fail:
2332
+    cle = device_priv->clEnqueueReleaseD3D11ObjectsKHR(
2333
+        frames_priv->command_queue, desc->nb_planes, desc->planes,
2334
+        0, NULL, &event);
2335
+    if (cle == CL_SUCCESS)
2336
+        opencl_wait_events(dst_fc, &event, 1);
2337
+    return err;
2338
+}
2339
+
2340
+static int opencl_frames_derive_from_d3d11(AVHWFramesContext *dst_fc,
2341
+                                           AVHWFramesContext *src_fc, int flags)
2342
+{
2343
+    AVOpenCLDeviceContext    *dst_dev = dst_fc->device_ctx->hwctx;
2344
+    AVD3D11VAFramesContext *src_hwctx = src_fc->hwctx;
2345
+    OpenCLDeviceContext  *device_priv = dst_fc->device_ctx->internal->priv;
2346
+    OpenCLFramesContext  *frames_priv = dst_fc->internal->priv;
2347
+    cl_mem_flags cl_flags;
2348
+    cl_int cle;
2349
+    int err, i, p, nb_planes;
2350
+
2351
+    if (src_fc->sw_format != AV_PIX_FMT_NV12) {
2352
+        av_log(dst_fc, AV_LOG_ERROR, "Only NV12 textures are supported "
2353
+               "for D3D11 to OpenCL mapping.\n");
2354
+        return AVERROR(EINVAL);
2355
+    }
2356
+    nb_planes = 2;
2357
+
2358
+    if (src_fc->initial_pool_size == 0) {
2359
+        av_log(dst_fc, AV_LOG_ERROR, "Only fixed-size pools are supported "
2360
+               "for D3D11 to OpenCL mapping.\n");
2361
+        return AVERROR(EINVAL);
2362
+    }
2363
+
2364
+    cl_flags = opencl_mem_flags_for_mapping(flags);
2365
+    if (!cl_flags)
2366
+        return AVERROR(EINVAL);
2367
+
2368
+    frames_priv->nb_mapped_frames = src_fc->initial_pool_size;
2369
+
2370
+    frames_priv->mapped_frames =
2371
+        av_mallocz_array(frames_priv->nb_mapped_frames,
2372
+                         sizeof(*frames_priv->mapped_frames));
2373
+    if (!frames_priv->mapped_frames)
2374
+        return AVERROR(ENOMEM);
2375
+
2376
+    for (i = 0; i < frames_priv->nb_mapped_frames; i++) {
2377
+        AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i];
2378
+        desc->nb_planes = nb_planes;
2379
+        for (p = 0; p < nb_planes; p++) {
2380
+            UINT subresource = 2 * i + p;
2381
+
2382
+            desc->planes[p] =
2383
+                device_priv->clCreateFromD3D11Texture2DKHR(
2384
+                    dst_dev->context, cl_flags, src_hwctx->texture,
2385
+                    subresource, &cle);
2386
+            if (!desc->planes[p]) {
2387
+                av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL "
2388
+                       "image from plane %d of D3D texture "
2389
+                       "index %d (subresource %u): %d.\n",
2390
+                       p, i, (unsigned int)subresource, cle);
2391
+                err = AVERROR(EIO);
2392
+                goto fail;
2393
+            }
2394
+        }
2395
+    }
2396
+
2397
+    return 0;
2398
+
2399
+fail:
2400
+    for (i = 0; i < frames_priv->nb_mapped_frames; i++) {
2401
+        AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i];
2402
+        for (p = 0; p < desc->nb_planes; p++) {
2403
+            if (desc->planes[p])
2404
+                clReleaseMemObject(desc->planes[p]);
2405
+        }
2406
+    }
2407
+    av_freep(&frames_priv->mapped_frames);
2408
+    frames_priv->nb_mapped_frames = 0;
2409
+    return err;
2410
+}
2411
+
2412
+#endif
2413
+
2261 2414
 static int opencl_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
2262 2415
                            const AVFrame *src, int flags)
2263 2416
 {
... ...
@@ -2289,6 +2589,11 @@ static int opencl_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
2289 2289
         if (priv->dxva2_mapping_usable)
2290 2290
             return opencl_map_from_dxva2(hwfc, dst, src, flags);
2291 2291
 #endif
2292
+#if HAVE_OPENCL_D3D11
2293
+    case AV_PIX_FMT_D3D11:
2294
+        if (priv->d3d11_mapping_usable)
2295
+            return opencl_map_from_d3d11(hwfc, dst, src, flags);
2296
+#endif
2292 2297
     }
2293 2298
     return AVERROR(ENOSYS);
2294 2299
 }
... ...
@@ -2323,6 +2628,18 @@ static int opencl_frames_derive_to(AVHWFramesContext *dst_fc,
2323 2323
         }
2324 2324
         break;
2325 2325
 #endif
2326
+#if HAVE_OPENCL_D3D11
2327
+    case AV_HWDEVICE_TYPE_D3D11VA:
2328
+        if (!priv->d3d11_mapping_usable)
2329
+            return AVERROR(ENOSYS);
2330
+        {
2331
+            int err;
2332
+            err = opencl_frames_derive_from_d3d11(dst_fc, src_fc, flags);
2333
+            if (err < 0)
2334
+                return err;
2335
+        }
2336
+        break;
2337
+#endif
2326 2338
     default:
2327 2339
         return AVERROR(ENOSYS);
2328 2340
     }