OSDN Git Service

Add info messages for failure cases of vaExportSurfaceHandle()
[android-x86/hardware-intel-common-vaapi.git] / src / i965_drv_video.c
index 67d1186..e27d76e 100644 (file)
@@ -30,6 +30,7 @@
 #include "sysdeps.h"
 #include <unistd.h>
 #include <dlfcn.h>
+#include <drm_fourcc.h>
 
 #ifdef HAVE_VA_X11
 # include "i965_output_dri.h"
@@ -537,7 +538,8 @@ i965_QueryConfigProfiles(VADriverContextP ctx,
 
     if (HAS_H264_DECODING(i965) ||
         HAS_H264_ENCODING(i965) ||
-        HAS_LP_H264_ENCODING(i965)) {
+        HAS_LP_H264_ENCODING(i965) ||
+        HAS_FEI_H264_ENCODING(i965)) {
         profile_list[i++] = VAProfileH264ConstrainedBaseline;
         profile_list[i++] = VAProfileH264Main;
         profile_list[i++] = VAProfileH264High;
@@ -646,6 +648,9 @@ i965_QueryConfigEntrypoints(VADriverContextP ctx,
         if (HAS_LP_H264_ENCODING(i965))
             entrypoint_list[n++] = VAEntrypointEncSliceLP;
 
+        if (HAS_FEI_H264_ENCODING(i965))
+            entrypoint_list[n++] = VAEntrypointFEI;
+
         break;
     case VAProfileH264MultiviewHigh:
     case VAProfileH264StereoHigh:
@@ -762,10 +767,11 @@ i965_validate_config(VADriverContextP ctx, VAProfile profile,
     case VAProfileH264High:
         if ((HAS_H264_DECODING(i965) && entrypoint == VAEntrypointVLD) ||
             (HAS_H264_ENCODING(i965) && entrypoint == VAEntrypointEncSlice) ||
-            (HAS_LP_H264_ENCODING(i965) && entrypoint == VAEntrypointEncSliceLP)) {
+            (HAS_LP_H264_ENCODING(i965) && entrypoint == VAEntrypointEncSliceLP) ||
+            (HAS_FEI_H264_ENCODING(i965) && entrypoint == VAEntrypointFEI)) {
             va_status = VA_STATUS_SUCCESS;
         } else if (!HAS_H264_DECODING(i965) && !HAS_H264_ENCODING(i965) &&
-                   !HAS_LP_H264_ENCODING(i965)) {
+                   !HAS_LP_H264_ENCODING(i965) && !HAS_FEI_H264_ENCODING(i965)) {
             va_status = VA_STATUS_ERROR_UNSUPPORTED_PROFILE;
         } else {
             va_status = VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT;
@@ -994,6 +1000,14 @@ i965_GetConfigAttributes(VADriverContextP ctx,
                     attrib_list[i].value = i965->codec_info->lp_h264_brc_mode;
                 else
                     attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
+            } else if (entrypoint == VAEntrypointFEI) {
+                /* Only CQP is supported in FEI Entrypoint */
+                if (profile == VAProfileH264ConstrainedBaseline ||
+                    profile == VAProfileH264Main ||
+                    profile == VAProfileH264High)
+                    attrib_list[i].value = VA_RC_CQP;
+                else
+                    attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
             } else
                 attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
 
@@ -1001,7 +1015,8 @@ i965_GetConfigAttributes(VADriverContextP ctx,
 
         case VAConfigAttribEncPackedHeaders:
             if (entrypoint == VAEntrypointEncSlice ||
-                entrypoint == VAEntrypointEncSliceLP) {
+                entrypoint == VAEntrypointEncSliceLP ||
+                entrypoint == VAEntrypointFEI) {
                 attrib_list[i].value = VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_PICTURE | VA_ENC_PACKED_HEADER_MISC;
                 if (profile == VAProfileH264ConstrainedBaseline ||
                     profile == VAProfileH264Main ||
@@ -1022,7 +1037,7 @@ i965_GetConfigAttributes(VADriverContextP ctx,
             break;
 
         case VAConfigAttribEncMaxRefFrames:
-            if (entrypoint == VAEntrypointEncSlice) {
+            if (entrypoint == VAEntrypointEncSlice || entrypoint == VAEntrypointFEI) {
                 attrib_list[i].value = (1 << 16) | (1 << 0);
                 if (profile == VAProfileH264ConstrainedBaseline ||
                     profile == VAProfileH264Main ||
@@ -1050,7 +1065,8 @@ i965_GetConfigAttributes(VADriverContextP ctx,
 
         case VAConfigAttribEncQualityRange:
             if (entrypoint == VAEntrypointEncSlice ||
-                entrypoint == VAEntrypointEncSliceLP) {
+                entrypoint == VAEntrypointEncSliceLP ||
+                entrypoint == VAEntrypointFEI) {
                 attrib_list[i].value = 1;
                 if (profile == VAProfileH264ConstrainedBaseline ||
                     profile == VAProfileH264Main ||
@@ -1087,7 +1103,8 @@ i965_GetConfigAttributes(VADriverContextP ctx,
 
         case VAConfigAttribEncROI:
             if (entrypoint == VAEntrypointEncSlice ||
-                entrypoint == VAEntrypointEncSliceLP) {
+                entrypoint == VAEntrypointEncSliceLP ||
+                entrypoint == VAEntrypointFEI) {
                 VAConfigAttribValEncROI *roi_config =
                     (VAConfigAttribValEncROI *) & (attrib_list[i].value);
 
@@ -1096,18 +1113,18 @@ i965_GetConfigAttributes(VADriverContextP ctx,
                     profile == VAProfileH264High) {
 
                     if (IS_GEN9(i965->intel.device_info) &&
-                        entrypoint == VAEntrypointEncSlice)
+                        (entrypoint == VAEntrypointEncSlice || entrypoint == VAEntrypointFEI))
                         attrib_list[i].value = 0;
                     else {
                         if (entrypoint == VAEntrypointEncSliceLP) {
                             roi_config->bits.num_roi_regions = 3;
                             roi_config->bits.roi_rc_priority_support = 0;
-                            roi_config->bits.roi_rc_qp_delat_support = 0;
+                            roi_config->bits.roi_rc_qp_delta_support = 0;
                         } else {
                             roi_config->bits.num_roi_regions =
                                 I965_MAX_NUM_ROI_REGIONS;
                             roi_config->bits.roi_rc_priority_support = 0;
-                            roi_config->bits.roi_rc_qp_delat_support = 1;
+                            roi_config->bits.roi_rc_qp_delta_support = 1;
                         }
                     }
                 } else if (profile == VAProfileHEVCMain ||
@@ -1115,7 +1132,7 @@ i965_GetConfigAttributes(VADriverContextP ctx,
                     roi_config->bits.num_roi_regions =
                         I965_MAX_NUM_ROI_REGIONS;
                     roi_config->bits.roi_rc_priority_support = 1;
-                    roi_config->bits.roi_rc_qp_delat_support = 1;
+                    roi_config->bits.roi_rc_qp_delta_support = 1;
                 } else {
                     attrib_list[i].value = 0;
                 }
@@ -1155,7 +1172,7 @@ i965_GetConfigAttributes(VADriverContextP ctx,
                            profile == VAProfileHEVCMain10) {
                     attrib_list[i].value = I965_MAX_NUM_SLICE;
                 }
-            } else if (entrypoint == VAEntrypointEncSliceLP) {
+            } else if (entrypoint == VAEntrypointEncSliceLP || entrypoint == VAEntrypointFEI) {
                 if ((profile == VAProfileH264ConstrainedBaseline ||
                      profile == VAProfileH264Main ||
                      profile == VAProfileH264High) ||
@@ -1181,6 +1198,17 @@ i965_GetConfigAttributes(VADriverContextP ctx,
             }
 
             break;
+
+        case VAConfigAttribFEIFunctionType:
+            /* Supporing all possible modes of FEI */
+            attrib_list[i].value = VA_FEI_FUNCTION_ENC |
+                                   VA_FEI_FUNCTION_PAK | VA_FEI_FUNCTION_ENC_PAK;
+            break;
+
+        case VAConfigAttribFEIMVPredictors:
+            attrib_list[i].value = 4;
+            break;
+
         default:
             /* Do nothing */
             attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
@@ -1311,6 +1339,9 @@ i965_CreateConfig(VADriverContextP ctx,
             else if ((entrypoint == VAEntrypointEncSliceLP) && attrib_found &&
                      !(attrib_found->value & i965->codec_info->lp_h264_brc_mode))
                 vaStatus = VA_STATUS_ERROR_INVALID_CONFIG;
+            else if ((entrypoint == VAEntrypointFEI) && attrib_found &&
+                     !(attrib_found->value == VA_RC_CQP))
+                vaStatus = VA_STATUS_ERROR_INVALID_CONFIG;
             break;
         default:
             break;
@@ -1331,7 +1362,7 @@ i965_CreateConfig(VADriverContextP ctx,
             } else if (profile == VAProfileHEVCMain ||
                        profile == VAProfileHEVCMain10)
                 attrib.value = I965_MAX_NUM_SLICE;
-        } else if (entrypoint == VAEntrypointEncSliceLP) {
+        } else if (entrypoint == VAEntrypointEncSliceLP || entrypoint == VAEntrypointFEI) {
             if ((profile == VAProfileH264ConstrainedBaseline ||
                  profile == VAProfileH264Main ||
                  profile == VAProfileH264High) ||
@@ -1543,7 +1574,6 @@ i965_suface_external_memory(VADriverContextP ctx,
         obj_surface->height = memory_attibute->offsets[1] / obj_surface->width;
 
     if (memory_attibute->num_planes > 1) {
-        ASSERT_RET(IS_ALIGNED(obj_surface->height, 16), VA_STATUS_ERROR_INVALID_PARAMETER);
         ASSERT_RET(obj_surface->height >= obj_surface->orig_height, VA_STATUS_ERROR_INVALID_PARAMETER);
     }
 
@@ -2466,7 +2496,8 @@ i965_CreateContext(VADriverContextP ctx,
             obj_context->hw_context = i965->codec_info->proc_hw_context_init(ctx, obj_config);
         } else if ((VAEntrypointEncSlice == obj_config->entrypoint) ||
                    (VAEntrypointEncPicture == obj_config->entrypoint) ||
-                   (VAEntrypointEncSliceLP == obj_config->entrypoint)) {
+                   (VAEntrypointEncSliceLP == obj_config->entrypoint) ||
+                   (VAEntrypointFEI == 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));
@@ -2648,6 +2679,12 @@ i965_create_buffer_internal(VADriverContextP ctx,
     case VAHuffmanTableBufferType:
     case VAProbabilityBufferType:
     case VAEncMacroblockMapBufferType:
+    case VAEncQPBufferType:
+    case VAEncFEIMVBufferType:
+    case VAEncFEIMBCodeBufferType:
+    case VAEncFEIDistortionBufferType:
+    case VAEncFEIMBControlBufferType:
+    case VAEncFEIMVPredictorBufferType:
         /* Ok */
         break;
 
@@ -2709,7 +2746,13 @@ i965_create_buffer_internal(VADriverContextP ctx,
                type == VAImageBufferType ||
                type == VAEncCodedBufferType ||
                type == VAEncMacroblockMapBufferType ||
-               type == VAProbabilityBufferType) {
+               type == VAProbabilityBufferType ||
+               type == VAEncQPBufferType ||
+               type == VAEncFEIMVBufferType ||
+               type == VAEncFEIMBCodeBufferType ||
+               type == VAEncFEIDistortionBufferType ||
+               type == VAEncFEIMBControlBufferType ||
+               type == VAEncFEIMVPredictorBufferType) {
 
         /* If the buffer is wrapped, the bo/buffer of buffer_store is bogus.
          * So it is enough to allocate one 64 byte bo
@@ -3737,7 +3780,8 @@ i965_RenderPicture(VADriverContextP ctx,
         vaStatus = i965_proc_render_picture(ctx, context, buffers, num_buffers);
     } else if ((VAEntrypointEncSlice == obj_config->entrypoint) ||
                (VAEntrypointEncPicture == obj_config->entrypoint) ||
-               (VAEntrypointEncSliceLP == obj_config->entrypoint)) {
+               (VAEntrypointEncSliceLP == obj_config->entrypoint) ||
+               (VAEntrypointFEI == obj_config->entrypoint)) {
         vaStatus = i965_encoder_render_picture(ctx, context, buffers, num_buffers);
     } else {
         vaStatus = i965_decoder_render_picture(ctx, context, buffers, num_buffers);
@@ -3762,7 +3806,8 @@ i965_EndPicture(VADriverContextP ctx, VAContextID context)
     } else if (obj_context->codec_type == CODEC_ENC) {
         ASSERT_RET(((VAEntrypointEncSlice == obj_config->entrypoint) ||
                     (VAEntrypointEncPicture == obj_config->entrypoint) ||
-                    (VAEntrypointEncSliceLP == obj_config->entrypoint)),
+                    (VAEntrypointEncSliceLP == obj_config->entrypoint) ||
+                    (VAEntrypointFEI == obj_config->entrypoint)),
                    VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT);
 
         if (obj_context->codec_state.encode.num_packed_header_params_ext !=
@@ -5721,7 +5766,8 @@ i965_GetSurfaceAttributes(
                            IS_GEN9(i965->intel.device_info)) {
                     if (obj_config->entrypoint == VAEntrypointEncSlice ||
                         obj_config->entrypoint == VAEntrypointVideoProc ||
-                        obj_config->entrypoint == VAEntrypointEncSliceLP) {
+                        obj_config->entrypoint == VAEntrypointEncSliceLP ||
+                        obj_config->entrypoint == VAEntrypointFEI) {
                         switch (attrib_list[i].value.value.i) {
                         case VA_FOURCC_NV12:
                         case VA_FOURCC_I420:
@@ -5992,6 +6038,12 @@ i965_QuerySurfaceAttributes(VADriverContextP ctx,
                 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_UYVY;
+                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_RGBA;
                 i++;
 
@@ -6084,7 +6136,8 @@ i965_QuerySurfaceAttributes(VADriverContextP ctx,
         } else if (obj_config->entrypoint == VAEntrypointEncSlice ||  /* encode */
                    obj_config->entrypoint == VAEntrypointVideoProc ||
                    obj_config->entrypoint == VAEntrypointEncSliceLP ||
-                   obj_config->entrypoint == VAEntrypointEncPicture) {
+                   obj_config->entrypoint == VAEntrypointEncPicture ||
+                   obj_config->entrypoint == VAEntrypointFEI) {
 
             if (obj_config->profile == VAProfileHEVCMain10) {
                 attribs[i].type = VASurfaceAttribPixelFormat;
@@ -6128,6 +6181,12 @@ i965_QuerySurfaceAttributes(VADriverContextP ctx,
                 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_UYVY;
+                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_RGBA;
                 i++;
 
@@ -6378,6 +6437,237 @@ i965_ReleaseBufferHandle(VADriverContextP ctx, VABufferID buf_id)
     return i965_release_buffer_handle(obj_buffer);
 }
 
+// Locally define DRM_FORMAT values not available in older but still
+// supported versions of libdrm.
+#ifndef DRM_FORMAT_R8
+#define DRM_FORMAT_R8        fourcc_code('R', '8', ' ', ' ')
+#endif
+#ifndef DRM_FORMAT_R16
+#define DRM_FORMAT_R16       fourcc_code('R', '1', '6', ' ')
+#endif
+#ifndef DRM_FORMAT_GR88
+#define DRM_FORMAT_GR88      fourcc_code('G', 'R', '8', '8')
+#endif
+#ifndef DRM_FORMAT_GR1616
+#define DRM_FORMAT_GR1616    fourcc_code('G', 'R', '3', '2')
+#endif
+
+static uint32_t drm_format_of_separate_plane(uint32_t fourcc, int plane)
+{
+    if (plane == 0) {
+        switch (fourcc) {
+        case VA_FOURCC_NV12:
+        case VA_FOURCC_I420:
+        case VA_FOURCC_YV12:
+        case VA_FOURCC_YV16:
+        case VA_FOURCC_Y800:
+            return DRM_FORMAT_R8;
+        case VA_FOURCC_P010:
+        case VA_FOURCC_I010:
+            return DRM_FORMAT_R16;
+
+        case VA_FOURCC_YUY2:
+        case VA_FOURCC_UYVY:
+            // These are not representable as separate planes.
+            return 0;
+
+        case VA_FOURCC_RGBA:
+            return DRM_FORMAT_ABGR8888;
+        case VA_FOURCC_RGBX:
+            return DRM_FORMAT_XBGR8888;
+        case VA_FOURCC_BGRA:
+            return DRM_FORMAT_ARGB8888;
+        case VA_FOURCC_BGRX:
+            return DRM_FORMAT_XRGB8888;
+        case VA_FOURCC_ARGB:
+            return DRM_FORMAT_BGRA8888;
+        case VA_FOURCC_ABGR:
+            return DRM_FORMAT_RGBA8888;
+        }
+    } else {
+        switch (fourcc) {
+        case VA_FOURCC_NV12:
+            return DRM_FORMAT_GR88;
+        case VA_FOURCC_I420:
+        case VA_FOURCC_YV12:
+        case VA_FOURCC_YV16:
+            return DRM_FORMAT_R8;
+        case VA_FOURCC_P010:
+            return DRM_FORMAT_GR1616;
+        case VA_FOURCC_I010:
+            return DRM_FORMAT_R16;
+        }
+    }
+    return 0;
+}
+
+static uint32_t drm_format_of_composite_object(uint32_t fourcc)
+{
+    switch (fourcc) {
+    case VA_FOURCC_NV12:
+        return DRM_FORMAT_NV12;
+    case VA_FOURCC_I420:
+        return DRM_FORMAT_YUV420;
+    case VA_FOURCC_YV12:
+        return DRM_FORMAT_YVU420;
+    case VA_FOURCC_YV16:
+        return DRM_FORMAT_YVU422;
+    case VA_FOURCC_YUY2:
+        return DRM_FORMAT_YUYV;
+    case VA_FOURCC_UYVY:
+        return DRM_FORMAT_UYVY;
+    case VA_FOURCC_Y800:
+        return DRM_FORMAT_R8;
+
+    case VA_FOURCC_P010:
+    case VA_FOURCC_I010:
+        // These currently have no composite DRM format - they are usable
+        // only as separate planes.
+        return 0;
+
+    case VA_FOURCC_RGBA:
+        return DRM_FORMAT_ABGR8888;
+    case VA_FOURCC_RGBX:
+        return DRM_FORMAT_XBGR8888;
+    case VA_FOURCC_BGRA:
+        return DRM_FORMAT_ARGB8888;
+    case VA_FOURCC_BGRX:
+        return DRM_FORMAT_XRGB8888;
+    case VA_FOURCC_ARGB:
+        return DRM_FORMAT_BGRA8888;
+    case VA_FOURCC_ABGR:
+        return DRM_FORMAT_RGBA8888;
+    }
+    return 0;
+}
+
+static VAStatus
+i965_ExportSurfaceHandle(VADriverContextP ctx, VASurfaceID surface_id,
+                         uint32_t mem_type, uint32_t flags,
+                         void *descriptor)
+{
+    struct i965_driver_data *const i965 = i965_driver_data(ctx);
+    struct object_surface *obj_surface = SURFACE(surface_id);
+    const i965_fourcc_info *info;
+    VADRMPRIMESurfaceDescriptor *desc;
+    unsigned int tiling, swizzle;
+    uint32_t formats[4], pitch, height, offset;
+    int fd, p;
+    int composite_object =
+        flags & VA_EXPORT_SURFACE_COMPOSED_LAYERS;
+
+    if (!obj_surface || !obj_surface->bo)
+        return VA_STATUS_ERROR_INVALID_SURFACE;
+
+    if (mem_type != VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2) {
+        i965_log_info(ctx, "vaExportSurfaceHandle: memory type %08x "
+                      "is not supported.\n", mem_type);
+        return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
+    }
+
+    info = get_fourcc_info(obj_surface->fourcc);
+    if (!info)
+        return VA_STATUS_ERROR_INVALID_SURFACE;
+    if (composite_object) {
+        formats[0] =
+            drm_format_of_composite_object(obj_surface->fourcc);
+        if (!formats[0]) {
+            i965_log_info(ctx, "vaExportSurfaceHandle: fourcc %08x "
+                          "is not supported for export as a composite "
+                          "object.\n", obj_surface->fourcc);
+            return VA_STATUS_ERROR_INVALID_SURFACE;
+        }
+    } else {
+        for (p = 0; p < info->num_planes; p++) {
+            formats[p] =
+                drm_format_of_separate_plane(obj_surface->fourcc, p);
+            if (!formats[p]) {
+                i965_log_info(ctx, "vaExportSurfaceHandle: fourcc %08x "
+                              "is not supported for export as separate "
+                              "planes.\n", obj_surface->fourcc);
+                return VA_STATUS_ERROR_INVALID_SURFACE;
+            }
+        }
+    }
+
+    if (drm_intel_bo_gem_export_to_prime(obj_surface->bo, &fd))
+        return VA_STATUS_ERROR_INVALID_SURFACE;
+
+    if (drm_intel_bo_get_tiling(obj_surface->bo, &tiling, &swizzle))
+        tiling = I915_TILING_NONE;
+
+    desc = descriptor;
+
+    desc->fourcc = obj_surface->fourcc;
+    desc->width  = obj_surface->width;
+    desc->height = obj_surface->height;
+
+    desc->num_objects     = 1;
+    desc->objects[0].fd   = fd;
+    desc->objects[0].size = obj_surface->size;
+    switch (tiling) {
+    case I915_TILING_X:
+        desc->objects[0].drm_format_modifier = I915_FORMAT_MOD_X_TILED;
+        break;
+    case I915_TILING_Y:
+        desc->objects[0].drm_format_modifier = I915_FORMAT_MOD_Y_TILED;
+        break;
+    case I915_TILING_NONE:
+    default:
+        desc->objects[0].drm_format_modifier = DRM_FORMAT_MOD_NONE;
+    }
+
+    if (composite_object) {
+        desc->num_layers = 1;
+
+        desc->layers[0].drm_format = formats[0];
+        desc->layers[0].num_planes = info->num_planes;
+
+        offset = 0;
+        for (p = 0; p < info->num_planes; p++) {
+            desc->layers[0].object_index[p] = 0;
+
+            if (p == 0) {
+                pitch  = obj_surface->width;
+                height = obj_surface->height;
+            } else {
+                pitch  = obj_surface->cb_cr_pitch;
+                height = obj_surface->cb_cr_height;
+            }
+
+            desc->layers[0].offset[p] = offset;
+            desc->layers[0].pitch[p]  = pitch;
+
+            offset += pitch * height;
+        }
+    } else {
+        desc->num_layers = info->num_planes;
+
+        offset = 0;
+        for (p = 0; p < info->num_planes; p++) {
+            desc->layers[p].drm_format = formats[p];
+            desc->layers[p].num_planes = 1;
+
+            desc->layers[p].object_index[0] = 0;
+
+            if (p == 0) {
+                pitch  = obj_surface->width;
+                height = obj_surface->height;
+            } else {
+                pitch  = obj_surface->cb_cr_pitch;
+                height = obj_surface->cb_cr_height;
+            }
+
+            desc->layers[p].offset[0] = offset;
+            desc->layers[p].pitch[0]  = pitch;
+
+            offset += pitch * height;
+        }
+    }
+
+    return VA_STATUS_SUCCESS;
+}
+
 static int
 i965_os_has_ring_support(VADriverContextP ctx,
                          int ring)
@@ -6625,6 +6915,53 @@ VAStatus i965_QueryVideoProcPipelineCaps(
     return VA_STATUS_SUCCESS;
 }
 
+void i965_log_error(VADriverContextP ctx, const char *format, ...)
+{
+    va_list vl;
+
+    va_start(vl, format);
+
+    if (!ctx->error_callback) {
+        // No error callback: this is a error message which should be
+        // user-visible, so print it to stderr instead.
+        vfprintf(stderr, format, vl);
+    } else {
+        // Put the message on the stack.  If it overruns the size of the
+        // then it will just be truncated - callers shouldn't be sending
+        // messages which are too long.
+        char tmp[1024];
+        int ret;
+        ret = vsnprintf(tmp, sizeof(tmp), format, vl);
+        if (ret > 0)
+            ctx->error_callback(ctx, tmp);
+    }
+
+    va_end(vl);
+}
+
+void i965_log_info(VADriverContextP ctx, const char *format, ...)
+{
+    va_list vl;
+
+    va_start(vl, format);
+
+    if (!ctx->info_callback) {
+        // No info callback: this message is only useful for developers,
+        // so just discard it.
+    } else {
+        // Put the message on the stack.  If it overruns the size of the
+        // then it will just be truncated - callers shouldn't be sending
+        // messages which are too long.
+        char tmp[1024];
+        int ret;
+        ret = vsnprintf(tmp, sizeof(tmp), format, vl);
+        if (ret > 0)
+            ctx->info_callback(ctx, tmp);
+    }
+
+    va_end(vl);
+}
+
 extern struct hw_codec_info *i965_get_codec_info(int devid);
 
 static bool
@@ -7083,6 +7420,9 @@ VA_DRIVER_INIT_FUNC(VADriverContextP ctx)
     vtable->vaAcquireBufferHandle = i965_AcquireBufferHandle;
     vtable->vaReleaseBufferHandle = i965_ReleaseBufferHandle;
 
+    /* 1.0.0 */
+    vtable->vaExportSurfaceHandle = i965_ExportSurfaceHandle;
+
     vtable_vpp->vaQueryVideoProcFilters = i965_QueryVideoProcFilters;
     vtable_vpp->vaQueryVideoProcFilterCaps = i965_QueryVideoProcFilterCaps;
     vtable_vpp->vaQueryVideoProcPipelineCaps = i965_QueryVideoProcPipelineCaps;