[vlc-commits] direct3d11: move the swapchain handling in a separate file

Steve Lhomme git at videolan.org
Wed Jun 5 17:39:21 CEST 2019


vlc | branch: master | Steve Lhomme <robux4 at ycbcr.xyz> | Wed Jun  5 16:50:53 2019 +0200| [f54260673b09dc79ba6ce82247976677ae4d738e] | committer: Steve Lhomme

direct3d11: move the swapchain handling in a separate file

When rendering externally none of this code is used.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=f54260673b09dc79ba6ce82247976677ae4d738e
---

 modules/video_output/Makefile.am             |   1 +
 modules/video_output/win32/d3d11_swapchain.c | 520 +++++++++++++++++++++++++++
 modules/video_output/win32/d3d11_swapchain.h |  59 +++
 modules/video_output/win32/direct3d11.c      | 494 +------------------------
 4 files changed, 581 insertions(+), 493 deletions(-)

diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
index 7983d3637b..a5b59f911a 100644
--- a/modules/video_output/Makefile.am
+++ b/modules/video_output/Makefile.am
@@ -320,6 +320,7 @@ endif
 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
 libdirect3d11_plugin_la_LIBADD = libchroma_copy.la libd3d11_common.la $(LIBCOM) -luuid
 if !HAVE_WINSTORE
diff --git a/modules/video_output/win32/d3d11_swapchain.c b/modules/video_output/win32/d3d11_swapchain.c
new file mode 100644
index 0000000000..bd4df02897
--- /dev/null
+++ b/modules/video_output/win32/d3d11_swapchain.c
@@ -0,0 +1,520 @@
+/*****************************************************************************
+ * d3d11_swapchain.c: Direct3D11 swapchain handled by the display module
+ *****************************************************************************
+ * Copyright (C) 2014-2019 VLC authors and VideoLAN
+ *
+ * Authors: Martell Malone <martellmalone at gmail.com>
+ *          Steve Lhomme <robux4 at gmail.com>
+ *
+ * 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 <vlc/libvlc.h>
+#include <vlc/libvlc_picture.h>
+#include <vlc/libvlc_media.h>
+#include <vlc/libvlc_renderer_discoverer.h>
+#include <vlc/libvlc_media_player.h>
+
+#if !defined(_WIN32_WINNT) || _WIN32_WINNT < _WIN32_WINNT_WIN7
+# undef _WIN32_WINNT
+# define _WIN32_WINNT _WIN32_WINNT_WIN7
+#endif
+
+#define COBJMACROS
+#include <initguid.h>
+#include <d3d11.h>
+#ifdef HAVE_DXGI1_6_H
+# include <dxgi1_6.h>
+#else
+# include <dxgi1_5.h>
+#endif
+
+#include "d3d11_swapchain.h"
+
+typedef enum video_color_axis {
+    COLOR_AXIS_RGB,
+    COLOR_AXIS_YCBCR,
+} video_color_axis;
+
+typedef struct dxgi_color_space {
+    DXGI_COLOR_SPACE_TYPE   dxgi;
+    const char              *name;
+    video_color_axis        axis;
+    video_color_primaries_t primaries;
+    video_transfer_func_t   transfer;
+    video_color_space_t     color;
+    bool                    b_full_range;
+} dxgi_color_space;
+
+#define DXGI_COLOR_RANGE_FULL   1 /* 0-255 */
+#define DXGI_COLOR_RANGE_STUDIO 0 /* 16-235 */
+
+#define TRANSFER_FUNC_10    TRANSFER_FUNC_LINEAR
+#define TRANSFER_FUNC_22    TRANSFER_FUNC_SRGB
+#define TRANSFER_FUNC_2084  TRANSFER_FUNC_SMPTE_ST2084
+
+#define COLOR_PRIMARIES_BT601  COLOR_PRIMARIES_BT601_525
+
+static const dxgi_color_space color_spaces[] = {
+#define DXGIMAP(AXIS, RANGE, GAMMA, SITTING, PRIMARIES) \
+    { DXGI_COLOR_SPACE_##AXIS##_##RANGE##_G##GAMMA##_##SITTING##_P##PRIMARIES, \
+      #AXIS " Rec." #PRIMARIES " gamma:" #GAMMA " range:" #RANGE, \
+      COLOR_AXIS_##AXIS, COLOR_PRIMARIES_BT##PRIMARIES, TRANSFER_FUNC_##GAMMA, \
+      COLOR_SPACE_BT##PRIMARIES, DXGI_COLOR_RANGE_##RANGE},
+
+    DXGIMAP(RGB,   FULL,     22,    NONE,   709)
+    DXGIMAP(YCBCR, STUDIO,   22,    LEFT,   601)
+    DXGIMAP(YCBCR, FULL,     22,    LEFT,   601)
+    DXGIMAP(RGB,   FULL,     10,    NONE,   709)
+    DXGIMAP(RGB,   STUDIO,   22,    NONE,   709)
+    DXGIMAP(YCBCR, STUDIO,   22,    LEFT,   709)
+    DXGIMAP(YCBCR, FULL,     22,    LEFT,   709)
+    DXGIMAP(RGB,   STUDIO,   22,    NONE,  2020)
+    DXGIMAP(YCBCR, STUDIO,   22,    LEFT,  2020)
+    DXGIMAP(YCBCR, FULL,     22,    LEFT,  2020)
+    DXGIMAP(YCBCR, STUDIO,   22, TOPLEFT,  2020)
+    DXGIMAP(RGB,   FULL,     22,    NONE,  2020)
+    DXGIMAP(RGB,   FULL,   2084,    NONE,  2020)
+    DXGIMAP(YCBCR, STUDIO, 2084,    LEFT,  2020)
+    DXGIMAP(RGB,   STUDIO, 2084,    NONE,  2020)
+    DXGIMAP(YCBCR, STUDIO, 2084, TOPLEFT,  2020)
+    DXGIMAP(YCBCR, STUDIO,  HLG, TOPLEFT,  2020)
+    DXGIMAP(YCBCR, FULL,    HLG, TOPLEFT,  2020)
+    /*DXGIMAP(YCBCR, FULL,     22,    NONE,  2020, 601)*/
+    {DXGI_COLOR_SPACE_RESERVED, NULL, 0, 0, 0, 0, 0},
+#undef DXGIMAP
+};
+
+#ifdef HAVE_DXGI1_6_H
+static bool canHandleConversion(const dxgi_color_space *src, const dxgi_color_space *dst)
+{
+    if (src == dst)
+        return true;
+    if (src->primaries == COLOR_PRIMARIES_BT2020)
+        return true; /* we can convert BT2020 to 2020 or 709 */
+    if (dst->transfer == TRANSFER_FUNC_BT709)
+        return true; /* we can handle anything to 709 */
+    return false; /* let Windows do the rest */
+}
+#endif
+
+static void SelectSwapchainColorspace(struct d3d11_local_swapchain *display, const libvlc_video_direct3d_cfg_t *cfg)
+{
+    HRESULT hr;
+    int best = 0;
+    int score, best_score = 0;
+    UINT support;
+    IDXGISwapChain3 *dxgiswapChain3 = NULL;
+    hr = IDXGISwapChain_QueryInterface( display->dxgiswapChain, &IID_IDXGISwapChain3, (void **)&dxgiswapChain3);
+    if (FAILED(hr)) {
+        msg_Warn(display->obj, "could not get a IDXGISwapChain3");
+        goto done;
+    }
+
+    /* pick the best output based on color support and transfer */
+    /* TODO support YUV output later */
+    best = -1;
+    for (int i=0; color_spaces[i].name; ++i)
+    {
+        hr = IDXGISwapChain3_CheckColorSpaceSupport(dxgiswapChain3, color_spaces[i].dxgi, &support);
+        if (SUCCEEDED(hr) && support) {
+            if (!display->logged_capabilities)
+                msg_Dbg(display->obj, "supports colorspace %s", color_spaces[i].name);
+            score = 0;
+            if (color_spaces[i].primaries == (video_color_primaries_t) cfg->primaries)
+                score++;
+            if (color_spaces[i].color == (video_color_space_t) cfg->colorspace)
+                score += 2; /* we don't want to translate color spaces */
+            if (color_spaces[i].transfer == (video_transfer_func_t) cfg->transfer ||
+                /* favor 2084 output for HLG source */
+                (color_spaces[i].transfer == TRANSFER_FUNC_SMPTE_ST2084 && cfg->transfer == TRANSFER_FUNC_HLG))
+                score++;
+            if (color_spaces[i].b_full_range == cfg->full_range)
+                score++;
+            if (score > best_score || (score && best == -1)) {
+                best = i;
+                best_score = score;
+            }
+        }
+    }
+    display->logged_capabilities = true;
+
+    if (best == -1)
+    {
+        best = 0;
+        msg_Warn(display->obj, "no matching colorspace found force %s", color_spaces[best].name);
+    }
+
+    IDXGISwapChain_QueryInterface( display->dxgiswapChain, &IID_IDXGISwapChain4, (void **)&display->dxgiswapChain4);
+
+#ifdef HAVE_DXGI1_6_H
+    IDXGIOutput *dxgiOutput = NULL;
+
+    if (SUCCEEDED(IDXGISwapChain_GetContainingOutput( display->dxgiswapChain, &dxgiOutput )))
+    {
+        IDXGIOutput6 *dxgiOutput6 = NULL;
+        if (SUCCEEDED(IDXGIOutput_QueryInterface( dxgiOutput, &IID_IDXGIOutput6, (void **)&dxgiOutput6 )))
+        {
+            DXGI_OUTPUT_DESC1 desc1;
+            if (SUCCEEDED(IDXGIOutput6_GetDesc1( dxgiOutput6, &desc1 )))
+            {
+                const dxgi_color_space *csp = NULL;
+                for (int i=0; color_spaces[i].name; ++i)
+                {
+                    if (color_spaces[i].dxgi == desc1.ColorSpace)
+                    {
+                        if (!canHandleConversion(&color_spaces[best], &color_spaces[i]))
+                            msg_Warn(display->obj, "Can't handle conversion to screen format %s", color_spaces[i].name);
+                        else
+                        {
+                            best = i;
+                            csp = &color_spaces[i];
+                        }
+                        break;
+                    }
+                }
+
+                msg_Dbg(display->obj, "Output max luminance: %.1f, colorspace %s, bits per pixel %d", desc1.MaxFullFrameLuminance, csp?csp->name:"unknown", desc1.BitsPerColor);
+                //sys->display.luminance_peak = desc1.MaxFullFrameLuminance;
+            }
+            IDXGIOutput6_Release( dxgiOutput6 );
+        }
+        IDXGIOutput_Release( dxgiOutput );
+    }
+#endif
+
+    hr = IDXGISwapChain3_SetColorSpace1(dxgiswapChain3, color_spaces[best].dxgi);
+    if (SUCCEEDED(hr))
+        msg_Dbg(display->obj, "using colorspace %s", color_spaces[best].name);
+    else
+        msg_Err(display->obj, "Failed to set colorspace %s. (hr=0x%lX)", color_spaces[best].name, hr);
+done:
+    display->colorspace = &color_spaces[best];
+    if (dxgiswapChain3)
+        IDXGISwapChain3_Release(dxgiswapChain3);
+}
+
+#if !VLC_WINSTORE_APP
+static void FillSwapChainDesc(struct d3d11_local_swapchain *display, UINT width, UINT height, DXGI_SWAP_CHAIN_DESC1 *out)
+{
+    ZeroMemory(out, sizeof(*out));
+    out->BufferCount = 3;
+    out->BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+    out->SampleDesc.Count = 1;
+    out->SampleDesc.Quality = 0;
+    out->Width = width;
+    out->Height = height;
+    out->Format = display->pixelFormat->formatTexture;
+    //out->Flags = 512; // DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO;
+
+    bool isWin10OrGreater = false;
+    HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32.dll"));
+    if (likely(hKernel32 != NULL))
+        isWin10OrGreater = GetProcAddress(hKernel32, "GetSystemCpuSetInformation") != NULL;
+    if (isWin10OrGreater)
+        out->SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
+    else
+    {
+        bool isWin80OrGreater = false;
+        if (likely(hKernel32 != NULL))
+            isWin80OrGreater = GetProcAddress(hKernel32, "CheckTokenCapability") != NULL;
+        if (isWin80OrGreater)
+            out->SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
+        else
+        {
+            out->SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
+            out->BufferCount = 1;
+        }
+    }
+}
+
+static void CreateSwapchain(struct d3d11_local_swapchain *display, UINT width, UINT height)
+{
+    if (display->swapchainHwnd == NULL)
+    {
+        msg_Err(display->obj, "missing a HWND to create the swapchain");
+        return;
+    }
+
+    DXGI_SWAP_CHAIN_DESC1 scd;
+    FillSwapChainDesc(display, width, height, &scd);
+
+    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_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);
+    }
+    IDXGIFactory2_Release(dxgifactory);
+    if (FAILED(hr)) {
+        msg_Err(display->obj, "Could not create the SwapChain. (hr=0x%lX)", hr);
+    }
+}
+#endif /* !VLC_WINSTORE_APP */
+
+static bool UpdateSwapchain( struct d3d11_local_swapchain *display, const libvlc_video_direct3d_cfg_t *cfg )
+{
+    ID3D11Texture2D* pBackBuffer;
+    HRESULT hr;
+
+    D3D11_TEXTURE2D_DESC dsc = { 0 };
+    uint8_t bitsPerChannel = 0;
+
+    if ( display->swapchainTargetView[0] ) {
+        ID3D11Resource *res = NULL;
+        ID3D11RenderTargetView_GetResource( display->swapchainTargetView[0], &res );
+        if ( res )
+        {
+            ID3D11Texture2D_GetDesc( (ID3D11Texture2D*) res, &dsc );
+            ID3D11Resource_Release( res );
+        }
+        assert(display->pixelFormat->formatTexture == dsc.Format);
+        bitsPerChannel = display->pixelFormat->bitsPerChannel;
+    }
+
+    if ( dsc.Width == cfg->width && dsc.Height == cfg->height && cfg->bitdepth <= bitsPerChannel )
+        /* TODO also check the colorimetry */
+        return true; /* nothing changed */
+
+    for ( size_t i = 0; i < ARRAY_SIZE( display->swapchainTargetView ); i++ )
+    {
+        if ( display->swapchainTargetView[i] ) {
+            ID3D11RenderTargetView_Release( display->swapchainTargetView[i] );
+            display->swapchainTargetView[i] = NULL;
+        }
+    }
+
+    const d3d_format_t *newPixelFormat = NULL;
+#if VLC_WINSTORE_APP
+    display->dxgiswapChain = var_InheritInteger(display->obj, "winrt-swapchain");
+    if (display->dxgiswapChain != NULL)
+    {
+        DXGI_SWAP_CHAIN_DESC1 scd;
+        if (SUCCEEDED(IDXGISwapChain1_GetDesc(display->dxgiswapChain, &scd)))
+        {
+            for (const d3d_format_t *output_format = GetRenderFormatList();
+                 output_format->name != NULL; ++output_format)
+            {
+                if (output_format->formatTexture == scd.Format &&
+                    !is_d3d11_opaque(output_format->fourcc))
+                {
+                    newPixelFormat = output_format;
+                    break;
+                }
+            }
+        }
+    }
+#else /* !VLC_WINSTORE_APP */
+    /* favor RGB formats first */
+    newPixelFormat = FindD3D11Format( display->obj, &display->d3d_dev, 0, true,
+                                      cfg->bitdepth > 8 ? 10 : 8,
+                                      0, 0,
+                                      false, D3D11_FORMAT_SUPPORT_DISPLAY );
+    if (unlikely(newPixelFormat == NULL))
+        newPixelFormat = FindD3D11Format( display->obj, &display->d3d_dev, 0, false,
+                                          cfg->bitdepth > 8 ? 10 : 8,
+                                          0, 0,
+                                          false, D3D11_FORMAT_SUPPORT_DISPLAY );
+#endif /* !VLC_WINSTORE_APP */
+    if (unlikely(newPixelFormat == NULL)) {
+        msg_Err(display->obj, "Could not get the SwapChain format.");
+        return false;
+    }
+
+#if !VLC_WINSTORE_APP
+    if (display->dxgiswapChain != NULL && display->pixelFormat != newPixelFormat)
+    {
+        // the pixel format changed, we need a new swapchain
+        IDXGISwapChain_Release(display->dxgiswapChain);
+        display->dxgiswapChain = NULL;
+        display->logged_capabilities = false;
+    }
+
+    if ( display->dxgiswapChain == NULL )
+    {
+        display->pixelFormat = newPixelFormat;
+        CreateSwapchain(display, cfg->width, cfg->height);
+
+        if (display->dxgiswapChain == NULL)
+            return false;
+    }
+    else
+#endif /* !VLC_WINSTORE_APP */
+    {
+        /* TODO detect is the size is the same as the output and switch to fullscreen mode */
+        hr = IDXGISwapChain_ResizeBuffers( display->dxgiswapChain, 0, cfg->width, cfg->height,
+                                           DXGI_FORMAT_UNKNOWN, 0 );
+        if ( FAILED( hr ) ) {
+            msg_Err( display->obj, "Failed to resize the backbuffer. (hr=0x%lX)", hr );
+            return false;
+        }
+    }
+
+    hr = IDXGISwapChain_GetBuffer( display->dxgiswapChain, 0, &IID_ID3D11Texture2D, (LPVOID *) &pBackBuffer );
+    if ( FAILED( hr ) ) {
+        msg_Err( display->obj, "Could not get the backbuffer for the Swapchain. (hr=0x%lX)", hr );
+        return false;
+    }
+
+    hr = D3D11_CreateRenderTargets( &display->d3d_dev, (ID3D11Resource *) pBackBuffer,
+                                    display->pixelFormat, display->swapchainTargetView );
+    ID3D11Texture2D_Release( pBackBuffer );
+    if ( FAILED( hr ) ) {
+        msg_Err( display->obj, "Failed to create the target view. (hr=0x%lX)", hr );
+        return false;
+    }
+
+    D3D11_ClearRenderTargets( &display->d3d_dev, display->pixelFormat, display->swapchainTargetView );
+
+    SelectSwapchainColorspace(display, cfg);
+
+    return true;
+}
+
+bool LocalSwapchainSetupDevice( void **opaque, const libvlc_video_direct3d_device_cfg_t *cfg, libvlc_video_direct3d_device_setup_t *out )
+{
+    struct d3d11_local_swapchain *display = *opaque;
+    HRESULT hr;
+#if VLC_WINSTORE_APP
+    ID3D11DeviceContext *legacy_ctx = var_InheritInteger( display->obj, "winrt-d3dcontext" ); /* LEGACY */
+    if ( legacy_ctx == NULL )
+        hr = E_FAIL;
+    else
+        hr = D3D11_CreateDeviceExternal( display->obj,
+                                         legacy_ctx,
+                                         cfg->hardware_decoding,
+                                         &display->d3d_dev );
+#else /* !VLC_WINSTORE_APP */
+    hr = D3D11_CreateDevice( display->obj, display->hd3d, NULL,
+                             cfg->hardware_decoding,
+                             &display->d3d_dev );
+#endif /* !VLC_WINSTORE_APP */
+    if ( FAILED( hr ) )
+        return false;
+    out->device_context = display->d3d_dev.d3dcontext;
+    return true;
+}
+
+void LocalSwapchainCleanupDevice( void *opaque )
+{
+    struct d3d11_local_swapchain *display = opaque;
+    for (size_t i=0; i < ARRAY_SIZE(display->swapchainTargetView); i++)
+    {
+        if (display->swapchainTargetView[i]) {
+            ID3D11RenderTargetView_Release(display->swapchainTargetView[i]);
+            display->swapchainTargetView[i] = NULL;
+        }
+    }
+    if (display->dxgiswapChain4)
+    {
+        IDXGISwapChain4_Release(display->dxgiswapChain4);
+        display->dxgiswapChain4 = NULL;
+    }
+    if (display->dxgiswapChain)
+    {
+        IDXGISwapChain_Release(display->dxgiswapChain);
+        display->dxgiswapChain = NULL;
+    }
+
+    D3D11_ReleaseDevice( &display->d3d_dev );
+}
+
+void LocalSwapchainSwap( void *opaque )
+{
+    struct d3d11_local_swapchain *display = opaque;
+    DXGI_PRESENT_PARAMETERS presentParams = { 0 };
+
+    HRESULT hr = IDXGISwapChain1_Present1( display->dxgiswapChain, 0, 0, &presentParams );
+    if ( hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET )
+    {
+        /* TODO device lost */
+        msg_Err( display->obj, "SwapChain Present failed. (hr=0x%lX)", hr );
+    }
+}
+
+bool LocalSwapchainUpdateOutput( void *opaque, const libvlc_video_direct3d_cfg_t *cfg, libvlc_video_output_cfg_t *out )
+{
+    struct d3d11_local_swapchain *display = opaque;
+    if ( !UpdateSwapchain( display, cfg ) )
+        return false;
+    out->surface_format = display->pixelFormat->formatTexture;
+    out->full_range     = display->colorspace->b_full_range;
+    out->colorspace     = (libvlc_video_color_space_t)     display->colorspace->color;
+    out->primaries      = (libvlc_video_color_primaries_t) display->colorspace->primaries;
+    out->transfer       = (libvlc_video_transfer_func_t)   display->colorspace->transfer;
+    return true;
+}
+
+bool LocalSwapchainStartEndRendering( void *opaque, bool enter, const libvlc_video_direct3d_hdr10_metadata_t *p_hdr10 )
+{
+    struct d3d11_local_swapchain *display = opaque;
+
+    if ( enter )
+    {
+        if ( display->dxgiswapChain4 && p_hdr10 != NULL )
+        {
+            DXGI_HDR_METADATA_HDR10 hdr10 = { 0 };
+            hdr10.GreenPrimary[0] = p_hdr10->GreenPrimary[0];
+            hdr10.GreenPrimary[1] = p_hdr10->GreenPrimary[1];
+            hdr10.BluePrimary[0] = p_hdr10->BluePrimary[0];
+            hdr10.BluePrimary[1] = p_hdr10->BluePrimary[1];
+            hdr10.RedPrimary[0] = p_hdr10->RedPrimary[0];
+            hdr10.RedPrimary[1] = p_hdr10->RedPrimary[1];
+            hdr10.WhitePoint[0] = p_hdr10->WhitePoint[0];
+            hdr10.WhitePoint[1] = p_hdr10->WhitePoint[1];
+            hdr10.MinMasteringLuminance = p_hdr10->MinMasteringLuminance;
+            hdr10.MaxMasteringLuminance = p_hdr10->MaxMasteringLuminance;
+            hdr10.MaxContentLightLevel = p_hdr10->MaxContentLightLevel;
+            hdr10.MaxFrameAverageLightLevel = p_hdr10->MaxFrameAverageLightLevel;
+            IDXGISwapChain4_SetHDRMetaData( display->dxgiswapChain4, DXGI_HDR_METADATA_TYPE_HDR10, sizeof( hdr10 ), &hdr10 );
+        }
+
+        D3D11_ClearRenderTargets( &display->d3d_dev, display->pixelFormat, display->swapchainTargetView );
+    }
+    return true;
+}
+
+bool LocalSwapchainSelectPlane( void *opaque, size_t plane )
+{
+    struct d3d11_local_swapchain *display = opaque;
+    if (!display->swapchainTargetView[plane])
+        return false;
+    ID3D11DeviceContext_OMSetRenderTargets(display->d3d_dev.d3dcontext, 1,
+                                            &display->swapchainTargetView[plane], NULL);
+    return true;
+}
diff --git a/modules/video_output/win32/d3d11_swapchain.h b/modules/video_output/win32/d3d11_swapchain.h
new file mode 100644
index 0000000000..74c2fc21a0
--- /dev/null
+++ b/modules/video_output/win32/d3d11_swapchain.h
@@ -0,0 +1,59 @@
+/*****************************************************************************
+ * d3d11_swapchain.h: Direct3D11 swapchain handled by the display module
+ *****************************************************************************
+ * Copyright (C) 2014-2019 VLC authors and VideoLAN
+ *
+ * Authors: Martell Malone <martellmalone at gmail.com>
+ *          Steve Lhomme <robux4 at gmail.com>
+ *
+ * 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_D3D11_SWAPCHAIN_H
+#define VLC_D3D11_SWAPCHAIN_H
+
+#include <vlc_common.h>
+
+#include "../../video_chroma/d3d11_fmt.h"
+#include "d3d11_shaders.h"
+
+struct d3d11_local_swapchain
+{
+    vlc_object_t           *obj;
+    d3d11_handle_t         *hd3d;
+    d3d11_device_t         d3d_dev;
+
+    const d3d_format_t     *pixelFormat;
+    const struct dxgi_color_space *colorspace;
+
+#if !VLC_WINSTORE_APP
+    HWND                   swapchainHwnd;
+#endif /* !VLC_WINSTORE_APP */
+    IDXGISwapChain1        *dxgiswapChain;   /* DXGI 1.2 swap chain */
+    IDXGISwapChain4        *dxgiswapChain4;  /* DXGI 1.5 for HDR metadata */
+
+    ID3D11RenderTargetView *swapchainTargetView[D3D11_MAX_RENDER_TARGET];
+
+    bool                   logged_capabilities;
+};
+
+bool LocalSwapchainSetupDevice( void **opaque, const libvlc_video_direct3d_device_cfg_t *cfg, libvlc_video_direct3d_device_setup_t *out );
+void LocalSwapchainCleanupDevice( void *opaque );
+void LocalSwapchainSwap( void *opaque );
+bool LocalSwapchainUpdateOutput( void *opaque, const libvlc_video_direct3d_cfg_t *cfg, libvlc_video_output_cfg_t *out );
+bool LocalSwapchainStartEndRendering( void *opaque, bool enter, const libvlc_video_direct3d_hdr10_metadata_t *p_hdr10 );
+bool LocalSwapchainSelectPlane( void *opaque, size_t plane );
+
+#endif /* VLC_D3D11_SWAPCHAIN_H */
diff --git a/modules/video_output/win32/direct3d11.c b/modules/video_output/win32/direct3d11.c
index f0054b0f3c..4ed6b73ca7 100644
--- a/modules/video_output/win32/direct3d11.c
+++ b/modules/video_output/win32/direct3d11.c
@@ -58,6 +58,7 @@
 #include "../../video_chroma/d3d11_fmt.h"
 #include "d3d11_quad.h"
 #include "d3d11_shaders.h"
+#include "d3d11_swapchain.h"
 
 #include "common.h"
 #include "../../video_chroma/copy.h"
@@ -93,41 +94,6 @@ vlc_module_begin ()
     set_callbacks(Open, Close)
 vlc_module_end ()
 
-typedef enum video_color_axis {
-    COLOR_AXIS_RGB,
-    COLOR_AXIS_YCBCR,
-} video_color_axis;
-
-typedef struct {
-    DXGI_COLOR_SPACE_TYPE   dxgi;
-    const char              *name;
-    video_color_axis        axis;
-    video_color_primaries_t primaries;
-    video_transfer_func_t   transfer;
-    video_color_space_t     color;
-    bool                    b_full_range;
-} dxgi_color_space;
-
-struct d3d11_local_swapchain
-{
-    vlc_object_t           *obj;
-    d3d11_handle_t         *hd3d;
-    d3d11_device_t         d3d_dev;
-
-    const d3d_format_t     *pixelFormat;
-    const dxgi_color_space *colorspace;
-
-#if !VLC_WINSTORE_APP
-    HWND                   swapchainHwnd;
-#endif /* !VLC_WINSTORE_APP */
-    IDXGISwapChain1        *dxgiswapChain;   /* DXGI 1.2 swap chain */
-    IDXGISwapChain4        *dxgiswapChain4;  /* DXGI 1.5 for HDR metadata */
-
-    ID3D11RenderTargetView *swapchainTargetView[D3D11_MAX_RENDER_TARGET];
-
-    bool                   logged_capabilities;
-};
-
 struct vout_display_sys_t
 {
     vout_display_sys_win32_t sys;       /* only use if sys.event is not NULL */
@@ -198,7 +164,6 @@ static void UpdatePicQuadPosition(vout_display_t *);
 
 static int Control(vout_display_t *, int, va_list);
 
-static void SelectSwapchainColorspace(struct d3d11_local_swapchain *, const libvlc_video_direct3d_cfg_t *);
 
 static int UpdateDisplayFormat(vout_display_t *vd, libvlc_video_output_cfg_t *out,
                                const video_format_t *input_fmt)
@@ -338,315 +303,6 @@ static void UpdateSize(vout_display_t *vd)
     d3d11_device_unlock( &sys->d3d_dev );
 }
 
-#if !VLC_WINSTORE_APP
-static void FillSwapChainDesc(struct d3d11_local_swapchain *display, UINT width, UINT height, DXGI_SWAP_CHAIN_DESC1 *out)
-{
-    ZeroMemory(out, sizeof(*out));
-    out->BufferCount = 3;
-    out->BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
-    out->SampleDesc.Count = 1;
-    out->SampleDesc.Quality = 0;
-    out->Width = width;
-    out->Height = height;
-    out->Format = display->pixelFormat->formatTexture;
-    //out->Flags = 512; // DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO;
-
-    bool isWin10OrGreater = false;
-    HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32.dll"));
-    if (likely(hKernel32 != NULL))
-        isWin10OrGreater = GetProcAddress(hKernel32, "GetSystemCpuSetInformation") != NULL;
-    if (isWin10OrGreater)
-        out->SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
-    else
-    {
-        bool isWin80OrGreater = false;
-        if (likely(hKernel32 != NULL))
-            isWin80OrGreater = GetProcAddress(hKernel32, "CheckTokenCapability") != NULL;
-        if (isWin80OrGreater)
-            out->SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
-        else
-        {
-            out->SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
-            out->BufferCount = 1;
-        }
-    }
-}
-
-static void CreateSwapchain(struct d3d11_local_swapchain *display, UINT width, UINT height)
-{
-    if (display->swapchainHwnd == NULL)
-    {
-        msg_Err(display->obj, "missing a HWND to create the swapchain");
-        return;
-    }
-
-    DXGI_SWAP_CHAIN_DESC1 scd;
-    FillSwapChainDesc(display, width, height, &scd);
-
-    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_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);
-    }
-    IDXGIFactory2_Release(dxgifactory);
-    if (FAILED(hr)) {
-        msg_Err(display->obj, "Could not create the SwapChain. (hr=0x%lX)", hr);
-    }
-}
-#endif /* !VLC_WINSTORE_APP */
-
-static bool UpdateSwapchain( struct d3d11_local_swapchain *display, const libvlc_video_direct3d_cfg_t *cfg )
-{
-    ID3D11Texture2D* pBackBuffer;
-    HRESULT hr;
-
-    D3D11_TEXTURE2D_DESC dsc = { 0 };
-    uint8_t bitsPerChannel = 0;
-
-    if ( display->swapchainTargetView[0] ) {
-        ID3D11Resource *res = NULL;
-        ID3D11RenderTargetView_GetResource( display->swapchainTargetView[0], &res );
-        if ( res )
-        {
-            ID3D11Texture2D_GetDesc( (ID3D11Texture2D*) res, &dsc );
-            ID3D11Resource_Release( res );
-        }
-        assert(display->pixelFormat->formatTexture == dsc.Format);
-        bitsPerChannel = display->pixelFormat->bitsPerChannel;
-    }
-
-    if ( dsc.Width == cfg->width && dsc.Height == cfg->height && cfg->bitdepth <= bitsPerChannel )
-        /* TODO also check the colorimetry */
-        return true; /* nothing changed */
-
-    for ( size_t i = 0; i < ARRAY_SIZE( display->swapchainTargetView ); i++ )
-    {
-        if ( display->swapchainTargetView[i] ) {
-            ID3D11RenderTargetView_Release( display->swapchainTargetView[i] );
-            display->swapchainTargetView[i] = NULL;
-        }
-    }
-
-    const d3d_format_t *newPixelFormat = NULL;
-#if VLC_WINSTORE_APP
-    display->dxgiswapChain = var_InheritInteger(display->obj, "winrt-swapchain");
-    if (display->dxgiswapChain != NULL)
-    {
-        DXGI_SWAP_CHAIN_DESC1 scd;
-        if (SUCCEEDED(IDXGISwapChain1_GetDesc(display->dxgiswapChain, &scd)))
-        {
-            for (const d3d_format_t *output_format = GetRenderFormatList();
-                 output_format->name != NULL; ++output_format)
-            {
-                if (output_format->formatTexture == scd.Format &&
-                    !is_d3d11_opaque(output_format->fourcc))
-                {
-                    newPixelFormat = output_format;
-                    break;
-                }
-            }
-        }
-    }
-#else /* !VLC_WINSTORE_APP */
-    /* favor RGB formats first */
-    newPixelFormat = FindD3D11Format( display->obj, &display->d3d_dev, 0, true,
-                                      cfg->bitdepth > 8 ? 10 : 8,
-                                      0, 0,
-                                      false, D3D11_FORMAT_SUPPORT_DISPLAY );
-    if (unlikely(newPixelFormat == NULL))
-        newPixelFormat = FindD3D11Format( display->obj, &display->d3d_dev, 0, false,
-                                          cfg->bitdepth > 8 ? 10 : 8,
-                                          0, 0,
-                                          false, D3D11_FORMAT_SUPPORT_DISPLAY );
-#endif /* !VLC_WINSTORE_APP */
-    if (unlikely(newPixelFormat == NULL)) {
-        msg_Err(display->obj, "Could not get the SwapChain format.");
-        return false;
-    }
-
-#if !VLC_WINSTORE_APP
-    if (display->dxgiswapChain != NULL && display->pixelFormat != newPixelFormat)
-    {
-        // the pixel format changed, we need a new swapchain
-        IDXGISwapChain_Release(display->dxgiswapChain);
-        display->dxgiswapChain = NULL;
-        display->logged_capabilities = false;
-    }
-
-    if ( display->dxgiswapChain == NULL )
-    {
-        display->pixelFormat = newPixelFormat;
-        CreateSwapchain(display, cfg->width, cfg->height);
-
-        if (display->dxgiswapChain == NULL)
-            return false;
-    }
-    else
-#endif /* !VLC_WINSTORE_APP */
-    {
-        /* TODO detect is the size is the same as the output and switch to fullscreen mode */
-        hr = IDXGISwapChain_ResizeBuffers( display->dxgiswapChain, 0, cfg->width, cfg->height,
-                                           DXGI_FORMAT_UNKNOWN, 0 );
-        if ( FAILED( hr ) ) {
-            msg_Err( display->obj, "Failed to resize the backbuffer. (hr=0x%lX)", hr );
-            return false;
-        }
-    }
-
-    hr = IDXGISwapChain_GetBuffer( display->dxgiswapChain, 0, &IID_ID3D11Texture2D, (LPVOID *) &pBackBuffer );
-    if ( FAILED( hr ) ) {
-        msg_Err( display->obj, "Could not get the backbuffer for the Swapchain. (hr=0x%lX)", hr );
-        return false;
-    }
-
-    hr = D3D11_CreateRenderTargets( &display->d3d_dev, (ID3D11Resource *) pBackBuffer,
-                                    display->pixelFormat, display->swapchainTargetView );
-    ID3D11Texture2D_Release( pBackBuffer );
-    if ( FAILED( hr ) ) {
-        msg_Err( display->obj, "Failed to create the target view. (hr=0x%lX)", hr );
-        return false;
-    }
-
-    D3D11_ClearRenderTargets( &display->d3d_dev, display->pixelFormat, display->swapchainTargetView );
-
-    SelectSwapchainColorspace(display, cfg);
-
-    return true;
-}
-
-static bool LocalSwapchainSetupDevice( void **opaque, const libvlc_video_direct3d_device_cfg_t *cfg, libvlc_video_direct3d_device_setup_t *out )
-{
-    struct d3d11_local_swapchain *display = *opaque;
-    HRESULT hr;
-#if VLC_WINSTORE_APP
-    ID3D11DeviceContext *legacy_ctx = var_InheritInteger( display->obj, "winrt-d3dcontext" ); /* LEGACY */
-    if ( legacy_ctx == NULL )
-        hr = E_FAIL;
-    else
-        hr = D3D11_CreateDeviceExternal( display->obj,
-                                         legacy_ctx,
-                                         cfg->hardware_decoding,
-                                         &display->d3d_dev );
-#else /* !VLC_WINSTORE_APP */
-    hr = D3D11_CreateDevice( display->obj, display->hd3d, NULL,
-                             cfg->hardware_decoding,
-                             &display->d3d_dev );
-#endif /* !VLC_WINSTORE_APP */
-    if ( FAILED( hr ) )
-        return false;
-    out->device_context = display->d3d_dev.d3dcontext;
-    return true;
-}
-
-static void LocalSwapchainCleanupDevice( void *opaque )
-{
-    struct d3d11_local_swapchain *display = opaque;
-    for (size_t i=0; i < ARRAY_SIZE(display->swapchainTargetView); i++)
-    {
-        if (display->swapchainTargetView[i]) {
-            ID3D11RenderTargetView_Release(display->swapchainTargetView[i]);
-            display->swapchainTargetView[i] = NULL;
-        }
-    }
-    if (display->dxgiswapChain4)
-    {
-        IDXGISwapChain4_Release(display->dxgiswapChain4);
-        display->dxgiswapChain4 = NULL;
-    }
-    if (display->dxgiswapChain)
-    {
-        IDXGISwapChain_Release(display->dxgiswapChain);
-        display->dxgiswapChain = NULL;
-    }
-
-    D3D11_ReleaseDevice( &display->d3d_dev );
-}
-
-static void LocalSwapchainSwap( void *opaque )
-{
-    struct d3d11_local_swapchain *display = opaque;
-    DXGI_PRESENT_PARAMETERS presentParams = { 0 };
-
-    HRESULT hr = IDXGISwapChain1_Present1( display->dxgiswapChain, 0, 0, &presentParams );
-    if ( hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET )
-    {
-        /* TODO device lost */
-        msg_Err( display->obj, "SwapChain Present failed. (hr=0x%lX)", hr );
-    }
-}
-
-static bool LocalSwapchainUpdateOutput( void *opaque, const libvlc_video_direct3d_cfg_t *cfg, libvlc_video_output_cfg_t *out )
-{
-    struct d3d11_local_swapchain *display = opaque;
-    if ( !UpdateSwapchain( display, cfg ) )
-        return false;
-    out->surface_format = display->pixelFormat->formatTexture;
-    out->full_range     = display->colorspace->b_full_range;
-    out->colorspace     = (libvlc_video_color_space_t)     display->colorspace->color;
-    out->primaries      = (libvlc_video_color_primaries_t) display->colorspace->primaries;
-    out->transfer       = (libvlc_video_transfer_func_t)   display->colorspace->transfer;
-    return true;
-}
-
-static bool LocalSwapchainStartEndRendering( void *opaque, bool enter, const libvlc_video_direct3d_hdr10_metadata_t *p_hdr10 )
-{
-    struct d3d11_local_swapchain *display = opaque;
-
-    if ( enter )
-    {
-        if ( display->dxgiswapChain4 && p_hdr10 != NULL )
-        {
-            DXGI_HDR_METADATA_HDR10 hdr10 = { 0 };
-            hdr10.GreenPrimary[0] = p_hdr10->GreenPrimary[0];
-            hdr10.GreenPrimary[1] = p_hdr10->GreenPrimary[1];
-            hdr10.BluePrimary[0] = p_hdr10->BluePrimary[0];
-            hdr10.BluePrimary[1] = p_hdr10->BluePrimary[1];
-            hdr10.RedPrimary[0] = p_hdr10->RedPrimary[0];
-            hdr10.RedPrimary[1] = p_hdr10->RedPrimary[1];
-            hdr10.WhitePoint[0] = p_hdr10->WhitePoint[0];
-            hdr10.WhitePoint[1] = p_hdr10->WhitePoint[1];
-            hdr10.MinMasteringLuminance = p_hdr10->MinMasteringLuminance;
-            hdr10.MaxMasteringLuminance = p_hdr10->MaxMasteringLuminance;
-            hdr10.MaxContentLightLevel = p_hdr10->MaxContentLightLevel;
-            hdr10.MaxFrameAverageLightLevel = p_hdr10->MaxFrameAverageLightLevel;
-            IDXGISwapChain4_SetHDRMetaData( display->dxgiswapChain4, DXGI_HDR_METADATA_TYPE_HDR10, sizeof( hdr10 ), &hdr10 );
-        }
-
-        D3D11_ClearRenderTargets( &display->d3d_dev, display->pixelFormat, display->swapchainTargetView );
-    }
-    return true;
-}
-
-static bool LocalSwapchainSelectPlane( void *opaque, size_t plane )
-{
-    struct d3d11_local_swapchain *display = opaque;
-    if (!display->swapchainTargetView[plane])
-        return false;
-    ID3D11DeviceContext_OMSetRenderTargets(display->d3d_dev.d3dcontext, 1,
-                                            &display->swapchainTargetView[plane], NULL);
-    return true;
-}
-
 static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
                 video_format_t *fmtp, vlc_video_context *context)
 {
@@ -1184,154 +840,6 @@ static void Direct3D11Destroy(vout_display_t *vd)
 #endif
 }
 
-#define DXGI_COLOR_RANGE_FULL   1 /* 0-255 */
-#define DXGI_COLOR_RANGE_STUDIO 0 /* 16-235 */
-
-#define TRANSFER_FUNC_10    TRANSFER_FUNC_LINEAR
-#define TRANSFER_FUNC_22    TRANSFER_FUNC_SRGB
-#define TRANSFER_FUNC_2084  TRANSFER_FUNC_SMPTE_ST2084
-
-#define COLOR_PRIMARIES_BT601  COLOR_PRIMARIES_BT601_525
-
-static const dxgi_color_space color_spaces[] = {
-#define DXGIMAP(AXIS, RANGE, GAMMA, SITTING, PRIMARIES) \
-    { DXGI_COLOR_SPACE_##AXIS##_##RANGE##_G##GAMMA##_##SITTING##_P##PRIMARIES, \
-      #AXIS " Rec." #PRIMARIES " gamma:" #GAMMA " range:" #RANGE, \
-      COLOR_AXIS_##AXIS, COLOR_PRIMARIES_BT##PRIMARIES, TRANSFER_FUNC_##GAMMA, \
-      COLOR_SPACE_BT##PRIMARIES, DXGI_COLOR_RANGE_##RANGE},
-
-    DXGIMAP(RGB,   FULL,     22,    NONE,   709)
-    DXGIMAP(YCBCR, STUDIO,   22,    LEFT,   601)
-    DXGIMAP(YCBCR, FULL,     22,    LEFT,   601)
-    DXGIMAP(RGB,   FULL,     10,    NONE,   709)
-    DXGIMAP(RGB,   STUDIO,   22,    NONE,   709)
-    DXGIMAP(YCBCR, STUDIO,   22,    LEFT,   709)
-    DXGIMAP(YCBCR, FULL,     22,    LEFT,   709)
-    DXGIMAP(RGB,   STUDIO,   22,    NONE,  2020)
-    DXGIMAP(YCBCR, STUDIO,   22,    LEFT,  2020)
-    DXGIMAP(YCBCR, FULL,     22,    LEFT,  2020)
-    DXGIMAP(YCBCR, STUDIO,   22, TOPLEFT,  2020)
-    DXGIMAP(RGB,   FULL,     22,    NONE,  2020)
-    DXGIMAP(RGB,   FULL,   2084,    NONE,  2020)
-    DXGIMAP(YCBCR, STUDIO, 2084,    LEFT,  2020)
-    DXGIMAP(RGB,   STUDIO, 2084,    NONE,  2020)
-    DXGIMAP(YCBCR, STUDIO, 2084, TOPLEFT,  2020)
-    DXGIMAP(YCBCR, STUDIO,  HLG, TOPLEFT,  2020)
-    DXGIMAP(YCBCR, FULL,    HLG, TOPLEFT,  2020)
-    /*DXGIMAP(YCBCR, FULL,     22,    NONE,  2020, 601)*/
-    {DXGI_COLOR_SPACE_RESERVED, NULL, 0, 0, 0, 0, 0},
-#undef DXGIMAP
-};
-
-#ifdef HAVE_DXGI1_6_H
-static bool canHandleConversion(const dxgi_color_space *src, const dxgi_color_space *dst)
-{
-    if (src == dst)
-        return true;
-    if (src->primaries == COLOR_PRIMARIES_BT2020)
-        return true; /* we can convert BT2020 to 2020 or 709 */
-    if (dst->transfer == TRANSFER_FUNC_BT709)
-        return true; /* we can handle anything to 709 */
-    return false; /* let Windows do the rest */
-}
-#endif
-
-static void SelectSwapchainColorspace(struct d3d11_local_swapchain *display, const libvlc_video_direct3d_cfg_t *cfg)
-{
-    HRESULT hr;
-    int best = 0;
-    int score, best_score = 0;
-    UINT support;
-    IDXGISwapChain3 *dxgiswapChain3 = NULL;
-    hr = IDXGISwapChain_QueryInterface( display->dxgiswapChain, &IID_IDXGISwapChain3, (void **)&dxgiswapChain3);
-    if (FAILED(hr)) {
-        msg_Warn(display->obj, "could not get a IDXGISwapChain3");
-        goto done;
-    }
-
-    /* pick the best output based on color support and transfer */
-    /* TODO support YUV output later */
-    best = -1;
-    for (int i=0; color_spaces[i].name; ++i)
-    {
-        hr = IDXGISwapChain3_CheckColorSpaceSupport(dxgiswapChain3, color_spaces[i].dxgi, &support);
-        if (SUCCEEDED(hr) && support) {
-            if (!display->logged_capabilities)
-                msg_Dbg(display->obj, "supports colorspace %s", color_spaces[i].name);
-            score = 0;
-            if (color_spaces[i].primaries == (video_color_primaries_t) cfg->primaries)
-                score++;
-            if (color_spaces[i].color == (video_color_space_t) cfg->colorspace)
-                score += 2; /* we don't want to translate color spaces */
-            if (color_spaces[i].transfer == (video_transfer_func_t) cfg->transfer ||
-                /* favor 2084 output for HLG source */
-                (color_spaces[i].transfer == TRANSFER_FUNC_SMPTE_ST2084 && cfg->transfer == TRANSFER_FUNC_HLG))
-                score++;
-            if (color_spaces[i].b_full_range == cfg->full_range)
-                score++;
-            if (score > best_score || (score && best == -1)) {
-                best = i;
-                best_score = score;
-            }
-        }
-    }
-    display->logged_capabilities = true;
-
-    if (best == -1)
-    {
-        best = 0;
-        msg_Warn(display->obj, "no matching colorspace found force %s", color_spaces[best].name);
-    }
-
-    IDXGISwapChain_QueryInterface( display->dxgiswapChain, &IID_IDXGISwapChain4, (void **)&display->dxgiswapChain4);
-
-#ifdef HAVE_DXGI1_6_H
-    IDXGIOutput *dxgiOutput = NULL;
-
-    if (SUCCEEDED(IDXGISwapChain_GetContainingOutput( display->dxgiswapChain, &dxgiOutput )))
-    {
-        IDXGIOutput6 *dxgiOutput6 = NULL;
-        if (SUCCEEDED(IDXGIOutput_QueryInterface( dxgiOutput, &IID_IDXGIOutput6, (void **)&dxgiOutput6 )))
-        {
-            DXGI_OUTPUT_DESC1 desc1;
-            if (SUCCEEDED(IDXGIOutput6_GetDesc1( dxgiOutput6, &desc1 )))
-            {
-                const dxgi_color_space *csp = NULL;
-                for (int i=0; color_spaces[i].name; ++i)
-                {
-                    if (color_spaces[i].dxgi == desc1.ColorSpace)
-                    {
-                        if (!canHandleConversion(&color_spaces[best], &color_spaces[i]))
-                            msg_Warn(display->obj, "Can't handle conversion to screen format %s", color_spaces[i].name);
-                        else
-                        {
-                            best = i;
-                            csp = &color_spaces[i];
-                        }
-                        break;
-                    }
-                }
-
-                msg_Dbg(display->obj, "Output max luminance: %.1f, colorspace %s, bits per pixel %d", desc1.MaxFullFrameLuminance, csp?csp->name:"unknown", desc1.BitsPerColor);
-                //sys->display.luminance_peak = desc1.MaxFullFrameLuminance;
-            }
-            IDXGIOutput6_Release( dxgiOutput6 );
-        }
-        IDXGIOutput_Release( dxgiOutput );
-    }
-#endif
-
-    hr = IDXGISwapChain3_SetColorSpace1(dxgiswapChain3, color_spaces[best].dxgi);
-    if (SUCCEEDED(hr))
-        msg_Dbg(display->obj, "using colorspace %s", color_spaces[best].name);
-    else
-        msg_Err(display->obj, "Failed to set colorspace %s. (hr=0x%lX)", color_spaces[best].name, hr);
-done:
-    display->colorspace = &color_spaces[best];
-    if (dxgiswapChain3)
-        IDXGISwapChain3_Release(dxgiswapChain3);
-}
-
 static const d3d_format_t *GetDirectRenderingFormat(vout_display_t *vd, vlc_fourcc_t i_src_chroma)
 {
     UINT supportFlags = D3D11_FORMAT_SUPPORT_SHADER_LOAD;




More information about the vlc-commits mailing list