vlc | branch: master | Pierre Lamot <pie...@videolabs.io> | Tue Mar 24 09:52:50 2020 +0100| [de2011c106829cce6e8cf0413861b4ee5fbb72d8] | committer: Pierre Lamot
d3d11: allow rendering video to DirectComposition surfaces > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=de2011c106829cce6e8cf0413861b4ee5fbb72d8 --- configure.ac | 13 +++ include/vlc_vout_window.h | 3 + modules/video_output/Makefile.am | 3 + modules/video_output/win32/d3d11_swapchain.c | 120 +++++++++++++++++++++++++-- modules/video_output/win32/d3d11_swapchain.h | 5 +- modules/video_output/win32/dcomp_wrapper.cpp | 35 ++++++++ modules/video_output/win32/dcomp_wrapper.h | 35 ++++++++ modules/video_output/win32/direct3d11.c | 15 +++- 8 files changed, 216 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index aa140c941d..ea50387801 100644 --- a/configure.ac +++ b/configure.ac @@ -2723,6 +2723,19 @@ dnl have_iapplication_data2="no" AC_CHECK_TYPES([IApplicationData2],[],[],[#include <windows.storage.h>]) +dnl +dnl DirectComposition +dnl +AC_LANG_PUSH([C++]) +AC_CHECK_HEADERS([dcomp.h], [ + have_dcomp="yes" +], [], [ + #include <windows.h> +]) +AC_LANG_POP([C++]) +AM_CONDITIONAL([HAVE_DCOMP], [test "${have_dcomp}" = "yes"]) + + dnl dnl avformat demuxer/muxer plugin dnl diff --git a/include/vlc_vout_window.h b/include/vlc_vout_window.h index ad16955ace..ea16d4b414 100644 --- a/include/vlc_vout_window.h +++ b/include/vlc_vout_window.h @@ -63,6 +63,7 @@ enum vout_window_type { VOUT_WINDOW_TYPE_NSOBJECT /**< macOS/iOS view */, VOUT_WINDOW_TYPE_ANDROID_NATIVE /**< Android native window */, VOUT_WINDOW_TYPE_WAYLAND /**< Wayland surface */, + VOUT_WINDOW_TYPE_DCOMP /**< Win32 DirectComposition */, }; /** @@ -360,6 +361,7 @@ typedef struct vout_window_t { void *nsobject; /**< macOS/iOS view object */ void *anativewindow; /**< Android native window */ struct wl_surface *wl; /**< Wayland surface (client pointer) */ + void *dcomp_visual; /**< Win32 direct composition visual */ } handle; /** Display server (mandatory) @@ -373,6 +375,7 @@ typedef struct vout_window_t { union { char *x11; /**< X11 display string (NULL = use default) */ struct wl_display *wl; /**< Wayland display (client pointer) */ + void* dcomp_device; /**< DirectComposition device */ } display; const struct vout_window_operations *ops; /**< operations handled by the diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am index 07ae276871..811da78b0e 100644 --- a/modules/video_output/Makefile.am +++ b/modules/video_output/Makefile.am @@ -157,6 +157,9 @@ libdirect3d11_plugin_la_SOURCES = video_output/win32/direct3d11.c \ video_output/win32/d3d11_swapchain.c video_output/win32/d3d11_swapchain.h \ video_output/win32/common.c video_output/win32/common.h libdirect3d11_plugin_la_LIBADD = libchroma_copy.la libd3d11_common.la $(LIBCOM) -luuid +if HAVE_DCOMP +libdirect3d11_plugin_la_SOURCES += video_output/win32/dcomp_wrapper.cpp video_output/win32/dcomp_wrapper.h +endif if !HAVE_WINSTORE libdirect3d11_plugin_la_SOURCES += video_output/win32/events.c \ video_output/win32/events.h \ diff --git a/modules/video_output/win32/d3d11_swapchain.c b/modules/video_output/win32/d3d11_swapchain.c index 7114bf57ef..efeb69b205 100644 --- a/modules/video_output/win32/d3d11_swapchain.c +++ b/modules/video_output/win32/d3d11_swapchain.c @@ -52,11 +52,20 @@ #include "d3d11_swapchain.h" #include "d3d11_shaders.h" +#ifdef HAVE_DCOMP_H +# include "dcomp_wrapper.h" +#endif + typedef enum video_color_axis { COLOR_AXIS_RGB, COLOR_AXIS_YCBCR, } video_color_axis; +typedef enum swapchain_surface_type { + SWAPCHAIN_SURFACE_HWND, + SWAPCHAIN_SURFACE_DCOMP, +} swapchain_surface_type; + typedef struct { DXGI_COLOR_SPACE_TYPE dxgi; const char *name; @@ -75,9 +84,17 @@ struct d3d11_local_swapchain const d3d_format_t *pixelFormat; const dxgi_color_space *colorspace; + swapchain_surface_type swapchainSurfaceType; + union { #if !VLC_WINSTORE_APP - HWND swapchainHwnd; + HWND hwnd; #endif /* !VLC_WINSTORE_APP */ + struct { + void* device; + void* visual; + } dcomp; + } swapchainSurface; + IDXGISwapChain1 *dxgiswapChain; /* DXGI 1.2 swap chain */ IDXGISwapChain4 *dxgiswapChain4; /* DXGI 1.5 for HDR metadata */ bool send_metadata; @@ -276,9 +293,10 @@ static void FillSwapChainDesc(struct d3d11_local_swapchain *display, UINT width, } } -static void CreateSwapchain(struct d3d11_local_swapchain *display, UINT width, UINT height) +static void CreateSwapchainHwnd(struct d3d11_local_swapchain *display, UINT width, UINT height) { - if (display->swapchainHwnd == NULL) + vlc_assert(display->swapchainSurfaceType == SWAPCHAIN_SURFACE_HWND); + if (display->swapchainSurface.hwnd == NULL) { msg_Err(display->obj, "missing a HWND to create the swapchain"); return; @@ -302,14 +320,15 @@ static void CreateSwapchain(struct d3d11_local_swapchain *display, UINT width, U } hr = IDXGIFactory2_CreateSwapChainForHwnd(dxgifactory, (IUnknown *)display->d3d_dev->d3ddevice, - display->swapchainHwnd, &scd, - NULL, NULL, &display->dxgiswapChain); + display->swapchainSurface.hwnd, &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, + display->swapchainSurface.hwnd, &scd, NULL, NULL, &display->dxgiswapChain); } IDXGIFactory2_Release(dxgifactory); @@ -317,6 +336,65 @@ static void CreateSwapchain(struct d3d11_local_swapchain *display, UINT width, U msg_Err(display->obj, "Could not create the SwapChain. (hr=0x%lX)", hr); } } + +#ifdef HAVE_DCOMP_H +static void CreateSwapchainDComp(struct d3d11_local_swapchain *display, UINT width, UINT height) +{ + vlc_assert(display->swapchainSurfaceType == SWAPCHAIN_SURFACE_DCOMP); + if (display->swapchainSurface.dcomp.device == NULL || display->swapchainSurface.dcomp.visual == NULL) + { + msg_Err(display->obj, "missing a HWND to create the swapchain"); + return; + } + + DXGI_SWAP_CHAIN_DESC1 scd; + FillSwapChainDesc(display, width, height, &scd); + ZeroMemory(&scd, sizeof(scd)); + scd.BufferCount = 3; + scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + scd.SampleDesc.Count = 1; + scd.SampleDesc.Quality = 0; + scd.Width = width; + scd.Height = height; + scd.Format = display->pixelFormat->formatTexture; + scd.Scaling = DXGI_SCALING_STRETCH; + scd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + scd.AlphaMode = DXGI_ALPHA_MODE_IGNORE; + + IDXGIAdapter *dxgiadapter = D3D11DeviceAdapter(display->d3d_dev->d3ddevice); + if (unlikely(dxgiadapter==NULL)) { + msg_Err(display->obj, "Could not get the DXGI Adapter"); + return; + } + + IDXGIFactory2 *dxgifactory; + HRESULT hr = IDXGIAdapter_GetParent(dxgiadapter, &IID_IDXGIFactory2, (void **)&dxgifactory); + IDXGIAdapter_Release(dxgiadapter); + if (FAILED(hr)) { + msg_Err(display->obj, "Could not get the DXGI Factory. (hr=0x%lX)", hr); + return; + } + + hr = IDXGIFactory2_CreateSwapChainForComposition(dxgifactory, (IUnknown *)display->d3d_dev->d3ddevice, + &scd, 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_CreateSwapChainForComposition(dxgifactory, (IUnknown *)display->d3d_dev->d3ddevice, + &scd, NULL, &display->dxgiswapChain); + } + IDXGIFactory2_Release(dxgifactory); + if (SUCCEEDED(hr)) { + IDCompositionVisual_SetContent(display->swapchainSurface.dcomp.visual, (IUnknown *)display->dxgiswapChain); + IDCompositionDevice_Commit(display->swapchainSurface.dcomp.device); + } + if (FAILED(hr)) { + msg_Err(display->obj, "Could not create the SwapChain. (hr=0x%lX)", hr); + } +} +#endif /* HAVE_DCOMP_H */ + #endif /* !VLC_WINSTORE_APP */ static bool UpdateSwapchain( struct d3d11_local_swapchain *display, const libvlc_video_render_cfg_t *cfg ) @@ -400,7 +478,13 @@ static bool UpdateSwapchain( struct d3d11_local_swapchain *display, const libvlc if ( display->dxgiswapChain == NULL ) { display->pixelFormat = newPixelFormat; - CreateSwapchain(display, cfg->width, cfg->height); + +#ifdef HAVE_DCOMP_H + if (display->swapchainSurfaceType == SWAPCHAIN_SURFACE_DCOMP) + CreateSwapchainDComp(display, cfg->width, cfg->height); + else // SWAPCHAIN_TARGET_HWND +#endif + CreateSwapchainHwnd(display, cfg->width, cfg->height); if (display->dxgiswapChain == NULL) return false; @@ -555,7 +639,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,7 +647,8 @@ void *CreateLocalSwapchainHandle(vlc_object_t *o, HWND hwnd, d3d11_device_t *d3d display->obj = o; #if !VLC_WINSTORE_APP - display->swapchainHwnd = hwnd; + display->swapchainSurfaceType = SWAPCHAIN_SURFACE_HWND; + display->swapchainSurface.hwnd = hwnd; #else // VLC_WINSTORE_APP VLC_UNUSED(hwnd); #endif // VLC_WINSTORE_APP @@ -571,3 +656,20 @@ void *CreateLocalSwapchainHandle(vlc_object_t *o, HWND hwnd, d3d11_device_t *d3d return display; } + +#ifdef HAVE_DCOMP_H +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; + display->swapchainSurfaceType = SWAPCHAIN_SURFACE_DCOMP; + display->swapchainSurface.dcomp.device = dcompDevice; + display->swapchainSurface.dcomp.visual = dcompVisual; + display->d3d_dev = d3d_dev; + + return display; +} +#endif diff --git a/modules/video_output/win32/d3d11_swapchain.h b/modules/video_output/win32/d3d11_swapchain.h index a5bfeac3c3..69b2e9a80c 100644 --- a/modules/video_output/win32/d3d11_swapchain.h +++ b/modules/video_output/win32/d3d11_swapchain.h @@ -28,7 +28,10 @@ #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); +#ifdef HAVE_DCOMP_H +void *CreateLocalSwapchainHandleDComp(vlc_object_t *, void* dcompDevice, void* dcompVisual, d3d11_device_t *d3d_dev); +#endif 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..6b80721353 --- /dev/null +++ b/modules/video_output/win32/dcomp_wrapper.cpp @@ -0,0 +1,35 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#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..365615a0fb --- /dev/null +++ b/modules/video_output/win32/dcomp_wrapper.h @@ -0,0 +1,35 @@ +/***************************************************************************** + * 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_ + +#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..ada535e977 100644 --- a/modules/video_output/win32/direct3d11.c +++ b/modules/video_output/win32/direct3d11.c @@ -321,13 +321,22 @@ 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); +#ifdef HAVE_DCOMP_H + if (cfg->window->type == VOUT_WINDOW_TYPE_DCOMP) + sys->outside_opaque = CreateLocalSwapchainHandleDComp(VLC_OBJECT(vd), cfg->window->display.dcomp_device, cfg->window->handle.dcomp_visual, sys->d3d_dev); + else +#endif + sys->outside_opaque = CreateLocalSwapchainHandleHwnd(VLC_OBJECT(vd), sys->sys.hvideownd, sys->d3d_dev); if (unlikely(sys->outside_opaque == NULL)) goto error; sys->updateOutputCb = LocalSwapchainUpdateOutput; _______________________________________________ vlc-commits mailing list vlc-commits@videolan.org https://mailman.videolan.org/listinfo/vlc-commits