commit e435677c2c9228eed9df09a41c8ffeedc5665401
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Mar 8 17:22:06 2010 +0100

    [G45] Implement vaDeriveImage().

diff --git a/i965_drv_video/i965_drv_video.c b/i965_drv_video/i965_drv_video.c
index 8669a4e..aad947a 100644
--- a/i965_drv_video/i965_drv_video.c
+++ b/i965_drv_video/i965_drv_video.c
@@ -66,19 +66,12 @@ i965_image_formats_map[I965_MAX_IMAGE_FORMATS + 1] = {
       { VA_FOURCC('Y','V','1','2'), VA_LSB_FIRST, 12, } },
 };
 
-static const i965_image_format_map_t *
-get_image_format(const VAImageFormat *va_format)
+static const i965_image_format_map_t *get_image_format(unsigned int fourcc)
 {
     unsigned int i;
     for (i = 0; i965_image_formats_map[i].type != 0; i++) {
         const i965_image_format_map_t * const m = &i965_image_formats_map[i];
-        if (m->va_format.fourcc == va_format->fourcc &&
-            (m->type == I965_SURFACETYPE_RGBA ?
-             (m->va_format.byte_order == va_format->byte_order &&
-              m->va_format.red_mask   == va_format->red_mask   &&
-              m->va_format.green_mask == va_format->green_mask &&
-              m->va_format.blue_mask  == va_format->blue_mask  &&
-              m->va_format.alpha_mask == va_format->alpha_mask) : 1))
+        if (m->va_format.fourcc == fourcc)
             return m;
     }
     return NULL;
@@ -357,12 +350,27 @@ VAStatus i965_QueryConfigAttributes(VADriverContextP ctx,
     return vaStatus;
 }
 
+static struct object_image *
+i965_CreateImage_impl(
+    VADriverContextP     ctx,
+    const VAImageFormat *format,
+    unsigned int         width,
+    unsigned int         height,
+    VASurfaceID          surface
+);
+
+static void
+i965_DestroyImage_impl(
+    VADriverContextP     ctx,
+    struct object_image *obj_image,
+    int                  from_surface
+);
+
 static void 
 i965_destroy_surface(struct object_heap *heap, struct object_base *obj)
 {
     struct object_surface *obj_surface = (struct object_surface *)obj;
 
-    dri_bo_unreference(obj_surface->bo);
     obj_surface->bo = NULL;
 
     if (obj_surface->free_private_data != NULL) {
@@ -393,6 +401,8 @@ i965_CreateSurfaces(VADriverContextP ctx,
     for (i = 0; i < num_surfaces; i++) {
         int surfaceID = NEW_SURFACE_ID();
         struct object_surface *obj_surface = SURFACE(surfaceID);
+        struct object_image *obj_image;
+        struct object_buffer *obj_buffer;
 
         if (NULL == obj_surface) {
             vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
@@ -404,19 +414,25 @@ i965_CreateSurfaces(VADriverContextP ctx,
         obj_surface->subpic = VA_INVALID_ID;
         obj_surface->width = ALIGN(width, 16);
         obj_surface->height = ALIGN(height, 16);
-        obj_surface->size = SIZE_YUV420(obj_surface->width, obj_surface->height);
-        obj_surface->bo = dri_bo_alloc(i965->intel.bufmgr,
-                                       "vaapi surface",
-                                       obj_surface->size,
-                                       64);
-
-        assert(obj_surface->bo);
-        if (NULL == obj_surface->bo) {
-            vaStatus = VA_STATUS_ERROR_UNKNOWN;
-            break;
-        }
+        obj_surface->is_derived = 0;
         obj_surface->private_data = NULL;
         obj_surface->free_private_data = NULL;
+
+        obj_image = i965_CreateImage_impl(ctx, NULL, obj_surface->width, obj_surface->height, surfaceID);
+        if (!obj_image) {
+            vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
+            break;
+        }
+        obj_surface->size = obj_image->image.data_size;
+        obj_surface->image = obj_image->image;
+
+        obj_buffer = BUFFER(obj_image->image.buf);
+        if (!obj_buffer) {
+            vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
+            break;
+        }
+        assert(obj_buffer->buffer_store);
+        obj_surface->bo = obj_buffer->buffer_store->bo;
     }
 
     /* Error recovery */
@@ -446,6 +462,7 @@ i965_DestroySurfaces(VADriverContextP ctx,
         struct object_surface *obj_surface = SURFACE(surface_list[i]);
 
         assert(obj_surface);
+        i965_DestroyImage_impl(ctx, IMAGE(obj_surface->image.image_id), 1);
         i965_destroy_surface(&i965->surface_heap, (struct object_base *)obj_surface);
     }
 
@@ -1289,46 +1306,22 @@ i965_destroy_heap(struct object_heap *heap,
 VAStatus 
 i965_DestroyImage(VADriverContextP ctx, VAImageID image);
 
-VAStatus 
-i965_CreateImage(VADriverContextP ctx,
-                 VAImageFormat *format,
-                 int width,
-                 int height,
-                 VAImage *out_image)        /* out */
+static int
+setup_image_format(
+    VAImage     *image,
+    unsigned int fourcc,
+    unsigned int width,
+    unsigned int height
+)
 {
-    struct i965_driver_data *i965 = i965_driver_data(ctx);
-    struct object_image *obj_image;
-    VAStatus va_status = VA_STATUS_ERROR_OPERATION_FAILED;
-    VAImageID image_id;
     unsigned int width2, height2, size2, size;
 
-    out_image->image_id = VA_INVALID_ID;
-    out_image->buf      = VA_INVALID_ID;
-
-    image_id = NEW_IMAGE_ID();
-    if (image_id == VA_INVALID_ID)
-        return VA_STATUS_ERROR_ALLOCATION_FAILED;
-
-    obj_image = IMAGE(image_id);
-    if (!obj_image)
-        return VA_STATUS_ERROR_ALLOCATION_FAILED;
-    obj_image->bo         = NULL;
-    obj_image->palette    = NULL;
-
-    VAImage * const image = &obj_image->image;
-    image->image_id       = image_id;
-    image->buf            = VA_INVALID_ID;
-
     size    = width * height;
     width2  = (width  + 1) / 2;
     height2 = (height + 1) / 2;
     size2   = width2 * height2;
 
-    image->num_palette_entries = 0;
-    image->entry_bytes         = 0;
-    memset(image->component_order, 0, sizeof(image->component_order));
-
-    switch (format->fourcc) {
+    switch (fourcc) {
     case VA_FOURCC('I','A','4','4'):
     case VA_FOURCC('A','I','4','4'):
         image->num_planes = 1;
@@ -1361,15 +1354,56 @@ i965_CreateImage(VADriverContextP ctx,
         image->data_size  = size + 2 * size2;
         break;
     default:
-        goto error;
+        return 0;
     }
+    return 1;
+}
 
-    va_status = i965_CreateBuffer(ctx, 0, VAImageBufferType,
-                                  image->data_size, 1, NULL, &image->buf);
-    if (va_status != VA_STATUS_SUCCESS)
-        goto error;
+static struct object_image *
+i965_CreateImage_impl(
+    VADriverContextP     ctx,
+    const VAImageFormat *format,
+    unsigned int         width,
+    unsigned int         height,
+    VASurfaceID          surface
+)
+{
+    struct i965_driver_data *i965 = i965_driver_data(ctx);
+    struct object_image *obj_image;
+    VAImageID image_id;
 
-    obj_image->bo = BUFFER(image->buf)->buffer_store->bo;
+    image_id = NEW_IMAGE_ID();
+    if (image_id == VA_INVALID_ID)
+        return NULL;
+
+    obj_image = IMAGE(image_id);
+    if (!obj_image)
+        return NULL;
+    obj_image->surface    = surface;
+    obj_image->bo         = NULL;
+    obj_image->palette    = NULL;
+
+    VAImage * const image = &obj_image->image;
+    image->image_id       = image_id;
+    image->buf            = VA_INVALID_ID;
+
+    image->num_palette_entries = 0;
+    image->entry_bytes         = 0;
+    memset(image->component_order, 0, sizeof(image->component_order));
+
+    if (surface == VA_INVALID_ID) {
+        if (!setup_image_format(image, format->fourcc, width, height))
+            goto error;
+        image->format = *format;
+    }
+    else {
+        /* VA image format will be initialized through first vaDeriveImage() */
+        if (!setup_image_format(image, VA_FOURCC_YV12, width, height))
+            goto error;
+        memset(&image->format, 0, sizeof(image->format));
+    }
+    image->width  = width;
+    image->height = height;
 
     if (image->num_palette_entries > 0 && image->entry_bytes > 0) {
         obj_image->palette = malloc(image->num_palette_entries * sizeof(obj_image->palette));
@@ -1377,25 +1411,66 @@ i965_CreateImage(VADriverContextP ctx,
             goto error;
     }
 
-    image->image_id             = image_id;
-    image->format               = *format;
-    image->width                = width;
-    image->height               = height;
+    if (i965_CreateBuffer(ctx, 0, VAImageBufferType,
+                          image->data_size, 1, NULL,
+                          &image->buf) != VA_STATUS_SUCCESS)
+        goto error;
 
-    *out_image                  = *image;
-    return VA_STATUS_SUCCESS;
+    obj_image->bo = BUFFER(image->buf)->buffer_store->bo;
+    return obj_image;
 
  error:
-    i965_DestroyImage(ctx, image_id);
-    return va_status;
+    i965_DestroyImage_impl(ctx, obj_image, 0);
+    return NULL;
+}
+
+VAStatus 
+i965_CreateImage(VADriverContextP ctx,
+                 VAImageFormat *format,
+                 int width,
+                 int height,
+                 VAImage *out_image)        /* out */
+{
+    struct object_image *obj_image;
+
+    obj_image = i965_CreateImage_impl(ctx, format, width, height, VA_INVALID_ID);
+    if (!obj_image)
+        return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+    *out_image = obj_image->image;
+    return VA_STATUS_SUCCESS;
 }
 
 VAStatus i965_DeriveImage(VADriverContextP ctx,
                           VASurfaceID surface,
                           VAImage *image)        /* out */
 {
-    /* TODO */
-    return VA_STATUS_ERROR_OPERATION_FAILED;
+    struct i965_driver_data *i965 = i965_driver_data(ctx);
+    struct i965_render_state *render_state = &i965->render_state;
+
+    struct object_surface *obj_surface = SURFACE(surface);
+    if (!obj_surface)
+        return VA_STATUS_ERROR_INVALID_SURFACE;
+
+    struct object_image *obj_image = IMAGE(obj_surface->image.image_id);
+    if (!obj_image)
+        return VA_STATUS_ERROR_INVALID_IMAGE;
+
+    if (!obj_surface->is_derived) {
+        /* Reset VA image format on each call so that a VA surface can
+           be re-used with another context (and internal surface format) */
+        VAImage * const image = &obj_surface->image;
+        const i965_image_format_map_t *m;
+        m = get_image_format(render_state->interleaved_uv ? VA_FOURCC_NV12 : VA_FOURCC_YV12);
+        if (!m)
+            return VA_STATUS_ERROR_OPERATION_FAILED;
+        if (!setup_image_format(image, m->va_format.fourcc, image->width, image->height))
+            return VA_STATUS_ERROR_OPERATION_FAILED;
+        image->format = m->va_format;
+        obj_surface->is_derived = 1;
+    }
+    *image = obj_surface->image;
+    return VA_STATUS_SUCCESS;
 }
 
 static void 
@@ -1404,15 +1479,24 @@ i965_destroy_image(struct object_heap *heap, struct object_base *obj)
     object_heap_free(heap, obj);
 }
 
-
-VAStatus 
-i965_DestroyImage(VADriverContextP ctx, VAImageID image)
+static void
+i965_DestroyImage_impl(
+    VADriverContextP     ctx,
+    struct object_image *obj_image,
+    int                  from_surface
+)
 {
-    struct i965_driver_data *i965 = i965_driver_data(ctx);
-    struct object_image *obj_image = IMAGE(image); 
+    struct i965_driver_data * const i965 = i965_driver_data(ctx);
 
     if (!obj_image)
-        return VA_STATUS_SUCCESS;
+        return;
+
+    if (!from_surface && obj_image->surface != VA_INVALID_ID) {
+        /* only destroy when called from vaDestroySurfaces() */
+        struct object_surface *obj_surface = SURFACE(obj_image->surface);
+        obj_surface->is_derived = 0;
+        return;
+    }
 
     if (obj_image->image.buf != VA_INVALID_ID) {
         i965_DestroyBuffer(ctx, obj_image->image.buf);
@@ -1425,6 +1509,15 @@ i965_DestroyImage(VADriverContextP ctx, VAImageID image)
     }
 
     i965_destroy_image(&i965->image_heap, (struct object_base *)obj_image);
+}
+
+VAStatus 
+i965_DestroyImage(VADriverContextP ctx, VAImageID image)
+{
+    struct i965_driver_data *i965 = i965_driver_data(ctx);
+    struct object_image *obj_image = IMAGE(image); 
+
+    i965_DestroyImage_impl(ctx, obj_image, 0);
 	
     return VA_STATUS_SUCCESS;
 }
@@ -1472,6 +1565,9 @@ i965_GetImage(VADriverContextP ctx,
     if (!obj_surface)
         return VA_STATUS_ERROR_INVALID_SURFACE;
 
+    if (obj_surface->is_derived)
+        return VA_STATUS_ERROR_SURFACE_BUSY;
+
     struct object_image *obj_image = IMAGE(image);
     if (!obj_image)
         return VA_STATUS_ERROR_INVALID_IMAGE;
@@ -1535,6 +1631,9 @@ i965_PutImage(VADriverContextP ctx,
     if (!obj_surface)
         return VA_STATUS_ERROR_INVALID_SURFACE;
 
+    if (obj_surface->is_derived)
+        return VA_STATUS_ERROR_SURFACE_BUSY;
+
     struct object_image *obj_image = IMAGE(image);
     if (!obj_image)
         return VA_STATUS_ERROR_INVALID_IMAGE;
diff --git a/i965_drv_video/i965_drv_video.h b/i965_drv_video/i965_drv_video.h
index 0a839e6..c05ed34 100644
--- a/i965_drv_video/i965_drv_video.h
+++ b/i965_drv_video/i965_drv_video.h
@@ -102,6 +102,8 @@ struct object_surface
     int width;
     int height;
     int size;
+    VAImage image;
+    int is_derived;
     dri_bo *bo;
     void (*free_private_data)(void **data);
     void *private_data;
@@ -121,6 +123,7 @@ struct object_image
 {
     struct object_base base;
     VAImage image;
+    VASurfaceID surface;
     dri_bo *bo;
     unsigned int *palette;
 };
