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

Gwenole Beauchesne gb.devel at gmail.com
Mon Jun 9 08:34:14 PDT 2014


2014-06-09 15:57 GMT+02:00 Xiang, Haihao <haihao.xiang at intel.com>:
>
> 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 () {}.

OK, we could even reduce this to:
if (fs_ctx->ref_age == 0 || fs_ctx->prev_poc != poc)
  fs_ctx->ref_age++;

>
>> +    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