[vlc-devel] [PATCH 2/3] direct3d11: support direct rendering of GPU textures coming from d3d11va

Steve Lhomme robux4 at gmail.com
Fri Jun 5 09:47:05 CEST 2015


New patch coming with internal cleaning.

On Tue, Jun 2, 2015 at 4:16 PM, Steve Lhomme <robux4 at gmail.com> wrote:
> ---
>  modules/video_output/msw/common.h     |   1 -
>  modules/video_output/msw/direct3d11.c | 189 +++++++++++++++++++++++++++++-----
>  2 files changed, 165 insertions(+), 25 deletions(-)
>
> diff --git a/modules/video_output/msw/common.h b/modules/video_output/msw/common.h
> index fa03735..4f7389d 100644
> --- a/modules/video_output/msw/common.h
> +++ b/modules/video_output/msw/common.h
> @@ -183,7 +183,6 @@ struct vout_display_sys_t
>      d3d_quad_cfg_t           picQuadConfig;
>      ID3D11RenderTargetView   *d3drenderTargetView;
>      ID3D11DepthStencilView   *d3ddepthStencilView;
> -    picture_sys_t            *picsys;
>      const char               *d3dPxShader;
>
>      // SPU
> diff --git a/modules/video_output/msw/direct3d11.c b/modules/video_output/msw/direct3d11.c
> index 3eb105e..5621d21 100644
> --- a/modules/video_output/msw/direct3d11.c
> +++ b/modules/video_output/msw/direct3d11.c
> @@ -83,6 +83,7 @@ static const d3d_format_t d3d_formats[] = {
>      { "I420",     DXGI_FORMAT_NV12,           VLC_CODEC_I420,     DXGI_FORMAT_R8_UNORM,           DXGI_FORMAT_R8G8_UNORM },
>      { "YV12",     DXGI_FORMAT_NV12,           VLC_CODEC_YV12,     DXGI_FORMAT_R8_UNORM,           DXGI_FORMAT_R8G8_UNORM },
>      { "NV12",     DXGI_FORMAT_NV12,           VLC_CODEC_NV12,     DXGI_FORMAT_R8_UNORM,           DXGI_FORMAT_R8G8_UNORM },
> +    { "VA_NV12",  DXGI_FORMAT_NV12,           VLC_CODEC_D3D11_OPAQUE, DXGI_FORMAT_R8_UNORM,       DXGI_FORMAT_R8G8_UNORM },
>  #ifdef BROKEN_PIXEL
>      { "YUY2",     DXGI_FORMAT_YUY2,           VLC_CODEC_I422,     DXGI_FORMAT_R8G8B8A8_UNORM,     0 },
>      { "AYUV",     DXGI_FORMAT_AYUV,           VLC_CODEC_YUVA,     DXGI_FORMAT_R8G8B8A8_UNORM,     0 },
> @@ -102,11 +103,14 @@ static const d3d_format_t d3d_formats[] = {
>      { NULL, 0, 0, 0, 0}
>  };
>
> +/* VLC_CODEC_D3D11_OPAQUE */
>  struct picture_sys_t
>  {
> -    ID3D11Texture2D     *texture;
> -    ID3D11DeviceContext *context;
> -    vout_display_t      *vd;
> +    ID3D11VideoDecoderOutputView  *decoder; /* we do not get access from here */
> +    ID3D11Texture2D               *texture;
> +    ID3D11Device                  *device;
> +    ID3D11DeviceContext           *context;
> +    HINSTANCE                     hd3d11_dll;
>  };
>
>  /* matches the D3D11_INPUT_ELEMENT_DESC we setup */
> @@ -122,6 +126,8 @@ typedef struct d3d_vertex_t {
>  static int  Open(vlc_object_t *);
>  static void Close(vlc_object_t *object);
>
> +static picture_pool_t *Pool(vout_display_t *vd, unsigned count);
> +
>  static void Prepare(vout_display_t *, picture_t *, subpicture_t *subpicture);
>  static void Display(vout_display_t *, picture_t *, subpicture_t *subpicture);
>
> @@ -134,6 +140,10 @@ static void Direct3D11Close(vout_display_t *);
>  static int  Direct3D11CreateResources (vout_display_t *, video_format_t *);
>  static void Direct3D11DestroyResources(vout_display_t *);
>
> +static int  Direct3D11CreatePool (vout_display_t *, video_format_t *);
> +static void Direct3D11DestroyPool(vout_display_t *);
> +
> +static void DestroyD3D11Picture(picture_t *);
>  static int  Direct3D11MapTexture(picture_t *);
>  static void Direct3D11DeleteRegions(int, picture_t **);
>  static int Direct3D11MapSubpicture(vout_display_t *, int *, picture_t ***, subpicture_t *);
> @@ -449,11 +459,12 @@ static int Open(vlc_object_t *object)
>      }
>
>      vout_display_info_t info  = vd->info;
> -    info.is_slow              = true;
> +    info.is_slow              = fmt.i_chroma != VLC_CODEC_D3D11_OPAQUE;
>      info.has_double_click     = true;
>      info.has_hide_mouse       = false;
>      info.has_pictures_invalid = true;
>      info.has_event_thread     = true;
> +    info.has_pictures_invalid = fmt.i_chroma != VLC_CODEC_D3D11_OPAQUE;
>
>      if (var_InheritBool(vd, "direct3d11-hw-blending") &&
>          sys->d3dregion_format != DXGI_FORMAT_UNKNOWN)
> @@ -465,7 +476,7 @@ static int Open(vlc_object_t *object)
>      video_format_Copy(&vd->fmt, &fmt);
>      vd->info = info;
>
> -    vd->pool    = CommonPool;
> +    vd->pool    = Pool;
>      vd->prepare = Prepare;
>      vd->display = Display;
>      vd->control = CommonControl;
> @@ -492,6 +503,105 @@ static void Close(vlc_object_t *object)
>      free(vd->sys);
>  }
>
> +static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
> +{
> +    if ( vd->sys->pool != NULL )
> +        return vd->sys->pool;
> +
> +    picture_t**       pictures = NULL;
> +    unsigned          picture_count = 0;
> +    HRESULT           hr;
> +
> +    ID3D10Multithread *pMultithread;
> +    hr = ID3D11Device_QueryInterface( vd->sys->d3ddevice, &IID_ID3D10Multithread, (void **)&pMultithread);
> +    if (SUCCEEDED(hr)) {
> +        ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);
> +        ID3D10Multithread_Release(pMultithread);
> +    }
> +
> +    pictures = calloc(pool_size, sizeof(*pictures));
> +    if (!pictures)
> +        goto error;
> +
> +    D3D11_TEXTURE2D_DESC texDesc;
> +    ZeroMemory(&texDesc, sizeof(texDesc));
> +    texDesc.Width = vd->fmt.i_width;
> +    texDesc.Height = vd->fmt.i_height;
> +    texDesc.MipLevels = 1;
> +    texDesc.Format = vd->sys->picQuadConfig.textureFormat;
> +    texDesc.SampleDesc.Count = 1;
> +    texDesc.MiscFlags = 0; //D3D11_RESOURCE_MISC_SHARED;
> +    texDesc.ArraySize = 1;
> +    texDesc.Usage = D3D11_USAGE_DYNAMIC;
> +    texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
> +    texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
> +
> +    unsigned surface_count;
> +    for (surface_count = 0; surface_count < pool_size; surface_count++) {
> +        picture_sys_t *picsys = calloc(1, sizeof(*picsys));
> +        if (unlikely(picsys == NULL))
> +            goto error;
> +
> +        hr = ID3D11Device_CreateTexture2D( vd->sys->d3ddevice, &texDesc, NULL, &picsys->texture );
> +        if (FAILED(hr)) {
> +            msg_Err(vd, "CreateTexture2D %d failed. (hr=0x%0lx)", pool_size, hr);
> +            goto error;
> +        }
> +
> +        picsys->context = vd->sys->d3dcontext;
> +        picsys->device = vd->sys->d3ddevice;
> +
> +        picture_resource_t resource = {
> +            .p_sys = picsys,
> +            .pf_destroy = DestroyD3D11Picture,
> +        };
> +
> +        picture_t *picture = picture_NewFromResource(&vd->fmt, &resource);
> +        if (unlikely(picture == NULL)) {
> +            free(picsys);
> +            goto error;
> +        }
> +
> +        pictures[surface_count] = picture;
> +        /* each picture_t holds a ref to the context and release it on Destroy */
> +        ID3D11DeviceContext_AddRef(picsys->context);
> +        /* each picture_t holds a ref to the DLL */
> +        picsys->hd3d11_dll = LoadLibrary(TEXT("D3D11.DLL"));
> +    }
> +    msg_Dbg(vd, "ID3D11VideoDecoderOutputView succeed with %d surfaces (%dx%d)",
> +            pool_size, vd->fmt.i_width, vd->fmt.i_height);
> +
> +    picture_pool_configuration_t pool_cfg;
> +    memset(&pool_cfg, 0, sizeof(pool_cfg));
> +    pool_cfg.picture_count = pool_size;
> +    pool_cfg.picture       = pictures;
> +    pool_cfg.lock          = Direct3D11MapTexture; /* TODO we only need to map once */
> +
> +    vd->sys->pool = picture_pool_NewExtended( &pool_cfg );
> +
> +error:
> +    if (vd->sys->pool ==NULL && pictures) {
> +        for (unsigned i=0;i<picture_count; ++i)
> +            DestroyD3D11Picture(pictures[i]);
> +        free(pictures);
> +    }
> +    return vd->sys->pool;
> +}
> +
> +static void DestroyD3D11Picture(picture_t *picture)
> +{
> +    picture_sys_t *p_sys = picture->p_sys;
> +    ID3D11DeviceContext_Release(p_sys->context);
> +
> +    if (p_sys->texture)
> +        ID3D11Texture2D_Release(p_sys->texture);
> +
> +    FreeLibrary(p_sys->hd3d11_dll);
> +
> +    free(p_sys);
> +    free(picture);
> +}
> +
>  static HRESULT UpdateBackBuffer(vout_display_t *vd)
>  {
>      vout_display_sys_t *sys = vd->sys;
> @@ -595,7 +705,21 @@ 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(picture);
> +
> +    if (picture->format.i_chroma == VLC_CODEC_D3D11_OPAQUE) {
> +        D3D11_BOX box;
> +        box.left = 0;
> +        box.right = picture->format.i_visible_width;
> +        box.top = 0;
> +        box.bottom = picture->format.i_visible_height;
> +        box.back = 1;
> +        box.front = 0;
> +        ID3D11DeviceContext_CopySubresourceRegion(sys->d3dcontext,
> +                                                  (ID3D11Resource*) sys->picQuad.pTexture,
> +                                                  0, 0, 0, 0,
> +                                                  (ID3D11Resource*) picture->p_sys->texture,
> +                                                  0, &box);
> +    }
>
>  #if VLC_WINSTORE_APP /* TODO: Choose the WinRT app background clear color */
>      float ClearColor[4] = { 1.0f, 0.125f, 0.3f, 1.0f };
> @@ -933,6 +1057,7 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
>      switch (fmt->i_chroma)
>      {
>      case VLC_CODEC_NV12:
> +    case VLC_CODEC_D3D11_OPAQUE:
>          if( fmt->i_height > 576 )
>              sys->d3dPxShader = globPixelShaderBiplanarYUV_BT709_2RGB;
>          else
> @@ -1228,18 +1353,36 @@ static int Direct3D11CreateResources(vout_display_t *vd, video_format_t *fmt)
>      ID3D11DeviceContext_PSSetSamplers(sys->d3dcontext, 0, 1, &d3dsampState);
>      ID3D11SamplerState_Release(d3dsampState);
>
> -    picture_sys_t *picsys = malloc(sizeof(*picsys));
> +    if (Direct3D11CreatePool(vd, fmt))
> +    {
> +        msg_Err(vd, "Direct3D picture pool initialization failed");
> +        return VLC_EGENERIC;
> +    }
> +
> +    msg_Dbg(vd, "Direct3D11 resources created");
> +    return VLC_SUCCESS;
> +}
> +
> +static int Direct3D11CreatePool(vout_display_t *vd, video_format_t *fmt)
> +{
> +    vout_display_sys_t *sys = vd->sys;
> +
> +    if ( fmt->i_chroma == VLC_CODEC_D3D11_OPAQUE )
> +        /* a D3D11VA pool will be created when needed */
> +        return VLC_SUCCESS;
> +
> +    picture_sys_t *picsys = calloc(1, sizeof(*picsys));
>      if (unlikely(picsys == NULL)) {
>          return VLC_ENOMEM;
>      }
>
>      picsys->texture  = sys->picQuad.pTexture;
>      picsys->context  = sys->d3dcontext;
> -    picsys->vd       = vd;
>
> -    picture_resource_t resource = { .p_sys = picsys };
> -    for (int i = 0; i < PICTURE_PLANE_MAX; i++)
> -        resource.p[i].i_lines = fmt->i_visible_height / (i > 0 ? 2 : 1);
> +    picture_resource_t resource = {
> +        .p_sys = picsys,
> +        .pf_destroy = DestroyD3D11Picture,
> +    };
>
>      picture_t *picture = picture_NewFromResource(fmt, &resource);
>      if (!picture) {
> @@ -1248,7 +1391,6 @@ static int Direct3D11CreateResources(vout_display_t *vd, video_format_t *fmt)
>      }
>      ID3D11Texture2D_AddRef(picsys->texture);
>      ID3D11DeviceContext_AddRef(picsys->context);
> -    sys->picsys = picsys;
>
>      picture_pool_configuration_t pool_cfg;
>      memset(&pool_cfg, 0, sizeof(pool_cfg));
> @@ -1262,10 +1404,18 @@ static int Direct3D11CreateResources(vout_display_t *vd, video_format_t *fmt)
>          return VLC_ENOMEM;
>      }
>
> -    msg_Dbg(vd, "Direct3D11 resources created");
>      return VLC_SUCCESS;
>  }
>
> +static void Direct3D11DestroyPool(vout_display_t *vd)
> +{
> +    vout_display_sys_t *sys = vd->sys;
> +
> +    if (sys->pool)
> +        picture_pool_Release(sys->pool);
> +    sys->pool = NULL;
> +}
> +
>  static int AllocQuad(vout_display_t *vd, const video_format_t *fmt, d3d_quad_t *quad,
>                       d3d_quad_cfg_t *cfg, ID3D11PixelShader *d3dpixelShader,
>                       const float vertices[4 * sizeof(d3d_vertex_t)])
> @@ -1358,14 +1508,7 @@ static void Direct3D11DestroyResources(vout_display_t *vd)
>  {
>      vout_display_sys_t *sys = vd->sys;
>
> -    /* TODO: Destroy Shaders? */
> -    if (sys->pool) {
> -        picture_sys_t *picsys = sys->picsys;
> -        ID3D11Texture2D_Release(picsys->texture);
> -        ID3D11DeviceContext_Release(picsys->context);
> -        picture_pool_Release(sys->pool);
> -    }
> -    sys->pool = NULL;
> +    Direct3D11DestroyPool(vd);
>
>      ReleaseQuad(&sys->picQuad);
>      Direct3D11DeleteRegions(sys->d3dregion_count, sys->d3dregions);
> @@ -1388,10 +1531,8 @@ static int Direct3D11MapTexture(picture_t *picture)
>      int res;
>      hr = ID3D11DeviceContext_Map(picture->p_sys->context, (ID3D11Resource *)picture->p_sys->texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
>      if( FAILED(hr) )
> -    {
> -        msg_Dbg( picture->p_sys->vd, "failed to map the texture (hr=0x%lX)", hr );
>          return VLC_EGENERIC;
> -    }
> +
>      res = CommonUpdatePicture(picture, NULL, mappedResource.pData, mappedResource.RowPitch);
>      ID3D11DeviceContext_Unmap(picture->p_sys->context,(ID3D11Resource *)picture->p_sys->texture, 0);
>      return res;
> --
> 2.4.0
>



More information about the vlc-devel mailing list