[vlc-devel] [PATCH 01/12] d3d11: allow rendering video to DirectComposition surfaces

Pierre Lamot pierre at videolabs.io
Mon May 11 18:04:51 CEST 2020


---
 include/vlc_vout_window.h                    |  5 ++
 modules/video_output/Makefile.am             |  3 +-
 modules/video_output/win32/d3d11_swapchain.c | 51 +++++++++++++++++---
 modules/video_output/win32/d3d11_swapchain.h |  3 +-
 modules/video_output/win32/dcomp_wrapper.cpp | 31 ++++++++++++
 modules/video_output/win32/dcomp_wrapper.h   | 42 ++++++++++++++++
 modules/video_output/win32/direct3d11.c      | 13 +++--
 7 files changed, 135 insertions(+), 13 deletions(-)
 create mode 100644 modules/video_output/win32/dcomp_wrapper.cpp
 create mode 100644 modules/video_output/win32/dcomp_wrapper.h

diff --git a/include/vlc_vout_window.h b/include/vlc_vout_window.h
index ad16955ace..2699d2f744 100644
--- a/include/vlc_vout_window.h
+++ b/include/vlc_vout_window.h
@@ -61,6 +61,7 @@ enum vout_window_type {
     VOUT_WINDOW_TYPE_XID /**< X11 window */,
     VOUT_WINDOW_TYPE_HWND /**< Win32 or OS/2 window */,
     VOUT_WINDOW_TYPE_NSOBJECT /**< macOS/iOS view */,
+    VOUT_WINDOW_TYPE_DCOMP /**< Win32 DirectComposition */,
     VOUT_WINDOW_TYPE_ANDROID_NATIVE /**< Android native window */,
     VOUT_WINDOW_TYPE_WAYLAND /**< Wayland surface */,
 };
@@ -360,6 +361,10 @@ typedef struct vout_window_t {
         void     *nsobject;      /**< macOS/iOS view object */
         void     *anativewindow; /**< Android native window */
         struct wl_surface *wl;   /**< Wayland surface (client pointer) */
+        struct {
+            void *device;
+            void *visual;
+        } dcomp;                 /**<  Win32 direct composition surface */
     } handle;
 
     /** Display server (mandatory)
diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
index c82e9a0ed7..3bdb6929fb 100644
--- a/modules/video_output/Makefile.am
+++ b/modules/video_output/Makefile.am
@@ -155,7 +155,8 @@ libdirect3d11_plugin_la_SOURCES = video_output/win32/direct3d11.c \
  video_output/win32/d3d11_quad.c video_output/win32/d3d11_quad.h \
  video_output/win32/d3d11_shaders.c video_output/win32/d3d11_shaders.h \
  video_output/win32/d3d11_swapchain.c video_output/win32/d3d11_swapchain.h \
- video_output/win32/common.c video_output/win32/common.h
+ video_output/win32/common.c video_output/win32/common.h \
+ video_output/win32/dcomp_wrapper.cpp video_output/win32/dcomp_wrapper.h
 libdirect3d11_plugin_la_LIBADD = libchroma_copy.la libd3d11_common.la $(LIBCOM) -luuid
 if !HAVE_WINSTORE
 libdirect3d11_plugin_la_SOURCES += video_output/win32/events.c \
diff --git a/modules/video_output/win32/d3d11_swapchain.c b/modules/video_output/win32/d3d11_swapchain.c
index 7114bf57ef..3bfa989982 100644
--- a/modules/video_output/win32/d3d11_swapchain.c
+++ b/modules/video_output/win32/d3d11_swapchain.c
@@ -51,6 +51,7 @@
 
 #include "d3d11_swapchain.h"
 #include "d3d11_shaders.h"
+#include "dcomp_wrapper.h"
 
 typedef enum video_color_axis {
     COLOR_AXIS_RGB,
@@ -76,7 +77,10 @@ struct d3d11_local_swapchain
     const dxgi_color_space *colorspace;
 
 #if !VLC_WINSTORE_APP
+    bool                   useDcomp;
     HWND                   swapchainHwnd;
+    void*                  dcompDevice;
+    void*                  dcompVisual;
 #endif /* !VLC_WINSTORE_APP */
     IDXGISwapChain1        *dxgiswapChain;   /* DXGI 1.2 swap chain */
     IDXGISwapChain4        *dxgiswapChain4;  /* DXGI 1.5 for HDR metadata */
@@ -278,7 +282,7 @@ static void FillSwapChainDesc(struct d3d11_local_swapchain *display, UINT width,
 
 static void CreateSwapchain(struct d3d11_local_swapchain *display, UINT width, UINT height)
 {
-    if (display->swapchainHwnd == NULL)
+    if (!display->useDcomp && display->swapchainHwnd == NULL)
     {
         msg_Err(display->obj, "missing a HWND to create the swapchain");
         return;
@@ -301,18 +305,31 @@ static void CreateSwapchain(struct d3d11_local_swapchain *display, UINT width, U
         return;
     }
 
-    hr = IDXGIFactory2_CreateSwapChainForHwnd(dxgifactory, (IUnknown *)display->d3d_dev->d3ddevice,
-                                              display->swapchainHwnd, &scd,
-                                              NULL, NULL, &display->dxgiswapChain);
+    if (display->useDcomp)
+        hr = IDXGIFactory2_CreateSwapChainForComposition(dxgifactory, (IUnknown *)display->d3d_dev->d3ddevice,
+                                                    &scd, NULL, &display->dxgiswapChain);
+    else
+        hr = IDXGIFactory2_CreateSwapChainForHwnd(dxgifactory, (IUnknown *)display->d3d_dev->d3ddevice,
+                                                  display->swapchainHwnd, &scd,
+                                                  NULL, NULL, &display->dxgiswapChain);
+
     if (hr == DXGI_ERROR_INVALID_CALL && scd.Format == DXGI_FORMAT_R10G10B10A2_UNORM)
     {
         msg_Warn(display->obj, "10 bits swapchain failed, try 8 bits");
         scd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
-        hr = IDXGIFactory2_CreateSwapChainForHwnd(dxgifactory, (IUnknown *)display->d3d_dev->d3ddevice,
-                                                  display->swapchainHwnd, &scd,
-                                                  NULL, NULL, &display->dxgiswapChain);
+        if (display->useDcomp)
+            hr = IDXGIFactory2_CreateSwapChainForComposition(dxgifactory, (IUnknown *)display->d3d_dev->d3ddevice,
+                                                        &scd, NULL, &display->dxgiswapChain);
+        else
+            hr = IDXGIFactory2_CreateSwapChainForHwnd(dxgifactory, (IUnknown *)display->d3d_dev->d3ddevice,
+                                                      display->swapchainHwnd, &scd,
+                                                      NULL, NULL, &display->dxgiswapChain);
     }
     IDXGIFactory2_Release(dxgifactory);
+    if (display->useDcomp && SUCCEEDED(hr)) {
+        IDCompositionVisual_SetContent(display->dcompVisual, (IUnknown *)display->dxgiswapChain);
+        IDCompositionDevice_Commit(display->dcompDevice);
+    }
     if (FAILED(hr)) {
         msg_Err(display->obj, "Could not create the SwapChain. (hr=0x%lX)", hr);
     }
@@ -555,7 +572,7 @@ bool LocalSwapchainSelectPlane( void *opaque, size_t plane )
     return true;
 }
 
-void *CreateLocalSwapchainHandle(vlc_object_t *o, HWND hwnd, d3d11_device_t *d3d_dev)
+void *CreateLocalSwapchainHandleHwnd(vlc_object_t *o, HWND hwnd, d3d11_device_t *d3d_dev)
 {
     struct d3d11_local_swapchain *display = vlc_obj_calloc(o, 1, sizeof(*display));
     if (unlikely(display == NULL))
@@ -563,6 +580,7 @@ void *CreateLocalSwapchainHandle(vlc_object_t *o, HWND hwnd, d3d11_device_t *d3d
 
     display->obj = o;
 #if !VLC_WINSTORE_APP
+    display->useDcomp = false;
     display->swapchainHwnd = hwnd;
 #else // VLC_WINSTORE_APP
     VLC_UNUSED(hwnd);
@@ -571,3 +589,20 @@ void *CreateLocalSwapchainHandle(vlc_object_t *o, HWND hwnd, d3d11_device_t *d3d
 
     return display;
 }
+
+void *CreateLocalSwapchainHandleDComp(vlc_object_t *o, void* dcompDevice, void* dcompVisual, d3d11_device_t *d3d_dev)
+{
+    struct d3d11_local_swapchain *display = vlc_obj_calloc(o, 1, sizeof(*display));
+    if (unlikely(display == NULL))
+        return NULL;
+
+    display->obj = o;
+#if !VLC_WINSTORE_APP
+    display->useDcomp = true;
+    display->dcompDevice = dcompDevice;
+    display->dcompVisual = dcompVisual;
+#endif /* !VLC_WINSTORE_APP */
+    display->d3d_dev = d3d_dev;
+
+    return display;
+}
diff --git a/modules/video_output/win32/d3d11_swapchain.h b/modules/video_output/win32/d3d11_swapchain.h
index a5bfeac3c3..b4f2374746 100644
--- a/modules/video_output/win32/d3d11_swapchain.h
+++ b/modules/video_output/win32/d3d11_swapchain.h
@@ -28,7 +28,8 @@
 #include <vlc_codec.h>
 #include "../../video_chroma/d3d11_fmt.h"
 
-void *CreateLocalSwapchainHandle(vlc_object_t *, HWND, d3d11_device_t *d3d_dev);
+void *CreateLocalSwapchainHandleHwnd(vlc_object_t *, HWND, d3d11_device_t *d3d_dev);
+void *CreateLocalSwapchainHandleDComp(vlc_object_t *, void* dcompDevice, void* dcompVisual, d3d11_device_t *d3d_dev);
 
 void LocalSwapchainCleanupDevice( void *opaque );
 void LocalSwapchainSwap( void *opaque );
diff --git a/modules/video_output/win32/dcomp_wrapper.cpp b/modules/video_output/win32/dcomp_wrapper.cpp
new file mode 100644
index 0000000000..f9798ff9bf
--- /dev/null
+++ b/modules/video_output/win32/dcomp_wrapper.cpp
@@ -0,0 +1,31 @@
+/*****************************************************************************
+ * Copyright (c) 2020 VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#include "dcomp_wrapper.h"
+#include <dcomp.h>
+
+HRESULT IDCompositionVisual_SetContent(void* opaque, IUnknown *content)
+{
+    IDCompositionVisual* visual = (IDCompositionVisual*)opaque;
+    return visual->SetContent(content);
+}
+
+HRESULT IDCompositionDevice_Commit(void* opaque)
+{
+    IDCompositionDevice* device = (IDCompositionDevice*)opaque;
+    return device->Commit();
+}
diff --git a/modules/video_output/win32/dcomp_wrapper.h b/modules/video_output/win32/dcomp_wrapper.h
new file mode 100644
index 0000000000..e589b038bf
--- /dev/null
+++ b/modules/video_output/win32/dcomp_wrapper.h
@@ -0,0 +1,42 @@
+/*****************************************************************************
+ * Copyright (c) 2020 VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifndef VLC_DCOMP_WRAPPER_H_
+#define VLC_DCOMP_WRAPPER_H_
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+
+#include <windows.h>
+#include <unknwn.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+HRESULT IDCompositionVisual_SetContent(void* visual, IUnknown *content);
+HRESULT IDCompositionDevice_Commit(void* device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/modules/video_output/win32/direct3d11.c b/modules/video_output/win32/direct3d11.c
index 66b06c50b9..ca213cc708 100644
--- a/modules/video_output/win32/direct3d11.c
+++ b/modules/video_output/win32/direct3d11.c
@@ -321,13 +321,20 @@ static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
     if ( sys->swapCb == NULL || sys->startEndRenderingCb == NULL || sys->updateOutputCb == NULL )
     {
 #if !VLC_WINSTORE_APP
-        if (CommonWindowInit(VLC_OBJECT(vd), &sys->area, &sys->sys,
+        if (cfg->window->type == VOUT_WINDOW_TYPE_HWND)
+        {
+            if (CommonWindowInit(VLC_OBJECT(vd), &sys->area, &sys->sys,
                        vd->source.projection_mode != PROJECTION_MODE_RECTANGULAR))
-            goto error;
+                goto error;
+        }
+
 #endif /* !VLC_WINSTORE_APP */
 
         /* use our internal swapchain callbacks */
-        sys->outside_opaque      = CreateLocalSwapchainHandle(VLC_OBJECT(vd), sys->sys.hvideownd, sys->d3d_dev);
+        if (cfg->window->type == VOUT_WINDOW_TYPE_DCOMP)
+            sys->outside_opaque      = CreateLocalSwapchainHandleDComp(VLC_OBJECT(vd), cfg->window->handle.dcomp.device, cfg->window->handle.dcomp.visual, sys->d3d_dev);
+        else
+            sys->outside_opaque      = CreateLocalSwapchainHandleHwnd(VLC_OBJECT(vd), sys->sys.hvideownd, sys->d3d_dev);
         if (unlikely(sys->outside_opaque == NULL))
             goto error;
         sys->updateOutputCb      = LocalSwapchainUpdateOutput;
-- 
2.25.1



More information about the vlc-devel mailing list