OSDN Git Service

i965_drv: add support for per-codec max resolution
[android-x86/hardware-intel-common-vaapi.git] / src / i965_drv_video.c
index 19b997f..66cdb9e 100644 (file)
@@ -48,6 +48,8 @@
 #include "i965_decoder.h"
 #include "i965_encoder.h"
 
+#include "gen9_vp9_encapi.h"
+
 #define CONFIG_ID_OFFSET                0x01000000
 #define CONTEXT_ID_OFFSET               0x02000000
 #define SURFACE_ID_OFFSET               0x04000000
@@ -67,6 +69,9 @@
 #define HAS_H264_ENCODING(ctx)  ((ctx)->codec_info->has_h264_encoding && \
                                  (ctx)->intel.has_bsd)
 
+#define HAS_LP_H264_ENCODING(ctx)  ((ctx)->codec_info->has_lp_h264_encoding && \
+                                    (ctx)->intel.has_bsd)
+
 #define HAS_VC1_DECODING(ctx)   ((ctx)->codec_info->has_vc1_decoding && \
                                  (ctx)->intel.has_bsd)
 
 #define HAS_HEVC_ENCODING(ctx)          ((ctx)->codec_info->has_hevc_encoding && \
                                          (ctx)->intel.has_bsd)
 
+#define HAS_VP9_DECODING(ctx)          ((ctx)->codec_info->has_vp9_decoding && \
+                                         (ctx)->intel.has_bsd)
+
+#define HAS_VP9_DECODING_PROFILE(ctx, profile)                     \
+    (HAS_VP9_DECODING(ctx) &&                                      \
+     ((ctx)->codec_info->vp9_dec_profiles & (1U << (profile - VAProfileVP9Profile0))))
+
+#define HAS_HEVC10_DECODING(ctx)        ((ctx)->codec_info->has_hevc10_decoding && \
+                                         (ctx)->intel.has_bsd)
+
+#define HAS_VPP_P010(ctx)        ((ctx)->codec_info->has_vpp_p010 && \
+                                         (ctx)->intel.has_bsd)
+
+#define HAS_VP9_ENCODING(ctx)          ((ctx)->codec_info->has_vp9_encoding && \
+                                         (ctx)->intel.has_bsd)
+
 static int get_sampling_from_fourcc(unsigned int fourcc);
 
 /* Check whether we are rendering to X11 (VA/X11 or VA/GLX API) */
@@ -141,11 +162,13 @@ static int get_sampling_from_fourcc(unsigned int fourcc);
 #define I_YV12  2, 2, 3, {I965_8BITS, I965_2BITS, I965_2BITS}, 3, { {PLANE_0, OFFSET_0}, {PLANE_2, OFFSET_0}, {PLANE_1, OFFSET_0} }
 #define I_IMC1  I_YV12
 
+#define I_P010  2, 2, 2, {I965_16BITS, I965_8BITS}, 3, { {PLANE_0, OFFSET_0}, {PLANE_1, OFFSET_0}, {PLANE_1, OFFSET_16} }
+
 #define I_422H  2, 1, 3, {I965_8BITS, I965_4BITS, I965_4BITS}, 3, { {PLANE_0, OFFSET_0}, {PLANE_1, OFFSET_0}, {PLANE_2, OFFSET_0} }
 #define I_422V  1, 2, 3, {I965_8BITS, I965_4BITS, I965_4BITS}, 3, { {PLANE_0, OFFSET_0}, {PLANE_1, OFFSET_0}, {PLANE_2, OFFSET_0} }
 #define I_YV16  2, 1, 3, {I965_8BITS, I965_4BITS, I965_4BITS}, 3, { {PLANE_0, OFFSET_0}, {PLANE_2, OFFSET_0}, {PLANE_1, OFFSET_0} }
-#define I_YUY2  2, 1, 1, {I965_32BITS}, 3, { {PLANE_0, OFFSET_0}, {PLANE_0, OFFSET_8}, {PLANE_0, OFFSET_24} }
-#define I_UYVY  2, 1, 1, {I965_32BITS}, 3, { {PLANE_0, OFFSET_0}, {PLANE_0, OFFSET_8}, {PLANE_0, OFFSET_16} }
+#define I_YUY2  2, 1, 1, {I965_16BITS}, 3, { {PLANE_0, OFFSET_0}, {PLANE_0, OFFSET_8}, {PLANE_0, OFFSET_24} }
+#define I_UYVY  2, 1, 1, {I965_16BITS}, 3, { {PLANE_0, OFFSET_8}, {PLANE_0, OFFSET_0}, {PLANE_0, OFFSET_16} }
 
 #define I_444P  1, 1, 3, {I965_8BITS, I965_8BITS, I965_8BITS}, 3, { {PLANE_0, OFFSET_0}, {PLANE_1, OFFSET_0}, {PLANE_2, OFFSET_0} }
 
@@ -185,6 +208,8 @@ static const i965_fourcc_info i965_fourcc_infos[] = {
     DEF_YUV(YV12, YUV420, I_SI),
     DEF_YUV(IMC1, YUV420, I_S),
 
+    DEF_YUV(P010, YUV420, I_SI),
+
     DEF_YUV(422H, YUV422H, I_SI),
     DEF_YUV(422V, YUV422V, I_S),
     DEF_YUV(YV16, YUV422H, I_S),
@@ -217,7 +242,7 @@ get_fourcc_info(unsigned int fourcc)
 {
     unsigned int i;
 
-    for (i = 0; ARRAY_ELEMS(i965_fourcc_infos); i++) {
+    for (i = 0; i < ARRAY_ELEMS(i965_fourcc_infos); i++) {
         const i965_fourcc_info * const info = &i965_fourcc_infos[i];
 
         if (info->fourcc == fourcc)
@@ -227,6 +252,22 @@ get_fourcc_info(unsigned int fourcc)
     return NULL;
 }
 
+static int
+get_bpp_from_fourcc(unsigned int fourcc)
+{
+    const i965_fourcc_info *info = get_fourcc_info(fourcc);
+    unsigned int i = 0;
+    unsigned int bpp = 0;
+
+    if (!info)
+        return 0;
+
+    for (i = 0; i < info->num_planes; i++)
+        bpp += info->bpp[i];
+
+    return bpp;
+}
+
 enum {
     I965_SURFACETYPE_RGBA = 1,
     I965_SURFACETYPE_YUV,
@@ -290,6 +331,8 @@ i965_image_formats_map[I965_MAX_IMAGE_FORMATS + 1] = {
       { VA_FOURCC_RGBX, VA_LSB_FIRST, 32, 24, 0x000000ff, 0x0000ff00, 0x00ff0000 } },
     { I965_SURFACETYPE_RGBA,
       { VA_FOURCC_BGRX, VA_LSB_FIRST, 32, 24, 0x00ff0000, 0x0000ff00, 0x000000ff } },
+    { I965_SURFACETYPE_YUV,
+      { VA_FOURCC_P010, VA_LSB_FIRST, 24, } },
 };
 
 /* List of supported subpicture formats */
@@ -524,14 +567,17 @@ i965_QueryConfigProfiles(VADriverContextP ctx,
     }
 
     if (HAS_H264_DECODING(i965) ||
-        HAS_H264_ENCODING(i965)) {
+        HAS_H264_ENCODING(i965) ||
+        HAS_LP_H264_ENCODING(i965)) {
         profile_list[i++] = VAProfileH264ConstrainedBaseline;
         profile_list[i++] = VAProfileH264Main;
         profile_list[i++] = VAProfileH264High;
     }
-    if (HAS_H264_MVC_DECODING_PROFILE(i965, VAProfileH264MultiviewHigh))
+    if (HAS_H264_MVC_DECODING_PROFILE(i965, VAProfileH264MultiviewHigh) ||
+        HAS_H264_MVC_ENCODING(i965))
         profile_list[i++] = VAProfileH264MultiviewHigh;
-    if (HAS_H264_MVC_DECODING_PROFILE(i965, VAProfileH264StereoHigh))
+    if (HAS_H264_MVC_DECODING_PROFILE(i965, VAProfileH264StereoHigh) ||
+        HAS_H264_MVC_ENCODING(i965))
         profile_list[i++] = VAProfileH264StereoHigh;
 
     if (HAS_VC1_DECODING(i965)) {
@@ -554,16 +600,43 @@ i965_QueryConfigProfiles(VADriverContextP ctx,
         profile_list[i++] = VAProfileVP8Version0_3;
     }
 
-    if (HAS_H264_MVC_ENCODING(i965)) {
-        profile_list[i++] = VAProfileH264MultiviewHigh;
-        profile_list[i++] = VAProfileH264StereoHigh;
-    }
-
     if (HAS_HEVC_DECODING(i965)||
         HAS_HEVC_ENCODING(i965)) {
         profile_list[i++] = VAProfileHEVCMain;
     }
 
+    if (HAS_HEVC10_DECODING(i965)) {
+        profile_list[i++] = VAProfileHEVCMain10;
+    }
+
+    if(HAS_VP9_DECODING_PROFILE(i965, VAProfileVP9Profile0) ||
+        HAS_VP9_ENCODING(i965)) {
+        profile_list[i++] = VAProfileVP9Profile0;
+    }
+
+    if(HAS_VP9_DECODING_PROFILE(i965, VAProfileVP9Profile2)) {
+        profile_list[i++] = VAProfileVP9Profile2;
+    }
+
+    if (i965->wrapper_pdrvctx) {
+        VAProfile wrapper_list[4];
+        int wrapper_num;
+        VADriverContextP pdrvctx;
+        VAStatus va_status;
+
+        pdrvctx = i965->wrapper_pdrvctx;
+        CALL_VTABLE(pdrvctx, va_status,
+                    vaQueryConfigProfiles(pdrvctx,
+                                          wrapper_list, &wrapper_num));
+
+        if (va_status == VA_STATUS_SUCCESS) {
+            int j;
+            for (j = 0; j < wrapper_num; j++)
+                if (wrapper_list[j] != VAProfileNone)
+                    profile_list[i++] = wrapper_list[j];
+        }
+    }
+
     /* If the assert fails then I965_MAX_PROFILES needs to be bigger */
     ASSERT_RET(i <= I965_MAX_PROFILES, VA_STATUS_ERROR_OPERATION_FAILED);
     *num_profiles = i;
@@ -600,6 +673,9 @@ i965_QueryConfigEntrypoints(VADriverContextP ctx,
         if (HAS_H264_ENCODING(i965))
             entrypoint_list[n++] = VAEntrypointEncSlice;
 
+        if (HAS_LP_H264_ENCODING(i965))
+            entrypoint_list[n++] = VAEntrypointEncSliceLP;
+
         break;
    case VAProfileH264MultiviewHigh:
    case VAProfileH264StereoHigh:
@@ -648,6 +724,35 @@ i965_QueryConfigEntrypoints(VADriverContextP ctx,
 
         break;
 
+    case VAProfileHEVCMain10:
+        if (HAS_HEVC10_DECODING(i965))
+            entrypoint_list[n++] = VAEntrypointVLD;
+
+        break;
+
+    case VAProfileVP9Profile0:
+    case VAProfileVP9Profile2:
+        if(HAS_VP9_DECODING_PROFILE(i965, profile))
+            entrypoint_list[n++] = VAEntrypointVLD;
+
+        if (HAS_VP9_ENCODING(i965) && (profile == VAProfileVP9Profile0))
+            entrypoint_list[n++] = VAEntrypointEncSlice;
+
+        if(profile == VAProfileVP9Profile0) {
+          if (i965->wrapper_pdrvctx) {
+              VAStatus va_status = VA_STATUS_SUCCESS;
+              VADriverContextP pdrvctx = i965->wrapper_pdrvctx;
+
+              CALL_VTABLE(pdrvctx, va_status,
+                          vaQueryConfigEntrypoints(pdrvctx, profile,
+                                                   entrypoint_list,
+                                                   num_entrypoints));
+              return va_status;
+          }
+        }
+
+        break;
+
     default:
         break;
     }
@@ -681,7 +786,8 @@ i965_validate_config(VADriverContextP ctx, VAProfile profile,
     case VAProfileH264Main:
     case VAProfileH264High:
         if ((HAS_H264_DECODING(i965) && entrypoint == VAEntrypointVLD) ||
-            (HAS_H264_ENCODING(i965) && entrypoint == VAEntrypointEncSlice)) {
+            (HAS_H264_ENCODING(i965) && entrypoint == VAEntrypointEncSlice) ||
+            (HAS_LP_H264_ENCODING(i965) && entrypoint == VAEntrypointEncSliceLP)) {
             va_status = VA_STATUS_SUCCESS;
         } else {
             va_status = VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT;
@@ -745,6 +851,26 @@ i965_validate_config(VADriverContextP ctx, VAProfile profile,
 
         break;
 
+    case VAProfileHEVCMain10:
+        if (HAS_HEVC10_DECODING(i965) && (entrypoint == VAEntrypointVLD))
+            va_status = VA_STATUS_SUCCESS;
+        else
+            va_status = VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT;
+
+        break;
+
+    case VAProfileVP9Profile0:
+    case VAProfileVP9Profile2:
+        if ((HAS_VP9_DECODING_PROFILE(i965, profile)) && (entrypoint == VAEntrypointVLD))
+            va_status = VA_STATUS_SUCCESS;
+       else if ((HAS_VP9_ENCODING(i965)) && (entrypoint == VAEntrypointEncSlice))
+            va_status = VA_STATUS_SUCCESS;
+        else if ((profile == VAProfileVP9Profile0) && i965->wrapper_pdrvctx)
+            va_status = VA_STATUS_SUCCESS;
+        else
+            va_status = VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT;
+        break;
+
     default:
         va_status = VA_STATUS_ERROR_UNSUPPORTED_PROFILE;
         break;
@@ -778,7 +904,22 @@ i965_get_default_chroma_formats(VADriverContextP ctx, VAProfile profile,
             chroma_formats |= i965->codec_info->jpeg_dec_chroma_formats;
         if (HAS_JPEG_ENCODING(i965) && entrypoint == VAEntrypointEncPicture)
             chroma_formats |= i965->codec_info->jpeg_enc_chroma_formats;
-        
+        break;
+
+    case VAProfileHEVCMain10:
+        if (HAS_HEVC10_DECODING(i965) && entrypoint == VAEntrypointVLD)
+            chroma_formats |= i965->codec_info->hevc_dec_chroma_formats;
+        break;
+
+    case VAProfileNone:
+       if(HAS_VPP_P010(i965))
+            chroma_formats |= VA_RT_FORMAT_YUV420_10BPP;
+        break;
+
+    case VAProfileVP9Profile0:
+    case VAProfileVP9Profile2:
+        if (HAS_VP9_DECODING_PROFILE(i965, profile) && entrypoint == VAEntrypointVLD)
+            chroma_formats |= i965->codec_info->vp9_dec_chroma_formats;
         break;
 
     default:
@@ -818,12 +959,29 @@ i965_GetConfigAttributes(VADriverContextP ctx,
                 if (profile != VAProfileMPEG2Main &&
                     profile != VAProfileMPEG2Simple)
                     attrib_list[i].value |= VA_RC_CBR;
+
+                if (profile == VAProfileVP9Profile0)
+                    attrib_list[i].value |= VA_RC_VBR;
+
                 break;
-            }
+            } else if (entrypoint == VAEntrypointEncSliceLP) {
+                struct i965_driver_data * const i965 = i965_driver_data(ctx);
+
+                /* Support low power encoding for H.264 only by now */
+                if (profile == VAProfileH264ConstrainedBaseline ||
+                    profile == VAProfileH264Main ||
+                    profile == VAProfileH264High)
+                    attrib_list[i].value = i965->codec_info->lp_h264_brc_mode;
+                else
+                    attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
+            } else
+                attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
+
             break;
 
         case VAConfigAttribEncPackedHeaders:
-            if (entrypoint == VAEntrypointEncSlice) {
+            if (entrypoint == VAEntrypointEncSlice ||
+                entrypoint == VAEntrypointEncSliceLP) {
                 attrib_list[i].value = VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_PICTURE | VA_ENC_PACKED_HEADER_MISC;
                 if (profile == VAProfileH264ConstrainedBaseline ||
                     profile == VAProfileH264Main ||
@@ -834,6 +992,8 @@ i965_GetConfigAttributes(VADriverContextP ctx,
                     attrib_list[i].value |= (VA_ENC_PACKED_HEADER_RAW_DATA |
                                              VA_ENC_PACKED_HEADER_SLICE);
                 }
+                else if (profile == VAProfileVP9Profile0)
+                    attrib_list[i].value = VA_ENC_PACKED_HEADER_RAW_DATA;
                 break;
             }
             else if (entrypoint == VAEntrypointEncPicture) {
@@ -843,14 +1003,23 @@ i965_GetConfigAttributes(VADriverContextP ctx,
             break;
 
         case VAConfigAttribEncMaxRefFrames:
-            if (entrypoint == VAEntrypointEncSlice) {
+            if (entrypoint == VAEntrypointEncSlice)
                 attrib_list[i].value = (1 << 16) | (1 << 0);
-                break;
+            else if (entrypoint == VAEntrypointEncSliceLP) {
+                /* Don't support B frame for low power mode */
+                if (profile == VAProfileH264ConstrainedBaseline ||
+                    profile == VAProfileH264Main ||
+                    profile == VAProfileH264High)
+                    attrib_list[i].value = (1 << 0);
+                else
+                    attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
             }
+
             break;
 
         case VAConfigAttribEncQualityRange:
-            if (entrypoint == VAEntrypointEncSlice) {
+            if (entrypoint == VAEntrypointEncSlice ||
+                entrypoint == VAEntrypointEncSliceLP) {
                 attrib_list[i].value = 1;
                 if (profile == VAProfileH264ConstrainedBaseline ||
                     profile == VAProfileH264Main ||
@@ -878,6 +1047,17 @@ i965_GetConfigAttributes(VADriverContextP ctx,
             attrib_list[i].value = VA_DEC_SLICE_MODE_NORMAL;
             break;
 
+        case VAConfigAttribEncROI:
+            if ((entrypoint == VAEntrypointEncSliceLP) &&
+                (profile == VAProfileH264ConstrainedBaseline ||
+                 profile == VAProfileH264Main ||
+                 profile == VAProfileH264High))
+                attrib_list[i].value = 3;
+            else
+                attrib_list[i].value = 0;
+
+            break;
+
         default:
             /* Do nothing */
             attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
@@ -990,7 +1170,9 @@ i965_CreateConfig(VADriverContextP ctx,
     }
 
     if ((vaStatus == VA_STATUS_SUCCESS) &&
-        (profile == VAProfileVP9Profile0)) {
+        (profile == VAProfileVP9Profile0) &&
+        (entrypoint == VAEntrypointVLD) &&
+        !HAS_VP9_DECODING(i965)) {
 
         if (i965->wrapper_pdrvctx) {
             VAGenericID wrapper_config;
@@ -1141,6 +1323,7 @@ i965_suface_external_memory(VADriverContextP ctx,
 
     switch (obj_surface->fourcc) {
     case VA_FOURCC_NV12:
+    case VA_FOURCC_P010:
         ASSERT_RET(memory_attibute->num_planes == 2, VA_STATUS_ERROR_INVALID_PARAMETER);
         ASSERT_RET(memory_attibute->pitches[0] == memory_attibute->pitches[1], VA_STATUS_ERROR_INVALID_PARAMETER);
 
@@ -1368,6 +1551,7 @@ i965_CreateSurfaces2(
     /* support 420 & 422 & RGB32 format, 422 and RGB32 are only used
      * for post-processing (including color conversion) */
     if (VA_RT_FORMAT_YUV420 != format &&
+        VA_RT_FORMAT_YUV420_10BPP != format &&
         VA_RT_FORMAT_YUV422 != format &&
         VA_RT_FORMAT_YUV444 != format &&
         VA_RT_FORMAT_YUV411 != format &&
@@ -1432,10 +1616,10 @@ i965_CreateSurfaces2(
                 if (memory_attibute->pitches[0]) {
                     int bpp_1stplane = bpp_1stplane_by_fourcc(expected_fourcc);
                     ASSERT_RET(bpp_1stplane, VA_STATUS_ERROR_INVALID_PARAMETER);
-                    obj_surface->width = memory_attibute->pitches[0]/bpp_1stplane;
+                    obj_surface->width = memory_attibute->pitches[0];
                     obj_surface->user_h_stride_set = true;
                     ASSERT_RET(IS_ALIGNED(obj_surface->width, 16), VA_STATUS_ERROR_INVALID_PARAMETER);
-                    ASSERT_RET(obj_surface->width >= width, VA_STATUS_ERROR_INVALID_PARAMETER);
+                    ASSERT_RET(obj_surface->width >= width * bpp_1stplane, VA_STATUS_ERROR_INVALID_PARAMETER);
 
                     if (memory_attibute->offsets[1]) {
                         ASSERT_RET(!memory_attibute->offsets[0], VA_STATUS_ERROR_INVALID_PARAMETER);
@@ -1876,6 +2060,9 @@ i965_destroy_context(struct object_heap *heap, struct object_base *obj)
         i965_release_buffer_store(&obj_context->codec_state.encode.pic_param);
         i965_release_buffer_store(&obj_context->codec_state.encode.seq_param);
 
+        i965_release_buffer_store(&obj_context->codec_state.encode.q_matrix);
+        i965_release_buffer_store(&obj_context->codec_state.encode.huffman_table);
+
         for (i = 0; i < obj_context->codec_state.encode.num_slice_params; i++)
             i965_release_buffer_store(&obj_context->codec_state.encode.slice_params[i]);
 
@@ -1920,6 +2107,7 @@ i965_destroy_context(struct object_heap *heap, struct object_base *obj)
             i965_release_buffer_store(&obj_context->codec_state.encode.packed_header_data_ext[i]);
         free(obj_context->codec_state.encode.packed_header_data_ext);
 
+        i965_release_buffer_store(&obj_context->codec_state.encode.encmb_map);
     } else {
         assert(obj_context->codec_state.decode.num_slice_params <= obj_context->codec_state.decode.max_slice_params);
         assert(obj_context->codec_state.decode.num_slice_datas <= obj_context->codec_state.decode.max_slice_datas);
@@ -1942,6 +2130,20 @@ i965_destroy_context(struct object_heap *heap, struct object_base *obj)
     object_heap_free(heap, obj);
 }
 
+static inline void
+max_resolution(struct i965_driver_data *i965,
+               struct object_config *obj_config,
+               int *w,                                  /* out */
+               int *h)                                  /* out */
+{
+    if (i965->codec_info->max_resolution) {
+        i965->codec_info->max_resolution(i965, obj_config, w, h);
+    } else {
+        *w = i965->codec_info->max_width;
+        *h = i965->codec_info->max_height;
+    }
+}
+
 VAStatus
 i965_CreateContext(VADriverContextP ctx,
                    VAConfigID config_id,
@@ -1953,21 +2155,24 @@ i965_CreateContext(VADriverContextP ctx,
                    VAContextID *context)                /* out */
 {
     struct i965_driver_data *i965 = i965_driver_data(ctx);
-    struct i965_render_state *render_state = &i965->render_state;
     struct object_config *obj_config = CONFIG(config_id);
     struct object_context *obj_context = NULL;
     VAConfigAttrib *attrib;
     VAStatus vaStatus = VA_STATUS_SUCCESS;
     int contextID;
     int i;
+    int max_width;
+    int max_height;
 
     if (NULL == obj_config) {
         vaStatus = VA_STATUS_ERROR_INVALID_CONFIG;
         return vaStatus;
     }
 
-    if (picture_width > i965->codec_info->max_width ||
-        picture_height > i965->codec_info->max_height) {
+    max_resolution(i965, obj_config, &max_width, &max_height);
+
+    if (picture_width > max_width ||
+        picture_height > max_height) {
         vaStatus = VA_STATUS_ERROR_RESOLUTION_NOT_SUPPORTED;
         return vaStatus;
     }
@@ -1994,6 +2199,9 @@ i965_CreateContext(VADriverContextP ctx,
     obj_context->hw_context = NULL;
     obj_context->wrapper_context = VA_INVALID_ID;
 
+    if (!obj_context->render_targets)
+        return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
     for(i = 0; i < num_render_targets; i++) {
         if (NULL == SURFACE(render_targets[i])) {
             vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
@@ -2011,7 +2219,8 @@ i965_CreateContext(VADriverContextP ctx,
             assert(i965->codec_info->proc_hw_context_init);
             obj_context->hw_context = i965->codec_info->proc_hw_context_init(ctx, obj_config);
          } else if ((VAEntrypointEncSlice == obj_config->entrypoint) || 
-                   (VAEntrypointEncPicture == obj_config->entrypoint)) { /*encode routine only*/
+                    (VAEntrypointEncPicture == obj_config->entrypoint) ||
+                    (VAEntrypointEncSliceLP == obj_config->entrypoint)) {
             VAConfigAttrib *packed_attrib;
             obj_context->codec_type = CODEC_ENC;
             memset(&obj_context->codec_state.encode, 0, sizeof(obj_context->codec_state.encode));
@@ -2042,9 +2251,12 @@ i965_CreateContext(VADriverContextP ctx,
 
             obj_context->codec_state.encode.slice_index = 0;
             packed_attrib = i965_lookup_config_attribute(obj_config, VAConfigAttribEncPackedHeaders);
-            if (packed_attrib)
+            if (packed_attrib) {
                 obj_context->codec_state.encode.packed_header_flag = packed_attrib->value;
-            else {
+                if (obj_config->profile == VAProfileVP9Profile0)
+                    obj_context->codec_state.encode.packed_header_flag =
+                            packed_attrib->value & VA_ENC_PACKED_HEADER_RAW_DATA;
+            } else {
                 /* use the default value. SPS/PPS/RAWDATA is passed from user
                  * while Slice_header data is generated by driver.
                  */
@@ -2052,6 +2264,10 @@ i965_CreateContext(VADriverContextP ctx,
                                VA_ENC_PACKED_HEADER_SEQUENCE |
                                VA_ENC_PACKED_HEADER_PICTURE |
                                VA_ENC_PACKED_HEADER_RAW_DATA;
+
+                /* it is not used for VP9 */
+                if (obj_config->profile == VAProfileVP9Profile0)
+                    obj_context->codec_state.encode.packed_header_flag = 0;
             }
             assert(i965->codec_info->enc_hw_context_init);
             obj_context->hw_context = i965->codec_info->enc_hw_context_init(ctx, obj_config);
@@ -2161,6 +2377,8 @@ i965_create_buffer_internal(VADriverContextP ctx,
     struct buffer_store *buffer_store = NULL;
     int bufferID;
     VAStatus vaStatus = VA_STATUS_ERROR_UNKNOWN;
+    struct object_context *obj_context = CONTEXT(context);
+    int wrapper_flag = 0;
 
     /* Validate type */
     switch (type) {
@@ -2186,6 +2404,7 @@ i965_create_buffer_internal(VADriverContextP ctx,
     case VAProcFilterParameterBufferType:
     case VAHuffmanTableBufferType:
     case VAProbabilityBufferType:
+    case VAEncMacroblockMapBufferType:
         /* Ok */
         break;
 
@@ -2212,27 +2431,61 @@ i965_create_buffer_internal(VADriverContextP ctx,
     obj_buffer->export_refcount = 0;
     obj_buffer->buffer_store = NULL;
     obj_buffer->wrapper_buffer = VA_INVALID_ID;
+    obj_buffer->context_id = context;
 
     buffer_store = calloc(1, sizeof(struct buffer_store));
     assert(buffer_store);
     buffer_store->ref_count = 1;
 
+    if (obj_context &&
+        (obj_context->wrapper_context != VA_INVALID_ID) &&
+        i965->wrapper_pdrvctx) {
+        VAGenericID wrapper_buffer;
+        VADriverContextP pdrvctx = i965->wrapper_pdrvctx;
+
+        CALL_VTABLE(pdrvctx, vaStatus,
+                    vaCreateBuffer(pdrvctx, obj_context->wrapper_context, type, size, num_elements,
+                                   data, &wrapper_buffer));
+        if (vaStatus == VA_STATUS_SUCCESS) {
+            obj_buffer->wrapper_buffer = wrapper_buffer;
+        } else {
+            free(buffer_store);
+            return vaStatus;
+        }
+        wrapper_flag = 1;
+    }
+
     if (store_bo != NULL) {
         buffer_store->bo = store_bo;
         dri_bo_reference(buffer_store->bo);
-        
-        if (data)
+
+        /* If the buffer is wrapped, the buffer_store is bogus. Unnecessary to copy it */
+        if (data && !wrapper_flag)
             dri_bo_subdata(buffer_store->bo, 0, size * num_elements, data);
     } else if (type == VASliceDataBufferType || 
                type == VAImageBufferType || 
                type == VAEncCodedBufferType ||
+               type == VAEncMacroblockMapBufferType ||
                type == VAProbabilityBufferType) {
-        buffer_store->bo = dri_bo_alloc(i965->intel.bufmgr, 
-                                        "Buffer", 
-                                        size * num_elements, 64);
+
+        /* If the buffer is wrapped, the bo/buffer of buffer_store is bogus.
+         * So it is enough to allocate one 64 byte bo
+         */
+        if (wrapper_flag)
+            buffer_store->bo = dri_bo_alloc(i965->intel.bufmgr, "Bogus buffer",
+                                            64, 64);
+        else
+            buffer_store->bo = dri_bo_alloc(i965->intel.bufmgr,
+                                            "Buffer",
+                                            size * num_elements, 64);
         assert(buffer_store->bo);
 
-        if (type == VAEncCodedBufferType) {
+        /* If the buffer is wrapped, the bo/buffer of buffer_store is bogus.
+         * In fact it can be skipped. But it is still allocated and it is
+         * only to follow the normal flowchart of buffer_allocation/release.
+         */
+        if (!wrapper_flag) {
+          if (type == VAEncCodedBufferType) {
             struct i965_coded_buffer_segment *coded_buffer_segment;
 
             dri_bo_map(buffer_store->bo, 1);
@@ -2244,10 +2497,12 @@ i965_create_buffer_internal(VADriverContextP ctx,
             coded_buffer_segment->base.next = NULL;
             coded_buffer_segment->mapped = 0;
             coded_buffer_segment->codec = 0;
+            coded_buffer_segment->status_support = 0;
             dri_bo_unmap(buffer_store->bo);
-        } else if (data) {
-            dri_bo_subdata(buffer_store->bo, 0, size * num_elements, data);
-        }
+          } else if (data) {
+              dri_bo_subdata(buffer_store->bo, 0, size * num_elements, data);
+          }
+       }
 
     } else {
         int msize = size;
@@ -2256,10 +2511,14 @@ i965_create_buffer_internal(VADriverContextP ctx,
             msize = ALIGN(size, 4);
         }
 
-        buffer_store->buffer = malloc(msize * num_elements);
+        /* If the buffer is wrapped, it is enough to allocate 4 bytes */
+        if (wrapper_flag)
+            buffer_store->buffer = malloc(4);
+        else
+            buffer_store->buffer = malloc(msize * num_elements);
         assert(buffer_store->buffer);
 
-        if (data)
+        if (data && (!wrapper_flag))
             memcpy(buffer_store->buffer, data, size * num_elements);
     }
 
@@ -2295,6 +2554,19 @@ i965_BufferSetNumElements(VADriverContextP ctx,
 
     ASSERT_RET(obj_buffer, VA_STATUS_ERROR_INVALID_BUFFER);
 
+    /* When the wrapper_buffer exists, it will wrapper to the
+     * buffer allocated from backend driver.
+     */
+    if ((obj_buffer->wrapper_buffer != VA_INVALID_ID) &&
+        i965->wrapper_pdrvctx) {
+        VADriverContextP pdrvctx = i965->wrapper_pdrvctx;
+
+        CALL_VTABLE(pdrvctx, vaStatus,
+                    vaBufferSetNumElements(pdrvctx, obj_buffer->wrapper_buffer,
+                                         num_elements));
+        return vaStatus;
+    }
+
     if ((num_elements < 0) || 
         (num_elements > obj_buffer->max_num_elements)) {
         vaStatus = VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
@@ -2316,8 +2588,24 @@ i965_MapBuffer(VADriverContextP ctx,
     struct i965_driver_data *i965 = i965_driver_data(ctx);
     struct object_buffer *obj_buffer = BUFFER(buf_id);
     VAStatus vaStatus = VA_STATUS_ERROR_UNKNOWN;
+    struct object_context *obj_context;
 
     ASSERT_RET(obj_buffer && obj_buffer->buffer_store, VA_STATUS_ERROR_INVALID_BUFFER);
+
+    obj_context = CONTEXT(obj_buffer->context_id);
+
+    /* When the wrapper_buffer exists, it will wrapper to the
+     * buffer allocated from backend driver.
+     */
+    if ((obj_buffer->wrapper_buffer != VA_INVALID_ID) &&
+        i965->wrapper_pdrvctx) {
+        VADriverContextP pdrvctx = i965->wrapper_pdrvctx;
+
+        CALL_VTABLE(pdrvctx, vaStatus,
+                    vaMapBuffer(pdrvctx, obj_buffer->wrapper_buffer, pbuf));
+        return vaStatus;
+    }
+
     ASSERT_RET(obj_buffer->buffer_store->bo || obj_buffer->buffer_store->buffer, VA_STATUS_ERROR_INVALID_BUFFER);
     ASSERT_RET(!(obj_buffer->buffer_store->bo && obj_buffer->buffer_store->buffer), VA_STATUS_ERROR_INVALID_BUFFER);
 
@@ -2336,6 +2624,7 @@ i965_MapBuffer(VADriverContextP ctx,
 
         ASSERT_RET(obj_buffer->buffer_store->bo->virtual, VA_STATUS_ERROR_OPERATION_FAILED);
         *pbuf = obj_buffer->buffer_store->bo->virtual;
+        vaStatus = VA_STATUS_SUCCESS;
 
         if (obj_buffer->type == VAEncCodedBufferType) {
             int i;
@@ -2348,69 +2637,89 @@ i965_MapBuffer(VADriverContextP ctx,
 
                 coded_buffer_segment->base.buf = buffer = (unsigned char *)(obj_buffer->buffer_store->bo->virtual) + I965_CODEDBUFFER_HEADER_SIZE;
 
-                if (coded_buffer_segment->codec == CODEC_H264 ||
-                    coded_buffer_segment->codec == CODEC_H264_MVC) {
-                    delimiter0 = H264_DELIMITER0;
-                    delimiter1 = H264_DELIMITER1;
-                    delimiter2 = H264_DELIMITER2;
-                    delimiter3 = H264_DELIMITER3;
-                    delimiter4 = H264_DELIMITER4;
-                } else if (coded_buffer_segment->codec == CODEC_MPEG2) {
-                    delimiter0 = MPEG2_DELIMITER0;
-                    delimiter1 = MPEG2_DELIMITER1;
-                    delimiter2 = MPEG2_DELIMITER2;
-                    delimiter3 = MPEG2_DELIMITER3;
-                    delimiter4 = MPEG2_DELIMITER4;
-                } else if(coded_buffer_segment->codec == CODEC_JPEG) {
-                    //In JPEG End of Image (EOI = 0xDDF9) marker can be used for delimiter.
-                    delimiter0 = 0xFF;
-                    delimiter1 = 0xD9;
-                } else if (coded_buffer_segment->codec == CODEC_HEVC) {
-                    delimiter0 = HEVC_DELIMITER0;
-                    delimiter1 = HEVC_DELIMITER1;
-                    delimiter2 = HEVC_DELIMITER2;
-                    delimiter3 = HEVC_DELIMITER3;
-                    delimiter4 = HEVC_DELIMITER4;
-                } else if (coded_buffer_segment->codec != CODEC_VP8) {
-                    ASSERT_RET(0, VA_STATUS_ERROR_UNSUPPORTED_PROFILE);
-                }
+                if (obj_context &&
+                    obj_context->hw_context &&
+                    obj_context->hw_context->get_status &&
+                    coded_buffer_segment->status_support) {
+                    vaStatus = obj_context->hw_context->get_status(ctx, obj_context->hw_context, coded_buffer_segment);
+                } else {
 
-                if(coded_buffer_segment->codec == CODEC_JPEG) {
-                    for(i = 0; i <  obj_buffer->size_element - header_offset - 1 - 0x1000; i++) {
-                        if( (buffer[i] == 0xFF) && (buffer[i + 1] == 0xD9)) {
-                            break;
+                    if (coded_buffer_segment->codec == CODEC_VP9) {
+
+                        if (obj_context == NULL)
+                            return VA_STATUS_ERROR_ENCODING_ERROR;
+
+                        gen9_vp9_get_coded_status(ctx, (char *)coded_buffer_segment,
+                                                  obj_context->hw_context);
+                    }
+                    else if (coded_buffer_segment->codec == CODEC_H264 ||
+                        coded_buffer_segment->codec == CODEC_H264_MVC) {
+                        delimiter0 = H264_DELIMITER0;
+                        delimiter1 = H264_DELIMITER1;
+                        delimiter2 = H264_DELIMITER2;
+                        delimiter3 = H264_DELIMITER3;
+                        delimiter4 = H264_DELIMITER4;
+                    } else if (coded_buffer_segment->codec == CODEC_MPEG2) {
+                        delimiter0 = MPEG2_DELIMITER0;
+                        delimiter1 = MPEG2_DELIMITER1;
+                        delimiter2 = MPEG2_DELIMITER2;
+                        delimiter3 = MPEG2_DELIMITER3;
+                        delimiter4 = MPEG2_DELIMITER4;
+                    } else if(coded_buffer_segment->codec == CODEC_JPEG) {
+                        //In JPEG End of Image (EOI = 0xDDF9) marker can be used for delimiter.
+                        delimiter0 = 0xFF;
+                        delimiter1 = 0xD9;
+                    } else if (coded_buffer_segment->codec == CODEC_HEVC) {
+                        delimiter0 = HEVC_DELIMITER0;
+                        delimiter1 = HEVC_DELIMITER1;
+                        delimiter2 = HEVC_DELIMITER2;
+                        delimiter3 = HEVC_DELIMITER3;
+                        delimiter4 = HEVC_DELIMITER4;
+                    } else if (coded_buffer_segment->codec != CODEC_VP8) {
+                        ASSERT_RET(0, VA_STATUS_ERROR_UNSUPPORTED_PROFILE);
+                    }
+
+                    if(coded_buffer_segment->codec == CODEC_VP9) {
+                        /* it is already handled */
+                    } else
+                    if(coded_buffer_segment->codec == CODEC_JPEG) {
+                        for(i = 0; i <  obj_buffer->size_element - header_offset - 1 - 0x1000; i++) {
+                            if( (buffer[i] == 0xFF) && (buffer[i + 1] == 0xD9)) {
+                                break;
+                            }
                         }
-                   }
-                   coded_buffer_segment->base.size = i + 2;
-                } else if (coded_buffer_segment->codec != CODEC_VP8) {
-                    /* vp8 coded buffer size can be told by vp8 internal statistics buffer,
-                       so it don't need to traversal the coded buffer */
-                    for (i = 0; i < obj_buffer->size_element - header_offset - 3 - 0x1000; i++) {
-                        if ((buffer[i] == delimiter0) &&
-                            (buffer[i + 1] == delimiter1) &&
-                            (buffer[i + 2] == delimiter2) &&
-                            (buffer[i + 3] == delimiter3) &&
-                            (buffer[i + 4] == delimiter4))
-                            break;
+                        coded_buffer_segment->base.size = i + 2;
+                    } else if (coded_buffer_segment->codec != CODEC_VP8) {
+                        /* vp8 coded buffer size can be told by vp8 internal statistics buffer,
+                           so it don't need to traversal the coded buffer */
+                        for (i = 0; i < obj_buffer->size_element - header_offset - 3 - 0x1000; i++) {
+                            if ((buffer[i] == delimiter0) &&
+                                (buffer[i + 1] == delimiter1) &&
+                                (buffer[i + 2] == delimiter2) &&
+                                (buffer[i + 3] == delimiter3) &&
+                                (buffer[i + 4] == delimiter4))
+                                break;
+                        }
+
+                        if (i == obj_buffer->size_element - header_offset - 3 - 0x1000) {
+                            coded_buffer_segment->base.status |= VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK;
+                        }
+                        coded_buffer_segment->base.size = i;
                     }
 
-                    if (i == obj_buffer->size_element - header_offset - 3 - 0x1000) {
+                    if (coded_buffer_segment->base.size >= obj_buffer->size_element - header_offset - 0x1000) {
                         coded_buffer_segment->base.status |= VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK;
                     }
-                    coded_buffer_segment->base.size = i;
-                }
 
-                if (coded_buffer_segment->base.size >= obj_buffer->size_element - header_offset - 0x1000) {
-                    coded_buffer_segment->base.status |= VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK;
+                    vaStatus = VA_STATUS_SUCCESS;
                 }
 
                 coded_buffer_segment->mapped = 1;
             } else {
                 assert(coded_buffer_segment->base.buf);
+                vaStatus = VA_STATUS_SUCCESS;
             }
         }
-
-        vaStatus = VA_STATUS_SUCCESS;
     } else if (NULL != obj_buffer->buffer_store->buffer) {
         *pbuf = obj_buffer->buffer_store->buffer;
         vaStatus = VA_STATUS_SUCCESS;
@@ -2430,6 +2739,18 @@ i965_UnmapBuffer(VADriverContextP ctx, VABufferID buf_id)
         return VA_STATUS_ERROR_INVALID_BUFFER;
 
     ASSERT_RET(obj_buffer && obj_buffer->buffer_store, VA_STATUS_ERROR_INVALID_BUFFER);
+    /* When the wrapper_buffer exists, it will wrapper to the
+     * buffer allocated from backend driver.
+     */
+    if ((obj_buffer->wrapper_buffer != VA_INVALID_ID) &&
+        i965->wrapper_pdrvctx) {
+        VADriverContextP pdrvctx = i965->wrapper_pdrvctx;
+
+        CALL_VTABLE(pdrvctx, vaStatus,
+                    vaUnmapBuffer(pdrvctx, obj_buffer->wrapper_buffer));
+        return vaStatus;
+    }
+
     ASSERT_RET(obj_buffer->buffer_store->bo || obj_buffer->buffer_store->buffer, VA_STATUS_ERROR_OPERATION_FAILED);
     ASSERT_RET(!(obj_buffer->buffer_store->bo && obj_buffer->buffer_store->buffer), VA_STATUS_ERROR_OPERATION_FAILED);
 
@@ -2535,6 +2856,14 @@ i965_BeginPicture(VADriverContextP ctx,
         obj_context->codec_state.encode.num_packed_header_data_ext = 0;
         obj_context->codec_state.encode.slice_index = 0;
         obj_context->codec_state.encode.vps_sps_seq_index = 0;
+        i965_release_buffer_store(&obj_context->codec_state.encode.encmb_map);
+
+        if (obj_config->profile == VAProfileVP9Profile0) {
+            for (i = 0; i < ARRAY_ELEMS(obj_context->codec_state.encode.misc_param); i++)
+                i965_release_buffer_store(&obj_context->codec_state.encode.misc_param[i]);
+
+            i965_release_buffer_store(&obj_context->codec_state.encode.seq_param_ext);
+        }
     } else {
         obj_context->codec_state.decode.current_render_target = render_target;
         i965_release_buffer_store(&obj_context->codec_state.decode.pic_param);
@@ -2549,6 +2878,20 @@ i965_BeginPicture(VADriverContextP ctx,
 
         obj_context->codec_state.decode.num_slice_params = 0;
         obj_context->codec_state.decode.num_slice_datas = 0;
+
+        if ((obj_context->wrapper_context != VA_INVALID_ID) &&
+            i965->wrapper_pdrvctx) {
+            if (obj_surface->wrapper_surface == VA_INVALID_ID)
+                vaStatus = i965_surface_wrapper(ctx, render_target);
+
+            if (vaStatus != VA_STATUS_SUCCESS)
+                return vaStatus;
+
+            CALL_VTABLE(i965->wrapper_pdrvctx, vaStatus,
+                        vaBeginPicture(i965->wrapper_pdrvctx,
+                                       obj_context->wrapper_context,
+                                       obj_surface->wrapper_surface));
+        }
     }
 
     return vaStatus;
@@ -2599,6 +2942,120 @@ DEF_RENDER_DECODE_SINGLE_BUFFER_FUNC(probability_data, probability_data)
 DEF_RENDER_DECODE_MULTI_BUFFER_FUNC(slice_parameter, slice_params)
 DEF_RENDER_DECODE_MULTI_BUFFER_FUNC(slice_data, slice_datas)
 
+
+static VAStatus
+i965_decoder_vp9_wrapper_picture(VADriverContextP ctx,
+                             VABufferID *buffers,
+                             int num_buffers)
+{
+    struct i965_driver_data *i965 = i965_driver_data(ctx);
+    VAStatus vaStatus = VA_STATUS_SUCCESS;
+    int i;
+    VADecPictureParameterBufferVP9 *pVp9PicParams;
+    VADriverContextP pdrvctx;
+    struct object_buffer *obj_buffer;
+
+    pdrvctx = i965->wrapper_pdrvctx;
+    /* do the conversion of VADecPictureParameterBufferVP9 */
+    for (i = 0; i < num_buffers; i++) {
+        obj_buffer = BUFFER(buffers[i]);
+
+        if (!obj_buffer)
+            continue;
+
+        if (obj_buffer->wrapper_buffer == VA_INVALID_ID)
+            continue;
+
+        if (obj_buffer->type == VAPictureParameterBufferType) {
+            int j;
+            VASurfaceID surface_id;
+            struct object_surface *obj_surface;
+
+            pdrvctx = i965->wrapper_pdrvctx;
+
+            CALL_VTABLE(pdrvctx, vaStatus,
+                        vaMapBuffer(pdrvctx, obj_buffer->wrapper_buffer,
+                                    (void **)(&pVp9PicParams)));
+
+            if (vaStatus != VA_STATUS_SUCCESS)
+                return vaStatus;
+
+            for (j = 0; j < 8; j++) {
+                surface_id = pVp9PicParams->reference_frames[j];
+                obj_surface = SURFACE(surface_id);
+
+                if (!obj_surface)
+                    continue;
+
+                if (obj_surface->wrapper_surface == VA_INVALID_ID) {
+                    vaStatus = i965_surface_wrapper(ctx, surface_id);
+                    if (vaStatus != VA_STATUS_SUCCESS) {
+                        pdrvctx->vtable->vaUnmapBuffer(pdrvctx,
+                                    obj_buffer->wrapper_buffer);
+                        goto fail_out;
+                    }
+                }
+
+                pVp9PicParams->reference_frames[j] = obj_surface->wrapper_surface;
+            }
+            CALL_VTABLE(pdrvctx, vaStatus,
+                        vaUnmapBuffer(pdrvctx, obj_buffer->wrapper_buffer));
+            break;
+        }
+    }
+
+    return VA_STATUS_SUCCESS;
+
+fail_out:
+    return vaStatus;
+}
+
+static VAStatus
+i965_decoder_wrapper_picture(VADriverContextP ctx,
+                             VAContextID context,
+                             VABufferID *buffers,
+                             int num_buffers)
+{
+    struct i965_driver_data *i965 = i965_driver_data(ctx);
+    struct object_context *obj_context = CONTEXT(context);
+    VAStatus vaStatus = VA_STATUS_SUCCESS;
+    int i;
+    VADriverContextP pdrvctx;
+    struct object_buffer *obj_buffer;
+
+    if (obj_context == NULL)
+        return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+    /* When it is not wrapped context, continue the normal flowchart */
+    if (obj_context->wrapper_context == VA_INVALID_ID)
+        return vaStatus;
+
+    if (obj_context->obj_config &&
+        (obj_context->obj_config->profile == VAProfileVP9Profile0)) {
+        vaStatus = i965_decoder_vp9_wrapper_picture(ctx, buffers, num_buffers);
+    } else
+        return VA_STATUS_ERROR_INVALID_PARAMETER;
+
+    pdrvctx = i965->wrapper_pdrvctx;
+
+    for (i = 0; i < num_buffers && vaStatus == VA_STATUS_SUCCESS; i++) {
+        obj_buffer = BUFFER(buffers[i]);
+
+        if (!obj_buffer)
+            continue;
+
+        if (obj_buffer->wrapper_buffer == VA_INVALID_ID) {
+            vaStatus = VA_STATUS_ERROR_INVALID_BUFFER;
+            break;
+        }
+
+        CALL_VTABLE(pdrvctx, vaStatus,
+                    vaRenderPicture(pdrvctx, obj_context->wrapper_context,
+                                    &(obj_buffer->wrapper_buffer), 1));
+    }
+    return vaStatus;
+}
+
 static VAStatus 
 i965_decoder_render_picture(VADriverContextP ctx,
                             VAContextID context,
@@ -2653,6 +3110,10 @@ i965_decoder_render_picture(VADriverContextP ctx,
         }
     }
 
+    if ((vaStatus == VA_STATUS_SUCCESS) &&
+        (obj_context->wrapper_context != VA_INVALID_ID))
+        vaStatus = i965_decoder_wrapper_picture(ctx, context, buffers, num_buffers);
+
     return vaStatus;
 }
 
@@ -2668,6 +3129,7 @@ DEF_RENDER_ENCODE_SINGLE_BUFFER_FUNC(huffman_table, huffman_table)
 /* extended buffer */
 DEF_RENDER_ENCODE_SINGLE_BUFFER_FUNC(sequence_parameter_ext, seq_param_ext)
 DEF_RENDER_ENCODE_SINGLE_BUFFER_FUNC(picture_parameter_ext, pic_param_ext)
+DEF_RENDER_ENCODE_SINGLE_BUFFER_FUNC(encmb_map, encmb_map)
 
 #define DEF_RENDER_ENCODE_MULTI_BUFFER_FUNC(name, member) DEF_RENDER_MULTI_BUFFER_FUNC(encode, name, member)
 // DEF_RENDER_ENCODE_MULTI_BUFFER_FUNC(slice_parameter, slice_params)
@@ -2819,7 +3281,7 @@ i965_encoder_render_picture(VADriverContextP ctx,
             if ((param->type == VAEncPackedHeaderRawData) ||
                 (param->type == VAEncPackedHeaderSlice)) {
                 vaStatus = I965_RENDER_ENCODE_BUFFER(packed_header_params_ext);
-            } else if((obj_config->profile == VAProfileHEVCMain)&&
+            } else if((obj_config->profile == VAProfileHEVCMain) &&
                 (encode->last_packed_header_type == VAEncPackedHeaderSequence)) {
                 vaStatus = i965_encoder_render_packed_header_parameter_buffer(ctx,
                                                                           obj_context,
@@ -2841,10 +3303,14 @@ i965_encoder_render_picture(VADriverContextP ctx,
                 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
                 return vaStatus;
             }
+
             if (encode->last_packed_header_type == VAEncPackedHeaderRawData ||
                 encode->last_packed_header_type == VAEncPackedHeaderSlice) {
                 vaStatus = I965_RENDER_ENCODE_BUFFER(packed_header_data_ext);
 
+                if (obj_config->profile == VAProfileVP9Profile0)
+                    break;
+
                 /* When the PACKED_SLICE_HEADER flag is passed, it will use
                  * the packed_slice_header as the delimeter to decide how
                  * the packed rawdata is inserted for the given slice.
@@ -2913,7 +3379,7 @@ i965_encoder_render_picture(VADriverContextP ctx,
                     ((encode->last_packed_header_type & (~VAEncPackedHeaderMiscMask)) != 0)),
                     VA_STATUS_ERROR_ENCODING_ERROR);
 
-                if((obj_config->profile == VAProfileHEVCMain)&&
+                if((obj_config->profile == VAProfileHEVCMain) &&
                     (encode->last_packed_header_type == VAEncPackedHeaderSequence)) {
 
                         vaStatus = i965_encoder_render_packed_header_data_buffer(ctx,
@@ -2939,6 +3405,10 @@ i965_encoder_render_picture(VADriverContextP ctx,
                                                                  obj_buffer);
             break;
             
+        case VAEncMacroblockMapBufferType:
+            vaStatus = I965_RENDER_ENCODE_BUFFER(encmb_map);
+            break;
+
         default:
             vaStatus = VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE;
             break;
@@ -3009,7 +3479,8 @@ i965_RenderPicture(VADriverContextP ctx,
     if (VAEntrypointVideoProc == obj_config->entrypoint) {
         vaStatus = i965_proc_render_picture(ctx, context, buffers, num_buffers);
     } else if ((VAEntrypointEncSlice == obj_config->entrypoint ) || 
-               (VAEntrypointEncPicture == obj_config->entrypoint)) {
+               (VAEntrypointEncPicture == obj_config->entrypoint) ||
+               (VAEntrypointEncSliceLP == obj_config->entrypoint)) {
         vaStatus = i965_encoder_render_picture(ctx, context, buffers, num_buffers);
     } else {
         vaStatus = i965_decoder_render_picture(ctx, context, buffers, num_buffers);
@@ -3032,7 +3503,10 @@ i965_EndPicture(VADriverContextP ctx, VAContextID context)
     if (obj_context->codec_type == CODEC_PROC) {
         ASSERT_RET(VAEntrypointVideoProc == obj_config->entrypoint, VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT);
     } else if (obj_context->codec_type == CODEC_ENC) {
-        ASSERT_RET(((VAEntrypointEncSlice == obj_config->entrypoint) || (VAEntrypointEncPicture == obj_config->entrypoint)), VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT);
+        ASSERT_RET(((VAEntrypointEncSlice == obj_config->entrypoint) ||
+                    (VAEntrypointEncPicture == obj_config->entrypoint) ||
+                    (VAEntrypointEncSliceLP == obj_config->entrypoint)),
+                   VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT);
 
         if (obj_context->codec_state.encode.num_packed_header_params_ext !=
                obj_context->codec_state.encode.num_packed_header_data_ext) {
@@ -3046,11 +3520,14 @@ i965_EndPicture(VADriverContextP ctx, VAContextID context)
         if (!(obj_context->codec_state.encode.seq_param ||
                 obj_context->codec_state.encode.seq_param_ext) &&
                 (VAEntrypointEncPicture != obj_config->entrypoint)) {
-            return VA_STATUS_ERROR_INVALID_PARAMETER;
+            /* The seq_param is not mandatory for VP9 encoding */
+            if (obj_config->profile != VAProfileVP9Profile0)
+                return VA_STATUS_ERROR_INVALID_PARAMETER;
         }
         if ((obj_context->codec_state.encode.num_slice_params <=0) &&
                 (obj_context->codec_state.encode.num_slice_params_ext <=0) &&
-                (obj_config->profile != VAProfileVP8Version0_3)) {
+                ((obj_config->profile != VAProfileVP8Version0_3) &&
+                 (obj_config->profile != VAProfileVP9Profile0))) {
             return VA_STATUS_ERROR_INVALID_PARAMETER;
         }
 
@@ -3076,6 +3553,18 @@ i965_EndPicture(VADriverContextP ctx, VAContextID context)
                 obj_context->codec_state.decode.num_slice_datas) {
             return VA_STATUS_ERROR_INVALID_PARAMETER;
         }
+
+        if (obj_context->wrapper_context != VA_INVALID_ID) {
+            /* call the vaEndPicture of wrapped driver */
+            VADriverContextP pdrvctx;
+            VAStatus va_status;
+
+            pdrvctx = i965->wrapper_pdrvctx;
+            CALL_VTABLE(pdrvctx, va_status,
+                        vaEndPicture(pdrvctx, obj_context->wrapper_context));
+
+            return va_status;
+        }
     }
 
     ASSERT_RET(obj_context->hw_context->run, VA_STATUS_ERROR_OPERATION_FAILED);
@@ -3437,6 +3926,14 @@ i965_CreateImage(VADriverContextP ctx,
         image->offsets[0] = 0;
         image->data_size  = size * 2;
         break;
+    case VA_FOURCC_P010:
+        image->num_planes = 2;
+        image->pitches[0] = awidth * 2;
+        image->offsets[0] = 0;
+        image->pitches[1] = awidth * 2;
+        image->offsets[1] = size * 2;
+        image->data_size  = size * 2 + 2 * size2 * 2;
+        break;
     default:
         goto error;
     }
@@ -3495,25 +3992,29 @@ i965_check_alloc_surface_bo(VADriverContextP ctx,
     obj_surface->x_cb_offset = 0; /* X offset is always 0 */
     obj_surface->x_cr_offset = 0;
 
+    int bpp_1stplane = bpp_1stplane_by_fourcc(fourcc);
+
     if ((tiled && !obj_surface->user_disable_tiling)) {
         ASSERT_RET(fourcc != VA_FOURCC_I420 &&
                fourcc != VA_FOURCC_IYUV &&
                fourcc != VA_FOURCC_YV12,
                VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT);
+
         if (obj_surface->user_h_stride_set) {
-            ASSERT_RET(IS_ALIGNED(obj_surface->width, 128), VA_STATUS_ERROR_INVALID_PARAMETER);
+           ASSERT_RET(IS_ALIGNED(obj_surface->width, 128), VA_STATUS_ERROR_INVALID_PARAMETER);
         } else
-            obj_surface->width = ALIGN(obj_surface->orig_width, 128);
+          obj_surface->width = ALIGN(obj_surface->orig_width * bpp_1stplane, 128);
 
         if (obj_surface->user_v_stride_set) {
-            ASSERT_RET(IS_ALIGNED(obj_surface->height, 32), VA_STATUS_ERROR_INVALID_PARAMETER);
-        } else
-            obj_surface->height = ALIGN(obj_surface->orig_height, 32);
+          ASSERT_RET(IS_ALIGNED(obj_surface->height, 32), VA_STATUS_ERROR_INVALID_PARAMETER);
+        }else
+          obj_surface->height = ALIGN(obj_surface->orig_height, 32);
 
         region_height = obj_surface->height;
 
         switch (fourcc) {
         case VA_FOURCC_NV12:
+        case VA_FOURCC_P010:
             assert(subsampling == SUBSAMPLE_YUV420);
             obj_surface->cb_cr_pitch = obj_surface->width;
             obj_surface->cb_cr_width = obj_surface->orig_width / 2;
@@ -3650,6 +4151,7 @@ i965_check_alloc_surface_bo(VADriverContextP ctx,
 
         switch (fourcc) {
         case VA_FOURCC_NV12:
+        case VA_FOURCC_P010:
             obj_surface->y_cb_offset = obj_surface->height;
             obj_surface->y_cr_offset = obj_surface->height;
             obj_surface->cb_cr_width = obj_surface->orig_width / 2;
@@ -3797,7 +4299,10 @@ VAStatus i965_DeriveImage(VADriverContextP ctx,
 
     image->format.fourcc = obj_surface->fourcc;
     image->format.byte_order = VA_LSB_FIRST;
-    image->format.bits_per_pixel = 12;
+    image->format.bits_per_pixel = get_bpp_from_fourcc(obj_surface->fourcc);
+
+    if (!image->format.bits_per_pixel)
+        goto error;
 
     switch (image->format.fourcc) {
     case VA_FOURCC_YV12:
@@ -3821,6 +4326,7 @@ VAStatus i965_DeriveImage(VADriverContextP ctx,
         break;
 
     case VA_FOURCC_NV12:
+    case VA_FOURCC_P010:
         image->num_planes = 2;
         image->pitches[0] = w_pitch; /* Y */
         image->offsets[0] = 0;
@@ -3856,6 +4362,39 @@ VAStatus i965_DeriveImage(VADriverContextP ctx,
     case VA_FOURCC_BGRX:
         image->num_planes = 1;
         image->pitches[0] = obj_surface->width;
+
+        switch (image->format.fourcc) {
+        case VA_FOURCC_RGBA:
+        case VA_FOURCC_RGBX:
+            image->format.red_mask = 0x000000ff;
+            image->format.green_mask = 0x0000ff00;
+            image->format.blue_mask = 0x00ff0000;
+            break;
+        case VA_FOURCC_BGRA:
+        case VA_FOURCC_BGRX:
+            image->format.red_mask = 0x00ff0000;
+            image->format.green_mask = 0x0000ff00;
+            image->format.blue_mask = 0x000000ff;
+            break;
+        default:
+            goto error;
+        }
+
+        switch (image->format.fourcc) {
+        case VA_FOURCC_RGBA:
+        case VA_FOURCC_BGRA:
+            image->format.alpha_mask = 0xff000000;
+            image->format.depth = 32;
+            break;
+        case VA_FOURCC_RGBX:
+        case VA_FOURCC_BGRX:
+            image->format.alpha_mask = 0x00000000;
+            image->format.depth = 24;
+            break;
+        default:
+            goto error;
+        }
+
         break;
     default:
         goto error;
@@ -4152,8 +4691,6 @@ i965_sw_getimage(VADriverContextP ctx,
     struct object_surface *obj_surface, struct object_image *obj_image,
     const VARectangle *rect)
 {
-    struct i965_driver_data * const i965 = i965_driver_data(ctx);
-    struct i965_render_state *render_state = &i965->render_state;
     void *image_data = NULL;
     VAStatus va_status;
 
@@ -4177,7 +4714,6 @@ i965_sw_getimage(VADriverContextP ctx,
         get_image_yuy2(obj_image, image_data, obj_surface, rect);
         break;
     default:
-    operation_failed:
         va_status = VA_STATUS_ERROR_OPERATION_FAILED;
         break;
     }
@@ -4907,7 +5443,8 @@ i965_GetSurfaceAttributes(
                            IS_GEN8(i965->intel.device_info) ||
                            IS_GEN9(i965->intel.device_info)) {
                     if (obj_config->entrypoint == VAEntrypointEncSlice ||
-                        obj_config->entrypoint == VAEntrypointVideoProc) {
+                        obj_config->entrypoint == VAEntrypointVideoProc ||
+                        obj_config->entrypoint == VAEntrypointEncSliceLP) {
                         switch (attrib_list[i].value.value.i) {
                         case VA_FOURCC_NV12:
                         case VA_FOURCC_I420:
@@ -4966,7 +5503,9 @@ i965_QuerySurfaceAttributes(VADriverContextP ctx,
     struct object_config *obj_config;
     int i = 0;
     VASurfaceAttrib *attribs = NULL;
-    
+    int max_width;
+    int max_height;
+
     if (config == VA_INVALID_ID)
         return VA_STATUS_ERROR_INVALID_CONFIG;
 
@@ -5127,7 +5666,13 @@ i965_QuerySurfaceAttributes(VADriverContextP ctx,
                 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
                 attribs[i].value.value.i = VA_FOURCC_444P;
                 i++;
-            } else {
+            } else if (obj_config->profile == VAProfileHEVCMain10) {
+                attribs[i].type = VASurfaceAttribPixelFormat;
+                attribs[i].value.type = VAGenericValueTypeInteger;
+                attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
+                attribs[i].value.value.i = VA_FOURCC_P010;
+                i++;
+             } else {
                 attribs[i].type = VASurfaceAttribPixelFormat;
                 attribs[i].value.type = VAGenericValueTypeInteger;
                 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
@@ -5251,31 +5796,40 @@ i965_QuerySurfaceAttributes(VADriverContextP ctx,
                 i++;
             }
         } else if (obj_config->entrypoint == VAEntrypointEncSlice ||  /* encode */
-                   obj_config->entrypoint == VAEntrypointVideoProc) { /* vpp */
-
-            attribs[i].type = VASurfaceAttribPixelFormat;
-            attribs[i].value.type = VAGenericValueTypeInteger;
-            attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
-            attribs[i].value.value.i = VA_FOURCC_NV12;
-            i++;
-
-            attribs[i].type = VASurfaceAttribPixelFormat;
-            attribs[i].value.type = VAGenericValueTypeInteger;
-            attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
-            attribs[i].value.value.i = VA_FOURCC_I420;
-            i++;
+                   obj_config->entrypoint == VAEntrypointVideoProc ||
+                   obj_config->entrypoint == VAEntrypointEncSliceLP) {
 
-            attribs[i].type = VASurfaceAttribPixelFormat;
-            attribs[i].value.type = VAGenericValueTypeInteger;
-            attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
-            attribs[i].value.value.i = VA_FOURCC_YV12;
-            i++;
-
-            attribs[i].type = VASurfaceAttribPixelFormat;
-            attribs[i].value.type = VAGenericValueTypeInteger;
-            attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
-            attribs[i].value.value.i = VA_FOURCC_IMC3;
-            i++;
+            if (obj_config->profile == VAProfileHEVCMain10) {
+                attribs[i].type = VASurfaceAttribPixelFormat;
+                attribs[i].value.type = VAGenericValueTypeInteger;
+                attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
+                attribs[i].value.value.i = VA_FOURCC_P010;
+                i++;
+            } else {
+              attribs[i].type = VASurfaceAttribPixelFormat;
+              attribs[i].value.type = VAGenericValueTypeInteger;
+              attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
+              attribs[i].value.value.i = VA_FOURCC_NV12;
+              i++;
+
+              attribs[i].type = VASurfaceAttribPixelFormat;
+              attribs[i].value.type = VAGenericValueTypeInteger;
+              attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
+              attribs[i].value.value.i = VA_FOURCC_I420;
+              i++;
+
+              attribs[i].type = VASurfaceAttribPixelFormat;
+              attribs[i].value.type = VAGenericValueTypeInteger;
+              attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
+              attribs[i].value.value.i = VA_FOURCC_YV12;
+              i++;
+
+              attribs[i].type = VASurfaceAttribPixelFormat;
+              attribs[i].value.type = VAGenericValueTypeInteger;
+              attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
+              attribs[i].value.value.i = VA_FOURCC_IMC3;
+              i++;
+            }
 
             if (obj_config->entrypoint == VAEntrypointVideoProc) {
                 attribs[i].type = VASurfaceAttribPixelFormat;
@@ -5313,6 +5867,14 @@ i965_QuerySurfaceAttributes(VADriverContextP ctx,
                 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
                 attribs[i].value.value.i = VA_FOURCC_YV16;
                 i++;
+
+                if(HAS_VPP_P010(i965)) {
+                  attribs[i].type = VASurfaceAttribPixelFormat;
+                  attribs[i].value.type = VAGenericValueTypeInteger;
+                  attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
+                  attribs[i].value.value.i = VA_FOURCC_P010;
+                  i++;
+                }
             }
         }
     }
@@ -5331,16 +5893,18 @@ i965_QuerySurfaceAttributes(VADriverContextP ctx,
     attribs[i].value.value.p = NULL; /* ignore */
     i++;
 
+    max_resolution(i965, obj_config, &max_width, &max_height);
+
     attribs[i].type = VASurfaceAttribMaxWidth;
     attribs[i].value.type = VAGenericValueTypeInteger;
     attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
-    attribs[i].value.value.i = i965->codec_info->max_width;
+    attribs[i].value.value.i = max_width;
     i++;
 
     attribs[i].type = VASurfaceAttribMaxHeight;
     attribs[i].value.type = VAGenericValueTypeInteger;
     attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
-    attribs[i].value.value.i = i965->codec_info->max_height;
+    attribs[i].value.value.i = max_height;
     i++;
 
     if (i > *num_attribs) {
@@ -5448,6 +6012,16 @@ i965_AcquireBufferHandle(VADriverContextP ctx, VABufferID buf_id,
     if (obj_buffer->type != VAImageBufferType)
         return VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE;
 
+    /*
+     * As the allocated buffer by calling vaCreateBuffer is related with
+     * the specific context, it is unnecessary to export it.
+     * So it is not supported when the buffer is allocated from wrapped
+     * backend dirver.
+     */
+    if (obj_buffer->wrapper_buffer != VA_INVALID_ID) {
+        return VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE;
+    }
+
     if (!buf_info)
         return VA_STATUS_ERROR_INVALID_PARAMETER;
 
@@ -5477,6 +6051,10 @@ i965_ReleaseBufferHandle(VADriverContextP ctx, VABufferID buf_id)
     if (!obj_buffer)
         return VA_STATUS_ERROR_INVALID_BUFFER;
 
+    if (obj_buffer->wrapper_buffer != VA_INVALID_ID) {
+        return VA_STATUS_ERROR_INVALID_BUFFER;
+    }
+
     return i965_release_buffer_handle(obj_buffer);
 }
 
@@ -5907,7 +6485,7 @@ error:
  * to initialize/load the wrapper context of backend driver.
  * Otherwise it is not loaded.
  */
-#if HAVE_USE_WRAPPER
+#if HAVE_HYBRID_CODEC
 
 static VAStatus
 i965_initialize_wrapper(VADriverContextP ctx, const char *driver_name)
@@ -5925,10 +6503,9 @@ i965_initialize_wrapper(VADriverContextP ctx, const char *driver_name)
     VAStatus va_status = VA_STATUS_SUCCESS;
     bool driver_loaded = false;
 
-    if (!(IS_HASWELL(i965->intel.device_info) ||
-          IS_GEN8(i965->intel.device_info) ||
-          IS_GEN9(i965->intel.device_info))) {
-        return VA_STATUS_ERROR_UNIMPLEMENTED;
+    if (HAS_VP9_DECODING(i965)) {
+        i965->wrapper_pdrvctx = NULL;
+        return va_status;
     }
 
     wrapper_pdrvctx = calloc(1, sizeof(*wrapper_pdrvctx));
@@ -5954,11 +6531,6 @@ i965_initialize_wrapper(VADriverContextP ctx, const char *driver_name)
         memset(driver_path, 0, sizeof(driver_path));
         sprintf(driver_path, "%s/%s%s", driver_dir, driver_name, DRIVER_EXTENSION);
 
-        if (access(driver_path, F_OK)) {
-            driver_dir = strtok_r(NULL, ":", &saveptr);
-            continue;
-        }
-
         handle = dlopen(driver_path, RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
         if (!handle) {
             fprintf(stderr, "failed to open %s\n", driver_path);
@@ -6062,7 +6634,7 @@ i965_Init(VADriverContextP ctx)
         if (i965->codec_info && i965->codec_info->preinit_hw_codec)
             i965->codec_info->preinit_hw_codec(ctx, i965->codec_info);
 
-#if HAVE_USE_WRAPPER
+#if HAVE_HYBRID_CODEC
         i965_initialize_wrapper(ctx, "hybrid");
 #endif
 
@@ -6087,20 +6659,20 @@ i965_Terminate(VADriverContextP ctx)
     struct i965_driver_data *i965 = i965_driver_data(ctx);
     int i;
 
-    if (i965->wrapper_pdrvctx) {
-       VADriverContextP pdrvctx;
-       pdrvctx = i965->wrapper_pdrvctx;
-       if (pdrvctx->handle) {
-           pdrvctx->vtable->vaTerminate(pdrvctx);
-           dlclose(pdrvctx->handle);
-           pdrvctx->handle = NULL;
-       }
-       free(pdrvctx->vtable);
-       free(pdrvctx);
-       i965->wrapper_pdrvctx = NULL;
-    }
-
     if (i965) {
+        if (i965->wrapper_pdrvctx) {
+            VADriverContextP pdrvctx;
+            pdrvctx = i965->wrapper_pdrvctx;
+            if (pdrvctx->handle) {
+                pdrvctx->vtable->vaTerminate(pdrvctx);
+                dlclose(pdrvctx->handle);
+                pdrvctx->handle = NULL;
+            }
+            free(pdrvctx->vtable);
+            free(pdrvctx);
+            i965->wrapper_pdrvctx = NULL;
+        }
+
         for (i = ARRAY_ELEMS(i965_sub_ops); i > 0; i--)
             if (i965_sub_ops[i - 1].display_type == 0 ||
                 i965_sub_ops[i - 1].display_type == (ctx->display_type & VA_DISPLAY_MAJOR_MASK)) {