st/va: change frame_idx from array to hash table
authorJulien Isorce <julien.isorce@gmail.com>
Tue, 25 Jul 2017 14:31:28 +0000 (15:31 +0100)
committerJulien Isorce <jisorce@oblong.com>
Mon, 14 Aug 2017 12:40:19 +0000 (13:40 +0100)
The picture_id was assumed to be a frame number so in 0-31.
But the vaapi client gstreamer-vaapi uses the surfaces handles
as identifier which are unsigned int.

This bug can happen when using a lot of vaapi surfaces within
the same process. Indeed Mesa/st/va increments a counter for the
surface ID: mesa/util/u_handle_table.c::handle_table_add which
starts from 0 and incremented by 1 at each call.
So creating more than 32 surfaces was a problem.

The following bug contains a test that reproduces the problem
by running a couple of vaapih264enc in the same process. The
above also explains why there was no pb when running them in
separated processes.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=102006
Signed-off-by: Julien Isorce <jisorce@oblong.com>
Tested-by: Tomas Rataj <rataj28@gmail.com>
Acked-by: Christian König <christian.koenig@amd.com>
Reviewed-and-tested-by: Boyuan Zhang <Boyuan.Zhang@amd.com>
src/gallium/include/pipe/p_video_state.h
src/gallium/state_trackers/va/context.c
src/gallium/state_trackers/va/picture.c
src/gallium/state_trackers/va/va_private.h

index 39b39051648366292e6c7be4d2c2e97b9782aef2..53f9ab3d5e11c2688a2c02174b2868c2b7e358f4 100644 (file)
@@ -32,6 +32,7 @@
 #include "pipe/p_format.h"
 #include "pipe/p_state.h"
 #include "pipe/p_screen.h"
+#include "util/u_hash_table.h"
 #include "util/u_inlines.h"
 
 #ifdef __cplusplus
@@ -407,7 +408,8 @@ struct pipe_h264_enc_picture_desc
    bool not_referenced;
    bool is_idr;
    bool enable_vui;
-   unsigned int frame_idx[32];
+   struct util_hash_table *frame_idx;
+
 };
 
 struct pipe_h265_sps
index 186f5066bd06162bcf52f68e6f494958a51c7445..f2cb37aa22a71e0c633cf86116a67ad19afe9775 100644 (file)
@@ -280,8 +280,10 @@ vlVaCreateContext(VADriverContextP ctx, VAConfigID config_id, int picture_width,
 
    context->desc.base.profile = config->profile;
    context->desc.base.entry_point = config->entrypoint;
-   if (config->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE)
+   if (config->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
       context->desc.h264enc.rate_ctrl.rate_ctrl_method = config->rc;
+      context->desc.h264enc.frame_idx = util_hash_table_create(handle_hash, handle_compare);
+   }
 
    mtx_lock(&drv->mutex);
    *context_id = handle_table_add(drv->htab, context);
@@ -308,7 +310,10 @@ vlVaDestroyContext(VADriverContextP ctx, VAContextID context_id)
    }
 
    if (context->decoder) {
-      if (context->desc.base.entry_point != PIPE_VIDEO_ENTRYPOINT_ENCODE) {
+      if (context->desc.base.entry_point == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
+         if (context->desc.h264enc.frame_idx)
+            util_hash_table_destroy (context->desc.h264enc.frame_idx);
+      } else {
          if (u_reduce_video_profile(context->decoder->profile) ==
                PIPE_VIDEO_FORMAT_MPEG4_AVC) {
             FREE(context->desc.h264.pps->sps);
index 20fe75085b92bbc690ba854282f2389bd8d99f66..338e0902d658a7dbf5da16c70b8246fbc6b3b90d 100644 (file)
@@ -427,7 +427,10 @@ handleVAEncPictureParameterBufferType(vlVaDriver *drv, vlVaContext *context, vlV
                                             PIPE_USAGE_STREAM, coded_buf->size);
    context->coded_buf = coded_buf;
 
-   context->desc.h264enc.frame_idx[h264->CurrPic.picture_id] = h264->frame_num;
+   util_hash_table_set(context->desc.h264enc.frame_idx,
+                      UINT_TO_PTR(h264->CurrPic.picture_id),
+                      UINT_TO_PTR(h264->frame_num));
+
    if (context->desc.h264enc.is_idr)
       context->desc.h264enc.picture_type = PIPE_H264_ENC_PICTURE_TYPE_IDR;
    else
@@ -455,11 +458,13 @@ handleVAEncSliceParameterBufferType(vlVaDriver *drv, vlVaContext *context, vlVaB
    for (int i = 0; i < 32; i++) {
       if (h264->RefPicList0[i].picture_id != VA_INVALID_ID) {
          if (context->desc.h264enc.ref_idx_l0 == VA_INVALID_ID)
-            context->desc.h264enc.ref_idx_l0 = context->desc.h264enc.frame_idx[h264->RefPicList0[i].picture_id];
+            context->desc.h264enc.ref_idx_l0 = PTR_TO_UINT(util_hash_table_get(context->desc.h264enc.frame_idx,
+                                                                              UINT_TO_PTR(h264->RefPicList0[i].picture_id)));
       }
       if (h264->RefPicList1[i].picture_id != VA_INVALID_ID && h264->slice_type == 1) {
          if (context->desc.h264enc.ref_idx_l1 == VA_INVALID_ID)
-            context->desc.h264enc.ref_idx_l1 = context->desc.h264enc.frame_idx[h264->RefPicList1[i].picture_id];
+            context->desc.h264enc.ref_idx_l1 = PTR_TO_UINT(util_hash_table_get(context->desc.h264enc.frame_idx,
+                                                                              UINT_TO_PTR(h264->RefPicList1[i].picture_id)));
       }
    }
 
index 9c32c084ea92de3371e3332634db13194ba5ffc3..dee0c2b4c48fcfddb77973664c90d2bb79a04523 100644 (file)
 #define VL_VA_MAX_IMAGE_FORMATS 11
 #define VL_VA_ENC_GOP_COEFF 16
 
+#define UINT_TO_PTR(x) ((void*)(uintptr_t)(x))
+#define PTR_TO_UINT(x) ((unsigned)((intptr_t)(x)))
+
+static inline unsigned handle_hash(void *key)
+{
+    return PTR_TO_UINT(key);
+}
+
+static inline int handle_compare(void *key1, void *key2)
+{
+    return PTR_TO_UINT(key1) != PTR_TO_UINT(key2);
+}
+
 static inline enum pipe_video_chroma_format
 ChromaToPipe(int format)
 {