[vlc-devel] [PATCH 7/7] direct3d11: add 3d playback

Steve Lhomme robux4 at ycbcr.xyz
Thu Aug 16 11:00:49 CEST 2018


From: "Mohammed (Shaan) Huzaifa Danish" <shaan3 at gmail.com>

This adds code for core stereo 3d files playback

Signed-off-by: Steve Lhomme <robux4 at ycbcr.xyz>
---
 modules/video_output/win32/d3d11_quad.c    | 216 ++++++++++++-----
 modules/video_output/win32/d3d11_quad.h    |  12 +-
 modules/video_output/win32/d3d11_shaders.c |  84 ++++---
 modules/video_output/win32/d3d11_shaders.h |  16 +-
 modules/video_output/win32/direct3d11.c    | 267 +++++++++++++++++++--
 5 files changed, 474 insertions(+), 121 deletions(-)

diff --git a/modules/video_output/win32/d3d11_quad.c b/modules/video_output/win32/d3d11_quad.c
index 3bb60d3e35..fd3a25f495 100644
--- a/modules/video_output/win32/d3d11_quad.c
+++ b/modules/video_output/win32/d3d11_quad.c
@@ -43,7 +43,8 @@
 
 void D3D11_RenderQuad(d3d11_device_t *d3d_dev, d3d_quad_t *quad, d3d_vshader_t *vsshader,
                       ID3D11ShaderResourceView *resourceView[D3D11_MAX_SHADER_VIEW],
-                      ID3D11RenderTargetView *d3drenderTargetView[D3D11_MAX_SHADER_VIEW])
+                      ID3D11RenderTargetView *d3drenderTargetView[D3D11_MAX_SHADER_VIEW][2],
+                      size_t eyeIndex, size_t targetEye)
 {
     UINT offset = 0;
 
@@ -74,9 +75,9 @@ void D3D11_RenderQuad(d3d11_device_t *d3d_dev, d3d_quad_t *quad, d3d_vshader_t *
 
         ID3D11DeviceContext_PSSetShader(d3d_dev->d3dcontext, quad->d3dpixelShader[i], NULL, 0);
 
-        ID3D11DeviceContext_RSSetViewports(d3d_dev->d3dcontext, 1, &quad->cropViewport[i]);
+        ID3D11DeviceContext_RSSetViewports(d3d_dev->d3dcontext, 1, &quad->cropViewport[i][eyeIndex]);
 
-        ID3D11DeviceContext_OMSetRenderTargets(d3d_dev->d3dcontext, 1, &d3drenderTargetView[i], NULL);
+        ID3D11DeviceContext_OMSetRenderTargets(d3d_dev->d3dcontext, 1, &d3drenderTargetView[i][targetEye], NULL);
 
         ID3D11DeviceContext_DrawIndexed(d3d_dev->d3dcontext, quad->indexCount, 0, 0);
     }
@@ -114,6 +115,9 @@ static bool AllocQuadVertices(vlc_object_t *o, d3d11_device_t *d3d_dev, d3d_quad
     bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
     bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
 
+    quad->pVertexBuffer = NULL;
+    quad->pIndexBuffer = NULL;
+
     hr = ID3D11Device_CreateBuffer(d3d_dev->d3ddevice, &bd, NULL, &quad->pVertexBuffer);
     if(FAILED(hr)) {
         msg_Err(o, "Failed to create vertex buffer. (hr=%lX)", hr);
@@ -133,7 +137,6 @@ static bool AllocQuadVertices(vlc_object_t *o, d3d11_device_t *d3d_dev, d3d_quad
         msg_Err(o, "Could not create the quad indices. (hr=0x%lX)", hr);
         goto fail;
     }
-
     return true;
 fail:
     if (quad->pVertexBuffer)
@@ -166,7 +169,7 @@ void D3D11_ReleaseQuad(d3d_quad_t *quad)
         ID3D11Buffer_Release(quad->pVertexBuffer);
         quad->pVertexBuffer = NULL;
     }
-    if (quad->pIndexBuffer)
+    if (quad->pVertexBuffer)
     {
         ID3D11Buffer_Release(quad->pIndexBuffer);
         quad->pIndexBuffer = NULL;
@@ -590,12 +593,12 @@ bool D3D11_UpdateQuadPosition( vlc_object_t *o, d3d11_device_t *d3d_dev, d3d_qua
         break;
     default:
         msg_Warn(o, "Projection mode %d not handled", quad->projection);
+        ID3D11DeviceContext_Unmap(d3d_dev->d3dcontext, (ID3D11Resource *)quad->pIndexBuffer, 0);
+        ID3D11DeviceContext_Unmap(d3d_dev->d3dcontext, (ID3D11Resource *)quad->pVertexBuffer, 0);
         result = false;
     }
-
     ID3D11DeviceContext_Unmap(d3d_dev->d3dcontext, (ID3D11Resource *)quad->pIndexBuffer, 0);
     ID3D11DeviceContext_Unmap(d3d_dev->d3dcontext, (ID3D11Resource *)quad->pVertexBuffer, 0);
-
     return result;
 }
 
@@ -692,7 +695,7 @@ error:
 #undef D3D11_SetupQuad
 int D3D11_SetupQuad(vlc_object_t *o, d3d11_device_t *d3d_dev, const video_format_t *fmt, d3d_quad_t *quad,
                     const display_info_t *displayFormat, const RECT *output,
-                    video_orientation_t orientation)
+                    video_orientation_t orientation, video_multiview_mode_t src_mode)
 {
     const bool RGB_shader = IsRGBShader(quad->textureFormat);
 
@@ -829,6 +832,7 @@ int D3D11_SetupQuad(vlc_object_t *o, d3d11_device_t *d3d_dev, const video_format
 
     ShaderUpdateConstants(o, d3d_dev, quad, PS_CONST_COLORSPACE, &colorspace);
 
+    quad->src_stereo = src_mode;
 
     quad->picSys.formatTexture = quad->textureFormat->formatTexture;
     quad->picSys.context = d3d_dev->d3dcontext;
@@ -839,78 +843,172 @@ int D3D11_SetupQuad(vlc_object_t *o, d3d11_device_t *d3d_dev, const video_format
 
     for (size_t i=0; i<D3D11_MAX_SHADER_VIEW; i++)
     {
-        quad->cropViewport[i].MinDepth = 0.0f;
-        quad->cropViewport[i].MaxDepth = 1.0f;
+        for (size_t eye=0; eye < 2;eye++)
+        {
+            quad->cropViewport[i][eye].MinDepth = 0.0f;
+            quad->cropViewport[i][eye].MaxDepth = 1.0f;
+        }
     }
     quad->resourceCount = DxgiResourceCount(quad->textureFormat);
 
     return VLC_SUCCESS;
 }
 
-void D3D11_UpdateViewport(d3d_quad_t *quad, const RECT *rect, const d3d_format_t *display)
+void D3D11_UpdateViewport(d3d_quad_t *quad, const RECT *rect,
+                          const d3d_format_t *display, vlc_stereoscopic_mode_t display_mode)
 {
 #define RECTWidth(r)   (LONG)((r)->right - (r)->left)
 #define RECTHeight(r)  (LONG)((r)->bottom - (r)->top)
     LONG srcAreaWidth, srcAreaHeight;
+    LONG rightEyeTop;
+
+    switch (quad->src_stereo)
+    {
+    case MULTIVIEW_STEREO_SBS:
+        srcAreaWidth = RECTWidth(rect) * 2;
+        srcAreaHeight = RECTHeight(rect);
+        rightEyeTop = rect->top;
+        break;
 
-    srcAreaWidth  = RECTWidth(rect);
-    srcAreaHeight = RECTHeight(rect);
+    case MULTIVIEW_STEREO_TB:
+        srcAreaWidth  = RECTWidth(rect);
+        srcAreaHeight = RECTHeight(rect) * 2;
+        rightEyeTop = rect->top - RECTHeight(rect);
+        break;
+
+    default:
+        srcAreaWidth  = RECTWidth(rect);
+        srcAreaHeight = RECTHeight(rect);
+        rightEyeTop = rect->top;
+        break;
+    }
 #undef RECTWidth
 #undef RECTHeight
 
-    quad->cropViewport[0].TopLeftX = rect->left;
-    quad->cropViewport[0].TopLeftY = rect->top;
-    quad->cropViewport[0].Width    = srcAreaWidth;
-    quad->cropViewport[0].Height   = srcAreaHeight;
+    quad->cropViewport[0][MONO_OR_LEFT_EYE].TopLeftX = rect->left;
+    quad->cropViewport[0][MONO_OR_LEFT_EYE].TopLeftY = rect->top;
+    quad->cropViewport[0][MONO_OR_LEFT_EYE].Width    = srcAreaWidth;
+    quad->cropViewport[0][MONO_OR_LEFT_EYE].Height   = srcAreaHeight;
+    quad->cropViewport[0][RIGHT_EYE].TopLeftY        = rightEyeTop;
 
-    switch ( quad->textureFormat->formatTexture )
+    //Default 2D mode selection
+    if (display_mode != VIDEO_STEREO_OUTPUT_STEREO)
     {
-    case DXGI_FORMAT_NV12:
-    case DXGI_FORMAT_P010:
-        quad->cropViewport[1].TopLeftX = rect->left / 2;
-        quad->cropViewport[1].TopLeftY = rect->top / 2;
-        quad->cropViewport[1].Width    = srcAreaWidth / 2;
-        quad->cropViewport[1].Height   = srcAreaHeight / 2;
-        break;
-    case DXGI_FORMAT_R8G8B8A8_UNORM:
-    case DXGI_FORMAT_B8G8R8A8_UNORM:
-    case DXGI_FORMAT_B8G8R8X8_UNORM:
-    case DXGI_FORMAT_B5G6R5_UNORM:
-    case DXGI_FORMAT_R10G10B10A2_UNORM:
-    case DXGI_FORMAT_R16G16B16A16_UNORM:
-    case DXGI_FORMAT_YUY2:
-    case DXGI_FORMAT_AYUV:
-        if ( display->formatTexture == DXGI_FORMAT_NV12 ||
-             display->formatTexture == DXGI_FORMAT_P010 )
+        switch ( quad->textureFormat->formatTexture )
         {
-            quad->cropViewport[1].TopLeftX = rect->left / 2;
-            quad->cropViewport[1].TopLeftY = rect->top / 2;
-            quad->cropViewport[1].Width    = srcAreaWidth / 2;
-            quad->cropViewport[1].Height   = srcAreaHeight / 2;
-        }
-        break;
-    case DXGI_FORMAT_UNKNOWN:
-        switch ( quad->textureFormat->fourcc )
-        {
-        case VLC_CODEC_YUVA:
-            if ( display->formatTexture != DXGI_FORMAT_NV12 &&
-                 display->formatTexture != DXGI_FORMAT_P010 )
+        case DXGI_FORMAT_NV12:
+        case DXGI_FORMAT_P010:
+            quad->cropViewport[1][MONO_OR_LEFT_EYE].TopLeftX = rect->left / 2;
+            quad->cropViewport[1][MONO_OR_LEFT_EYE].TopLeftY = rect->top / 2;
+            break;
+        case DXGI_FORMAT_R8G8B8A8_UNORM:
+        case DXGI_FORMAT_B8G8R8A8_UNORM:
+        case DXGI_FORMAT_B8G8R8X8_UNORM:
+        case DXGI_FORMAT_B5G6R5_UNORM:
+        case DXGI_FORMAT_R10G10B10A2_UNORM:
+        case DXGI_FORMAT_R16G16B16A16_UNORM:
+        case DXGI_FORMAT_YUY2:
+        case DXGI_FORMAT_AYUV:
+            if ( display->formatTexture == DXGI_FORMAT_NV12 ||
+                 display->formatTexture == DXGI_FORMAT_P010 )
             {
-                quad->cropViewport[1] = quad->cropViewport[2] =
-                quad->cropViewport[3] = quad->cropViewport[0];
+                quad->cropViewport[1][MONO_OR_LEFT_EYE].TopLeftX = rect->left / 2;
+                quad->cropViewport[1][MONO_OR_LEFT_EYE].TopLeftY = rect->top / 2;
+            }
+            break;
+        case DXGI_FORMAT_UNKNOWN:
+            switch ( quad->textureFormat->fourcc )
+            {
+            case VLC_CODEC_YUVA:
+                if ( display->formatTexture != DXGI_FORMAT_NV12 &&
+                     display->formatTexture != DXGI_FORMAT_P010 )
+                {
+                    quad->cropViewport[1][MONO_OR_LEFT_EYE] = quad->cropViewport[2][MONO_OR_LEFT_EYE] =
+                    quad->cropViewport[3][MONO_OR_LEFT_EYE] = quad->cropViewport[0][MONO_OR_LEFT_EYE];
+                    break;
+                }
+                /* fallthrough */
+            case VLC_CODEC_I420:
+                quad->cropViewport[1][MONO_OR_LEFT_EYE].TopLeftX = quad->cropViewport[0][MONO_OR_LEFT_EYE].TopLeftX / 2;
+                quad->cropViewport[1][MONO_OR_LEFT_EYE].TopLeftY = quad->cropViewport[0][MONO_OR_LEFT_EYE].TopLeftY / 2;
+                quad->cropViewport[2][MONO_OR_LEFT_EYE] = quad->cropViewport[1][MONO_OR_LEFT_EYE];
                 break;
             }
-            /* fallthrough */
-        case VLC_CODEC_I420:
-            quad->cropViewport[1].TopLeftX = quad->cropViewport[0].TopLeftX / 2;
-            quad->cropViewport[1].TopLeftY = quad->cropViewport[0].TopLeftY / 2;
-            quad->cropViewport[1].Width    = quad->cropViewport[0].Width / 2;
-            quad->cropViewport[1].Height   = quad->cropViewport[0].Height / 2;
-            quad->cropViewport[2] = quad->cropViewport[1];
             break;
+        default:
+            vlc_assert_unreachable();
+        }
+
+        if (display_mode == VIDEO_STEREO_OUTPUT_RIGHT_ONLY)
+        {
+            /* the right eye will be shown on the "left"(mono) eye */
+            if (quad->src_stereo != MULTIVIEW_2D)
+            {
+                if (quad->src_stereo == MULTIVIEW_STEREO_TB)
+                {
+                    quad->cropViewport[0][MONO_OR_LEFT_EYE].TopLeftY -= srcAreaHeight / 2;
+                }
+                else if (quad->src_stereo == MULTIVIEW_STEREO_SBS)
+                {
+                    quad->cropViewport[0][MONO_OR_LEFT_EYE].TopLeftX -= srcAreaWidth / 2;
+                }
+            }
+        }
+        else if (display_mode == VIDEO_STEREO_OUTPUT_SIDE_BY_SIDE)
+        {
+            quad->cropViewport[0][MONO_OR_LEFT_EYE].TopLeftX /= 2;
+            quad->cropViewport[0][MONO_OR_LEFT_EYE].Width    /= 2;
+            quad->cropViewport[0][RIGHT_EYE].Height   = quad->cropViewport[0][MONO_OR_LEFT_EYE].Height;
+
+            if (quad->src_stereo == MULTIVIEW_2D)
+            {
+                quad->cropViewport[0][RIGHT_EYE].Width    = quad->cropViewport[0][MONO_OR_LEFT_EYE].Width;
+                quad->cropViewport[0][RIGHT_EYE].TopLeftY = quad->cropViewport[0][MONO_OR_LEFT_EYE].TopLeftY;
+                quad->cropViewport[0][RIGHT_EYE].TopLeftX = quad->cropViewport[0][MONO_OR_LEFT_EYE].TopLeftX + srcAreaWidth / 2;
+            }
+            else if (quad->src_stereo == MULTIVIEW_STEREO_SBS)
+            {
+                quad->cropViewport[0][RIGHT_EYE].Width    = quad->cropViewport[0][MONO_OR_LEFT_EYE].Width / 2;
+                quad->cropViewport[0][RIGHT_EYE].TopLeftY = quad->cropViewport[0][MONO_OR_LEFT_EYE].TopLeftY;
+                quad->cropViewport[0][RIGHT_EYE].TopLeftX = quad->cropViewport[0][MONO_OR_LEFT_EYE].TopLeftX + srcAreaWidth / 2;
+            }
+            else if (quad->src_stereo == MULTIVIEW_STEREO_TB)
+            {
+                quad->cropViewport[0][RIGHT_EYE].Width    = quad->cropViewport[0][MONO_OR_LEFT_EYE].Width;
+                quad->cropViewport[0][RIGHT_EYE].TopLeftX = srcAreaWidth / 2;
+            }
+            else if (quad->src_stereo == MULTIVIEW_STEREO_FRAME)
+            {
+                quad->cropViewport[0][RIGHT_EYE].Width    = quad->cropViewport[0][MONO_OR_LEFT_EYE].Width;
+                quad->cropViewport[0][RIGHT_EYE].TopLeftY = quad->cropViewport[0][MONO_OR_LEFT_EYE].TopLeftY;
+                quad->cropViewport[0][RIGHT_EYE].TopLeftX = quad->cropViewport[0][MONO_OR_LEFT_EYE].TopLeftX + srcAreaWidth / 2;
+            }
+        }
+
+        quad->cropViewport[1][MONO_OR_LEFT_EYE].Width    = quad->cropViewport[0][MONO_OR_LEFT_EYE].Width / 2;
+        quad->cropViewport[1][MONO_OR_LEFT_EYE].Height   = quad->cropViewport[0][MONO_OR_LEFT_EYE].Height / 2;
+    }
+    else { /* VIDEO_STEREO_OUTPUT_STEREO */
+        quad->cropViewport[0][RIGHT_EYE].Width           = srcAreaWidth;
+        quad->cropViewport[0][RIGHT_EYE].Height          = srcAreaHeight;
+
+        //For stereoscopic side by side left-right format
+        if (quad->src_stereo == MULTIVIEW_2D)
+        {
+            quad->cropViewport[0][RIGHT_EYE].TopLeftX = quad->cropViewport[0][MONO_OR_LEFT_EYE].TopLeftX;
+            quad->cropViewport[0][RIGHT_EYE].TopLeftY = quad->cropViewport[0][MONO_OR_LEFT_EYE].TopLeftY;
+        }
+        else if (quad->src_stereo == MULTIVIEW_STEREO_SBS)
+        {
+            quad->cropViewport[0][RIGHT_EYE].TopLeftX =  quad->projection == PROJECTION_MODE_EQUIRECTANGULAR ?
+                        rect->left : rect->left - srcAreaWidth / 2;
+        }
+        //For stereoscopic side by side top-bottom format
+        else if (quad->src_stereo == MULTIVIEW_STEREO_TB)
+        {
+            quad->cropViewport[0][RIGHT_EYE].TopLeftX = rect->left;
+            if (quad->projection == PROJECTION_MODE_EQUIRECTANGULAR)
+                quad->cropViewport[0][RIGHT_EYE].TopLeftY = rect->top;
         }
-        break;
-    default:
-        vlc_assert_unreachable();
     }
 }
diff --git a/modules/video_output/win32/d3d11_quad.h b/modules/video_output/win32/d3d11_quad.h
index c39eb58307..5855a48868 100644
--- a/modules/video_output/win32/d3d11_quad.h
+++ b/modules/video_output/win32/d3d11_quad.h
@@ -23,6 +23,8 @@
 #ifndef VLC_D3D11_QUAD_H
 #define VLC_D3D11_QUAD_H
 
+#include <vlc_vout.h>
+
 #include "../../video_chroma/d3d11_fmt.h"
 #include "d3d11_shaders.h"
 
@@ -47,7 +49,8 @@ typedef struct d3d_vertex_t {
 
 void D3D11_RenderQuad(d3d11_device_t *, d3d_quad_t *, d3d_vshader_t *,
                       ID3D11ShaderResourceView *resourceViews[D3D11_MAX_SHADER_VIEW],
-                      ID3D11RenderTargetView *renderTarget[D3D11_MAX_SHADER_VIEW]);
+                      ID3D11RenderTargetView *renderTarget[D3D11_MAX_SHADER_VIEW][2],
+                      size_t eyeIndex, size_t targetEye);
 
 int D3D11_AllocateQuad(vlc_object_t *, d3d11_device_t *, video_projection_mode_t, d3d_quad_t *);
 #define D3D11_AllocateQuad(a,b,c,d)  D3D11_AllocateQuad(VLC_OBJECT(a),b,c,d)
@@ -56,14 +59,15 @@ void D3D11_ReleaseQuad(d3d_quad_t *);
 
 int D3D11_SetupQuad(vlc_object_t *, d3d11_device_t *, const video_format_t *, d3d_quad_t *,
                     const display_info_t *, const RECT *,
-                    video_orientation_t);
-#define D3D11_SetupQuad(a,b,c,d,e,f,g)  D3D11_SetupQuad(VLC_OBJECT(a),b,c,d,e,f,g)
+                    video_orientation_t, video_multiview_mode_t);
+#define D3D11_SetupQuad(a,b,c,d,e,f,g,h)  D3D11_SetupQuad(VLC_OBJECT(a),b,c,d,e,f,g,h)
 
 bool D3D11_UpdateQuadPosition( vlc_object_t *, d3d11_device_t *, d3d_quad_t *,
                                const RECT *output, video_orientation_t );
 #define D3D11_UpdateQuadPosition(a,b,c,d,e)  D3D11_UpdateQuadPosition(VLC_OBJECT(a),b,c,d,e)
 
-void D3D11_UpdateViewport(d3d_quad_t *, const RECT *, const d3d_format_t *display);
+void D3D11_UpdateViewport(d3d_quad_t *, const RECT *src, const d3d_format_t *display,
+                          vlc_stereoscopic_mode_t display_mode);
 
 void D3D11_UpdateQuadOpacity(vlc_object_t *, d3d11_device_t *, d3d_quad_t *, float opacity);
 #define D3D11_UpdateQuadOpacity(a,b,c,d)  D3D11_UpdateQuadOpacity(VLC_OBJECT(a),b,c,d)
diff --git a/modules/video_output/win32/d3d11_shaders.c b/modules/video_output/win32/d3d11_shaders.c
index e54dcfca9e..c39c360d42 100644
--- a/modules/video_output/win32/d3d11_shaders.c
+++ b/modules/video_output/win32/d3d11_shaders.c
@@ -658,22 +658,32 @@ float GetFormatLuminance(vlc_object_t *o, const video_format_t *fmt)
 }
 
 HRESULT D3D11_CreateRenderTargets( d3d11_device_t *d3d_dev, ID3D11Resource *texture,
-                                   const d3d_format_t *cfg, ID3D11RenderTargetView *output[D3D11_MAX_SHADER_VIEW] )
+                                   const d3d_format_t *cfg, bool both_eyes,
+                                   ID3D11RenderTargetView *output[D3D11_MAX_SHADER_VIEW][2] )
 {
-    D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;
-    renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
-    renderTargetViewDesc.Texture2D.MipSlice = 0;
+    D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc = { 0 };
+    if (both_eyes)
+    {
+        renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
+        renderTargetViewDesc.Texture2DArray.ArraySize = 1;
+    }
+    else
+        renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
 
     for (size_t i=0; i<D3D11_MAX_SHADER_VIEW; i++)
     {
         if (cfg->resourceFormat[i])
         {
             renderTargetViewDesc.Format = cfg->resourceFormat[i];
-            HRESULT hr = ID3D11Device_CreateRenderTargetView(d3d_dev->d3ddevice, texture,
-                                                             &renderTargetViewDesc, &output[i]);
-            if (FAILED(hr))
+            for (size_t eye=0; eye < (both_eyes ? 2 : 1); eye++)
             {
-                return hr;
+                renderTargetViewDesc.Texture2DArray.FirstArraySlice = eye;
+                HRESULT hr = ID3D11Device_CreateRenderTargetView(d3d_dev->d3ddevice, texture,
+                                                                 &renderTargetViewDesc, &output[i][eye]);
+                if (FAILED(hr))
+                {
+                    return hr;
+                }
             }
         }
     }
@@ -681,7 +691,8 @@ HRESULT D3D11_CreateRenderTargets( d3d11_device_t *d3d_dev, ID3D11Resource *text
 }
 
 void D3D11_ClearRenderTargets(d3d11_device_t *d3d_dev, const d3d_format_t *cfg,
-                              ID3D11RenderTargetView *targets[D3D11_MAX_SHADER_VIEW])
+                              ID3D11RenderTargetView *targets[D3D11_MAX_SHADER_VIEW][2],
+                              int clear_eye)
 {
     static const FLOAT blackY[1] = {0.0f};
     static const FLOAT blackUV[2] = {0.5f, 0.5f};
@@ -689,28 +700,41 @@ void D3D11_ClearRenderTargets(d3d11_device_t *d3d_dev, const d3d_format_t *cfg,
     static const FLOAT blackYUY2[4] = {0.0f, 0.5f, 0.0f, 0.5f};
     static const FLOAT blackVUYA[4] = {0.5f, 0.5f, 0.0f, 1.0f};
 
-    switch (cfg->formatTexture)
+    for (size_t eye=0; eye < 2;eye++)
     {
-    case DXGI_FORMAT_NV12:
-    case DXGI_FORMAT_P010:
-        ID3D11DeviceContext_ClearRenderTargetView( d3d_dev->d3dcontext, targets[0], blackY);
-        ID3D11DeviceContext_ClearRenderTargetView( d3d_dev->d3dcontext, targets[1], blackUV);
-        break;
-    case DXGI_FORMAT_R8G8B8A8_UNORM:
-    case DXGI_FORMAT_B8G8R8A8_UNORM:
-    case DXGI_FORMAT_B8G8R8X8_UNORM:
-    case DXGI_FORMAT_R10G10B10A2_UNORM:
-    case DXGI_FORMAT_B5G6R5_UNORM:
-        ID3D11DeviceContext_ClearRenderTargetView( d3d_dev->d3dcontext, targets[0], blackRGBA);
-        break;
-    case DXGI_FORMAT_YUY2:
-        ID3D11DeviceContext_ClearRenderTargetView( d3d_dev->d3dcontext, targets[0], blackYUY2);
-        break;
-    case DXGI_FORMAT_AYUV:
-        ID3D11DeviceContext_ClearRenderTargetView( d3d_dev->d3dcontext, targets[0], blackVUYA);
-        break;
-    default:
-        vlc_assert_unreachable();
+        if (!(clear_eye & D3D11_SHOW_EYE_LEFT) && eye == MONO_OR_LEFT_EYE)
+            continue;
+        if (!(clear_eye & D3D11_SHOW_EYE_RIGHT) && eye == RIGHT_EYE)
+            continue;
+
+        switch (cfg->formatTexture)
+        {
+        case DXGI_FORMAT_NV12:
+        case DXGI_FORMAT_P010:
+            if (targets[0][eye])
+                ID3D11DeviceContext_ClearRenderTargetView( d3d_dev->d3dcontext, targets[0][eye], blackY);
+            if (targets[1][eye])
+                ID3D11DeviceContext_ClearRenderTargetView( d3d_dev->d3dcontext, targets[1][eye], blackUV);
+            break;
+        case DXGI_FORMAT_R8G8B8A8_UNORM:
+        case DXGI_FORMAT_B8G8R8A8_UNORM:
+        case DXGI_FORMAT_B8G8R8X8_UNORM:
+        case DXGI_FORMAT_R10G10B10A2_UNORM:
+        case DXGI_FORMAT_B5G6R5_UNORM:
+            if (targets[0][eye])
+                ID3D11DeviceContext_ClearRenderTargetView( d3d_dev->d3dcontext, targets[0][eye], blackRGBA);
+            break;
+        case DXGI_FORMAT_YUY2:
+            if (targets[0][eye])
+                ID3D11DeviceContext_ClearRenderTargetView( d3d_dev->d3dcontext, targets[0][eye], blackYUY2);
+            break;
+        case DXGI_FORMAT_AYUV:
+            if (targets[0][eye])
+                ID3D11DeviceContext_ClearRenderTargetView( d3d_dev->d3dcontext, targets[0][eye], blackVUYA);
+            break;
+        default:
+            vlc_assert_unreachable();
+        }
     }
 }
 
diff --git a/modules/video_output/win32/d3d11_shaders.h b/modules/video_output/win32/d3d11_shaders.h
index 2f87bafd4a..e014f06171 100644
--- a/modules/video_output/win32/d3d11_shaders.h
+++ b/modules/video_output/win32/d3d11_shaders.h
@@ -26,6 +26,9 @@
 #include "../../video_chroma/d3d11_fmt.h"
 #include <dxgi1_4.h>
 
+#define MONO_OR_LEFT_EYE 0
+#define RIGHT_EYE 1
+
 #define DEFAULT_BRIGHTNESS         100
 #define DEFAULT_SRGB_BRIGHTNESS    100
 #define MAX_PQ_BRIGHTNESS        10000
@@ -97,10 +100,11 @@ typedef struct
     UINT                       PSConstantsCount;
     ID3D11PixelShader         *d3dpixelShader[D3D11_MAX_SHADER_VIEW];
     ID3D11SamplerState        *d3dsampState[2];
-    D3D11_VIEWPORT            cropViewport[D3D11_MAX_SHADER_VIEW];
+    D3D11_VIEWPORT            cropViewport[D3D11_MAX_SHADER_VIEW][2];
     unsigned int              i_width;
     unsigned int              i_height;
     video_projection_mode_t   projection;
+    video_multiview_mode_t    src_stereo;
 
     PS_CONSTANT_BUFFER        shaderConstants;
 } d3d_quad_t;
@@ -129,10 +133,16 @@ float GetFormatLuminance(vlc_object_t *, const video_format_t *);
 #define GetFormatLuminance(a,b)  GetFormatLuminance(VLC_OBJECT(a),b)
 
 HRESULT D3D11_CreateRenderTargets(d3d11_device_t *, ID3D11Resource *, const d3d_format_t *,
-                                  ID3D11RenderTargetView *output[D3D11_MAX_SHADER_VIEW]);
+                                  bool both_eyes,
+                                  ID3D11RenderTargetView *output[D3D11_MAX_SHADER_VIEW][2]);
+
+#define D3D11_SHOW_EYE_LEFT   1
+#define D3D11_SHOW_EYE_RIGHT  2
+#define D3D11_SHOW_EYE_BOTH  (D3D11_SHOW_EYE_LEFT|D3D11_SHOW_EYE_RIGHT)
 
 void D3D11_ClearRenderTargets(d3d11_device_t *, const d3d_format_t *,
-                              ID3D11RenderTargetView *targets[D3D11_MAX_SHADER_VIEW]);
+                              ID3D11RenderTargetView *targets[D3D11_MAX_SHADER_VIEW][2],
+                              int eyes);
 
 void D3D11_SetVertexShader(d3d_vshader_t *dst, d3d_vshader_t *src);
 void D3D11_ReleaseVertexShader(d3d_vshader_t *);
diff --git a/modules/video_output/win32/direct3d11.c b/modules/video_output/win32/direct3d11.c
index ae8f4449a9..4ded9279d1 100644
--- a/modules/video_output/win32/direct3d11.c
+++ b/modules/video_output/win32/direct3d11.c
@@ -102,7 +102,7 @@ struct vout_display_sys_t
 
     picture_sys_t            stagingSys;
 
-    ID3D11RenderTargetView   *swapchainTargetView[D3D11_MAX_SHADER_VIEW];
+    ID3D11RenderTargetView   *swapchainTargetView[D3D11_MAX_SHADER_VIEW][2];
 
     d3d_vshader_t            projectionVShader;
     d3d_vshader_t            flatVShader;
@@ -111,6 +111,11 @@ struct vout_display_sys_t
      * Uses a Texture2D with slices rather than a Texture2DArray for the decoder */
     bool                     legacy_shader;
 
+    /* Stereo info */
+    bool                     device_3d_capable;
+    vlc_stereoscopic_mode_t  stereo_mode; /* actual mode, not auto */
+    picture_t                *stereo_pic;
+
     // SPU
     vlc_fourcc_t             pSubpictureChromas[2];
     d3d_quad_t               regionQuad;
@@ -298,6 +303,8 @@ static int Open(vlc_object_t *object)
 
     vd->info.has_double_click     = true;
     vd->info.has_pictures_invalid = vd->info.is_slow;
+    vd->info.stereo_modes = (1 << MULTIVIEW_2D) | (1 << MULTIVIEW_STEREO_FRAME) |
+                            (1 << MULTIVIEW_STEREO_SBS) | (1 << MULTIVIEW_STEREO_TB);
 
     if (var_InheritBool(vd, "direct3d11-hw-blending") &&
         vd->sys->regionQuad.textureFormat != NULL)
@@ -360,7 +367,7 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
     }
 
     if (D3D11_SetupQuad( vd, &sys->d3d_dev, &surface_fmt, &sys->picQuad, &sys->display, &sys->sys.rect_src_clipped,
-                   vd->fmt.orientation ) != VLC_SUCCESS) {
+                   vd->fmt.orientation, vd->fmt.multiview_mode ) != VLC_SUCCESS) {
         msg_Err(vd, "Could not Create the main quad picture.");
         return NULL;
     }
@@ -485,7 +492,8 @@ static void DestroyDisplayPoolPicture(picture_t *picture)
 static void FillSwapChainDesc(vout_display_t *vd, DXGI_SWAP_CHAIN_DESC1 *out)
 {
     ZeroMemory(out, sizeof(*out));
-    out->BufferCount = 3;
+    out->Stereo = vd->sys->stereo_mode == VIDEO_STEREO_OUTPUT_STEREO;
+    out->BufferCount = out->Stereo ? 2 : 3;
     out->BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
     out->SampleDesc.Count = 1;
     out->SampleDesc.Quality = 0;
@@ -495,6 +503,63 @@ static void FillSwapChainDesc(vout_display_t *vd, DXGI_SWAP_CHAIN_DESC1 *out)
     //out->Flags = 512; // DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO;
     out->SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
 }
+
+static int UpdateSwapChain(vout_display_t *vd)
+{
+    vout_display_sys_t *sys = vd->sys;
+    DXGI_SWAP_CHAIN_DESC1 scd;
+    IDXGIFactory2 *dxgifactory;
+    HRESULT hr = S_OK;
+
+    IDXGIAdapter *dxgiadapter = D3D11DeviceAdapter(sys->d3d_dev.d3ddevice);
+    if (FAILED(hr)) {
+       msg_Err(vd, "Could not get the DXGI Adapter");
+       return VLC_EGENERIC;
+    }
+
+    hr = IDXGIAdapter_GetParent(dxgiadapter, &IID_IDXGIFactory2, (void **)&dxgifactory);
+    IDXGIAdapter_Release(dxgiadapter);
+    if (FAILED(hr)) {
+       msg_Err(vd, "Could not get the DXGI Factory. (hr=0x%lX)", hr);
+       return VLC_EGENERIC;
+    }
+
+    //Release references to recreate the swapchain
+    if (sys->d3d_dev.d3dcontext)
+    {
+        ID3D11DeviceContext_Flush(sys->d3d_dev.d3dcontext);
+    }
+    if (sys->dxgiswapChain4)
+    {
+        IDXGISwapChain4_Release(sys->dxgiswapChain4);
+        sys->dxgiswapChain4 = NULL;
+    }
+    if (sys->dxgiswapChain)
+    {
+        IDXGISwapChain_Release(sys->dxgiswapChain);
+        sys->dxgiswapChain = NULL;
+    }
+    if (sys->swapchainTargetView[0][MONO_OR_LEFT_EYE])
+    {
+        ID3D11RenderTargetView_Release(sys->swapchainTargetView[0][MONO_OR_LEFT_EYE]);
+        sys->swapchainTargetView[0][MONO_OR_LEFT_EYE] = NULL;
+    }
+    if (sys->swapchainTargetView[0][RIGHT_EYE])
+    {
+        ID3D11RenderTargetView_Release(sys->swapchainTargetView[0][RIGHT_EYE]);
+        sys->swapchainTargetView[0][RIGHT_EYE] = NULL;
+    }
+
+    FillSwapChainDesc(vd, &scd);
+    hr = IDXGIFactory2_CreateSwapChainForHwnd(dxgifactory, (IUnknown *)sys->d3d_dev.d3ddevice,
+                                 sys->sys.hvideownd, &scd, NULL, NULL, &sys->dxgiswapChain);
+    IDXGIFactory2_Release(dxgifactory);
+    if (FAILED(hr)) {
+       msg_Err(vd, "Could not recreate the %s SwapChain. (hr=0x%lX)", sys->stereo_mode == VIDEO_STEREO_OUTPUT_STEREO ? "stereo ":"", hr);
+       return VLC_EGENERIC;
+    }
+    return VLC_SUCCESS;
+}
 #endif
 
 static HRESULT UpdateBackBuffer(vout_display_t *vd)
@@ -511,9 +576,9 @@ static HRESULT UpdateBackBuffer(vout_display_t *vd)
     uint32_t i_height = RECTHeight(rect);
     D3D11_TEXTURE2D_DESC dsc = { 0 };
 
-    if (sys->swapchainTargetView[0]) {
+    if (sys->swapchainTargetView[0][MONO_OR_LEFT_EYE]) {
         ID3D11Resource *res = NULL;
-        ID3D11RenderTargetView_GetResource(sys->swapchainTargetView[0], &res);
+        ID3D11RenderTargetView_GetResource(sys->swapchainTargetView[0][MONO_OR_LEFT_EYE], &res);
         if (res)
         {
             ID3D11Texture2D_GetDesc((ID3D11Texture2D*) res, &dsc);
@@ -526,15 +591,18 @@ static HRESULT UpdateBackBuffer(vout_display_t *vd)
 
     for (size_t i=0; i < D3D11_MAX_SHADER_VIEW; i++)
     {
-        if (sys->swapchainTargetView[i]) {
-            ID3D11RenderTargetView_Release(sys->swapchainTargetView[i]);
-            sys->swapchainTargetView[i] = NULL;
+        for (size_t eye=0; eye<2; eye++)
+        {
+            if (sys->swapchainTargetView[i][eye]) {
+                ID3D11RenderTargetView_Release(sys->swapchainTargetView[i][eye]);
+                sys->swapchainTargetView[i][eye] = NULL;
+            }
         }
     }
 
     /* TODO detect is the size is the same as the output and switch to fullscreen mode */
-    hr = IDXGISwapChain_ResizeBuffers(sys->dxgiswapChain, 0, i_width, i_height,
-        DXGI_FORMAT_UNKNOWN, 0);
+    hr = IDXGISwapChain_ResizeBuffers(sys->dxgiswapChain, sys->stereo_mode == VIDEO_STEREO_OUTPUT_STEREO ? 4 : 0,
+                                      i_width, i_height, DXGI_FORMAT_UNKNOWN, 0);
     if (FAILED(hr)) {
        msg_Err(vd, "Failed to resize the backbuffer. (hr=0x%lX)", hr);
        return hr;
@@ -547,18 +615,53 @@ static HRESULT UpdateBackBuffer(vout_display_t *vd)
     }
 
     hr = D3D11_CreateRenderTargets( &sys->d3d_dev, (ID3D11Resource *)pBackBuffer,
-                                    sys->display.pixelFormat, sys->swapchainTargetView );
+                                    sys->display.pixelFormat, sys->stereo_mode == VIDEO_STEREO_OUTPUT_STEREO,
+                                    sys->swapchainTargetView );
     ID3D11Texture2D_Release(pBackBuffer);
     if (FAILED(hr)) {
         msg_Err(vd, "Failed to create the target view. (hr=0x%lX)", hr);
         return hr;
     }
 
-    D3D11_ClearRenderTargets( &sys->d3d_dev, sys->display.pixelFormat, sys->swapchainTargetView );
+    D3D11_ClearRenderTargets( &sys->d3d_dev, sys->display.pixelFormat, sys->swapchainTargetView, D3D11_SHOW_EYE_BOTH );
 
     return S_OK;
 }
 
+#if !VLC_WINSTORE_APP
+static int ChangeStereoSwapChain(vout_display_t *vd, vlc_stereoscopic_mode_t new_mode)
+{
+    vout_display_sys_t *sys = vd->sys;
+    if (sys->stereo_mode == new_mode)
+        return VLC_SUCCESS;
+
+    if (new_mode == VIDEO_STEREO_OUTPUT_STEREO && !sys->device_3d_capable)
+    {
+        sys->stereo_mode = VIDEO_STEREO_OUTPUT_LEFT_ONLY;
+        UpdatePicQuadPosition(vd);
+        return VLC_EGENERIC;
+    }
+
+    vlc_stereoscopic_mode_t old_mode = sys->stereo_mode;
+    sys->stereo_mode = new_mode;
+    int res = UpdateSwapChain(vd);
+    if (res == VLC_SUCCESS)
+    {
+        UpdateBackBuffer(vd);
+    }
+
+    if (res != VLC_SUCCESS)
+    {
+        if (new_mode == VIDEO_STEREO_OUTPUT_STEREO)
+            sys->device_3d_capable = false;
+        sys->stereo_mode = new_mode = old_mode;
+        UpdateSwapChain(vd);
+    }
+    UpdatePicQuadPosition(vd);
+    return res;
+}
+#endif /* VLC_WINSTORE_APP */
+
 /* rotation around the Z axis */
 static void getZRotMatrix(float theta, FLOAT matrix[static 16])
 {
@@ -726,6 +829,20 @@ static void UpdateSize(vout_display_t *vd)
     d3d11_device_unlock( &sys->d3d_dev );
 }
 
+static vlc_stereoscopic_mode_t GetStereoMode(vout_display_t *vd, vlc_stereoscopic_mode_t stereo_output, video_multiview_mode_t src_mode)
+{
+    vout_display_sys_t *sys = vd->sys;
+    if (stereo_output == VIDEO_STEREO_OUTPUT_AUTO)
+    {
+        /* decide which mode we're going with */
+        if (sys->device_3d_capable && src_mode != MULTIVIEW_2D)
+            stereo_output = VIDEO_STEREO_OUTPUT_STEREO;
+        else
+            stereo_output = VIDEO_STEREO_OUTPUT_LEFT_ONLY;
+    }
+    return stereo_output;
+}
+
 static inline bool RectEquals(const RECT *r1, const RECT *r2)
 {
     return r1->bottom == r2->bottom && r1->top == r2->top &&
@@ -750,6 +867,15 @@ static int Control(vout_display_t *vd, int query, va_list args)
             res = VLC_SUCCESS;
         }
     }
+#if !VLC_WINSTORE_APP
+    else if (query == VOUT_DISPLAY_CHANGE_STEREO_MODE)
+    {
+        const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t*);
+        vlc_stereoscopic_mode_t new_mode = GetStereoMode(vd, cfg->stereo_mode, vd->source.multiview_mode);
+        /* reset the swapchain to 2D/3D accordingly */
+        res = ChangeStereoSwapChain(vd, new_mode);
+    }
+#endif
 
     if (!RectEquals(&before_src_clipped,  &sys->sys.rect_src_clipped) ||
         !RectEquals(&before_dest_clipped, &sys->sys.rect_dest_clipped) ||
@@ -779,15 +905,36 @@ static void Manage(vout_display_t *vd)
 }
 
 static void DisplayPicture(vout_display_sys_t *sys, d3d_quad_t *quad, d3d_vshader_t *vs_shader,
-                           ID3D11ShaderResourceView *renderSrc[D3D11_MAX_SHADER_VIEW])
+                           ID3D11ShaderResourceView *renderSrc[D3D11_MAX_SHADER_VIEW],
+                           int showEyes)
 {
-    D3D11_RenderQuad(&sys->d3d_dev, quad, vs_shader, renderSrc, sys->swapchainTargetView);
+    if (showEyes & D3D11_SHOW_EYE_LEFT)
+        D3D11_RenderQuad(&sys->d3d_dev, quad, vs_shader, renderSrc, sys->swapchainTargetView, MONO_OR_LEFT_EYE, MONO_OR_LEFT_EYE);
+    if (showEyes & D3D11_SHOW_EYE_RIGHT)
+        D3D11_RenderQuad(&sys->d3d_dev, quad, vs_shader, renderSrc, sys->swapchainTargetView, RIGHT_EYE,
+                         sys->stereo_mode == VIDEO_STEREO_OUTPUT_STEREO ? RIGHT_EYE : MONO_OR_LEFT_EYE);
 }
 
 static void PreparePicture(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
 {
     vout_display_sys_t *sys = vd->sys;
 
+    if (sys->picQuad.src_stereo != picture->format.multiview_mode)
+    {
+        D3D11_SetupQuad( vd, &sys->d3d_dev, &picture->format, &sys->picQuad, &sys->display,
+                         &sys->sys.rect_src_clipped, vd->fmt.orientation, picture->format.multiview_mode );
+#if !VLC_WINSTORE_APP
+        vlc_stereoscopic_mode_t new_mode = GetStereoMode(vd, vd->cfg->stereo_mode, picture->format.multiview_mode);
+        if (sys->stereo_mode != new_mode)
+        {
+            /* stereo mode changed */
+            ChangeStereoSwapChain(vd, new_mode);
+        }
+        else
+#endif
+        UpdatePicQuadPosition(vd);
+    }
+
     if (sys->picQuad.textureFormat->formatTexture == DXGI_FORMAT_UNKNOWN)
     {
         D3D11_MAPPED_SUBRESOURCE mappedResource;
@@ -884,6 +1031,19 @@ static void PreparePicture(vout_display_t *vd, picture_t *picture, subpicture_t
         sys->d3dregions      = subpicture_regions;
     }
 
+    int showEyes;
+    if (sys->stereo_mode == VIDEO_STEREO_OUTPUT_LEFT_ONLY || sys->stereo_mode == VIDEO_STEREO_OUTPUT_RIGHT_ONLY)
+        showEyes = D3D11_SHOW_EYE_LEFT;
+    else if (sys->picQuad.src_stereo == MULTIVIEW_STEREO_FRAME)
+    {
+        if (picture->format.b_multiview_left_eye)
+            showEyes = D3D11_SHOW_EYE_LEFT;
+        else
+            showEyes = D3D11_SHOW_EYE_RIGHT;
+    }
+    else
+        showEyes = D3D11_SHOW_EYE_BOTH;
+
     if (picture->format.mastering.max_luminance)
     {
         D3D11_UpdateQuadLuminanceScale(vd, &sys->d3d_dev, &sys->picQuad, GetFormatLuminance(VLC_OBJECT(vd), &picture->format) / (float)sys->display.luminance_peak);
@@ -917,7 +1077,7 @@ static void PreparePicture(vout_display_t *vd, picture_t *picture, subpicture_t
     }
     DisplayPicture(sys, &sys->picQuad,
                    vd->fmt.projection_mode == PROJECTION_MODE_RECTANGULAR ? &sys->flatVShader : &sys->projectionVShader,
-                   renderSrc);
+                   renderSrc, showEyes);
 
     if (subpicture) {
         // draw the additional vertices
@@ -925,7 +1085,7 @@ static void PreparePicture(vout_display_t *vd, picture_t *picture, subpicture_t
             if (sys->d3dregions[i])
             {
                 d3d_quad_t *quad = (d3d_quad_t *) sys->d3dregions[i]->p_sys;
-                DisplayPicture(sys, quad, &sys->flatVShader, quad->picSys.renderSrc);
+                DisplayPicture(sys, quad, &sys->flatVShader, quad->picSys.renderSrc, showEyes);
             }
         }
     }
@@ -941,11 +1101,33 @@ static void Prepare(vout_display_t *vd, picture_t *picture,
 {
     vout_display_sys_t *sys = vd->sys;
 
+    /* keep the first of a stereo sequence for later */
+    /* TODO move this to the core so it's kept during a pause */
+    if (sys->picQuad.src_stereo == MULTIVIEW_STEREO_FRAME)
+    {
+        if (picture->format.b_multiview_right_eye_first == !picture->format.b_multiview_left_eye)
+        {
+            /* first picture in the sequence, wait for the next one */
+            if (sys->stereo_pic)
+                picture_Release(sys->stereo_pic);
+            sys->stereo_pic = picture;
+            return;
+        }
+    }
+
     Manage(vd);
     VLC_UNUSED(date);
 
-    D3D11_ClearRenderTargets( &sys->d3d_dev, sys->display.pixelFormat, sys->swapchainTargetView );
+    int cleanEyes;
+    if (sys->stereo_mode == VIDEO_STEREO_OUTPUT_STEREO)
+        cleanEyes = D3D11_SHOW_EYE_BOTH;
+    else
+        cleanEyes = D3D11_SHOW_EYE_LEFT;
 
+    D3D11_ClearRenderTargets( &sys->d3d_dev, sys->display.pixelFormat, sys->swapchainTargetView, cleanEyes );
+
+    if (sys->stereo_pic)
+        PreparePicture(vd, sys->stereo_pic, subpicture);
     PreparePicture(vd, picture, subpicture);
 }
 
@@ -953,6 +1135,17 @@ static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
 {
     vout_display_sys_t *sys = vd->sys;
 
+    if (sys->picQuad.src_stereo == MULTIVIEW_STEREO_FRAME)
+    {
+        if (picture->format.b_multiview_right_eye_first == !picture->format.b_multiview_left_eye)
+        {
+            if (subpicture)
+                subpicture_Delete(subpicture);
+            /* wait for the next picture to display anything */
+            return;
+        }
+    }
+
     DXGI_PRESENT_PARAMETERS presentParams;
     memset(&presentParams, 0, sizeof(presentParams));
     d3d11_device_lock( &sys->d3d_dev );
@@ -1217,6 +1410,16 @@ static int Direct3D11Open(vout_display_t *vd)
         return VLC_EGENERIC;
     }
 
+    //Disable 3D if not supported by the system
+    sys->device_3d_capable = sys->d3d_dev.feature_level >= D3D_FEATURE_LEVEL_10_0 /*&&
+                             IDXGIFactory2_IsWindowedStereoEnabled(dxgifactory)*/;
+
+    if (vd->source.multiview_mode != MULTIVIEW_2D && !sys->device_3d_capable)
+    {
+        msg_Dbg(vd, "Could not create the D3D11 device for Stereoscopic 3D. 3D won't work.");
+    }
+    sys->stereo_mode = GetStereoMode(vd, vd->cfg->stereo_mode, vd->source.multiview_mode);
+
     FillSwapChainDesc(vd, &scd);
 
     hr = IDXGIFactory2_CreateSwapChainForHwnd(dxgifactory, (IUnknown *)sys->d3d_dev.d3ddevice,
@@ -1233,6 +1436,9 @@ static int Direct3D11Open(vout_display_t *vd)
        msg_Err(vd, "Could not create the SwapChain. (hr=0x%lX)", hr);
        return VLC_EGENERIC;
     }
+#else
+    // We can't switch to 3D on UWP
+    sys->device_3d_capable = false;
 #endif
 
     IDXGISwapChain_QueryInterface( sys->dxgiswapChain, &IID_IDXGISwapChain4, (void **)&sys->dxgiswapChain4);
@@ -1354,6 +1560,12 @@ static void Direct3D11Close(vout_display_t *vd)
 {
     vout_display_sys_t *sys = vd->sys;
 
+    if (sys->stereo_pic)
+    {
+        picture_Release(sys->stereo_pic);
+        sys->stereo_pic = NULL;
+    }
+
     Direct3D11DestroyResources(vd);
     if (sys->dxgiswapChain4)
     {
@@ -1375,14 +1587,15 @@ static void UpdatePicQuadPosition(vout_display_t *vd)
 {
     vout_display_sys_t *sys = vd->sys;
 
-    D3D11_UpdateViewport( &sys->picQuad, &sys->sys.rect_dest_clipped, sys->display.pixelFormat );
+    D3D11_UpdateViewport( &sys->picQuad, &sys->sys.rect_dest_clipped, sys->display.pixelFormat,
+                          sys->stereo_mode );
 
     SetQuadVSProjection(vd, &sys->picQuad, &vd->cfg->viewpoint);
 
 #ifndef NDEBUG
     msg_Dbg( vd, "picQuad position (%.02f,%.02f) %.02fx%.02f",
-             sys->picQuad.cropViewport[0].TopLeftX, sys->picQuad.cropViewport[0].TopLeftY,
-             sys->picQuad.cropViewport[0].Width, sys->picQuad.cropViewport[0].Height );
+             sys->picQuad.cropViewport[0][MONO_OR_LEFT_EYE].TopLeftX, sys->picQuad.cropViewport[0][MONO_OR_LEFT_EYE].TopLeftY,
+             sys->picQuad.cropViewport[0][MONO_OR_LEFT_EYE].Width, sys->picQuad.cropViewport[0][MONO_OR_LEFT_EYE].Height );
 #endif
 }
 
@@ -1578,9 +1791,12 @@ static void Direct3D11DestroyResources(vout_display_t *vd)
     D3D11_ReleasePixelShader(&sys->regionQuad);
     for (size_t i=0; i < D3D11_MAX_SHADER_VIEW; i++)
     {
-        if (sys->swapchainTargetView[i]) {
-            ID3D11RenderTargetView_Release(sys->swapchainTargetView[i]);
-            sys->swapchainTargetView[i] = NULL;
+        for (size_t eye=0; eye<2; eye++)
+        {
+            if (sys->swapchainTargetView[i][eye]) {
+                ID3D11RenderTargetView_Release(sys->swapchainTargetView[i][eye]);
+                sys->swapchainTargetView[i][eye] = NULL;
+            }
         }
     }
 
@@ -1687,7 +1903,7 @@ static int Direct3D11MapSubpicture(vout_display_t *vd, int *subpicture_region_co
             }
 
             err = D3D11_SetupQuad( vd, &sys->d3d_dev, &r->fmt, d3dquad, &sys->display, &output,
-                                   ORIENT_NORMAL );
+                                   ORIENT_NORMAL, MULTIVIEW_2D );
             if (err != VLC_SUCCESS) {
                 msg_Err(vd, "Failed to setup %dx%d quad for OSD",
                         r->fmt.i_visible_width, r->fmt.i_visible_height);
@@ -1750,7 +1966,8 @@ static int Direct3D11MapSubpicture(vout_display_t *vd, int *subpicture_region_co
         spuViewport.right  = sys->sys.rect_dest.left + (FLOAT) (r->i_x + r->fmt.i_visible_width)  * RECTWidth(sys->sys.rect_dest)  / subpicture->i_original_picture_width;
         spuViewport.bottom = sys->sys.rect_dest.top  + (FLOAT) (r->i_y + r->fmt.i_visible_height) * RECTHeight(sys->sys.rect_dest) / subpicture->i_original_picture_height;
 
-        D3D11_UpdateViewport( quad, &spuViewport, sys->display.pixelFormat );
+        D3D11_UpdateViewport( quad, &spuViewport, sys->display.pixelFormat,
+                              sys->stereo_mode );
 
         D3D11_UpdateQuadOpacity(vd, &sys->d3d_dev, quad, r->i_alpha / 255.0f );
     }
-- 
2.17.0




More information about the vlc-devel mailing list