[Libva] [PATCH v5 intel-driver 11/11] decoder: h264: fix frame store logic for MVC.

Xiang, Haihao haihao.xiang at intel.com
Mon Jun 9 06:57:46 PDT 2014


I am OK with the patch if you can remove the redundant line (see below) when 
You push the code.

Thanks
Haihao

> -----Original Message-----
> From: Libva [mailto:libva-bounces at lists.freedesktop.org] On Behalf Of
> Gwenole Beauchesne
> Sent: Friday, June 06, 2014 5:16 PM
> To: libva at lists.freedesktop.org
> Subject: [Libva] [PATCH v5 intel-driver 11/11] decoder: h264: fix frame store
> logic for MVC.
> 
> In strict MVC decoding mode, when only the necessary set of inter-view
> reference pictures are passed to the ReferenceFrames array for decoding the
> current picture, we should not re-use a frame store id that might be needed for
> decoding another view component in the same access unit.
> 
> One way to solve this problem is to track when the VA surface in a specified
> frame store id was last referenced. So, a "ref_age" field is introduced to the
> GenFrameStore struct and is updated whenever the surface is being
> referenced.
> 
> Additionally, the list of retired refs candidates (free_refs) is kept ordered by
> increasing ref_age. That way, we can immediately know what is the oldest
> frame store id to recycle.
> 
> Let deltaAge = CurrAge - RefAge:
> If deltaAge > 1, we know for sure that the VA surface is gone ; If deltaAge = 1,
> the surface could be re-used for inter prediction ; If deltaAge = 0, the surface
> could be re-used for inter-view prediction.
> 
> The ref_age in each Frame Store entry is always current, i.e. it is the same for
> all reference frames that intervened in the decoding process of all inter view
> components of the previous access unit. The age tracks access units.
> 
> Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne at intel.com>
> ---
>  src/gen6_mfd.c           |    4 +-
>  src/gen6_mfd.h           |    1 +
>  src/gen75_mfd.c          |    1 +
>  src/gen7_mfd.c           |    4 +-
>  src/gen7_mfd.h           |    1 +
>  src/gen8_mfd.c           |    6 +--
>  src/i965_avc_bsd.c       |    4 +-
>  src/i965_decoder.h       |   15 ++++++
>  src/i965_decoder_utils.c |  114
> +++++++++++++++++++++++++++++++---------------
>  src/i965_decoder_utils.h |   11 +++--
>  src/i965_media_h264.h    |    1 +
>  src/intel_media.h        |    1 +
>  12 files changed, 115 insertions(+), 48 deletions(-)
> 
> diff --git a/src/gen6_mfd.c b/src/gen6_mfd.c index 437ad3b..8128a80 100755
> --- a/src/gen6_mfd.c
> +++ b/src/gen6_mfd.c
> @@ -61,6 +61,7 @@ gen6_mfd_init_avc_surface(VADriverContextP ctx,
> 
>      if (!gen6_avc_surface) {
>          gen6_avc_surface = calloc(sizeof(GenAvcSurface), 1);
> +        gen6_avc_surface->frame_store_id = -1;
>          assert((obj_surface->size & 0x3f) == 0);
>          obj_surface->private_data = gen6_avc_surface;
>      }
> @@ -825,7 +826,8 @@ gen6_mfd_avc_decode_init(VADriverContextP ctx,
> 
>      assert(decode_state->pic_param && decode_state->pic_param->buffer);
>      pic_param = (VAPictureParameterBufferH264
> *)decode_state->pic_param->buffer;
> -    intel_update_avc_frame_store_index(ctx, decode_state, pic_param,
> gen6_mfd_context->reference_surface);
> +    intel_update_avc_frame_store_index(ctx, decode_state, pic_param,
> +        gen6_mfd_context->reference_surface,
> + &gen6_mfd_context->fs_ctx);
>      width_in_mbs = ((pic_param->picture_width_in_mbs_minus1 + 1) &
> 0xff);
> 
>      /* Current decoded picture */
> diff --git a/src/gen6_mfd.h b/src/gen6_mfd.h index de131d6..f499803 100644
> --- a/src/gen6_mfd.h
> +++ b/src/gen6_mfd.h
> @@ -62,6 +62,7 @@ struct gen6_mfd_context
>          VAIQMatrixBufferMPEG2 mpeg2;
>      } iq_matrix;
> 
> +    GenFrameStoreContext fs_ctx;
>      GenFrameStore
> reference_surface[MAX_GEN_REFERENCE_FRAMES];
>      GenBuffer           post_deblocking_output;
>      GenBuffer           pre_deblocking_output;
> diff --git a/src/gen75_mfd.c b/src/gen75_mfd.c index 67d4c51..1a068ec
> 100644
> --- a/src/gen75_mfd.c
> +++ b/src/gen75_mfd.c
> @@ -67,6 +67,7 @@ gen75_mfd_init_avc_surface(VADriverContextP ctx,
> 
>      if (!gen7_avc_surface) {
>          gen7_avc_surface = calloc(sizeof(GenAvcSurface), 1);
> +        gen7_avc_surface->frame_store_id = -1;
>          assert((obj_surface->size & 0x3f) == 0);
>          obj_surface->private_data = gen7_avc_surface;
>      }
> diff --git a/src/gen7_mfd.c b/src/gen7_mfd.c index 4141b83..07466b1 100755
> --- a/src/gen7_mfd.c
> +++ b/src/gen7_mfd.c
> @@ -65,6 +65,7 @@ gen7_mfd_init_avc_surface(VADriverContextP ctx,
> 
>      if (!gen7_avc_surface) {
>          gen7_avc_surface = calloc(sizeof(GenAvcSurface), 1);
> +        gen7_avc_surface->frame_store_id = -1;
>          assert((obj_surface->size & 0x3f) == 0);
>          obj_surface->private_data = gen7_avc_surface;
>      }
> @@ -740,7 +741,8 @@ gen7_mfd_avc_decode_init(VADriverContextP ctx,
> 
>      assert(decode_state->pic_param && decode_state->pic_param->buffer);
>      pic_param = (VAPictureParameterBufferH264
> *)decode_state->pic_param->buffer;
> -    intel_update_avc_frame_store_index(ctx, decode_state, pic_param,
> gen7_mfd_context->reference_surface);
> +    intel_update_avc_frame_store_index(ctx, decode_state, pic_param,
> +        gen7_mfd_context->reference_surface,
> + &gen7_mfd_context->fs_ctx);
>      width_in_mbs = pic_param->picture_width_in_mbs_minus1 + 1;
>      height_in_mbs = pic_param->picture_height_in_mbs_minus1 + 1;
>      assert(width_in_mbs > 0 && width_in_mbs <= 256); /* 4K */ diff --git
> a/src/gen7_mfd.h b/src/gen7_mfd.h index 0200216..af8e960 100644
> --- a/src/gen7_mfd.h
> +++ b/src/gen7_mfd.h
> @@ -77,6 +77,7 @@ struct gen7_mfd_context
>          VAIQMatrixBufferH264  h264;     /* flat scaling lists (default) */
>      } iq_matrix;
> 
> +    GenFrameStoreContext fs_ctx;
>      GenFrameStore
> reference_surface[MAX_GEN_REFERENCE_FRAMES];
>      GenBuffer           post_deblocking_output;
>      GenBuffer           pre_deblocking_output;
> diff --git a/src/gen8_mfd.c b/src/gen8_mfd.c index 065302d..1a3d063 100644
> --- a/src/gen8_mfd.c
> +++ b/src/gen8_mfd.c
> @@ -27,10 +27,7 @@
>   *
>   */
> 
> -#include <stdio.h>
> -#include <stdlib.h>
> -#include <string.h>
> -#include <assert.h>
> +#include "sysdeps.h"
>  #include <math.h>
>  #include <va/va_dec_jpeg.h>
>  #include <va/va_dec_vp8.h>
> @@ -74,6 +71,7 @@ gen8_mfd_init_avc_surface(VADriverContextP ctx,
> 
>      if (!gen7_avc_surface) {
>          gen7_avc_surface = calloc(sizeof(GenAvcSurface), 1);
> +        gen7_avc_surface->frame_store_id = -1;
>          assert((obj_surface->size & 0x3f) == 0);
>          obj_surface->private_data = gen7_avc_surface;
>      }
> diff --git a/src/i965_avc_bsd.c b/src/i965_avc_bsd.c index aca3c01..ebeb2a6
> 100644
> --- a/src/i965_avc_bsd.c
> +++ b/src/i965_avc_bsd.c
> @@ -51,6 +51,7 @@ i965_avc_bsd_init_avc_bsd_surface(VADriverContextP
> ctx,
> 
>      if (!avc_bsd_surface) {
>          avc_bsd_surface = calloc(sizeof(GenAvcSurface), 1);
> +        avc_bsd_surface->frame_store_id = -1;
>          assert((obj_surface->size & 0x3f) == 0);
>          obj_surface->private_data = avc_bsd_surface;
>      }
> @@ -795,7 +796,8 @@ i965_avc_bsd_pipeline(VADriverContextP ctx, struct
> decode_state *decode_state, v
> 
>      assert(decode_state->pic_param && decode_state->pic_param->buffer);
>      pic_param = (VAPictureParameterBufferH264
> *)decode_state->pic_param->buffer;
> -    intel_update_avc_frame_store_index(ctx, decode_state, pic_param,
> i965_h264_context->fsid_list);
> +    intel_update_avc_frame_store_index(ctx, decode_state, pic_param,
> +        i965_h264_context->fsid_list, &i965_h264_context->fs_ctx);
> 
>      i965_h264_context->enable_avc_ildb = 0;
>      i965_h264_context->picture.i_flag = 1; diff --git a/src/i965_decoder.h
> b/src/i965_decoder.h index 01c093f..14d4d0c 100644
> --- a/src/i965_decoder.h
> +++ b/src/i965_decoder.h
> @@ -39,6 +39,21 @@ struct gen_frame_store {
>      VASurfaceID surface_id;
>      int         frame_store_id;
>      struct      object_surface *obj_surface;
> +
> +    /* This represents the time when this frame store was last used to
> +       hold a reference frame. This is not connected to a presentation
> +       timestamp (PTS), and this is not a common decoding time stamp
> +       (DTS) either. It serves the purpose of tracking retired
> +       reference frame candidates.
> +
> +       This is only used for H.264 decoding on platforms before Haswell */
> +    uint64_t    ref_age;
> +};
> +
> +typedef struct gen_frame_store_context GenFrameStoreContext; struct
> +gen_frame_store_context {
> +    uint64_t    age;
> +    int         prev_poc;
>  };
> 
>  typedef struct gen_buffer GenBuffer;
> diff --git a/src/i965_decoder_utils.c b/src/i965_decoder_utils.c index
> 7833919..64be7b6 100644
> --- a/src/i965_decoder_utils.c
> +++ b/src/i965_decoder_utils.c
> @@ -22,10 +22,11 @@
>   */
> 
>  #include "sysdeps.h"
> -
> +#include <limits.h>
>  #include <alloca.h>
> 
>  #include "intel_batchbuffer.h"
> +#include "intel_media.h"
>  #include "i965_drv_video.h"
>  #include "i965_decoder_utils.h"
>  #include "i965_defines.h"
> @@ -254,6 +255,21 @@ avc_gen_default_iq_matrix(VAIQMatrixBufferH264
> *iq_matrix)
>      memset(&iq_matrix->ScalingList8x8, 16,
> sizeof(iq_matrix->ScalingList8x8));
>  }
> 
> +/* Returns the POC of the supplied VA picture */ static int
> +avc_get_picture_poc(const VAPictureH264 *va_pic) {
> +    int structure, field_poc[2];
> +
> +    structure = va_pic->flags &
> +        (VA_PICTURE_H264_TOP_FIELD |
> VA_PICTURE_H264_BOTTOM_FIELD);
> +    field_poc[0] = structure != VA_PICTURE_H264_BOTTOM_FIELD ?
> +        va_pic->TopFieldOrderCnt : INT_MAX;
> +    field_poc[1] = structure != VA_PICTURE_H264_TOP_FIELD ?
> +        va_pic->BottomFieldOrderCnt : INT_MAX;
> +    return MIN(field_poc[0], field_poc[1]); }
> +
>  /* Returns a unique picture ID that represents the supplied VA surface object
> */  int  avc_get_picture_id(struct object_surface *obj_surface) @@ -471,68
> +487,92 @@ gen6_send_avc_ref_idx_state(
>      );
>  }
> 
> +/* Comparison function for sorting out the array of free frame store
> +entries */ static int compare_avc_ref_store_func(const void *p1, const
> +void *p2) {
> +    const GenFrameStore * const fs1 = *((GenFrameStore **)p1);
> +    const GenFrameStore * const fs2 = *((GenFrameStore **)p2);
> +
> +    return fs1->ref_age - fs2->ref_age; }
> +
>  void
>  intel_update_avc_frame_store_index(
>      VADriverContextP              ctx,
>      struct decode_state          *decode_state,
>      VAPictureParameterBufferH264 *pic_param,
> -    GenFrameStore
> frame_store[MAX_GEN_REFERENCE_FRAMES]
> +    GenFrameStore
> frame_store[MAX_GEN_REFERENCE_FRAMES],
> +    GenFrameStoreContext         *fs_ctx
>  )
>  {
>      GenFrameStore *free_refs[MAX_GEN_REFERENCE_FRAMES];
> -    int i, j, n, num_free_refs;
> +    uint32_t used_refs = 0, add_refs = 0;
> +    uint64_t age;
> +    int i, n, num_free_refs;
> +
> +    /* Detect changes of access unit */
> +    const int poc = avc_get_picture_poc(&pic_param->CurrPic);
> +    if (fs_ctx->age == 0)
> +        fs_ctx->age++;
> +    else if (fs_ctx->prev_poc != poc) {
> +        fs_ctx->prev_poc = poc;
> +        fs_ctx->age++;
> +    }

Fs_ctx->prev_poc is always updated after else if (){}, so we can remove the above redundant line in else if () {}.

> +    fs_ctx->prev_poc = poc;
> +    age = fs_ctx->age;
> 
> -    /* Remove obsolete entries from the internal DPB */
> -    for (i = 0, n = 0; i < MAX_GEN_REFERENCE_FRAMES; i++) {
> -        GenFrameStore * const fs = &frame_store[i];
> -        if (fs->surface_id == VA_INVALID_ID || !fs->obj_surface) {
> -            free_refs[n++] = fs;
> +    /* Tag entries that are still available in our Frame Store */
> +    for (i = 0; i < ARRAY_ELEMS(decode_state->reference_objects); i++) {
> +        struct object_surface * const obj_surface =
> +            decode_state->reference_objects[i];
> +        if (!obj_surface)
>              continue;
> -        }
> 
> -        // Find whether the current entry is still a valid reference frame
> -        for (j = 0; j < ARRAY_ELEMS(decode_state->reference_objects); j++) {
> -            struct object_surface * const obj_surface =
> -                decode_state->reference_objects[j];
> -            if (obj_surface && obj_surface == fs->obj_surface)
> -                break;
> +        GenAvcSurface * const avc_surface = obj_surface->private_data;
> +        if (avc_surface->frame_store_id >= 0) {
> +            GenFrameStore * const fs =
> +                &frame_store[avc_surface->frame_store_id];
> +            if (fs->surface_id == obj_surface->base.id) {
> +                fs->obj_surface = obj_surface;
> +                fs->ref_age = age;
> +                used_refs |= 1 << fs->frame_store_id;
> +                continue;
> +            }
>          }
> +        add_refs |= 1 << i;
> +    }
> 
> -        // ... or remove it
> -        if (j == ARRAY_ELEMS(decode_state->reference_objects)) {
> -            fs->surface_id = VA_INVALID_ID;
> +    /* Build and sort out the list of retired candidates. The resulting
> +       list is ordered by increasing age when they were last used */
> +    for (i = 0, n = 0; i < MAX_GEN_REFERENCE_FRAMES; i++) {
> +        if (!(used_refs & (1 << i))) {
> +            GenFrameStore * const fs = &frame_store[i];
>              fs->obj_surface = NULL;
> -            fs->frame_store_id = -1;
>              free_refs[n++] = fs;
>          }
>      }
>      num_free_refs = n;
> +    qsort(&free_refs[0], n, sizeof(free_refs[0]),
> + compare_avc_ref_store_func);
> 
>      /* Append the new reference frames */
>      for (i = 0, n = 0; i < ARRAY_ELEMS(decode_state->reference_objects); i++)
> {
>          struct object_surface * const obj_surface =
>              decode_state->reference_objects[i];
> -        if (!obj_surface)
> +        if (!obj_surface || !(add_refs & (1 << i)))
>              continue;
> 
> -        // Find whether the current frame is not already in our frame store
> -        for (j = 0; j < MAX_GEN_REFERENCE_FRAMES; j++) {
> -            GenFrameStore * const fs = &frame_store[j];
> -            if (fs->obj_surface == obj_surface)
> -                break;
> -        }
> -
> -        // ... or add it
> -        if (j == MAX_GEN_REFERENCE_FRAMES) {
> -            if (n < num_free_refs) {
> -                GenFrameStore * const fs = free_refs[n++];
> -                fs->surface_id = obj_surface->base.id;
> -                fs->obj_surface = obj_surface;
> -                fs->frame_store_id = fs - frame_store;
> -                continue;
> -            }
> -            WARN_ONCE("No free slot found for DPB reference list!!!\n");
> +        GenAvcSurface * const avc_surface = obj_surface->private_data;
> +        if (n < num_free_refs) {
> +            GenFrameStore * const fs = free_refs[n++];
> +            fs->surface_id = obj_surface->base.id;
> +            fs->obj_surface = obj_surface;
> +            fs->frame_store_id = fs - frame_store;
> +            fs->ref_age = age;
> +            avc_surface->frame_store_id = fs->frame_store_id;
> +            continue;
>          }
> +        WARN_ONCE("No free slot found for DPB reference list!!!\n");
>      }
>  }
> 
> diff --git a/src/i965_decoder_utils.h b/src/i965_decoder_utils.h index
> 0ffbd7f..3d39b21 100644
> --- a/src/i965_decoder_utils.h
> +++ b/src/i965_decoder_utils.h
> @@ -95,10 +95,13 @@ intel_decoder_sanity_check_input(VADriverContextP
> ctx,
>                                   struct decode_state *decode_state);
> 
>  void
> -intel_update_avc_frame_store_index(VADriverContextP ctx,
> -                                   struct decode_state *decode_state,
> -                                   VAPictureParameterBufferH264
> *pic_param,
> -                                   GenFrameStore
> frame_store[MAX_GEN_REFERENCE_FRAMES]);
> +intel_update_avc_frame_store_index(
> +    VADriverContextP                    ctx,
> +    struct decode_state                *decode_state,
> +    VAPictureParameterBufferH264       *pic_param,
> +    GenFrameStore
> frame_store[MAX_GEN_REFERENCE_FRAMES],
> +    GenFrameStoreContext               *fs_ctx
> +);
> 
>  void
>  gen75_update_avc_frame_store_index(
> diff --git a/src/i965_media_h264.h b/src/i965_media_h264.h index
> 490213c..e507e1d 100644
> --- a/src/i965_media_h264.h
> +++ b/src/i965_media_h264.h
> @@ -61,6 +61,7 @@ struct i965_h264_context
>      struct i965_avc_hw_scoreboard_context avc_hw_scoreboard_context;
>      struct i965_avc_ildb_context avc_ildb_context;
> 
> +    GenFrameStoreContext fs_ctx;
>      GenFrameStore fsid_list[MAX_GEN_REFERENCE_FRAMES];
> 
>      struct i965_kernel avc_kernels[NUM_H264_AVC_KERNELS];
> diff --git a/src/intel_media.h b/src/intel_media.h index b30740a..55136d6
> 100644
> --- a/src/intel_media.h
> +++ b/src/intel_media.h
> @@ -39,6 +39,7 @@ struct gen_avc_surface
>      dri_bo *dmv_top;
>      dri_bo *dmv_bottom;
>      int dmv_bottom_flag;
> +    int frame_store_id; /* only used for H.264 on earlier generations
> + (<HSW) */
>  };
> 
>  extern void gen_free_avc_surface(void **data);
> --
> 1.7.9.5
> 
> _______________________________________________
> Libva mailing list
> Libva at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/libva


More information about the Libva mailing list