Imported Upstream version 6.1
[platform/upstream/ffmpeg.git] / libavutil / hwcontext_vaapi.c
index c3a98bc..12bc951 100644 (file)
 
 #include "config.h"
 
+#if HAVE_VAAPI_WIN32
+#   include <windows.h>
+#define COBJMACROS
+#   include <initguid.h>
+#   include <dxgi1_2.h>
+#   include "compat/w32dlfcn.h"
+#   include <va/va_win32.h>
+typedef HRESULT (WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);
+#endif
 #if HAVE_VAAPI_X11
 #   include <va/va_x11.h>
 #endif
@@ -122,13 +131,22 @@ static const VAAPIFormatDescriptor vaapi_format_map[] = {
 #ifdef VA_FOURCC_Y210
     MAP(Y210, YUV422_10,  Y210, 0),
 #endif
+#ifdef VA_FOURCC_Y212
+    MAP(Y212, YUV422_12,  Y212, 0),
+#endif
     MAP(411P, YUV411,  YUV411P, 0),
     MAP(422V, YUV422,  YUV440P, 0),
     MAP(444P, YUV444,  YUV444P, 0),
+#ifdef VA_FOURCC_XYUV
+    MAP(XYUV, YUV444,  VUYX,    0),
+#endif
     MAP(Y800, YUV400,  GRAY8,   0),
 #ifdef VA_FOURCC_P010
     MAP(P010, YUV420_10BPP, P010, 0),
 #endif
+#ifdef VA_FOURCC_P012
+    MAP(P012, YUV420_12, P012, 0),
+#endif
     MAP(BGRA, RGB32,   BGRA, 0),
     MAP(BGRX, RGB32,   BGR0, 0),
     MAP(RGBA, RGB32,   RGBA, 0),
@@ -142,6 +160,16 @@ static const VAAPIFormatDescriptor vaapi_format_map[] = {
 #ifdef VA_FOURCC_X2R10G10B10
     MAP(X2R10G10B10, RGB32_10, X2RGB10, 0),
 #endif
+#ifdef VA_FOURCC_Y410
+    // libva doesn't include a fourcc for XV30 and the driver only declares
+    // support for Y410, so we must fudge the mapping here.
+    MAP(Y410, YUV444_10,  XV30, 0),
+#endif
+#ifdef VA_FOURCC_Y412
+    // libva doesn't include a fourcc for XV36 and the driver only declares
+    // support for Y412, so we must fudge the mapping here.
+    MAP(Y412, YUV444_12,  XV36, 0),
+#endif
 };
 #undef MAP
 
@@ -189,7 +217,7 @@ static int vaapi_get_image_format(AVHWDeviceContext *hwdev,
             return 0;
         }
     }
-    return AVERROR(EINVAL);
+    return AVERROR(ENOSYS);
 }
 
 static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
@@ -789,7 +817,7 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc,
     err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
     if (err < 0) {
         // Requested format is not a valid output format.
-        return AVERROR(EINVAL);
+        return err;
     }
 
     map = av_malloc(sizeof(*map));
@@ -964,7 +992,7 @@ static int vaapi_map_to_memory(AVHWFramesContext *hwfc, AVFrame *dst,
     if (dst->format != AV_PIX_FMT_NONE) {
         err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
         if (err < 0)
-            return AVERROR(ENOSYS);
+            return err;
     }
 
     err = vaapi_map_frame(hwfc, dst, src, flags);
@@ -998,6 +1026,9 @@ static const struct {
 #if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
     DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
 #endif
+#if defined(VA_FOURCC_P012) && defined(DRM_FORMAT_R16)
+    DRM_MAP(P012, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
+#endif
     DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888),
     DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888),
     DRM_MAP(RGBA, 1, DRM_FORMAT_ABGR8888),
@@ -1008,6 +1039,18 @@ static const struct {
 #endif
     DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888),
     DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888),
+#if defined(VA_FOURCC_XYUV) && defined(DRM_FORMAT_XYUV8888)
+    DRM_MAP(XYUV, 1, DRM_FORMAT_XYUV8888),
+#endif
+#if defined(VA_FOURCC_Y412) && defined(DRM_FORMAT_XVYU2101010)
+    DRM_MAP(Y410, 1, DRM_FORMAT_XVYU2101010),
+#endif
+#if defined(VA_FOURCC_Y412) && defined(DRM_FORMAT_XVYU12_16161616)
+    DRM_MAP(Y412, 1, DRM_FORMAT_XVYU12_16161616),
+#endif
+#if defined(VA_FOURCC_X2R10G10B10) && defined(DRM_FORMAT_XRGB2101010)
+    DRM_MAP(X2R10G10B10, 1, DRM_FORMAT_XRGB2101010),
+#endif
 };
 #undef DRM_MAP
 
@@ -1288,8 +1331,17 @@ static int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst,
     surface_id = (VASurfaceID)(uintptr_t)src->data[3];
 
     export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
-    if (flags & AV_HWFRAME_MAP_READ)
+    if (flags & AV_HWFRAME_MAP_READ) {
         export_flags |= VA_EXPORT_SURFACE_READ_ONLY;
+
+        vas = vaSyncSurface(hwctx->display, surface_id);
+        if (vas != VA_STATUS_SUCCESS) {
+            av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
+                   "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
+            return AVERROR(EIO);
+        }
+    }
+
     if (flags & AV_HWFRAME_MAP_WRITE)
         export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
 
@@ -1480,7 +1532,7 @@ static int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst,
         goto fail_derived;
     }
 
-    av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
+    av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %"PRIdPTR".\n",
            mapping->buffer_info.handle);
 
     mapping->drm_desc.nb_objects = 1;
@@ -1623,7 +1675,7 @@ static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
     VAAPIDevicePriv *priv;
     VADisplay display = NULL;
     const AVDictionaryEntry *ent;
-    int try_drm, try_x11, try_all;
+    int try_drm, try_x11, try_win32, try_all;
 
     priv = av_mallocz(sizeof(*priv));
     if (!priv)
@@ -1636,11 +1688,13 @@ static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
 
     ent = av_dict_get(opts, "connection_type", NULL, 0);
     if (ent) {
-        try_all = try_drm = try_x11 = 0;
+        try_all = try_drm = try_x11 = try_win32 = 0;
         if (!strcmp(ent->value, "drm")) {
             try_drm = 1;
         } else if (!strcmp(ent->value, "x11")) {
             try_x11 = 1;
+        } else if (!strcmp(ent->value, "win32")) {
+            try_win32 = 1;
         } else {
             av_log(ctx, AV_LOG_ERROR, "Invalid connection type %s.\n",
                    ent->value);
@@ -1650,6 +1704,7 @@ static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
         try_all = 1;
         try_drm = HAVE_VAAPI_DRM;
         try_x11 = HAVE_VAAPI_X11;
+        try_win32 = HAVE_VAAPI_WIN32;
     }
 
 #if HAVE_VAAPI_DRM
@@ -1669,6 +1724,7 @@ static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
             char path[64];
             int n, max_devices = 8;
 #if CONFIG_LIBDRM
+            drmVersion *info;
             const AVDictionaryEntry *kernel_driver;
             kernel_driver = av_dict_get(opts, "kernel_driver", NULL, 0);
 #endif
@@ -1682,9 +1738,15 @@ static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
                     break;
                 }
 #if CONFIG_LIBDRM
+                info = drmGetVersion(priv->drm_fd);
+                if (!info) {
+                    av_log(ctx, AV_LOG_VERBOSE,
+                           "Failed to get DRM version for device %d.\n", n);
+                    close(priv->drm_fd);
+                    priv->drm_fd = -1;
+                    continue;
+                }
                 if (kernel_driver) {
-                    drmVersion *info;
-                    info = drmGetVersion(priv->drm_fd);
                     if (strcmp(kernel_driver->value, info->name)) {
                         av_log(ctx, AV_LOG_VERBOSE, "Ignoring device %d "
                                "with non-matching kernel driver (%s).\n",
@@ -1699,12 +1761,20 @@ static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
                            "with matching kernel driver (%s).\n",
                            n, info->name);
                     drmFreeVersion(info);
-                } else
-#endif
-                {
-                    av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
-                           "DRM render node for device %d.\n", n);
+                    break;
+                // drmGetVersion() ensures |info->name| is 0-terminated.
+                } else if (!strcmp(info->name, "vgem")) {
+                    av_log(ctx, AV_LOG_VERBOSE,
+                           "Skipping vgem node for device %d.\n", n);
+                    drmFreeVersion(info);
+                    close(priv->drm_fd);
+                    priv->drm_fd = -1;
+                    continue;
                 }
+                drmFreeVersion(info);
+#endif
+                av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
+                       "DRM render node for device %d.\n", n);
                 break;
             }
             if (n >= max_devices)
@@ -1742,6 +1812,68 @@ static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
     }
 #endif
 
+#if HAVE_VAAPI_WIN32
+    if (!display && try_win32) {
+        // Try to create a display from the specified device, if any.
+        if (!device) {
+            display = vaGetDisplayWin32(NULL);
+        } else {
+            IDXGIFactory2 *pDXGIFactory = NULL;
+            IDXGIAdapter *pAdapter = NULL;
+#if !HAVE_UWP
+            HANDLE dxgi = dlopen("dxgi.dll", 0);
+            if (!dxgi) {
+                av_log(ctx, AV_LOG_ERROR, "Failed to load dxgi.dll\n");
+                return AVERROR_UNKNOWN;
+            }
+            PFN_CREATE_DXGI_FACTORY pfnCreateDXGIFactory =
+                (PFN_CREATE_DXGI_FACTORY)dlsym(dxgi, "CreateDXGIFactory");
+            if (!pfnCreateDXGIFactory) {
+                av_log(ctx, AV_LOG_ERROR, "CreateDXGIFactory load failed\n");
+                dlclose(dxgi);
+                return AVERROR_UNKNOWN;
+            }
+#else
+            // In UWP (which lacks LoadLibrary), CreateDXGIFactory isn't
+            // available, only CreateDXGIFactory1
+            PFN_CREATE_DXGI_FACTORY pfnCreateDXGIFactory =
+                (PFN_CREATE_DXGI_FACTORY)CreateDXGIFactory1;
+#endif
+            if (SUCCEEDED(pfnCreateDXGIFactory(&IID_IDXGIFactory2,
+                                              (void **)&pDXGIFactory))) {
+                int adapter = atoi(device);
+                if (SUCCEEDED(IDXGIFactory2_EnumAdapters(pDXGIFactory,
+                                                         adapter,
+                                                         &pAdapter))) {
+                    DXGI_ADAPTER_DESC desc;
+                    if (SUCCEEDED(IDXGIAdapter2_GetDesc(pAdapter, &desc))) {
+                        av_log(ctx, AV_LOG_INFO,
+                              "Using device %04x:%04x (%ls) - LUID %lu %ld.\n",
+                              desc.VendorId, desc.DeviceId, desc.Description,
+                              desc.AdapterLuid.LowPart,
+                              desc.AdapterLuid.HighPart);
+                        display = vaGetDisplayWin32(&desc.AdapterLuid);
+                    }
+                    IDXGIAdapter_Release(pAdapter);
+                }
+                IDXGIFactory2_Release(pDXGIFactory);
+            }
+#if !HAVE_UWP
+            dlclose(dxgi);
+#endif
+        }
+
+        if (!display) {
+            av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
+                    "from Win32 display.\n");
+            return AVERROR_UNKNOWN;
+        }
+
+        av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
+                "Win32 display.\n");
+    }
+#endif
+
     if (!display) {
         if (device)
             av_log(ctx, AV_LOG_ERROR, "No VA display found for "