[vlc-devel] [PATCH 7/7] direct3d11: add support for subpicture chroma handling

Steve Lhomme robUx4 at videolabs.io
Mon May 25 13:49:51 CEST 2015


the subpicture buffer is stored in a picture_t with a d3d_quad_t in place of picture_sys_t
---
 modules/video_output/msw/common.h     |   8 +
 modules/video_output/msw/direct3d11.c | 354 ++++++++++++++++++++++++++++++++--
 2 files changed, 344 insertions(+), 18 deletions(-)

diff --git a/modules/video_output/msw/common.h b/modules/video_output/msw/common.h
index 2091124..42e000b 100644
--- a/modules/video_output/msw/common.h
+++ b/modules/video_output/msw/common.h
@@ -186,6 +186,14 @@ struct vout_display_sys_t
     picture_sys_t            *picsys;
     vlc_fourcc_t             vlcFormat;
     const char               *d3dPxShader;
+
+    // SPU
+    vlc_fourcc_t             pSubpictureChromas[2];
+    const char               *psz_rgbaPxShader;
+    ID3D11PixelShader        *pSPUPixelShader;
+    DXGI_FORMAT              d3dregion_format;
+    int                      d3dregion_count;
+    picture_t                **d3dregions;
 #endif
 
 #ifdef MODULE_NAME_IS_direct3d9
diff --git a/modules/video_output/msw/direct3d11.c b/modules/video_output/msw/direct3d11.c
index 9562d8d..9bff816 100644
--- a/modules/video_output/msw/direct3d11.c
+++ b/modules/video_output/msw/direct3d11.c
@@ -53,6 +53,9 @@ static int  Open(vlc_object_t *);
 static void Close(vlc_object_t *);
 
 #define D3D11_HELP N_("Recommended video output for Windows 8 and later versions")
+#define HW_BLENDING_TEXT N_("Use hardware blending support")
+#define HW_BLENDING_LONGTEXT N_(\
+    "Try to use hardware acceleration for subtitle/OSD blending.")
 
 vlc_module_begin ()
     set_shortname("Direct3D11")
@@ -60,6 +63,9 @@ vlc_module_begin ()
     set_help(D3D11_HELP)
     set_category(CAT_VIDEO)
     set_subcategory(SUBCAT_VIDEO_VOUT)
+
+    add_bool("direct3d11-hw-blending", true, HW_BLENDING_TEXT, HW_BLENDING_LONGTEXT, true)
+
     set_capability("vout display", 240)
     add_shortcut("direct3d11")
     set_callbacks(Open, Close)
@@ -97,11 +103,6 @@ static const d3d_format_t d3d_formats[] = {
     { NULL, 0, 0, 0, 0}
 };
 
-static const vlc_fourcc_t d3d_subpicture_chromas[] = {
-    VLC_CODEC_RGBA,
-    0
-};
-
 struct picture_sys_t
 {
     ID3D11Texture2D     *texture;
@@ -113,6 +114,7 @@ struct picture_sys_t
 typedef struct d3d_vertex_t {
     D3DXVECTOR3 position;
     D3DXVECTOR2 texture;
+    FLOAT       opacity;
 } d3d_vertex_t;
 
 #define RECTWidth(r)   (int)(r.right - r.left)
@@ -134,6 +136,8 @@ static int  Direct3D11CreateResources (vout_display_t *, video_format_t *);
 static void Direct3D11DestroyResources(vout_display_t *);
 
 static int  Direct3D11MapTexture(picture_t *);
+static void Direct3D11DeleteRegions(int, picture_t **);
+static int Direct3D11MapSubpicture(vout_display_t *, int *, picture_t ***, subpicture_t *);
 
 static int AllocQuad(vout_display_t *, const video_format_t *, d3d_quad_t *,
                      d3d_quad_cfg_t *, ID3D11PixelShader *,
@@ -156,12 +160,14 @@ static const char* globVertexShaderDefault = "\
   {\
     float4 Position   : POSITION;\
     float2 Texture    : TEXCOORD0;\
+    float  Opacity    : OPACITY;\
   };\
   \
   struct VS_OUTPUT\
   {\
     float4 Position   : SV_POSITION;\
     float2 Texture    : TEXCOORD0;\
+    float  Opacity    : OPACITY;\
   };\
   \
   VS_OUTPUT VS( VS_INPUT In )\
@@ -169,6 +175,7 @@ static const char* globVertexShaderDefault = "\
     VS_OUTPUT Output;\
     Output.Position = float4(In.Position.xy, 0.0f, 1.0f);\
     Output.Texture = In.Texture;\
+    Output.Opacity = In.Opacity;\
     return Output;\
   }\
 ";
@@ -181,11 +188,16 @@ static const char* globPixelShaderDefault = "\
   {\
     float4 Position   : SV_POSITION;\
     float2 Texture    : TEXCOORD0;\
+    float  Opacity    : OPACITY;\
   };\
   \
   float4 PS( PS_INPUT In ) : SV_TARGET\
   {\
-    return shaderTexture.Sample(SampleType, In.Texture);\
+    float4 rgba; \
+    \
+    rgba = shaderTexture.Sample(SampleType, In.Texture);\
+    rgba.a = rgba.a * In.Opacity;\
+    return rgba; \
   }\
 ";
 
@@ -198,6 +210,7 @@ static const char *globPixelShaderBiplanarI420_BT601_2RGB = "\
   {\
     float4 Position   : SV_POSITION;\
     float2 Texture    : TEXCOORD0;\
+    float  Opacity    : OPACITY;\
   };\
   \
   float4 PS( PS_INPUT In ) : SV_TARGET\
@@ -225,7 +238,7 @@ static const char *globPixelShaderBiplanarI420_BT601_2RGB = "\
     rgba.x = saturate(Y + 1.596026785714286 * VCr);\
     rgba.y = saturate(Y - 0.812967647237771 * VCr - 0.391762290094914 * UCb);\
     rgba.z = saturate(Y + 2.017232142857142 * UCb);\
-    rgba.w = 1.0;\
+    rgba.a = In.Opacity;\
     return rgba;\
   }\
 ";
@@ -239,6 +252,7 @@ static const char *globPixelShaderBiplanarI420_BT709_2RGB = "\
   {\
     float4 Position   : SV_POSITION;\
     float2 Texture    : TEXCOORD0;\
+    float  Opacity    : OPACITY;\
   };\
   \
   float4 PS( PS_INPUT In ) : SV_TARGET\
@@ -266,7 +280,7 @@ static const char *globPixelShaderBiplanarI420_BT709_2RGB = "\
     rgba.x = saturate(Y + 1.792741071428571 * VCr);\
     rgba.y = saturate(Y - 0.532909328559444 * VCr - 0.21324861427373 * UCb);\
     rgba.z = saturate(Y + 2.112401785714286 * UCb);\
-    rgba.w = 1.0;\
+    rgba.a = In.Opacity;\
     return rgba;\
   }\
 ";
@@ -280,6 +294,7 @@ static const char *globPixelShaderBiplanarYUV_BT601_2RGB = "\
   {\
     float4 Position   : SV_POSITION;\
     float2 Texture    : TEXCOORD0;\
+    float  Opacity    : OPACITY;\
   };\
   \
   float4 PS( PS_INPUT In ) : SV_TARGET\
@@ -294,7 +309,7 @@ static const char *globPixelShaderBiplanarYUV_BT601_2RGB = "\
     rgba.x = saturate(yuv.x + 1.596026785714286 * yuv.z);\
     rgba.y = saturate(yuv.x - 0.812967647237771 * yuv.z - 0.391762290094914 * yuv.y);\
     rgba.z = saturate(yuv.x + 2.017232142857142 * yuv.y);\
-    rgba.w = 1.0;\
+    rgba.a = In.Opacity;\
     return rgba;\
   }\
 ";
@@ -308,6 +323,7 @@ static const char *globPixelShaderBiplanarYUV_BT709_2RGB = "\
   {\
     float4 Position   : SV_POSITION;\
     float2 Texture    : TEXCOORD0;\
+    float  Opacity    : OPACITY;\
   };\
   \
   float4 PS( PS_INPUT In ) : SV_TARGET\
@@ -322,7 +338,7 @@ static const char *globPixelShaderBiplanarYUV_BT709_2RGB = "\
     rgba.x = saturate(yuv.x + 1.792741071428571 * yuv.z);\
     rgba.y = saturate(yuv.x - 0.532909328559444 * yuv.z - 0.21324861427373 * yuv.y);\
     rgba.z = saturate(yuv.x + 2.112401785714286 * yuv.y);\
-    rgba.w = 1.0;\
+    rgba.a = In.Opacity;\
     return rgba;\
   }\
 ";
@@ -440,8 +456,11 @@ static int Open(vlc_object_t *object)
     info.has_pictures_invalid = true;
     info.has_event_thread     = true;
 
-    /* TODO : subtitle support */
-    info.subpicture_chromas   = NULL;
+    if (var_InheritBool(vd, "direct3d11-hw-blending") &&
+        sys->d3dregion_format != DXGI_FORMAT_UNKNOWN)
+        info.subpicture_chromas = sys->pSubpictureChromas;
+    else
+        info.subpicture_chromas = NULL;
 
     video_format_Clean(&vd->fmt);
     video_format_Copy(&vd->fmt, &fmt);
@@ -577,12 +596,20 @@ static void Manage(vout_display_t *vd)
 static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
 {
     vout_display_sys_t *sys = vd->sys;
-    VLC_UNUSED(subpicture);
     VLC_UNUSED(picture);
 
     /* float ClearColor[4] = { 1.0f, 0.125f, 0.3f, 1.0f }; */
     /* ID3D11DeviceContext_ClearRenderTargetView(sys->d3dcontext,sys->d3drenderTargetView, ClearColor); */
     ID3D11DeviceContext_ClearDepthStencilView(sys->d3dcontext,sys->d3ddepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);
+
+    if (subpicture) {
+        int subpicture_region_count    = 0;
+        picture_t **subpicture_regions = NULL;
+        Direct3D11MapSubpicture(vd, &subpicture_region_count, &subpicture_regions, subpicture);
+        Direct3D11DeleteRegions(sys->d3dregion_count, sys->d3dregions);
+        sys->d3dregion_count = subpicture_region_count;
+        sys->d3dregions      = subpicture_regions;
+    }
 }
 
 static void DisplayD3DPicture(vout_display_sys_t *sys, d3d_quad_t *quad)
@@ -610,6 +637,13 @@ static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
     /* Render the quad */
     DisplayD3DPicture(sys, &sys->picQuad);
 
+    if (subpicture) {
+        // draw the additional vertices
+        for (int i = 0; i < sys->d3dregion_count; ++i) {
+            DisplayD3DPicture(sys, (d3d_quad_t *) sys->d3dregions[i]->p_sys);
+        }
+    }
+
     IDXGISwapChain_Present(sys->dxgiswapChain, 0, 0);
 
     picture_Release(picture);
@@ -882,6 +916,26 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
        return VLC_EGENERIC;
     }
 
+    /* check the region pixel format */
+    i_quadSupportFlags |= D3D11_FORMAT_SUPPORT_BLENDABLE;
+    if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys->d3ddevice,
+                                                   DXGI_FORMAT_R8G8B8A8_UNORM,
+                                                   &i_formatSupport)) &&
+            ( i_formatSupport & i_quadSupportFlags )) {
+        sys->d3dregion_format = DXGI_FORMAT_R8G8B8A8_UNORM;
+        sys->pSubpictureChromas[0] = VLC_CODEC_RGBA;
+        sys->pSubpictureChromas[1] = 0;
+    } else if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys->d3ddevice,
+                                                          DXGI_FORMAT_B8G8R8A8_UNORM,
+                                                          &i_formatSupport)) &&
+                   ( i_formatSupport & i_quadSupportFlags )) {
+        sys->d3dregion_format = DXGI_FORMAT_B8G8R8A8_UNORM;
+        sys->pSubpictureChromas[0] = VLC_CODEC_BGRA;
+        sys->pSubpictureChromas[1] = 0;
+    } else {
+        sys->d3dregion_format = DXGI_FORMAT_UNKNOWN;
+    }
+
     switch (sys->vlcFormat)
     {
     case VLC_CODEC_NV12:
@@ -904,6 +958,10 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
         sys->d3dPxShader = globPixelShaderDefault;
         break;
     }
+    if (sys->d3dregion_format != DXGI_FORMAT_UNKNOWN)
+        sys->psz_rgbaPxShader = globPixelShaderDefault;
+    else
+        sys->psz_rgbaPxShader = NULL;
 
     UpdateRects(vd, NULL, NULL, true);
 
@@ -948,6 +1006,64 @@ static int Direct3D11CreateResources(vout_display_t *vd, video_format_t *fmt)
        return VLC_EGENERIC;
     }
 
+    ID3D11BlendState *pSpuBlendState;
+    D3D11_BLEND_DESC spuBlendDesc = { 0 };
+    spuBlendDesc.RenderTarget[0].BlendEnable = TRUE;
+    spuBlendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
+    spuBlendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
+    spuBlendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+
+    spuBlendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
+    spuBlendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
+    spuBlendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+
+    spuBlendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
+
+    spuBlendDesc.RenderTarget[1].BlendEnable = TRUE;
+    spuBlendDesc.RenderTarget[1].SrcBlend = D3D11_BLEND_ONE;
+    spuBlendDesc.RenderTarget[1].DestBlend = D3D11_BLEND_ZERO;
+    spuBlendDesc.RenderTarget[1].BlendOp = D3D11_BLEND_OP_ADD;
+
+    spuBlendDesc.RenderTarget[1].SrcBlendAlpha = D3D11_BLEND_ONE;
+    spuBlendDesc.RenderTarget[1].DestBlendAlpha = D3D11_BLEND_ZERO;
+    spuBlendDesc.RenderTarget[1].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+
+    spuBlendDesc.RenderTarget[1].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
+    hr = ID3D11Device_CreateBlendState(sys->d3ddevice, &spuBlendDesc, &pSpuBlendState);
+    if (FAILED(hr)) {
+       msg_Err(vd, "Could not create SPU blend state. (hr=0x%lX)", hr);
+       return VLC_EGENERIC;
+    }
+    ID3D11DeviceContext_OMSetBlendState(sys->d3dcontext, pSpuBlendState, NULL, 0xFFFFFFFF);
+    ID3D11BlendState_Release(pSpuBlendState);
+
+    /* disable depth testing as we're only doing 2D
+     * see https://msdn.microsoft.com/en-us/library/windows/desktop/bb205074%28v=vs.85%29.aspx
+     * see http://rastertek.com/dx11tut11.html
+    */
+    D3D11_DEPTH_STENCIL_DESC stencilDesc;
+    ZeroMemory(&stencilDesc, sizeof(stencilDesc));
+    stencilDesc.DepthEnable                  = FALSE;
+    stencilDesc.StencilEnable                = TRUE;
+    stencilDesc.DepthWriteMask               = D3D11_DEPTH_WRITE_MASK_ALL;
+    stencilDesc.DepthFunc                    = D3D11_COMPARISON_LESS;
+    stencilDesc.StencilReadMask              = 0xFF;
+    stencilDesc.StencilWriteMask             = 0xFF;
+    stencilDesc.FrontFace.StencilFailOp      = D3D11_STENCIL_OP_KEEP;
+    stencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
+    stencilDesc.FrontFace.StencilPassOp      = D3D11_STENCIL_OP_KEEP;
+    stencilDesc.FrontFace.StencilFunc        = D3D11_COMPARISON_ALWAYS;
+    stencilDesc.BackFace.StencilFailOp       = D3D11_STENCIL_OP_KEEP;
+    stencilDesc.BackFace.StencilDepthFailOp  = D3D11_STENCIL_OP_DECR;
+    stencilDesc.BackFace.StencilPassOp       = D3D11_STENCIL_OP_KEEP;
+    stencilDesc.BackFace.StencilFunc         = D3D11_COMPARISON_ALWAYS;
+
+    ID3D11DepthStencilState *pDepthStencilState;
+    hr = ID3D11Device_CreateDepthStencilState(sys->d3ddevice, &stencilDesc, &pDepthStencilState );
+    if (SUCCEEDED(hr)) {
+        ID3D11DeviceContext_OMSetDepthStencilState(sys->d3dcontext, pDepthStencilState, 0);
+        ID3D11DepthStencilState_Release(pDepthStencilState);
+    }
 
     D3D11_VIEWPORT vp;
     vp.Width = (FLOAT)fmt->i_visible_width;
@@ -985,10 +1101,11 @@ static int Direct3D11CreateResources(vout_display_t *vd, video_format_t *fmt)
     D3D11_INPUT_ELEMENT_DESC layout[] = {
     { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0},
     { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
+    { "OPACITY",  0, DXGI_FORMAT_R32_FLOAT,       0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0},
     };
 
     ID3D11InputLayout* pVertexLayout = NULL;
-    hr = ID3D11Device_CreateInputLayout(sys->d3ddevice, layout, 2, (void *)ID3D10Blob_GetBufferPointer(pVSBlob),
+    hr = ID3D11Device_CreateInputLayout(sys->d3ddevice, layout, 3, (void *)ID3D10Blob_GetBufferPointer(pVSBlob),
                                         ID3D10Blob_GetBufferSize(pVSBlob), &pVertexLayout);
 
     ID3D10Blob_Release(pVSBlob);
@@ -1052,11 +1169,33 @@ static int Direct3D11CreateResources(vout_display_t *vd, video_format_t *fmt)
       return VLC_EGENERIC;
     }
 
+    if (sys->psz_rgbaPxShader != NULL)
+    {
+        hr = D3DCompile(sys->psz_rgbaPxShader, strlen(sys->psz_rgbaPxShader),
+                        NULL, NULL, NULL, "PS", "ps_4_0_level_9_1", 0, 0, &pPSBlob, NULL);
+        if( FAILED(hr)) {
+          ID3D11PixelShader_Release(pPicQuadShader);
+          msg_Err(vd, "The RGBA Pixel Shader is invalid. (hr=0x%lX)", hr );
+          return VLC_EGENERIC;
+        }
+
+        hr = ID3D11Device_CreatePixelShader(sys->d3ddevice, (void *)ID3D10Blob_GetBufferPointer(pPSBlob),
+                                            ID3D10Blob_GetBufferSize(pPSBlob), NULL, &sys->pSPUPixelShader);
+
+        ID3D10Blob_Release(pPSBlob);
+
+        if(FAILED(hr)) {
+          ID3D11PixelShader_Release(pPicQuadShader);
+          msg_Err(vd, "Failed to create the SPU pixel shader.");
+          return VLC_EGENERIC;
+        }
+    }
+
     float vertices[4 * sizeof(d3d_vertex_t)] = {
-    -1.0f, -1.0f, -1.0f, 0.0f, 1.0f,
-     1.0f, -1.0f, -1.0f, 1.0f, 1.0f,
-     1.0f,  1.0f, -1.0f, 1.0f, 0.0f,
-    -1.0f,  1.0f, -1.0f, 0.0f, 0.0f,
+    -1.0f, -1.0f, -1.0f,  0.0f, 1.0f,  1.0f, // bottom left
+     1.0f, -1.0f, -1.0f,  1.0f, 1.0f,  1.0f, // bottom right
+     1.0f,  1.0f, -1.0f,  1.0f, 0.0f,  1.0f, // top right
+    -1.0f,  1.0f, -1.0f,  0.0f, 0.0f,  1.0f, // top left
     };
 
     if (AllocQuad( vd, fmt, &sys->picQuad, &sys->picQuadConfig, pPicQuadShader, vertices )!=VLC_SUCCESS) {
@@ -1226,11 +1365,15 @@ static void Direct3D11DestroyResources(vout_display_t *vd)
     sys->pool = NULL;
 
     ReleaseQuad(&sys->picQuad);
+    Direct3D11DeleteRegions(sys->d3dregion_count, sys->d3dregions);
+    sys->d3dregion_count = 0;
 
     if (sys->d3drenderTargetView)
         ID3D11RenderTargetView_Release(sys->d3drenderTargetView);
     if (sys->d3ddepthStencilView)
         ID3D11DepthStencilView_Release(sys->d3ddepthStencilView);
+    if (sys->pSPUPixelShader)
+        ID3D11VertexShader_Release(sys->pSPUPixelShader);
 
     msg_Dbg(vd, "Direct3D11 resources destroyed");
 }
@@ -1250,3 +1393,178 @@ static int Direct3D11MapTexture(picture_t *picture)
     ID3D11DeviceContext_Unmap(picture->p_sys->context,(ID3D11Resource *)picture->p_sys->texture, 0);
     return res;
 }
+
+static void Direct3D11DeleteRegions(int count, picture_t **region)
+{
+    for (int i = 0; i < count; ++i) {
+        if (region[i]) {
+            picture_Release(region[i]);
+        }
+    }
+    free(region);
+}
+
+static void DestroyPictureQuad(picture_t *p_picture)
+{
+    ReleaseQuad( (d3d_quad_t *) p_picture->p_sys );
+    free( p_picture );
+}
+
+static int Direct3D11MapSubpicture(vout_display_t *vd, int *subpicture_region_count,
+                                   picture_t ***region, subpicture_t *subpicture)
+{
+    vout_display_sys_t *sys = vd->sys;
+    D3D11_MAPPED_SUBRESOURCE mappedResource;
+    D3D11_TEXTURE2D_DESC texDesc;
+    HRESULT hr;
+    int err;
+
+    int count = 0;
+    for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
+        count++;
+
+    *region = calloc(count, sizeof(picture_t *));
+    if (unlikely(*region==NULL))
+        return VLC_ENOMEM;
+    *subpicture_region_count = count;
+
+    int i = 0;
+    for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
+        for (int j = 0; j < sys->d3dregion_count; j++) {
+            picture_t *cache = sys->d3dregions[j];
+            if (((d3d_quad_t *) cache->p_sys)->pTexture) {
+                ID3D11Texture2D_GetDesc( ((d3d_quad_t *) cache->p_sys)->pTexture, &texDesc );
+                if (texDesc.Format == sys->d3dregion_format &&
+                    texDesc.Width  == r->fmt.i_visible_width &&
+                    texDesc.Height == r->fmt.i_visible_height) {
+#ifndef NDEBUG
+                    msg_Dbg(vd, "Reusing %dx%d texture for OSD",
+                            texDesc.Width, texDesc.Height);
+#endif
+                    (*region)[i] = cache;
+                    memset(&sys->d3dregions[j], 0, sizeof(cache)); // do not reuse this cached value
+                    break;
+                }
+            }
+        }
+
+        picture_t *quad_picture = (*region)[i];
+        if (quad_picture == NULL) {
+            d3d_quad_t *d3dquad = calloc(1, sizeof(*d3dquad));
+            if (unlikely(d3dquad==NULL)) {
+                continue;
+            }
+            d3d_quad_cfg_t rgbaCfg = {
+                .textureFormat      = sys->d3dregion_format,
+                .resourceFormatYRGB = sys->d3dregion_format,
+            };
+            err = AllocQuad(vd, &r->fmt, d3dquad, &rgbaCfg, sys->pSPUPixelShader, NULL);
+            if (err != VLC_SUCCESS) {
+                msg_Err(vd, "Failed to create %dx%d texture for OSD",
+                        r->fmt.i_visible_width, r->fmt.i_visible_height);
+                free(d3dquad);
+                continue;
+            }
+            picture_resource_t picres = {
+                .p_sys      = (picture_sys_t *) d3dquad,
+                .pf_destroy = DestroyPictureQuad,
+            };
+            (*region)[i] = picture_NewFromResource(&r->fmt, &picres);
+            if ((*region)[i] == NULL) {
+                msg_Err(vd, "Failed to create %dx%d picture for OSD",
+                        r->fmt.i_visible_width, r->fmt.i_visible_height);
+                ReleaseQuad(d3dquad);
+                continue;
+            }
+            quad_picture = (*region)[i];
+            hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource *)((d3d_quad_t *) quad_picture->p_sys)->pTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
+            if( SUCCEEDED(hr) ) {
+                err = CommonUpdatePicture(quad_picture, NULL, mappedResource.pData, mappedResource.RowPitch);
+                ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)((d3d_quad_t *) quad_picture->p_sys)->pTexture, 0);
+                if (err != VLC_SUCCESS) {
+                    msg_Err(vd, "Failed to set the buffer on the OSD picture" );
+                    picture_Release(quad_picture);
+                    continue;
+                }
+            } else {
+                msg_Err(vd, "Failed to map the OSD texture (hr=0x%lX)", hr );
+                picture_Release(quad_picture);
+                continue;
+            }
+#ifndef NDEBUG
+            msg_Dbg(vd, "Created %dx%d texture for OSD",
+                    r->fmt.i_visible_width, r->fmt.i_visible_height);
+#endif
+        }
+
+        picture_CopyPixels(quad_picture, r->p_picture);
+
+        /* Map the subpicture to sys->rect_dest */
+        RECT src;
+        src.left   = 0;
+        src.right  = src.left + r->fmt.i_visible_width;
+        src.top    = 0;
+        src.bottom = src.top  + r->fmt.i_visible_height;
+
+        const RECT video = sys->rect_dest;
+        const float scale_w = (float)(video.right  - video.left) / subpicture->i_original_picture_width;
+        const float scale_h = (float)(video.bottom - video.top)  / subpicture->i_original_picture_height;
+
+        RECT dst;
+        dst.left   = video.left + scale_w * r->i_x,
+        dst.right  = dst.left + scale_w * r->fmt.i_visible_width,
+        dst.top    = video.top  + scale_h * r->i_y,
+        dst.bottom = dst.top  + scale_h * r->fmt.i_visible_height;
+
+        // adjust with the center at 0,0 and the edges at -1/1
+        float left   = ((float)dst.left   / subpicture->i_original_picture_width ) * 2.0f - 1.0f;
+        float right  = ((float)dst.right  / subpicture->i_original_picture_width ) * 2.0f - 1.0f;
+        float top    = 1.0f - 2.0f * dst.top    / subpicture->i_original_picture_height;
+        float bottom = 1.0f - 2.0f * dst.bottom / subpicture->i_original_picture_height;
+
+        float opacity = (float)r->i_alpha / 255.0f;
+
+        hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource *)((d3d_quad_t *) quad_picture->p_sys)->pVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
+        if( SUCCEEDED(hr) ) {
+            d3d_vertex_t *dst_data = mappedResource.pData;
+
+            // bottom left
+            dst_data[0].position.x = left;
+            dst_data[0].position.y = bottom;
+            dst_data[0].position.z = 0.0f;
+            dst_data[0].texture.x = 0.0f;
+            dst_data[0].texture.y = 1.0f;
+            dst_data[0].opacity   = opacity;
+
+            // bottom right
+            dst_data[1].position.x = right;
+            dst_data[1].position.y = bottom;
+            dst_data[1].position.z = 0.0f;
+            dst_data[1].texture.x = 1.0f;
+            dst_data[1].texture.y = 1.0f;
+            dst_data[1].opacity   = opacity;
+
+            // top right
+            dst_data[2].position.x = right;
+            dst_data[2].position.y = top;
+            dst_data[2].position.z = 0.0f;
+            dst_data[2].texture.x = 1.0f;
+            dst_data[2].texture.y = 0.0f;
+            dst_data[2].opacity   = opacity;
+
+            // top left
+            dst_data[3].position.x = left;
+            dst_data[3].position.y = top;
+            dst_data[3].position.z = 0.0f;
+            dst_data[3].texture.x = 0.0f;
+            dst_data[3].texture.y = 0.0f;
+            dst_data[3].opacity   = opacity;
+
+            ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)((d3d_quad_t *) quad_picture->p_sys)->pVertexBuffer, 0);
+        } else {
+            msg_Err(vd, "Failed to lock the subpicture vertex buffer (hr=0x%lX)", hr );
+        }
+    }
+    return VLC_SUCCESS;
+}
+
-- 
2.4.0




More information about the vlc-devel mailing list