[vlc-devel] [PATCH] direct3d11: simplify the I420 handling

Steve Lhomme robux4 at videolabs.io
Mon Oct 16 13:25:33 CEST 2017


Rather than use buffers in the GPU and then copy in the staging texture, use
CPU buffers and copy in the staging texture from there.

Fixes #18766

---
In Direct3D9 we can create I420 textures, but given the fast speed to read/write
from these buffers it's unlikely to be in the GPU. There must be a copy later
when actually displaying those.
---
 modules/video_chroma/d3d11_fmt.h        |   1 -
 modules/video_output/win32/direct3d11.c | 324 +++++++++++++-------------------
 2 files changed, 131 insertions(+), 194 deletions(-)

diff --git a/modules/video_chroma/d3d11_fmt.h b/modules/video_chroma/d3d11_fmt.h
index db462111ba..d88c3d2419 100644
--- a/modules/video_chroma/d3d11_fmt.h
+++ b/modules/video_chroma/d3d11_fmt.h
@@ -46,7 +46,6 @@ struct picture_sys_t
     ID3D11VideoProcessorOutputView *processorOutput; /* when used as processor output */
     ID3D11ShaderResourceView      *resourceView[D3D11_MAX_SHADER_VIEW];
     DXGI_FORMAT                   formatTexture;
-    bool                          mapped;
 };
 
 #include "../codec/avcodec/va_surface.h"
diff --git a/modules/video_output/win32/direct3d11.c b/modules/video_output/win32/direct3d11.c
index b8241f3df4..5914d65487 100644
--- a/modules/video_output/win32/direct3d11.c
+++ b/modules/video_output/win32/direct3d11.c
@@ -412,47 +412,6 @@ 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 = ActivePictureSys(picture);
-    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)
 {
@@ -623,9 +582,8 @@ static void Close(vlc_object_t *object)
 }
 
 static int AllocateTextures(vout_display_t *vd, const d3d_format_t *cfg,
-                            video_format_t *fmt, unsigned pool_size,
-                            ID3D11Texture2D *textures[],
-                            bool pool_type_display)
+                            const video_format_t *fmt, unsigned pool_size,
+                            ID3D11Texture2D *textures[])
 {
     vout_display_sys_t *sys = vd->sys;
     plane_t planes[PICTURE_PLANE_MAX];
@@ -637,13 +595,22 @@ 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.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;
+
     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);
@@ -656,47 +623,19 @@ static int AllocateTextures(vout_display_t *vd, const d3d_format_t *cfg,
         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_height_aligned + 15 ) & ~15;
-        }
-
         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_lines         = fmt->i_height * 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_pitch         = fmt->i_width * 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( (planes[0].i_pitch % 16) == 0 );
-        }
-
-        texDesc.ArraySize = 1;
     } else {
         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;
 
@@ -767,9 +706,7 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
     ID3D11Texture2D  *textures[pool_size * D3D11_MAX_SHADER_VIEW];
     picture_t **pictures = NULL;
     picture_t *picture;
-    unsigned  plane;
     unsigned  picture_count = 0;
-    picture_pool_configuration_t pool_cfg = {};
 
     if (sys->sys.pool)
         return sys->sys.pool;
@@ -781,10 +718,6 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
     surface_fmt.i_width  = sys->picQuad.i_width;
     surface_fmt.i_height = sys->picQuad.i_height;
 
-    if (AllocateTextures(vd, sys->picQuadConfig, &surface_fmt, pool_size, textures,
-                         sys->picQuadConfig->formatTexture != DXGI_FORMAT_UNKNOWN))
-        goto error;
-
     if (!vd->info.is_slow) {
         HRESULT           hr;
         ID3D10Multithread *pMultithread;
@@ -795,44 +728,50 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
         }
     }
 
-    pictures = calloc(pool_size, sizeof(*pictures));
-    if (!pictures)
-        goto error;
+    if (sys->picQuadConfig->formatTexture != DXGI_FORMAT_UNKNOWN)
+    {
+        if (AllocateTextures(vd, sys->picQuadConfig, &surface_fmt, pool_size, textures))
+            goto error;
 
-    for (picture_count = 0; picture_count < pool_size; picture_count++) {
-        picture_sys_t *picsys = calloc(1, sizeof(*picsys));
-        if (unlikely(picsys == NULL))
+        pictures = calloc(pool_size, sizeof(*pictures));
+        if (!pictures)
             goto error;
 
-        for (plane = 0; plane < D3D11_MAX_SHADER_VIEW; plane++)
-            picsys->texture[plane] = textures[picture_count * D3D11_MAX_SHADER_VIEW + plane];
+        for (picture_count = 0; picture_count < pool_size; picture_count++) {
+            picture_sys_t *picsys = calloc(1, sizeof(*picsys));
+            if (unlikely(picsys == NULL))
+                goto error;
 
-        picsys->slice_index = picture_count;
-        picsys->formatTexture = sys->picQuadConfig->formatTexture;
-        picsys->context = sys->d3dcontext;
+            for (unsigned plane = 0; plane < D3D11_MAX_SHADER_VIEW; plane++)
+                picsys->texture[plane] = textures[picture_count * D3D11_MAX_SHADER_VIEW + plane];
 
-        picture_resource_t resource = {
-            .p_sys = picsys,
-            .pf_destroy = DestroyDisplayPoolPicture,
-        };
+            picsys->slice_index = picture_count;
+            picsys->formatTexture = sys->picQuadConfig->formatTexture;
+            picsys->context = sys->d3dcontext;
 
-        picture = picture_NewFromResource(&surface_fmt, &resource);
-        if (unlikely(picture == NULL)) {
-            free(picsys);
-            msg_Err( vd, "Failed to create picture %d in the pool.", picture_count );
-            goto error;
-        }
+            picture_resource_t resource = {
+                .p_sys = picsys,
+                .pf_destroy = DestroyDisplayPoolPicture,
+            };
 
-        pictures[picture_count] = picture;
-        /* each picture_t holds a ref to the context and release it on Destroy */
-        ID3D11DeviceContext_AddRef(picsys->context);
+            picture = picture_NewFromResource(&surface_fmt, &resource);
+            if (unlikely(picture == NULL)) {
+                free(picsys);
+                msg_Err( vd, "Failed to create picture %d in the pool.", picture_count );
+                goto error;
+            }
+
+            pictures[picture_count] = picture;
+            /* each picture_t holds a ref to the context and release it on Destroy */
+            ID3D11DeviceContext_AddRef(picsys->context);
+        }
     }
 
 #ifdef HAVE_ID3D11VIDEODECODER
     if (!is_d3d11_opaque(surface_fmt.i_chroma) || sys->legacy_shader)
     {
         /* we need a staging texture */
-        if (AllocateTextures(vd, sys->picQuadConfig, &surface_fmt, 1, textures, true))
+        if (AllocateTextures(vd, sys->picQuadConfig, &surface_fmt, 1, textures))
             goto error;
 
         sys->picQuad.p_chroma_sampling = vlc_fourcc_GetChromaDescription( surface_fmt.i_chroma );
@@ -862,20 +801,25 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
     }
 
     if (sys->picQuadConfig->formatTexture == DXGI_FORMAT_UNKNOWN)
+        sys->sys.pool = picture_pool_NewFromFormat( &surface_fmt, pool_size );
+    else
     {
-        pool_cfg.lock = Direct3D11LockDirectTexture;
-        pool_cfg.unlock = Direct3D11UnlockDirectTexture;
-    }
-    else if (vd->info.is_slow) {
-        pool_cfg.lock          = Direct3D11MapPoolTexture;
-        //pool_cfg.unlock        = Direct3D11UnmapPoolTexture;
+        picture_pool_configuration_t pool_cfg = {
+            .picture       = pictures,
+            .picture_count = pool_size,
+        };
+        if (vd->info.is_slow) {
+            pool_cfg.lock          = Direct3D11MapPoolTexture;
+            //pool_cfg.unlock        = Direct3D11UnmapPoolTexture;
+        }
+        sys->sys.pool = picture_pool_NewExtended( &pool_cfg );
     }
-    pool_cfg.picture       = pictures;
-    pool_cfg.picture_count = pool_size;
-    sys->sys.pool = picture_pool_NewExtended( &pool_cfg );
 
 error:
     if (sys->sys.pool == NULL) {
+        picture_pool_configuration_t pool_cfg = {
+            .picture_count = 0,
+        };
         if (pictures) {
             msg_Dbg(vd, "Failed to create the picture d3d11 pool");
             for (unsigned i=0;i<picture_count; ++i)
@@ -884,7 +828,6 @@ error:
         }
 
         /* create an empty pool to avoid crashing */
-        pool_cfg.picture_count = 0;
         sys->sys.pool = picture_pool_NewExtended( &pool_cfg );
     } else {
         msg_Dbg(vd, "D3D11 pool succeed with %d surfaces (%dx%d) context 0x%p",
@@ -1254,92 +1197,87 @@ static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
 {
     vout_display_sys_t *sys = vd->sys;
 
-    picture_sys_t *p_sys = ActivePictureSys(picture);
-
-#if defined(HAVE_ID3D11VIDEODECODER)
-    if (sys->context_lock != INVALID_HANDLE_VALUE && is_d3d11_opaque(picture->format.i_chroma))
-        WaitForSingleObjectEx( sys->context_lock, INFINITE, FALSE );
-#endif
-    if (p_sys->formatTexture == DXGI_FORMAT_UNKNOWN)
+    if (sys->picQuadConfig->formatTexture == DXGI_FORMAT_UNKNOWN)
     {
-        Direct3D11UnlockDirectTexture(picture);
-        for (int plane = 0; plane < D3D11_MAX_SHADER_VIEW; plane++)
-        {
-            if (!p_sys->resource[plane])
-                continue;
+        D3D11_MAPPED_SUBRESOURCE mappedResource;
+        D3D11_TEXTURE2D_DESC texDesc;
+        int i;
+        HRESULT hr;
 
-            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;
+        for (i = 0; i < picture->i_planes; i++) {
+            hr = ID3D11DeviceContext_Map(sys->d3dcontext, sys->stagingSys.resource[i],
+                                         0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
+            if( FAILED(hr) )
+                break;
+            ID3D11Texture2D_GetDesc(sys->stagingSys.texture[i], &texDesc);
+            plane_t texture_plane;
+            texture_plane.i_lines = texDesc.Height;
+            texture_plane.i_pitch = mappedResource.RowPitch;
+            texture_plane.p_pixels = mappedResource.pData;
+            texture_plane.i_visible_lines = picture->p[i].i_visible_lines;
+            texture_plane.i_visible_pitch = picture->p[i].i_visible_pitch;
+            plane_CopyPixels(&texture_plane, &picture->p[i]);
+            ID3D11DeviceContext_Unmap(sys->d3dcontext, sys->stagingSys.resource[i], 0);
+        }
+    }
+    else
+    {
+        picture_sys_t *p_sys = ActivePictureSys(picture);
 
+#if defined(HAVE_ID3D11VIDEODECODER)
+        if (sys->context_lock != INVALID_HANDLE_VALUE && is_d3d11_opaque(picture->format.i_chroma))
+            WaitForSingleObjectEx( sys->context_lock, INFINITE, FALSE );
+#endif
+        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);
+            ID3D11Texture2D_GetDesc(sys->stagingSys.texture[0], &texDesc);
             D3D11_BOX box = {
-                .top = y_offset,
-                .bottom = y_offset + height,
-                .left = x_offset,
-                .right = x_offset + width,
+                .top = 0,
+                .bottom = picture->format.i_y_offset + picture->format.i_visible_height,
+                .left = 0,
+                .right = picture->format.i_x_offset + picture->format.i_visible_width,
                 .back = 1,
             };
+            if ( sys->picQuadConfig->formatTexture != DXGI_FORMAT_R8G8B8A8_UNORM &&
+                 sys->picQuadConfig->formatTexture != DXGI_FORMAT_B5G6R5_UNORM )
+            {
+                box.bottom = (box.bottom + 0x01) & ~0x01;
+                box.right  = (box.right  + 0x01) & ~0x01;
+            }
+            assert(box.right <= texDesc.Width);
+            assert(box.bottom <= texDesc.Height);
             ID3D11DeviceContext_CopySubresourceRegion(sys->d3dcontext,
-                                                      sys->stagingSys.resource[plane],
+                                                      sys->stagingSys.resource[KNOWN_DXGI_INDEX],
                                                       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);
-        ID3D11Texture2D_GetDesc(sys->stagingSys.texture[0], &texDesc);
-        D3D11_BOX box = {
-            .top = 0,
-            .bottom = picture->format.i_y_offset + picture->format.i_visible_height,
-            .left = 0,
-            .right = picture->format.i_x_offset + picture->format.i_visible_width,
-            .back = 1,
-        };
-        if ( sys->picQuadConfig->formatTexture != DXGI_FORMAT_R8G8B8A8_UNORM &&
-             sys->picQuadConfig->formatTexture != DXGI_FORMAT_B5G6R5_UNORM )
-        {
-            box.bottom = (box.bottom + 0x01) & ~0x01;
-            box.right  = (box.right  + 0x01) & ~0x01;
+                                                      p_sys->resource[KNOWN_DXGI_INDEX],
+                                                      p_sys->slice_index, &box);
         }
-        assert(box.right <= texDesc.Width);
-        assert(box.bottom <= texDesc.Height);
-        ID3D11DeviceContext_CopySubresourceRegion(sys->d3dcontext,
-                                                  sys->stagingSys.resource[KNOWN_DXGI_INDEX],
-                                                  0, 0, 0, 0,
-                                                  p_sys->resource[KNOWN_DXGI_INDEX],
-                                                  p_sys->slice_index, &box);
-    }
-    else
-    {
-        D3D11_TEXTURE2D_DESC texDesc;
-        ID3D11Texture2D_GetDesc(p_sys->texture[0], &texDesc);
-        if (texDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE)
+        else
         {
-            /* for performance reason we don't want to allocate this during
-             * display, do it preferrably when creating the texture */
-            assert(p_sys->resourceView[0]!=NULL);
-        }
+            D3D11_TEXTURE2D_DESC texDesc;
+            ID3D11Texture2D_GetDesc(p_sys->texture[0], &texDesc);
+            if (texDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE)
+            {
+                /* for performance reason we don't want to allocate this during
+                 * display, do it preferrably when creating the texture */
+                assert(p_sys->resourceView[0]!=NULL);
+            }
 
-        if ( sys->picQuad.i_height != texDesc.Height ||
-             sys->picQuad.i_width != texDesc.Width )
-        {
-            /* the decoder produced different sizes than the vout, we need to
-             * adjust the vertex */
-            sys->picQuad.i_height = texDesc.Height;
-            sys->picQuad.i_width = texDesc.Width;
-
-            BEFORE_UPDATE_RECTS;
-            UpdateRects(vd, NULL, true);
-            AFTER_UPDATE_RECTS;
-            UpdateSize(vd);
+            if ( sys->picQuad.i_height != texDesc.Height ||
+                 sys->picQuad.i_width != texDesc.Width )
+            {
+                /* the decoder produced different sizes than the vout, we need to
+                 * adjust the vertex */
+                sys->picQuad.i_height = texDesc.Height;
+                sys->picQuad.i_width = texDesc.Width;
+
+                BEFORE_UPDATE_RECTS;
+                UpdateRects(vd, NULL, true);
+                AFTER_UPDATE_RECTS;
+                UpdateSize(vd);
+            }
         }
     }
 
@@ -3051,7 +2989,7 @@ static int Direct3D11MapSubpicture(vout_display_t *vd, int *subpicture_region_co
             if (unlikely(d3dquad==NULL)) {
                 continue;
             }
-            if (AllocateTextures(vd, sys->d3dregion_format, &r->fmt, 1, textures, true)) {
+            if (AllocateTextures(vd, sys->d3dregion_format, &r->fmt, 1, textures)) {
                 msg_Err(vd, "Failed to allocate %dx%d texture for OSD",
                         r->fmt.i_visible_width, r->fmt.i_visible_height);
                 for (int i=0; i<D3D11_MAX_SHADER_VIEW; i++)
-- 
2.14.2



More information about the vlc-devel mailing list