[vlc-devel] [PATCH 26/29] direct3d11: use a Texture2DArray in the pixel shader

Steve Lhomme robux4 at videolabs.io
Thu Jan 19 11:11:01 CET 2017


So that it can receive a view from a texture with multiple slices, like the
ones needed by d3d11va.

With this change we move from D3D9.1 compatibility to D3D10. Which is fine as
we only want D3D11 on Windows 7 and above. If the device cannot compile a
pixel shader with Texture2DArray, we fall back to Texture2D with a copy of
the texture when displaying.

Add an advanced parameter to use 0-copy with hardware decoding as some AMD
hardware have issues using Texture2DArray in the pixel shader but allow it
anyway.
---
 modules/video_output/win32/common.h     |   1 +
 modules/video_output/win32/direct3d11.c | 101 ++++++++++++++++++++++++--------
 2 files changed, 79 insertions(+), 23 deletions(-)

diff --git a/modules/video_output/win32/common.h b/modules/video_output/win32/common.h
index 9fca8eb..9ae2487 100644
--- a/modules/video_output/win32/common.h
+++ b/modules/video_output/win32/common.h
@@ -192,6 +192,7 @@ struct vout_display_sys_t
     IDXGISwapChain1          *dxgiswapChain;   /* DXGI 1.1 swap chain */
     ID3D11Device             *d3ddevice;       /* D3D device */
     ID3D11DeviceContext      *d3dcontext;      /* D3D context */
+    bool                     legacy_shader;
     d3d_quad_t               picQuad;
     const d3d_format_t       *picQuadConfig;
 
diff --git a/modules/video_output/win32/direct3d11.c b/modules/video_output/win32/direct3d11.c
index 4b466e2..9310445 100644
--- a/modules/video_output/win32/direct3d11.c
+++ b/modules/video_output/win32/direct3d11.c
@@ -62,6 +62,9 @@ static void Close(vlc_object_t *);
 #define HW_BLENDING_TEXT N_("Use hardware blending support")
 #define HW_BLENDING_LONGTEXT N_(\
     "Try to use hardware acceleration for subtitle/OSD blending.")
+#define HW_0COPY_TEXT N_("Use 0-copy with hardware decoder")
+#define HW_0COPY_LONGTEXT N_(\
+    "Use one less copy per frame displayed, may not work on all hardware.")
 
 vlc_module_begin ()
     set_shortname("Direct3D11")
@@ -71,6 +74,7 @@ vlc_module_begin ()
     set_subcategory(SUBCAT_VIDEO_VOUT)
 
     add_bool("direct3d11-hw-blending", true, HW_BLENDING_TEXT, HW_BLENDING_LONGTEXT, true)
+    add_bool("direct3d11-direct-hw", true, HW_0COPY_TEXT, HW_0COPY_LONGTEXT, true)
 
 #if VLC_WINSTORE_APP
     add_integer("winrt-d3dcontext",    0x0, NULL, NULL, true); /* ID3D11DeviceContext* */
@@ -230,7 +234,7 @@ static const char* globPixelShaderDefault = "\
     float whitePadding;\
     float4x4 Colorspace;\
   };\
-  Texture2D shaderTexture;\
+  Texture2D%s shaderTexture;\
   SamplerState SampleType;\
   \
   struct PS_INPUT\
@@ -267,8 +271,8 @@ static const char *globPixelShaderBiplanarYUV_2RGB = "\
     float whitePadding;\
     float4x4 Colorspace;\
   };\
-  Texture2D shaderTextureY;\
-  Texture2D shaderTextureUV;\
+  Texture2D%s shaderTextureY;\
+  Texture2D%s shaderTextureUV;\
   SamplerState SampleType;\
   \
   struct PS_INPUT\
@@ -306,7 +310,7 @@ static const char *globPixelShaderBiplanarYUYV_2RGB = "\
     float whitePadding;\
     float4x4 Colorspace;\
   };\
-  Texture2D shaderTextureYUYV;\
+  Texture2D%s shaderTextureYUYV;\
   SamplerState SampleType;\
   \
   struct PS_INPUT\
@@ -981,7 +985,7 @@ static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
     }
 
 #ifdef HAVE_ID3D11VIDEODECODER
-    if (is_d3d11_opaque(picture->format.i_chroma)) {
+    if (is_d3d11_opaque(picture->format.i_chroma) && sys->legacy_shader) {
         D3D11_BOX box;
         picture_sys_t *p_sys = picture->p_sys;
         D3D11_TEXTURE2D_DESC texDesc;
@@ -1076,7 +1080,10 @@ static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
         Direct3D11UnmapTexture(picture);
 
     /* Render the quad */
-    DisplayD3DPicture(sys, &sys->picQuad, sys->picQuad.picSys.resourceView);
+    if (is_d3d11_opaque(picture->format.i_chroma) && !sys->legacy_shader)
+        DisplayD3DPicture(sys, &sys->picQuad, picture->p_sys->resourceView);
+    else
+        DisplayD3DPicture(sys, &sys->picQuad, sys->picQuad.picSys.resourceView);
 
     if (subpicture) {
         // draw the additional vertices
@@ -1230,7 +1237,7 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
     for (UINT driver = 0; driver < ARRAYSIZE(driverAttempts); driver++) {
         D3D_FEATURE_LEVEL i_feature_level;
         hr = D3D11CreateDevice(NULL, driverAttempts[driver], NULL, creationFlags,
-                    featureLevels, 9, D3D11_SDK_VERSION,
+                    featureLevels, 6, D3D11_SDK_VERSION,
                     &sys->d3ddevice, &i_feature_level, &sys->d3dcontext);
         if (SUCCEEDED(hr)) {
 #ifndef NDEBUG
@@ -1328,13 +1335,6 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
             msg_Warn(vd, "Could not get a suitable SPU pixel shader for %s", sys->picQuadConfig->name);
     }
 
-    if ( fmt->i_height != fmt->i_visible_height || fmt->i_width != fmt->i_visible_width )
-    {
-        msg_Dbg( vd, "use a staging texture to crop to visible size" );
-        AllocQuad( vd, fmt, &sys->stagingQuad, &sys->picQuadConfig, NULL, false,
-                   PROJECTION_MODE_RECTANGULAR );
-    }
-
     video_format_t core_source;
     CropStagingFormat( vd, &core_source );
     UpdateRects(vd, NULL, NULL, true);
@@ -1364,6 +1364,13 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
     }
 #endif
 
+    if ( fmt->i_height != fmt->i_visible_height || fmt->i_width != fmt->i_visible_width )
+    {
+        msg_Dbg( vd, "use a staging texture to crop to visible size" );
+        AllocQuad( vd, fmt, &sys->stagingQuad, sys->picQuadConfig, NULL,
+                   PROJECTION_MODE_RECTANGULAR );
+    }
+
 #if !VLC_WINSTORE_APP
     EventThreadUpdateTitle(sys->event, VOUT_TITLE " (Direct3D11 output)");
 #endif
@@ -1429,12 +1436,28 @@ static ID3DBlob* CompileShader(vout_display_t *vd, const char *psz_shader, bool
 {
     vout_display_sys_t *sys = vd->sys;
     ID3DBlob* pShaderBlob = NULL, *pErrBlob;
+    char *shader;
+    if (!pixel)
+        shader = (char*)psz_shader;
+    else
+    {
+        shader = malloc(strlen(psz_shader) + 32);
+        if (!shader)
+        {
+            msg_Err(vd, "no room for the Pixel Shader");
+            return NULL;
+        }
+        sprintf(shader, psz_shader, sys->legacy_shader ? "" : "Array", sys->legacy_shader ? "" : "Array");
+    }
 
     /* TODO : Match the version to the D3D_FEATURE_LEVEL */
-    HRESULT hr = D3DCompile(psz_shader, strlen(psz_shader),
+    HRESULT hr = D3DCompile(shader, strlen(shader),
                             NULL, NULL, NULL, pixel ? "PS" : "VS",
-                            pixel ? "ps_4_0_level_9_1" : "vs_4_0_level_9_1",
+                            pixel ? (sys->legacy_shader ? "ps_4_0_level_9_1" : "ps_4_0") :
+                                    (sys->legacy_shader ? "vs_4_0_level_9_1" : "vs_4_0"),
                             0, 0, &pShaderBlob, &pErrBlob);
+    if (pixel)
+        free(shader);
 
     if (FAILED(hr)) {
         char *err = pErrBlob ? ID3D10Blob_GetBufferPointer(pErrBlob) : NULL;
@@ -1524,12 +1547,34 @@ static int Direct3D11CreateResources(vout_display_t *vd, video_format_t *fmt)
         ID3D11DepthStencilState_Release(pDepthStencilState);
     }
 
+#ifdef HAVE_ID3D11VIDEODECODER
+    sys->legacy_shader = !var_InheritBool(vd, "direct3d11-direct-hw");
+#if 0
+    IDXGIAdapter *pAdapter = D3D11DeviceAdapter(sys->d3ddevice);
+    if (pAdapter) {
+        DXGI_ADAPTER_DESC adapterDesc;
+        if (SUCCEEDED(IDXGIAdapter_GetDesc(pAdapter, &adapterDesc)) &&
+                      adapterDesc.VendorId == 0x1002) {
+            /* ATI/AMD hardware has issues with pixel shaders with Texture2DArray */
+            sys->legacy_shader = true;
+        }
+        IDXGIAdapter_Release(pAdapter);
+    }
+#endif
+#else
+    sys->legacy_shader = true;
+#endif
     ID3D11PixelShader *pPicQuadShader;
     hr = CompilePixelShader(vd, sys->d3dPxShader, &pPicQuadShader);
     if (FAILED(hr))
     {
-        msg_Err(vd, "Failed to create the pixel shader. (hr=0x%lX)", hr);
-        return VLC_EGENERIC;
+        sys->legacy_shader = true;
+        hr = CompilePixelShader(vd, sys->d3dPxShader, &pPicQuadShader);
+        if (FAILED(hr))
+        {
+            msg_Err(vd, "Failed to create the pixel shader. (hr=0x%lX)", hr);
+            return VLC_EGENERIC;
+        }
     }
 
     if (sys->psz_rgbaPxShader != NULL)
@@ -2036,11 +2081,21 @@ static int AllocQuad(vout_display_t *vd, const video_format_t *fmt, d3d_quad_t *
     }
 
     /* map texture planes to resource views */
-    D3D11_SHADER_RESOURCE_VIEW_DESC resviewDesc;
-    memset(&resviewDesc, 0, sizeof(resviewDesc));
-    resviewDesc.Format = cfg->formatY;
-    resviewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
-    resviewDesc.Texture2D.MipLevels = texDesc.MipLevels;
+    D3D11_SHADER_RESOURCE_VIEW_DESC resviewDesc = {
+        .Format = cfg->formatY,
+    };
+    if (sys->legacy_shader)
+    {
+        resviewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+        resviewDesc.Texture2D.MipLevels = 1;
+    }
+    else
+    {
+        resviewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
+        resviewDesc.Texture2DArray.MipLevels = -1;
+        resviewDesc.Texture2DArray.ArraySize = 1;
+        resviewDesc.Texture2DArray.FirstArraySlice = slice_index;
+    }
 
     hr = ID3D11Device_CreateShaderResourceView(sys->d3ddevice, (ID3D11Resource *)quad->pTexture, &resviewDesc, &quad->picSys.resourceView[0]);
     if (FAILED(hr)) {
-- 
2.10.2



More information about the vlc-devel mailing list