[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