st/va: remove unneeded code
[mesa.git] / src / gallium / state_trackers / va / surface.c
index 84a94949c47a77a6d3c4d7cd42fa31746a0e9e41..bfad93f8f3d5269bf68d4798cfcaa5587d586bb2 100644 (file)
@@ -36,6 +36,7 @@
 #include "util/u_rect.h"
 #include "util/u_sampler.h"
 #include "util/u_surface.h"
+#include "util/u_video.h"
 
 #include "vl/vl_compositor.h"
 #include "vl/vl_video_buffer.h"
@@ -44,6 +45,7 @@
 #include "va_private.h"
 
 #include <va/va_drmcommon.h>
+#include "drm-uapi/drm_fourcc.h"
 
 static const enum pipe_format vpp_surface_formats[] = {
    PIPE_FORMAT_B8G8R8A8_UNORM, PIPE_FORMAT_R8G8B8A8_UNORM,
@@ -68,16 +70,20 @@ vlVaDestroySurfaces(VADriverContextP ctx, VASurfaceID *surface_list, int num_sur
       return VA_STATUS_ERROR_INVALID_CONTEXT;
 
    drv = VL_VA_DRIVER(ctx);
-   pipe_mutex_lock(drv->mutex);
+   mtx_lock(&drv->mutex);
    for (i = 0; i < num_surfaces; ++i) {
       vlVaSurface *surf = handle_table_get(drv->htab, surface_list[i]);
+      if (!surf) {
+         mtx_unlock(&drv->mutex);
+         return VA_STATUS_ERROR_INVALID_SURFACE;
+      }
       if (surf->buffer)
          surf->buffer->destroy(surf->buffer);
       util_dynarray_fini(&surf->subpics);
       FREE(surf);
       handle_table_remove(drv->htab, surface_list[i]);
    }
-   pipe_mutex_unlock(drv->mutex);
+   mtx_unlock(&drv->mutex);
 
    return VA_STATUS_SUCCESS;
 }
@@ -85,18 +91,95 @@ vlVaDestroySurfaces(VADriverContextP ctx, VASurfaceID *surface_list, int num_sur
 VAStatus
 vlVaSyncSurface(VADriverContextP ctx, VASurfaceID render_target)
 {
+   vlVaDriver *drv;
+   vlVaContext *context;
+   vlVaSurface *surf;
+
    if (!ctx)
       return VA_STATUS_ERROR_INVALID_CONTEXT;
 
+   drv = VL_VA_DRIVER(ctx);
+   if (!drv)
+      return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+   mtx_lock(&drv->mutex);
+   surf = handle_table_get(drv->htab, render_target);
+
+   if (!surf || !surf->buffer) {
+      mtx_unlock(&drv->mutex);
+      return VA_STATUS_ERROR_INVALID_SURFACE;
+   }
+
+   if (!surf->feedback) {
+      // No outstanding operation: nothing to do.
+      mtx_unlock(&drv->mutex);
+      return VA_STATUS_SUCCESS;
+   }
+
+   context = handle_table_get(drv->htab, surf->ctx);
+   if (!context) {
+      mtx_unlock(&drv->mutex);
+      return VA_STATUS_ERROR_INVALID_CONTEXT;
+   }
+
+   if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
+      if (u_reduce_video_profile(context->templat.profile) == PIPE_VIDEO_FORMAT_MPEG4_AVC) {
+         int frame_diff;
+         if (context->desc.h264enc.frame_num_cnt >= surf->frame_num_cnt)
+            frame_diff = context->desc.h264enc.frame_num_cnt - surf->frame_num_cnt;
+         else
+            frame_diff = 0xFFFFFFFF - surf->frame_num_cnt + 1 + context->desc.h264enc.frame_num_cnt;
+         if ((frame_diff == 0) &&
+             (surf->force_flushed == false) &&
+             (context->desc.h264enc.frame_num_cnt % 2 != 0)) {
+            context->decoder->flush(context->decoder);
+            context->first_single_submitted = true;
+         }
+      }
+      context->decoder->get_feedback(context->decoder, surf->feedback, &(surf->coded_buf->coded_size));
+      surf->feedback = NULL;
+   }
+   mtx_unlock(&drv->mutex);
    return VA_STATUS_SUCCESS;
 }
 
 VAStatus
 vlVaQuerySurfaceStatus(VADriverContextP ctx, VASurfaceID render_target, VASurfaceStatus *status)
 {
+   vlVaDriver *drv;
+   vlVaSurface *surf;
+   vlVaContext *context;
+
    if (!ctx)
       return VA_STATUS_ERROR_INVALID_CONTEXT;
 
+   drv = VL_VA_DRIVER(ctx);
+   if (!drv)
+      return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+   mtx_lock(&drv->mutex);
+
+   surf = handle_table_get(drv->htab, render_target);
+   if (!surf || !surf->buffer) {
+      mtx_unlock(&drv->mutex);
+      return VA_STATUS_ERROR_INVALID_SURFACE;
+   }
+
+   context = handle_table_get(drv->htab, surf->ctx);
+   if (!context) {
+      mtx_unlock(&drv->mutex);
+      return VA_STATUS_ERROR_INVALID_CONTEXT;
+   }
+
+   if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
+      if(surf->feedback == NULL)
+         *status=VASurfaceReady;
+      else
+         *status=VASurfaceRendering;
+   }
+
+   mtx_unlock(&drv->mutex);
+
    return VA_STATUS_SUCCESS;
 }
 
@@ -232,16 +315,17 @@ vlVaPutSurface(VADriverContextP ctx, VASurfaceID surface_id, void* draw, short s
    struct vl_screen *vscreen;
    struct u_rect src_rect, *dirty_area;
    struct u_rect dst_rect = {destx, destx + destw, desty, desty + desth};
+   enum pipe_format format;
    VAStatus status;
 
    if (!ctx)
       return VA_STATUS_ERROR_INVALID_CONTEXT;
 
    drv = VL_VA_DRIVER(ctx);
-   pipe_mutex_lock(drv->mutex);
+   mtx_lock(&drv->mutex);
    surf = handle_table_get(drv->htab, surface_id);
    if (!surf) {
-      pipe_mutex_unlock(drv->mutex);
+      mtx_unlock(&drv->mutex);
       return VA_STATUS_ERROR_INVALID_SURFACE;
    }
 
@@ -250,7 +334,7 @@ vlVaPutSurface(VADriverContextP ctx, VASurfaceID surface_id, void* draw, short s
 
    tex = vscreen->texture_from_drawable(vscreen, draw);
    if (!tex) {
-      pipe_mutex_unlock(drv->mutex);
+      mtx_unlock(&drv->mutex);
       return VA_STATUS_ERROR_INVALID_DISPLAY;
    }
 
@@ -261,7 +345,7 @@ vlVaPutSurface(VADriverContextP ctx, VASurfaceID surface_id, void* draw, short s
    surf_draw = drv->pipe->create_surface(drv->pipe, tex, &surf_templ);
    if (!surf_draw) {
       pipe_resource_reference(&tex, NULL);
-      pipe_mutex_unlock(drv->mutex);
+      mtx_unlock(&drv->mutex);
       return VA_STATUS_ERROR_INVALID_DISPLAY;
    }
 
@@ -270,25 +354,40 @@ vlVaPutSurface(VADriverContextP ctx, VASurfaceID surface_id, void* draw, short s
    src_rect.x1 = srcw + srcx;
    src_rect.y1 = srch + srcy;
 
+   format = surf->buffer->buffer_format;
+
    vl_compositor_clear_layers(&drv->cstate);
-   vl_compositor_set_buffer_layer(&drv->cstate, &drv->compositor, 0, surf->buffer, &src_rect, NULL, VL_COMPOSITOR_WEAVE);
+
+   if (format == PIPE_FORMAT_B8G8R8A8_UNORM || format == PIPE_FORMAT_B8G8R8X8_UNORM ||
+       format == PIPE_FORMAT_R8G8B8A8_UNORM || format == PIPE_FORMAT_R8G8B8X8_UNORM) {
+      struct pipe_sampler_view **views;
+
+      views = surf->buffer->get_sampler_view_planes(surf->buffer);
+      vl_compositor_set_rgba_layer(&drv->cstate, &drv->compositor, 0, views[0], &src_rect, NULL, NULL);
+   } else
+      vl_compositor_set_buffer_layer(&drv->cstate, &drv->compositor, 0, surf->buffer, &src_rect, NULL, VL_COMPOSITOR_WEAVE);
+
    vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dst_rect);
    vl_compositor_render(&drv->cstate, &drv->compositor, surf_draw, dirty_area, true);
 
    status = vlVaPutSubpictures(surf, drv, surf_draw, dirty_area, &src_rect, &dst_rect);
    if (status) {
-      pipe_mutex_unlock(drv->mutex);
+      mtx_unlock(&drv->mutex);
       return status;
    }
 
+   /* flush before calling flush_frontbuffer so that rendering is flushed
+    * to back buffer so the texture can be copied in flush_frontbuffer
+    */
+   drv->pipe->flush(drv->pipe, NULL, 0);
+
    screen->flush_frontbuffer(screen, tex, 0, 0,
                              vscreen->get_private(vscreen), NULL);
 
-   drv->pipe->flush(drv->pipe, NULL, 0);
 
    pipe_resource_reference(&tex, NULL);
    pipe_surface_reference(&surf_draw, NULL);
-   pipe_mutex_unlock(drv->mutex);
+   mtx_unlock(&drv->mutex);
 
    return VA_STATUS_SUCCESS;
 }
@@ -315,17 +414,18 @@ vlVaUnlockSurface(VADriverContextP ctx, VASurfaceID surface)
 }
 
 VAStatus
-vlVaQuerySurfaceAttributes(VADriverContextP ctx, VAConfigID config,
+vlVaQuerySurfaceAttributes(VADriverContextP ctx, VAConfigID config_id,
                            VASurfaceAttrib *attrib_list, unsigned int *num_attribs)
 {
    vlVaDriver *drv;
+   vlVaConfig *config;
    VASurfaceAttrib *attribs;
    struct pipe_screen *pscreen;
    int i, j;
 
    STATIC_ASSERT(ARRAY_SIZE(vpp_surface_formats) <= VL_VA_MAX_IMAGE_FORMATS);
 
-   if (config == VA_INVALID_ID)
+   if (config_id == VA_INVALID_ID)
       return VA_STATUS_ERROR_INVALID_CONFIG;
 
    if (!attrib_list && !num_attribs)
@@ -344,6 +444,13 @@ vlVaQuerySurfaceAttributes(VADriverContextP ctx, VAConfigID config,
    if (!drv)
       return VA_STATUS_ERROR_INVALID_CONTEXT;
 
+   mtx_lock(&drv->mutex);
+   config = handle_table_get(drv->htab, config_id);
+   mtx_unlock(&drv->mutex);
+
+   if (!config)
+      return VA_STATUS_ERROR_INVALID_CONFIG;
+
    pscreen = VL_VA_PSCREEN(ctx);
 
    if (!pscreen)
@@ -359,22 +466,36 @@ vlVaQuerySurfaceAttributes(VADriverContextP ctx, VAConfigID config,
 
    /* vlVaCreateConfig returns PIPE_VIDEO_PROFILE_UNKNOWN
     * only for VAEntrypointVideoProc. */
-   if (config == PIPE_VIDEO_PROFILE_UNKNOWN) {
-      for (j = 0; j < ARRAY_SIZE(vpp_surface_formats); ++j) {
-         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 = PipeFormatToVaFourcc(vpp_surface_formats[j]);
-         i++;
+   if (config->profile == PIPE_VIDEO_PROFILE_UNKNOWN) {
+      if (config->rt_format & VA_RT_FORMAT_RGB32) {
+         for (j = 0; j < ARRAY_SIZE(vpp_surface_formats); ++j) {
+            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 = PipeFormatToVaFourcc(vpp_surface_formats[j]);
+            i++;
+         }
       }
-   } else {
-      /* Assume VAEntrypointVLD for now. */
+   }
+   if (config->rt_format & VA_RT_FORMAT_YUV420) {
       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++;
    }
+   if (config->rt_format & VA_RT_FORMAT_YUV420_10BPP) {
+      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++;
+      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_P016;
+      i++;
+   }
 
    attribs[i].type = VASurfaceAttribMemoryType;
    attribs[i].value.type = VAGenericValueTypeInteger;
@@ -389,17 +510,37 @@ vlVaQuerySurfaceAttributes(VADriverContextP ctx, VAConfigID config,
    attribs[i].value.value.p = NULL; /* ignore */
    i++;
 
-   attribs[i].type = VASurfaceAttribMaxWidth;
-   attribs[i].value.type = VAGenericValueTypeInteger;
-   attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
-   attribs[i].value.value.i = vl_video_buffer_max_size(pscreen);
-   i++;
+   if (config->entrypoint != PIPE_VIDEO_ENTRYPOINT_UNKNOWN) {
+      attribs[i].type = VASurfaceAttribMaxWidth;
+      attribs[i].value.type = VAGenericValueTypeInteger;
+      attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
+      attribs[i].value.value.i =
+         pscreen->get_video_param(pscreen,
+                                  config->profile, config->entrypoint,
+                                  PIPE_VIDEO_CAP_MAX_WIDTH);
+      i++;
 
-   attribs[i].type = VASurfaceAttribMaxHeight;
-   attribs[i].value.type = VAGenericValueTypeInteger;
-   attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
-   attribs[i].value.value.i = vl_video_buffer_max_size(pscreen);
-   i++;
+      attribs[i].type = VASurfaceAttribMaxHeight;
+      attribs[i].value.type = VAGenericValueTypeInteger;
+      attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
+      attribs[i].value.value.i =
+         pscreen->get_video_param(pscreen,
+                                  config->profile, config->entrypoint,
+                                  PIPE_VIDEO_CAP_MAX_HEIGHT);
+      i++;
+   } else {
+      attribs[i].type = VASurfaceAttribMaxWidth;
+      attribs[i].value.type = VAGenericValueTypeInteger;
+      attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
+      attribs[i].value.value.i = vl_video_buffer_max_size(pscreen);
+      i++;
+
+      attribs[i].type = VASurfaceAttribMaxHeight;
+      attribs[i].value.type = VAGenericValueTypeInteger;
+      attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
+      attribs[i].value.value.i = vl_video_buffer_max_size(pscreen);
+      i++;
+   }
 
    if (i > *num_attribs) {
       *num_attribs = i;
@@ -415,80 +556,108 @@ vlVaQuerySurfaceAttributes(VADriverContextP ctx, VAConfigID config,
 }
 
 static VAStatus
-suface_from_external_memory(VADriverContextP ctx, vlVaSurface *surface,
-                            VASurfaceAttribExternalBuffers *memory_attibute,
-                            int index, VASurfaceID *surfaces,
-                            struct pipe_video_buffer *templat)
+surface_from_external_memory(VADriverContextP ctx, vlVaSurface *surface,
+                             VASurfaceAttribExternalBuffers *memory_attribute,
+                             unsigned index, struct pipe_video_buffer *templat)
 {
    vlVaDriver *drv;
    struct pipe_screen *pscreen;
-   struct pipe_resource *resource;
    struct pipe_resource res_templ;
    struct winsys_handle whandle;
    struct pipe_resource *resources[VL_NUM_COMPONENTS];
-
-   if (!ctx)
-      return VA_STATUS_ERROR_INVALID_PARAMETER;
+   enum pipe_format resource_formats[VL_NUM_COMPONENTS];
+   VAStatus result;
+   int i;
 
    pscreen = VL_VA_PSCREEN(ctx);
    drv = VL_VA_DRIVER(ctx);
 
-   if (!memory_attibute || !memory_attibute->buffers ||
-       index > memory_attibute->num_buffers)
+   if (!memory_attribute || !memory_attribute->buffers ||
+       index > memory_attribute->num_buffers)
       return VA_STATUS_ERROR_INVALID_PARAMETER;
 
-   if (surface->templat.width != memory_attibute->width ||
-       surface->templat.height != memory_attibute->height ||
-       memory_attibute->num_planes < 1)
+   if (surface->templat.width != memory_attribute->width ||
+       surface->templat.height != memory_attribute->height ||
+       memory_attribute->num_planes < 1)
       return VA_STATUS_ERROR_INVALID_PARAMETER;
 
-   switch (memory_attibute->pixel_format) {
-   case VA_FOURCC_RGBA:
-   case VA_FOURCC_RGBX:
-   case VA_FOURCC_BGRA:
-   case VA_FOURCC_BGRX:
-      if (memory_attibute->num_planes != 1)
-         return VA_STATUS_ERROR_INVALID_PARAMETER;
-      break;
-   default:
+   if (memory_attribute->num_planes > VL_NUM_COMPONENTS)
       return VA_STATUS_ERROR_INVALID_PARAMETER;
-   }
+
+   vl_get_video_buffer_formats(pscreen, templat->buffer_format, resource_formats);
 
    memset(&res_templ, 0, sizeof(res_templ));
    res_templ.target = PIPE_TEXTURE_2D;
    res_templ.last_level = 0;
    res_templ.depth0 = 1;
    res_templ.array_size = 1;
-   res_templ.width0 = memory_attibute->width;
-   res_templ.height0 = memory_attibute->height;
-   res_templ.format = surface->templat.buffer_format;
+   res_templ.width0 = memory_attribute->width;
+   res_templ.height0 = memory_attribute->height;
    res_templ.bind = PIPE_BIND_SAMPLER_VIEW;
    res_templ.usage = PIPE_USAGE_DEFAULT;
 
    memset(&whandle, 0, sizeof(struct winsys_handle));
-   whandle.type = DRM_API_HANDLE_TYPE_FD;
-   whandle.handle = memory_attibute->buffers[index];
-   whandle.stride = memory_attibute->pitches[index];
-
-   resource = pscreen->resource_from_handle(pscreen, &res_templ, &whandle);
-
-   if (!resource)
-      return VA_STATUS_ERROR_ALLOCATION_FAILED;
+   whandle.type = WINSYS_HANDLE_TYPE_FD;
+   whandle.handle = memory_attribute->buffers[index];
 
+   // Create a resource for each plane.
    memset(resources, 0, sizeof resources);
-   resources[0] = resource;
+   for (i = 0; i < memory_attribute->num_planes; i++) {
+      res_templ.format = resource_formats[i];
+      if (res_templ.format == PIPE_FORMAT_NONE) {
+         result = VA_STATUS_ERROR_INVALID_PARAMETER;
+         goto fail;
+      }
+
+      whandle.stride = memory_attribute->pitches[i];
+      whandle.offset = memory_attribute->offsets[i];
+      resources[i] = pscreen->resource_from_handle(pscreen, &res_templ, &whandle,
+                                                   PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
+      if (!resources[i]) {
+         result = VA_STATUS_ERROR_ALLOCATION_FAILED;
+         goto fail;
+      }
+   }
 
    surface->buffer = vl_video_buffer_create_ex2(drv->pipe, templat, resources);
+   if (!surface->buffer) {
+      result = VA_STATUS_ERROR_ALLOCATION_FAILED;
+      goto fail;
+   }
+   return VA_STATUS_SUCCESS;
+
+fail:
+   for (i = 0; i < VL_NUM_COMPONENTS; i++)
+      pipe_resource_reference(&resources[i], NULL);
+   return result;
+}
+
+VAStatus
+vlVaHandleSurfaceAllocate(vlVaDriver *drv, vlVaSurface *surface,
+                          struct pipe_video_buffer *templat)
+{
+   struct pipe_surface **surfaces;
+   unsigned i;
+
+   surface->buffer = drv->pipe->create_video_buffer(drv->pipe, templat);
    if (!surface->buffer)
       return VA_STATUS_ERROR_ALLOCATION_FAILED;
 
-   util_dynarray_init(&surface->subpics);
-   surfaces[index] = handle_table_add(drv->htab, surface);
+   surfaces = surface->buffer->get_surfaces(surface->buffer);
+   for (i = 0; i < VL_MAX_SURFACES; ++i) {
+      union pipe_color_union c = {};
 
-   if (!surfaces[index]) {
-      surface->buffer->destroy(surface->buffer);
-      return VA_STATUS_ERROR_ALLOCATION_FAILED;
+      if (!surfaces[i])
+         continue;
+
+      if (i > !!surface->buffer->interlaced)
+         c.f[0] = c.f[1] = c.f[2] = c.f[3] = 0.5f;
+
+      drv->pipe->clear_render_target(drv->pipe, surfaces[i], &c, 0, 0,
+                                    surfaces[i]->width, surfaces[i]->height,
+                                    false);
    }
+   drv->pipe->flush(drv->pipe, NULL, 0);
 
    return VA_STATUS_SUCCESS;
 }
@@ -500,13 +669,14 @@ vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format,
                     VASurfaceAttrib *attrib_list, unsigned int num_attribs)
 {
    vlVaDriver *drv;
-   VASurfaceAttribExternalBuffers *memory_attibute;
+   VASurfaceAttribExternalBuffers *memory_attribute;
    struct pipe_video_buffer templat;
    struct pipe_screen *pscreen;
    int i;
    int memory_type;
    int expected_fourcc;
    VAStatus vaStatus;
+   vlVaSurface *surf;
 
    if (!ctx)
       return VA_STATUS_ERROR_INVALID_CONTEXT;
@@ -525,7 +695,7 @@ vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format,
       return VA_STATUS_ERROR_INVALID_CONTEXT;
 
    /* Default. */
-   memory_attibute = NULL;
+   memory_attribute = NULL;
    memory_type = VA_SURFACE_ATTRIB_MEM_TYPE_VA;
    expected_fourcc = 0;
 
@@ -557,13 +727,14 @@ vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format,
           (attrib_list[i].flags == VA_SURFACE_ATTRIB_SETTABLE)) {
          if (attrib_list[i].value.type != VAGenericValueTypePointer)
             return VA_STATUS_ERROR_INVALID_PARAMETER;
-         memory_attibute = (VASurfaceAttribExternalBuffers *)attrib_list[i].value.value.p;
+         memory_attribute = (VASurfaceAttribExternalBuffers *)attrib_list[i].value.value.p;
       }
    }
 
    if (VA_RT_FORMAT_YUV420 != format &&
        VA_RT_FORMAT_YUV422 != format &&
        VA_RT_FORMAT_YUV444 != format &&
+       VA_RT_FORMAT_YUV420_10BPP != format &&
        VA_RT_FORMAT_RGB32  != format) {
       return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
    }
@@ -572,10 +743,10 @@ vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format,
    case VA_SURFACE_ATTRIB_MEM_TYPE_VA:
       break;
    case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
-      if (!memory_attibute)
+      if (!memory_attribute)
          return VA_STATUS_ERROR_INVALID_PARAMETER;
 
-      expected_fourcc = memory_attibute->pixel_format;
+      expected_fourcc = memory_attribute->pixel_format;
       break;
    default:
       assert(0);
@@ -583,72 +754,91 @@ vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format,
 
    memset(&templat, 0, sizeof(templat));
 
+   templat.buffer_format = pscreen->get_video_param(
+      pscreen,
+      PIPE_VIDEO_PROFILE_UNKNOWN,
+      PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
+      PIPE_VIDEO_CAP_PREFERED_FORMAT
+   );
+   templat.interlaced = pscreen->get_video_param(
+      pscreen,
+      PIPE_VIDEO_PROFILE_UNKNOWN,
+      PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
+      PIPE_VIDEO_CAP_PREFERS_INTERLACED
+   );
+
    if (expected_fourcc) {
-      templat.buffer_format = VaFourccToPipeFormat(expected_fourcc);
-      templat.interlaced = 0;
-   } else {
-      templat.buffer_format = pscreen->get_video_param
-            (
-               pscreen,
-               PIPE_VIDEO_PROFILE_UNKNOWN,
-               PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
-               PIPE_VIDEO_CAP_PREFERED_FORMAT
-               );
-      templat.interlaced = pscreen->get_video_param
-            (
-               pscreen,
-               PIPE_VIDEO_PROFILE_UNKNOWN,
-               PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
-               PIPE_VIDEO_CAP_PREFERS_INTERLACED
-               );
-   }
-
-   templat.chroma_format = ChromaToPipe(format);
+      enum pipe_format expected_format = VaFourccToPipeFormat(expected_fourcc);
+
+      if (expected_format != templat.buffer_format || memory_attribute)
+        templat.interlaced = 0;
+
+      templat.buffer_format = expected_format;
+   }
 
    templat.width = width;
    templat.height = height;
 
    memset(surfaces, VA_INVALID_ID, num_surfaces * sizeof(VASurfaceID));
 
-   pipe_mutex_lock(drv->mutex);
+   mtx_lock(&drv->mutex);
    for (i = 0; i < num_surfaces; i++) {
-      vlVaSurface *surf = CALLOC(1, sizeof(vlVaSurface));
-      if (!surf)
+      surf = CALLOC(1, sizeof(vlVaSurface));
+      if (!surf) {
+         vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
          goto no_res;
+      }
 
       surf->templat = templat;
 
       switch (memory_type) {
       case VA_SURFACE_ATTRIB_MEM_TYPE_VA:
-         surf->buffer = drv->pipe->create_video_buffer(drv->pipe, &templat);
-         if (!surf->buffer) {
-            FREE(surf);
-            goto no_res;
-         }
-         util_dynarray_init(&surf->subpics);
-         surfaces[i] = handle_table_add(drv->htab, surf);
+         /* The application will clear the TILING flag when the surface is
+          * intended to be exported as dmabuf. Adding shared flag because not
+          * null memory_attribute means VASurfaceAttribExternalBuffers is used.
+          */
+         if (memory_attribute &&
+             !(memory_attribute->flags & VA_SURFACE_EXTBUF_DESC_ENABLE_TILING))
+            templat.bind = PIPE_BIND_LINEAR | PIPE_BIND_SHARED;
+
+        vaStatus = vlVaHandleSurfaceAllocate(drv, surf, &templat);
+         if (vaStatus != VA_STATUS_SUCCESS)
+            goto free_surf;
          break;
+
       case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
-         vaStatus = suface_from_external_memory(ctx, surf, memory_attibute, i, surfaces, &templat);
-         if (vaStatus != VA_STATUS_SUCCESS) {
-            FREE(surf);
-            goto no_res;
-         }
+         vaStatus = surface_from_external_memory(ctx, surf, memory_attribute, i, &templat);
+         if (vaStatus != VA_STATUS_SUCCESS)
+            goto free_surf;
          break;
+
       default:
          assert(0);
       }
+
+      util_dynarray_init(&surf->subpics, NULL);
+      surfaces[i] = handle_table_add(drv->htab, surf);
+      if (!surfaces[i]) {
+         vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
+         goto destroy_surf;
+      }
    }
-   pipe_mutex_unlock(drv->mutex);
+   mtx_unlock(&drv->mutex);
 
    return VA_STATUS_SUCCESS;
 
+destroy_surf:
+   surf->buffer->destroy(surf->buffer);
+
+free_surf:
+   FREE(surf);
+
 no_res:
-   pipe_mutex_unlock(drv->mutex);
+   mtx_unlock(&drv->mutex);
    if (i)
       vlVaDestroySurfaces(ctx, surfaces, i);
 
-   return VA_STATUS_ERROR_ALLOCATION_FAILED;
+   return vaStatus;
 }
 
 VAStatus
@@ -744,9 +934,9 @@ vlVaQueryVideoProcPipelineCaps(VADriverContextP ctx, VAContextID context,
    pipeline_cap->filter_flags = 0;
    pipeline_cap->num_forward_references = 0;
    pipeline_cap->num_backward_references = 0;
-   pipeline_cap->num_input_color_standards = Elements(vpp_input_color_standards);
+   pipeline_cap->num_input_color_standards = ARRAY_SIZE(vpp_input_color_standards);
    pipeline_cap->input_color_standards = vpp_input_color_standards;
-   pipeline_cap->num_output_color_standards = Elements(vpp_output_color_standards);
+   pipeline_cap->num_output_color_standards = ARRAY_SIZE(vpp_output_color_standards);
    pipeline_cap->output_color_standards = vpp_output_color_standards;
 
    for (i = 0; i < num_filters; i++) {
@@ -761,8 +951,8 @@ vlVaQueryVideoProcPipelineCaps(VADriverContextP ctx, VAContextID context,
       case VAProcFilterDeinterlacing: {
          VAProcFilterParameterBufferDeinterlacing *deint = buf->data;
          if (deint->algorithm == VAProcDeinterlacingMotionAdaptive) {
-            pipeline_cap->num_forward_references = 1;
-            pipeline_cap->num_backward_references = 2;
+            pipeline_cap->num_forward_references = 2;
+            pipeline_cap->num_backward_references = 1;
          }
          break;
       }
@@ -773,3 +963,148 @@ vlVaQueryVideoProcPipelineCaps(VADriverContextP ctx, VAContextID context,
 
    return VA_STATUS_SUCCESS;
 }
+
+#if VA_CHECK_VERSION(1, 1, 0)
+VAStatus
+vlVaExportSurfaceHandle(VADriverContextP ctx,
+                        VASurfaceID surface_id,
+                        uint32_t mem_type,
+                        uint32_t flags,
+                        void *descriptor)
+{
+   vlVaDriver *drv;
+   vlVaSurface *surf;
+   struct pipe_surface **surfaces;
+   struct pipe_screen *screen;
+   VAStatus ret;
+   unsigned int usage;
+   int i, p;
+
+   VADRMPRIMESurfaceDescriptor *desc = descriptor;
+
+   if (mem_type != VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2)
+      return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
+   if (flags & VA_EXPORT_SURFACE_COMPOSED_LAYERS)
+      return VA_STATUS_ERROR_INVALID_SURFACE;
+
+   drv    = VL_VA_DRIVER(ctx);
+   screen = VL_VA_PSCREEN(ctx);
+   mtx_lock(&drv->mutex);
+
+   surf = handle_table_get(drv->htab, surface_id);
+   if (!surf || !surf->buffer) {
+      mtx_unlock(&drv->mutex);
+      return VA_STATUS_ERROR_INVALID_SURFACE;
+   }
+
+   if (surf->buffer->interlaced) {
+      struct pipe_video_buffer *interlaced = surf->buffer;
+      struct u_rect src_rect, dst_rect;
+
+      surf->templat.interlaced = false;
+
+      ret = vlVaHandleSurfaceAllocate(drv, surf, &surf->templat);
+      if (ret != VA_STATUS_SUCCESS) {
+         mtx_unlock(&drv->mutex);
+         return VA_STATUS_ERROR_ALLOCATION_FAILED;
+      }
+
+      src_rect.x0 = dst_rect.x0 = 0;
+      src_rect.y0 = dst_rect.y0 = 0;
+      src_rect.x1 = dst_rect.x1 = surf->templat.width;
+      src_rect.y1 = dst_rect.y1 = surf->templat.height;
+
+      vl_compositor_yuv_deint_full(&drv->cstate, &drv->compositor,
+                                   interlaced, surf->buffer,
+                                   &src_rect, &dst_rect,
+                                   VL_COMPOSITOR_WEAVE);
+
+      interlaced->destroy(interlaced);
+   }
+
+   surfaces = surf->buffer->get_surfaces(surf->buffer);
+
+   usage = 0;
+   if (flags & VA_EXPORT_SURFACE_WRITE_ONLY)
+      usage |= PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE;
+
+   desc->fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format);
+   desc->width  = surf->buffer->width;
+   desc->height = surf->buffer->height;
+
+   for (p = 0; p < VL_MAX_SURFACES; p++) {
+      struct winsys_handle whandle;
+      struct pipe_resource *resource;
+      uint32_t drm_format;
+
+      if (!surfaces[p])
+         break;
+
+      resource = surfaces[p]->texture;
+
+      switch (resource->format) {
+      case PIPE_FORMAT_R8_UNORM:
+         drm_format = DRM_FORMAT_R8;
+         break;
+      case PIPE_FORMAT_R8G8_UNORM:
+         drm_format = DRM_FORMAT_GR88;
+         break;
+      case PIPE_FORMAT_R16_UNORM:
+         drm_format = DRM_FORMAT_R16;
+         break;
+      case PIPE_FORMAT_R16G16_UNORM:
+         drm_format = DRM_FORMAT_GR1616;
+         break;
+      case PIPE_FORMAT_B8G8R8A8_UNORM:
+         drm_format = DRM_FORMAT_ARGB8888;
+         break;
+      case PIPE_FORMAT_R8G8B8A8_UNORM:
+         drm_format = DRM_FORMAT_ABGR8888;
+         break;
+      case PIPE_FORMAT_B8G8R8X8_UNORM:
+         drm_format = DRM_FORMAT_XRGB8888;
+         break;
+      case PIPE_FORMAT_R8G8B8X8_UNORM:
+         drm_format = DRM_FORMAT_XBGR8888;
+         break;
+      default:
+         ret = VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
+         goto fail;
+      }
+
+      memset(&whandle, 0, sizeof(whandle));
+      whandle.type = WINSYS_HANDLE_TYPE_FD;
+
+      if (!screen->resource_get_handle(screen, drv->pipe, resource,
+                                       &whandle, usage)) {
+         ret = VA_STATUS_ERROR_INVALID_SURFACE;
+         goto fail;
+      }
+
+      desc->objects[p].fd   = (int)whandle.handle;
+      desc->objects[p].size = 0;
+      desc->objects[p].drm_format_modifier = whandle.modifier;
+
+      desc->layers[p].drm_format      = drm_format;
+      desc->layers[p].num_planes      = 1;
+      desc->layers[p].object_index[0] = p;
+      desc->layers[p].offset[0]       = whandle.offset;
+      desc->layers[p].pitch[0]        = whandle.stride;
+   }
+
+   desc->num_objects = p;
+   desc->num_layers  = p;
+
+   mtx_unlock(&drv->mutex);
+
+   return VA_STATUS_SUCCESS;
+
+fail:
+   for (i = 0; i < p; i++)
+      close(desc->objects[i].fd);
+
+   mtx_unlock(&drv->mutex);
+
+   return ret;
+}
+#endif