[vlc-commits] dxva: balance the surface API and avoid dirty casts

Steve Lhomme git at videolan.org
Tue Oct 8 15:56:11 CEST 2019


vlc | branch: master | Steve Lhomme <robux4 at ycbcr.xyz> | Fri Sep 13 14:32:18 2019 +0200| [fc8b0c8d0b53c3b1fb77a76a40b0345f28284a3f] | committer: Steve Lhomme

dxva: balance the surface API and avoid dirty casts

d3d11va/dxva2 only get a va_surface from the API and deal with the references.

They need to create a copy of the internal picture context so it's not released
when the picture is finished in the display. A copy also increments the surface
refcount, so we need to release one after the copy.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=fc8b0c8d0b53c3b1fb77a76a40b0345f28284a3f
---

 modules/codec/avcodec/d3d11va.c             | 29 +++++++++++++++++------------
 modules/codec/avcodec/dxva2.c               | 29 +++++++++++++++++------------
 modules/codec/avcodec/va_surface.c          | 22 +++++++++++++---------
 modules/codec/avcodec/va_surface_internal.h |  4 +++-
 4 files changed, 50 insertions(+), 34 deletions(-)

diff --git a/modules/codec/avcodec/d3d11va.c b/modules/codec/avcodec/d3d11va.c
index 3b4e89c6c0..532a03fa00 100644
--- a/modules/codec/avcodec/d3d11va.c
+++ b/modules/codec/avcodec/d3d11va.c
@@ -154,12 +154,10 @@ static void SetupAVCodecContext(vlc_va_sys_t *sys, unsigned surfaces)
 static void d3d11va_pic_context_destroy(picture_context_t *opaque)
 {
     struct d3d11va_pic_context *pic_ctx = D3D11VA_PICCONTEXT_FROM_PICCTX(opaque);
-    if (pic_ctx->va_surface)
-    {
-        ReleaseD3D11PictureSys(&pic_ctx->ctx.picsys);
-        va_surface_Release(pic_ctx->va_surface);
-        free(pic_ctx);
-    }
+    struct vlc_va_surface_t *va_surface = pic_ctx->va_surface;
+    d3d11_pic_context_destroy(&pic_ctx->ctx.s);
+    if (va_surface)
+        va_surface_Release(va_surface);
 }
 
 static struct d3d11va_pic_context *CreatePicContext(ID3D11VideoDecoderOutputView *,
@@ -176,10 +174,9 @@ static picture_context_t *d3d11va_pic_context_copy(picture_context_t *ctx)
                                                       src_ctx->ctx.picsys.slice_index, src_ctx->ctx.picsys.renderSrc);
     if (unlikely(pic_ctx==NULL))
         return NULL;
-    if (src_ctx->va_surface) {
-        pic_ctx->va_surface = src_ctx->va_surface;
+    pic_ctx->va_surface = src_ctx->va_surface;
+    if (pic_ctx->va_surface)
         va_surface_AddRef(pic_ctx->va_surface);
-    }
     return &pic_ctx->ctx.s;
 }
 
@@ -288,10 +285,18 @@ static int Get(vlc_va_t *va, picture_t *pic, uint8_t **data)
     else
 #endif
     {
-        picture_context_t *pic_ctx = va_pool_Get(&sys->va_pool);
-        if (unlikely(pic_ctx == NULL))
+        vlc_va_surface_t *va_surface = va_pool_Get(&sys->va_pool);
+        if (unlikely(va_surface == NULL))
+            return VLC_ENOITEM;
+        picture_context_t *pic_ctx = va_surface_GetContext(va_surface);
+        pic->context = pic_ctx->copy(pic_ctx);
+        if (unlikely(pic->context == NULL))
+        {
+            va_surface_Release(va_surface);
             return VLC_ENOITEM;
-        pic->context = pic_ctx;
+        }
+        // the internal copy adds an extra reference we already had with va_pool_Get()
+        va_surface_Release(va_surface);
     }
     *data = (uint8_t*)D3D11VA_PICCONTEXT_FROM_PICCTX(pic->context)->ctx.picsys.decoder;
     return VLC_SUCCESS;
diff --git a/modules/codec/avcodec/dxva2.c b/modules/codec/avcodec/dxva2.c
index 350e7f08a0..325a5fb64a 100644
--- a/modules/codec/avcodec/dxva2.c
+++ b/modules/codec/avcodec/dxva2.c
@@ -161,20 +161,17 @@ static void SetupAVCodecContext(vlc_va_sys_t *sys, unsigned surfaces)
 
 static void dxva2_pic_context_destroy(picture_context_t *opaque)
 {
-    struct dxva2_pic_context *pic_ctx = (struct dxva2_pic_context*)opaque;
-    if (pic_ctx->va_surface)
-    {
-        ReleaseD3D9PictureSys(&pic_ctx->ctx.picsys);
-        va_surface_Release(pic_ctx->va_surface);
-        free(pic_ctx);
-    }
+    struct dxva2_pic_context *pic_ctx = DXVA2_PICCONTEXT_FROM_PICCTX(opaque);
+    struct vlc_va_surface_t *va_surface = pic_ctx->va_surface;
+    d3d9_pic_context_destroy(&pic_ctx->ctx.s);
+    va_surface_Release(va_surface);
 }
 
 static struct dxva2_pic_context *CreatePicContext(IDirect3DSurface9 *, IDirectXVideoDecoder *);
 
 static picture_context_t *dxva2_pic_context_copy(picture_context_t *ctx)
 {
-    struct dxva2_pic_context *src_ctx = (struct dxva2_pic_context*)ctx;
+    struct dxva2_pic_context *src_ctx = DXVA2_PICCONTEXT_FROM_PICCTX(ctx);
     struct dxva2_pic_context *pic_ctx = CreatePicContext(src_ctx->ctx.picsys.surface, src_ctx->ctx.picsys.decoder);
     if (unlikely(pic_ctx==NULL))
         return NULL;
@@ -225,12 +222,20 @@ static int Get(vlc_va_t *va, picture_t *pic, uint8_t **data)
         return VLC_EGENERIC;
     }
 
-    picture_context_t *pic_ctx = va_pool_Get(&sys->va_pool);
-    if (likely(pic_ctx==NULL))
+    vlc_va_surface_t *va_surface = va_pool_Get(&sys->va_pool);
+    if (unlikely(va_surface==NULL))
         return VLC_ENOITEM;
 
-    pic->context = pic_ctx;
-    *data = (uint8_t*)DXVA2_PICCONTEXT_FROM_PICCTX(pic->context)->ctx.picsys.surface;
+    picture_context_t *pic_ctx = va_surface_GetContext(va_surface);
+    pic->context = pic_ctx->copy(pic_ctx);
+    if (unlikely(pic->context == NULL))
+    {
+        va_surface_Release(va_surface);
+        return VLC_ENOITEM;
+    }
+    // the internal copy adds an extra reference we already had with va_pool_Get()
+    va_surface_Release(va_surface);
+    *data = (uint8_t*)DXVA2_PICCONTEXT_FROM_PICCTX(pic_ctx)->ctx.picsys.surface;
     return VLC_SUCCESS;
 }
 
diff --git a/modules/codec/avcodec/va_surface.c b/modules/codec/avcodec/va_surface.c
index 05617b0ddc..e055ee0120 100644
--- a/modules/codec/avcodec/va_surface.c
+++ b/modules/codec/avcodec/va_surface.c
@@ -39,7 +39,7 @@
 #include "avcodec.h"
 
 struct vlc_va_surface_t {
-    atomic_uintptr_t     refcount;
+    atomic_uintptr_t     refcount; // 1 ref for the surface existance, 1 per surface/clone in-flight
     picture_context_t    *pic_va_ctx;
 };
 
@@ -118,7 +118,7 @@ done:
     return err;
 }
 
-static picture_context_t *GetSurface(va_pool_t *va_pool)
+static vlc_va_surface_t *GetSurface(va_pool_t *va_pool)
 {
     for (unsigned i = 0; i < va_pool->surface_count; i++) {
         vlc_va_surface_t *surface = va_pool->surface[i];
@@ -126,25 +126,24 @@ static picture_context_t *GetSurface(va_pool_t *va_pool)
 
         if (atomic_compare_exchange_strong(&surface->refcount, &expected, 2))
         {
-            picture_context_t *pic_ctx = surface->pic_va_ctx;
-            picture_context_t *field = pic_ctx->copy(pic_ctx);
             /* the copy should have added an extra reference */
             atomic_fetch_sub(&surface->refcount, 1);
-            return field;
+            va_surface_AddRef(surface);
+            return surface;
         }
     }
     return NULL;
 }
 
-picture_context_t *va_pool_Get(va_pool_t *va_pool)
+vlc_va_surface_t *va_pool_Get(va_pool_t *va_pool)
 {
     unsigned tries = (VLC_TICK_FROM_SEC(1) + VOUT_OUTMEM_SLEEP) / VOUT_OUTMEM_SLEEP;
-    picture_context_t *field;
+    vlc_va_surface_t *surface;
 
     if (va_pool->surface_count == 0)
         return NULL;
 
-    while ((field = GetSurface(va_pool)) == NULL)
+    while ((surface = GetSurface(va_pool)) == NULL)
     {
         if (--tries == 0)
             return NULL;
@@ -152,7 +151,12 @@ picture_context_t *va_pool_Get(va_pool_t *va_pool)
          * XXX: Both this and the core should use a semaphore or a CV. */
         vlc_tick_sleep(VOUT_OUTMEM_SLEEP);
     }
-    return field;
+    return surface;
+}
+
+picture_context_t *va_surface_GetContext(vlc_va_surface_t *surface)
+{
+    return surface->pic_va_ctx;
 }
 
 void va_surface_AddRef(vlc_va_surface_t *surface)
diff --git a/modules/codec/avcodec/va_surface_internal.h b/modules/codec/avcodec/va_surface_internal.h
index 6d451e233a..040a1bff53 100644
--- a/modules/codec/avcodec/va_surface_internal.h
+++ b/modules/codec/avcodec/va_surface_internal.h
@@ -77,7 +77,9 @@ struct va_pool_cfg {
 int va_pool_Open(vlc_va_t *, const struct va_pool_cfg *, va_pool_t *);
 void va_pool_Close(vlc_va_t *va, va_pool_t *);
 int va_pool_SetupDecoder(vlc_va_t *, va_pool_t *, const AVCodecContext *, const video_format_t *, unsigned count);
-picture_context_t *va_pool_Get(va_pool_t *);
+vlc_va_surface_t *va_pool_Get(va_pool_t *);
+
+picture_context_t *va_surface_GetContext(vlc_va_surface_t *);
 void va_surface_AddRef(vlc_va_surface_t *surface);
 void va_surface_Release(vlc_va_surface_t *surface);
 



More information about the vlc-commits mailing list