[vlc-devel] [PATCH 3/3] direct3d11: add support for I420 picture pools

Steve Lhomme robux4 at gmail.com
Mon Jul 3 13:26:12 CEST 2017


On Sun, Jul 2, 2017 at 11:38 AM, Steve Lhomme <robux4 at videolabs.io> wrote:
> Allow direct rendering to I420 textures directly in the GPU memory mapped to CPU
> The texture to display is copied to the staging texture just before rendering.
> ---
>  modules/video_chroma/d3d11_fmt.h        |   1 +
>  modules/video_chroma/dxgi_fmt.c         |   1 +
>  modules/video_output/win32/direct3d11.c | 204 +++++++++++++++++++++++++++-----
>  3 files changed, 178 insertions(+), 28 deletions(-)
>
> diff --git a/modules/video_chroma/d3d11_fmt.h b/modules/video_chroma/d3d11_fmt.h
> index 3b461cb1bf..f1651ffa73 100644
> --- a/modules/video_chroma/d3d11_fmt.h
> +++ b/modules/video_chroma/d3d11_fmt.h
> @@ -47,6 +47,7 @@ struct picture_sys_t
>      ID3D11ShaderResourceView      *resourceView[D3D11_MAX_SHADER_VIEW];
>      DXGI_FORMAT                   decoderFormat;
>      DXGI_FORMAT                   formatTexture;
> +    bool                          mapped;
>  };
>
>  #include "../codec/avcodec/va_surface.h"
> diff --git a/modules/video_chroma/dxgi_fmt.c b/modules/video_chroma/dxgi_fmt.c
> index bc462919ca..bacf329cac 100644
> --- a/modules/video_chroma/dxgi_fmt.c
> +++ b/modules/video_chroma/dxgi_fmt.c
> @@ -80,6 +80,7 @@ static const d3d_format_t d3d_formats[] = {
>      { "Y410",     DXGI_FORMAT_Y410,           VLC_CODEC_I444,         10, 1, 1, { DXGI_FORMAT_R10G10B10A2_UNORM } },
>      { "NV11",     DXGI_FORMAT_NV11,           VLC_CODEC_I411,          8, 4, 1, { DXGI_FORMAT_R8_UNORM,           DXGI_FORMAT_R8G8_UNORM} },
>  #endif
> +    { "I420",     DXGI_FORMAT_UNKNOWN,        VLC_CODEC_I420,          8, 2, 2, { DXGI_FORMAT_R8_UNORM,      DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM } },
>      { "R8G8B8A8", DXGI_FORMAT_R8G8B8A8_UNORM, VLC_CODEC_RGBA,          8, 1, 1, { DXGI_FORMAT_R8G8B8A8_UNORM } },
>      { "VA_RGBA",  DXGI_FORMAT_R8G8B8A8_UNORM, VLC_CODEC_D3D11_OPAQUE,  8, 1, 1, { DXGI_FORMAT_R8G8B8A8_UNORM } },
>      { "B8G8R8A8", DXGI_FORMAT_B8G8R8A8_UNORM, VLC_CODEC_BGRA,          8, 1, 1, { DXGI_FORMAT_B8G8R8A8_UNORM } },
> diff --git a/modules/video_output/win32/direct3d11.c b/modules/video_output/win32/direct3d11.c
> index 9b6a879ef5..c0bd23ed03 100644
> --- a/modules/video_output/win32/direct3d11.c
> +++ b/modules/video_output/win32/direct3d11.c
> @@ -99,6 +99,7 @@ typedef struct
>      UINT                       PSConstantsCount;
>      ID3D11PixelShader         *d3dpixelShader;
>      D3D11_VIEWPORT            cropViewport;
> +    const vlc_chroma_description_t *p_chroma_sampling;
>      unsigned int              i_x_offset;
>      unsigned int              i_y_offset;
>      unsigned int              i_width;
> @@ -405,6 +406,47 @@ static void Direct3D11UnmapPoolTexture(picture_t *picture)
>      ID3D11DeviceContext_Unmap(p_sys->context, p_sys->resource[KNOWN_DXGI_INDEX], 0);
>  }
>
> +static int Direct3D11LockDirectTexture(picture_t *picture)
> +{
> +    picture_sys_t *p_sys = picture->p_sys;
> +    D3D11_MAPPED_SUBRESOURCE mappedResource;
> +    HRESULT hr;
> +    D3D11_TEXTURE2D_DESC texDesc;
> +    int i;
> +
> +    for (i = 0; i < picture->i_planes; i++) {
> +        hr = ID3D11DeviceContext_Map(p_sys->context, p_sys->resource[i], 0, D3D11_MAP_WRITE, 0, &mappedResource);
> +        if( FAILED(hr) )
> +            break;
> +        ID3D11Texture2D_GetDesc(p_sys->texture[i], &texDesc);
> +        picture->p[i].p_pixels = mappedResource.pData;
> +        picture->p[i].i_pitch  = mappedResource.RowPitch;
> +        picture->p[i].i_lines  = texDesc.Height;
> +        assert(picture->p[i].i_visible_pitch <= picture->p[i].i_pitch);
> +        assert(picture->p[i].i_visible_lines <= picture->p[i].i_lines);
> +    }
> +
> +    if( FAILED(hr) )
> +    {
> +        while (i-- > 0)
> +            ID3D11DeviceContext_Unmap(p_sys->context, p_sys->resource[i+1], 0);
> +        return VLC_EGENERIC;
> +    }
> +
> +    p_sys->mapped = true;
> +    return VLC_SUCCESS;
> +}
> +
> +static void Direct3D11UnlockDirectTexture(picture_t *picture)
> +{
> +    picture_sys_t *p_sys = picture->p_sys;
> +    if (p_sys->mapped) {
> +        for (int i = 0; i < picture->i_planes; i++)
> +            ID3D11DeviceContext_Unmap(p_sys->context, p_sys->resource[i], 0);
> +        p_sys->mapped = false;
> +    }
> +}
> +
>  #if !VLC_WINSTORE_APP
>  static int OpenHwnd(vout_display_t *vd)
>  {
> @@ -580,7 +622,8 @@ static int AllocateTextures(vout_display_t *vd, const d3d_format_t *cfg,
>                              bool pool_type_display)
>  {
>      vout_display_sys_t *sys = vd->sys;
> -    int plane;
> +    plane_t planes[PICTURE_PLANE_MAX];
> +    int plane, plane_count;
>      HRESULT hr;
>      ID3D11Texture2D *slicedTexture = NULL;
>      D3D11_TEXTURE2D_DESC texDesc;
> @@ -588,31 +631,93 @@ static int AllocateTextures(vout_display_t *vd, const d3d_format_t *cfg,
>      texDesc.MipLevels = 1;
>      texDesc.SampleDesc.Count = 1;
>      texDesc.MiscFlags = 0; //D3D11_RESOURCE_MISC_SHARED;
> -    texDesc.Format = cfg->formatTexture;
> -    texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
> -    if (is_d3d11_opaque(fmt->i_chroma)) {
> -        texDesc.BindFlags |= D3D11_BIND_DECODER;
> -        texDesc.Usage = D3D11_USAGE_DEFAULT;
> -        texDesc.CPUAccessFlags = 0;
> +    const vlc_chroma_description_t *p_chroma_desc = vlc_fourcc_GetChromaDescription( fmt->i_chroma );
> +    if( !p_chroma_desc )
> +        return VLC_EGENERIC;
> +
> +    if (cfg->formatTexture == DXGI_FORMAT_UNKNOWN) {
> +        int i_width_aligned  = fmt->i_width;
> +        int i_height_aligned = fmt->i_height;
> +        if (p_chroma_desc->plane_count == 0)
> +        {
> +            msg_Dbg(vd, "failed to get the pixel format planes for %4.4s", (char *)&fmt->i_chroma);
> +            return VLC_EGENERIC;
> +        }
> +        assert(p_chroma_desc->plane_count <= D3D11_MAX_SHADER_VIEW);
> +        plane_count = p_chroma_desc->plane_count;
> +
> +        texDesc.Format = cfg->resourceFormat[0];
> +        assert(cfg->resourceFormat[1] == cfg->resourceFormat[0]);
> +        assert(cfg->resourceFormat[2] == cfg->resourceFormat[0]);
> +
> +        if (pool_type_display) {
> +            texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
> +            texDesc.Usage = D3D11_USAGE_DEFAULT;
> +        } else {
> +            texDesc.Usage = D3D11_USAGE_STAGING;
> +            texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
> +
> +            /* align on 16 pixel boundaries */
> +            i_width_aligned  = ( i_width_aligned  + 15 ) & ~15;
> +            i_height_aligned = ( i_width_aligned + 15 ) & ~15;

typo, it should be the height

> +        }
> +
> +        for( int i = 0; i < plane_count; i++ )
> +        {
> +            plane_t *p = &planes[i];
> +
> +            p->i_lines         = i_height_aligned * p_chroma_desc->p[i].h.num / p_chroma_desc->p[i].h.den;
> +            p->i_visible_lines = fmt->i_visible_height * p_chroma_desc->p[i].h.num / p_chroma_desc->p[i].h.den;
> +            p->i_pitch         = i_width_aligned * p_chroma_desc->p[i].w.num / p_chroma_desc->p[i].w.den * p_chroma_desc->pixel_size;
> +            p->i_visible_pitch = fmt->i_visible_width * p_chroma_desc->p[i].w.num / p_chroma_desc->p[i].w.den * p_chroma_desc->pixel_size;
> +            p->i_pixel_pitch   = p_chroma_desc->pixel_size;
> +
> +            if (!pool_type_display) {
> +                assert( (p->i_pitch % 16) == 0 );

sub-planes don't need to be aligned to 16 bytes.

> +            }
> +        }
> +
> +        texDesc.ArraySize = 1;
>      } else {
> -        texDesc.Usage = D3D11_USAGE_DYNAMIC;
> -        texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
> -    }
> -    texDesc.ArraySize = pool_size;
> -    texDesc.Height = fmt->i_height;
> -    texDesc.Width = fmt->i_width;
> +        plane_count = 1;
> +        texDesc.Format = cfg->formatTexture;
> +        texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
> +        if (is_d3d11_opaque(fmt->i_chroma)) {
> +            texDesc.BindFlags |= D3D11_BIND_DECODER;
> +            texDesc.Usage = D3D11_USAGE_DEFAULT;
> +            texDesc.CPUAccessFlags = 0;
> +        } else {
> +            texDesc.Usage = D3D11_USAGE_DYNAMIC;
> +            texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
> +        }
> +        texDesc.ArraySize = pool_size;
> +        texDesc.Height = fmt->i_height;
> +        texDesc.Width = fmt->i_width;
>
> -    hr = ID3D11Device_CreateTexture2D( sys->d3ddevice, &texDesc, NULL, &slicedTexture );
> -    if (FAILED(hr)) {
> -        msg_Err(vd, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size, hr);
> -        goto error;
> +        hr = ID3D11Device_CreateTexture2D( sys->d3ddevice, &texDesc, NULL, &slicedTexture );
> +        if (FAILED(hr)) {
> +            msg_Err(vd, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size, hr);
> +            goto error;
> +        }
>      }
>
>      for (unsigned picture_count = 0; picture_count < pool_size; picture_count++) {
> -        textures[picture_count * D3D11_MAX_SHADER_VIEW] = slicedTexture;
> -        ID3D11Texture2D_AddRef(slicedTexture);
> -
> -        for (plane = 1; plane < D3D11_MAX_SHADER_VIEW; plane++) {
> +        for (plane = 0; plane < plane_count; plane++)
> +        {
> +            if (slicedTexture) {
> +                textures[picture_count * D3D11_MAX_SHADER_VIEW + plane] = slicedTexture;
> +                ID3D11Texture2D_AddRef(slicedTexture);
> +            } else {
> +                texDesc.Height = planes[plane].i_lines;
> +                texDesc.Width = planes[plane].i_pitch;
> +                hr = ID3D11Device_CreateTexture2D( sys->d3ddevice, &texDesc, NULL, &textures[picture_count * D3D11_MAX_SHADER_VIEW + plane] );
> +                if (FAILED(hr)) {
> +                    msg_Err(vd, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size, hr);
> +                    goto error;
> +                }
> +            }
> +        }
> +        for (; plane < D3D11_MAX_SHADER_VIEW; plane++) {
>              if (!cfg->resourceFormat[plane])
>                  textures[picture_count * D3D11_MAX_SHADER_VIEW + plane] = NULL;
>              else
> @@ -623,10 +728,8 @@ static int AllocateTextures(vout_display_t *vd, const d3d_format_t *cfg,
>          }
>      }
>
> -    if (!is_d3d11_opaque(fmt->i_chroma)) {
> +    if (!is_d3d11_opaque(fmt->i_chroma) && cfg->formatTexture != DXGI_FORMAT_UNKNOWN) {
>          D3D11_MAPPED_SUBRESOURCE mappedResource;
> -        const vlc_chroma_description_t *p_chroma_desc = vlc_fourcc_GetChromaDescription( fmt->i_chroma );
> -
>          hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource*)textures[0], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
>          if( FAILED(hr) ) {
>              msg_Err(vd, "The texture cannot be mapped. (hr=0x%lX)", hr);
> @@ -677,7 +780,7 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
>      }
>
>      if (AllocateTextures(vd, sys->picQuadConfig, &surface_fmt, pool_size, textures,
> -                         true))
> +                         sys->picQuadConfig->formatTexture != DXGI_FORMAT_UNKNOWN))
>          goto error;
>
>      if (!vd->info.is_slow) {
> @@ -740,6 +843,8 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
>          sys->picQuad.i_width    = staging_fmt.i_width;
>          sys->picQuad.i_height   = staging_fmt.i_height;
>
> +        sys->picQuad.p_chroma_sampling = vlc_fourcc_GetChromaDescription( staging_fmt.i_chroma );
> +
>          for (unsigned plane = 0; plane < D3D11_MAX_SHADER_VIEW; plane++)
>              sys->stagingSys.texture[plane] = textures[plane];
>
> @@ -768,7 +873,12 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
>          return NULL;
>      }
>
> -    if (vd->info.is_slow) {
> +    if (sys->picQuadConfig->formatTexture == DXGI_FORMAT_UNKNOWN)
> +    {
> +        pool_cfg.lock = Direct3D11LockDirectTexture;
> +        pool_cfg.unlock = Direct3D11UnlockDirectTexture;
> +    }
> +    else if (vd->info.is_slow) {
>          pool_cfg.lock          = Direct3D11MapPoolTexture;
>          //pool_cfg.unlock        = Direct3D11UnmapPoolTexture;
>      }
> @@ -1106,7 +1216,38 @@ static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
>          WaitForSingleObjectEx( sys->context_lock, INFINITE, FALSE );
>  #endif
>      picture_sys_t *p_sys = ActivePictureSys(picture);
> -    if (!is_d3d11_opaque(picture->format.i_chroma) || sys->legacy_shader) {
> +    if (picture->p_sys->formatTexture == DXGI_FORMAT_UNKNOWN)
> +    {
> +        Direct3D11UnlockDirectTexture(picture);
> +        for (int plane = 0; plane < D3D11_MAX_SHADER_VIEW; plane++)
> +        {
> +            if (!p_sys->resource[plane])
> +                continue;
> +
> +            unsigned int width  = sys->picQuad.i_width;
> +            unsigned int height = sys->picQuad.i_height;
> +            unsigned int x_offset = picture->format.i_x_offset;
> +            unsigned int y_offset = picture->format.i_y_offset;
> +            x_offset = x_offset * sys->picQuad.p_chroma_sampling->p[plane].h.num / sys->picQuad.p_chroma_sampling->p[plane].h.den;
> +            y_offset = y_offset * sys->picQuad.p_chroma_sampling->p[plane].w.num / sys->picQuad.p_chroma_sampling->p[plane].w.den;
> +            width  = width * sys->picQuad.p_chroma_sampling->p[plane].h.num / sys->picQuad.p_chroma_sampling->p[plane].h.den;
> +            height = height * sys->picQuad.p_chroma_sampling->p[plane].w.num / sys->picQuad.p_chroma_sampling->p[plane].w.den;
> +
> +            D3D11_BOX box = {
> +                .top = y_offset,
> +                .bottom = y_offset + height,
> +                .left = x_offset,
> +                .right = x_offset + width,
> +                .back = 1,
> +            };
> +            ID3D11DeviceContext_CopySubresourceRegion(sys->d3dcontext,
> +                                                      sys->stagingSys.resource[plane],
> +                                                      0, 0, 0, 0,
> +                                                      p_sys->resource[plane],
> +                                                      0, &box);
> +        }
> +    }
> +    else if (!is_d3d11_opaque(picture->format.i_chroma) || sys->legacy_shader) {
>          D3D11_TEXTURE2D_DESC texDesc;
>          if (!is_d3d11_opaque(picture->format.i_chroma))
>              Direct3D11UnmapPoolTexture(picture);
> @@ -1745,6 +1886,13 @@ static HRESULT CompilePixelShader(vout_display_t *vd, const d3d_format_t *format
>          psz_sampler =
>                  "sample = shaderTexture[0].Sample(SampleType, In.Texture);";
>          break;
> +    case DXGI_FORMAT_UNKNOWN:
> +        psz_sampler =
> +               "sample.x  = shaderTexture[0].Sample(SampleType, In.Texture).x;\
> +                sample.y  = shaderTexture[1].Sample(SampleType, In.Texture).x;\
> +                sample.z  = shaderTexture[2].Sample(SampleType, In.Texture).x;\
> +                sample.a  = 1;";
> +        break;
>      default:
>          vlc_assert_unreachable();
>      }
> @@ -2108,7 +2256,7 @@ static int Direct3D11CreateResources(vout_display_t *vd, video_format_t *fmt)
>      }
>
>      sys->legacy_shader = !CanUseTextureArray(vd);
> -    vd->info.is_slow = !is_d3d11_opaque(fmt->i_chroma);
> +    vd->info.is_slow = !is_d3d11_opaque(fmt->i_chroma) && sys->picQuadConfig->formatTexture != DXGI_FORMAT_UNKNOWN;
>
>      hr = CompilePixelShader(vd, sys->picQuadConfig, fmt->transfer, fmt->b_color_range_full, &sys->picQuadPixelShader);
>      if (FAILED(hr))
> --
> 2.13.0
>


More information about the vlc-devel mailing list