From aaacd6fc291e406f81a4739ae7f7828937a215a5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Wed, 4 Mar 2015 03:57:29 +0100
Subject: dxva2: Add DRM mode for vaapi.

---
 configure.ac               |  9 ++---
 dlls/dxva2/dxva2_private.h |  7 +++-
 dlls/dxva2/main.c          |  8 +++++
 dlls/dxva2/vaapi.c         | 89 +++++++++++++++++++++++++++++++++++++---------
 4 files changed, 91 insertions(+), 22 deletions(-)

diff --git a/configure.ac b/configure.ac
index c925f6b..bdacada 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1264,17 +1264,18 @@ This probably prevents linking to OpenGL. Try deleting the file and restarting c
 OpenGL and Direct3D won't be supported.])
 
     dnl **** Check for libva ****
-    AC_CHECK_HEADERS([va/va_x11.h])
-    if test "$ac_cv_header_va_va_x11_h" = "yes"
+    AC_CHECK_HEADERS([va/va_x11.h va/va_drm.h])
+    if test "$ac_cv_header_va_va_x11_h" = "yes" -a "$ac_cv_header_va_va_drm_h" = "yes"
     then
         WINE_CHECK_SONAME(va,vaQuerySurfaceAttributes,,,[$X_LIBS])
         WINE_CHECK_SONAME(va-x11,vaGetDisplay,,,[$X_LIBS -lva])
-        if test "x$ac_cv_lib_soname_va" != "x" -a "x$ac_cv_lib_soname_va_x11" != "x"
+        WINE_CHECK_SONAME(va-drm,vaGetDisplayDRM,,,[$X_LIBS -lva])
+        if test "x$ac_cv_lib_soname_va" != "x" -a "x$ac_cv_lib_soname_va_x11" != "x" -a "x$ac_cv_lib_soname_va_drm" != "x"
         then
             AC_DEFINE(HAVE_VAAPI, 1, [Define if you have the libva development files])
         fi
     fi
-    WINE_NOTICE_WITH(va,[test "x$ac_cv_lib_soname_va" = "x" -o "x$ac_cv_lib_soname_va_x11" = "x"],
+    WINE_NOTICE_WITH(va,[test "x$ac_cv_lib_soname_va" = "x" -o "x$ac_cv_lib_soname_va_x11" = "x" -o "x$ac_cv_lib_soname_va_drm" = "x"],
                      [libva ${notice_platform}development files not found, GPU video acceleration won't be supported.])
 
     CPPFLAGS="$ac_save_CPPFLAGS"
diff --git a/dlls/dxva2/dxva2_private.h b/dlls/dxva2/dxva2_private.h
index 5df59bd..14ac586 100644
--- a/dlls/dxva2/dxva2_private.h
+++ b/dlls/dxva2/dxva2_private.h
@@ -22,6 +22,7 @@
 #ifdef HAVE_VAAPI
 # undef Status
 # include <va/va_x11.h>
+# include <va/va_drm.h>
 #endif
 
 extern HRESULT videoservice_create( IDirect3DDevice9 *device, REFIID riid, void **ppv ) DECLSPEC_HIDDEN;
@@ -39,6 +40,8 @@ extern HRESULT genericdecoder_create( IDirectXVideoDecoderService *videodecoder,
 
 /* public */
 extern BOOL config_vaapi_enabled DECLSPEC_HIDDEN;
+BOOL config_vaapi_drm DECLSPEC_HIDDEN;
+char config_vaapi_drm_path[MAX_PATH] DECLSPEC_HIDDEN;
 extern IWineVideoService *vaapi_videoservice_create( void ) DECLSPEC_HIDDEN;
 
 /* internal */
@@ -101,11 +104,13 @@ typedef struct
     /* libraries */
     void *va_handle;
     void *va_x11_handle;
+    void *va_drm_handle;
     void *x11_handle;
 
-    /* display */
+    /* display / drm connection */
     Display *x11_display;
     VADisplay va_display;
+    int drm_fd;
 } WineVideoServiceImpl;
 
 static inline WineVideoServiceImpl *impl_from_IWineVideoService( IWineVideoService *iface )
diff --git a/dlls/dxva2/main.c b/dlls/dxva2/main.c
index 758c146..0442c63 100644
--- a/dlls/dxva2/main.c
+++ b/dlls/dxva2/main.c
@@ -33,6 +33,8 @@
 WINE_DEFAULT_DEBUG_CHANNEL(dxva2);
 
 BOOL config_vaapi_enabled = FALSE;
+BOOL config_vaapi_drm = FALSE;
+char config_vaapi_drm_path[MAX_PATH] = "";
 
 BOOL WINAPI CapabilitiesRequestAndCapabilitiesReply( HMONITOR monitor, LPSTR buffer, DWORD length )
 {
@@ -379,6 +381,12 @@ static void dxva2_init( void )
     if (get_config_key(defkey, appkey, "backend", buffer, sizeof(buffer)))
         config_vaapi_enabled = !strcmp(buffer, "va");
 
+    if (get_config_key(defkey, appkey, "va_mode", buffer, sizeof(buffer)))
+        config_vaapi_drm = !strcmp(buffer, "drm");
+
+    if (!get_config_key(defkey, appkey, "va_drm_device", config_vaapi_drm_path, sizeof(config_vaapi_drm_path)))
+        strcpy(config_vaapi_drm_path, "/dev/dri/card0");
+
     if (defkey) RegCloseKey(defkey);
     if (appkey) RegCloseKey(appkey);
 }
diff --git a/dlls/dxva2/vaapi.c b/dlls/dxva2/vaapi.c
index 4c570f5..1b19684 100644
--- a/dlls/dxva2/vaapi.c
+++ b/dlls/dxva2/vaapi.c
@@ -55,6 +55,7 @@ MAKE_FUNCPTR(vaEndPicture);
 MAKE_FUNCPTR(vaErrorStr);
 MAKE_FUNCPTR(vaGetConfigAttributes);
 MAKE_FUNCPTR(vaGetDisplay);
+MAKE_FUNCPTR(vaGetDisplayDRM);
 MAKE_FUNCPTR(vaGetImage);
 MAKE_FUNCPTR(vaInitialize);
 MAKE_FUNCPTR(vaMapBuffer);
@@ -135,6 +136,23 @@ error:
     return NULL;
 }
 
+static void *load_libva_drm( void )
+{
+    void *handle = wine_dlopen(SONAME_LIBVA_DRM, RTLD_NOW, NULL, 0);
+    if (!handle)
+    {
+        FIXME("Wine cannot find the %s library.\n", SONAME_LIBVA_DRM);
+        return FALSE;
+    }
+
+    LOAD_FUNCPTR(vaGetDisplayDRM);
+    return handle;
+
+error:
+    wine_dlclose(handle, NULL, 0);
+    return NULL;
+}
+
 static void *load_libx11( void )
 {
     void *handle = wine_dlopen(SONAME_LIBX11, RTLD_NOW, NULL, 0);
@@ -480,11 +498,18 @@ static ULONG WINAPI WineVideoService_Release( IWineVideoService *iface )
         pvaTerminate(This->va_display);
         vaapi_unlock();
 
-        pXCloseDisplay(This->x11_display);
-
-        wine_dlclose(This->x11_handle, NULL, 0);
-        wine_dlclose(This->va_x11_handle, NULL, 0);
-        wine_dlclose(This->va_handle, NULL, 0);
+        if (This->x11_display)
+            pXCloseDisplay(This->x11_display);
+        if (This->x11_handle)
+            wine_dlclose(This->x11_handle, NULL, 0);
+        if (This->drm_fd > 0)
+            close(This->drm_fd);
+        if (This->va_drm_handle)
+            wine_dlclose(This->va_drm_handle, NULL, 0);
+        if (This->va_x11_handle)
+            wine_dlclose(This->va_x11_handle, NULL, 0);
+        if (This->va_handle)
+            wine_dlclose(This->va_handle, NULL, 0);
 
         CoTaskMemFree(This);
     }
@@ -703,30 +728,56 @@ IWineVideoService *vaapi_videoservice_create( void )
 
     videoservice->va_handle     = NULL;
     videoservice->va_x11_handle = NULL;
+    videoservice->va_drm_handle = NULL;
     videoservice->x11_handle    = NULL;
 
     videoservice->x11_display   = NULL;
     videoservice->va_display    = NULL;
+    videoservice->drm_fd        = -1;
 
     videoservice->va_handle = load_libva();
     if (!videoservice->va_handle)
         goto err;
 
-    videoservice->va_x11_handle = load_libva_x11();
-    if (!videoservice->va_x11_handle)
-        goto err;
+    if (config_vaapi_drm)
+    {
+        TRACE("Using VAAPI in DRM mode.\n");
 
-    videoservice->x11_handle = load_libx11();
-    if (!videoservice->x11_handle)
-        goto err;
+        videoservice->va_drm_handle = load_libva_drm();
+        if (!videoservice->va_drm_handle)
+            goto err;
 
-    videoservice->x11_display = pXOpenDisplay(NULL);
-    if (!videoservice->x11_display)
-        goto err;
+        videoservice->drm_fd = open(config_vaapi_drm_path, O_RDWR);
+        if (videoservice->drm_fd < 0)
+        {
+            FIXME("Failed to open device %s\n", config_vaapi_drm_path);
+            goto err;
+        }
 
-    videoservice->va_display = pvaGetDisplay(videoservice->x11_display);
-    if (!videoservice->va_display)
-        goto err;
+        videoservice->va_display = pvaGetDisplayDRM(videoservice->drm_fd);
+        if (!videoservice->va_display)
+            goto err;
+    }
+    else
+    {
+        TRACE("Using VAAPI in X11 mode.\n");
+
+        videoservice->va_x11_handle = load_libva_x11();
+        if (!videoservice->va_x11_handle)
+            goto err;
+
+        videoservice->x11_handle = load_libx11();
+        if (!videoservice->x11_handle)
+            goto err;
+
+        videoservice->x11_display = pXOpenDisplay(NULL);
+        if (!videoservice->x11_display)
+            goto err;
+
+        videoservice->va_display = pvaGetDisplay(videoservice->x11_display);
+        if (!videoservice->va_display)
+            goto err;
+    }
 
     if (pvaInitialize(videoservice->va_display, &major, &minor) != VA_STATUS_SUCCESS)
         goto err;
@@ -749,6 +800,10 @@ err:
         pXCloseDisplay(videoservice->x11_display);
     if (videoservice->x11_handle)
         wine_dlclose(videoservice->x11_handle, NULL, 0);
+    if (videoservice->drm_fd > 0)
+        close(videoservice->drm_fd);
+    if (videoservice->va_drm_handle)
+        wine_dlclose(videoservice->va_drm_handle, NULL, 0);
     if (videoservice->va_x11_handle)
         wine_dlclose(videoservice->va_x11_handle, NULL, 0);
     if (videoservice->va_handle)
-- 
2.3.0

