st/va: implement VaDeriveImage
authorJulien Isorce <j.isorce@samsung.com>
Fri, 30 Oct 2015 11:42:52 +0000 (11:42 +0000)
committerChristian König <christian.koenig@amd.com>
Fri, 30 Oct 2015 12:21:11 +0000 (13:21 +0100)
And apply relatives change to:
vlVaBufferSetNumElements
vlVaCreateBuffer
vlVaMapBuffer
vlVaUnmapBuffer
vlVaDestroyBuffer
vlVaPutImage

It is unfortunate that there is no proper va buffer type and struct
for this. Only possible to use VAImageBufferType which is normally
used for normal user data array.
On of the consequences is that it is only possible VaDeriveImage
is only useful on surfaces backed with contiguous planes.
Implementation inspired from cgit.freedesktop.org/vaapi/intel-driver

Signed-off-by: Julien Isorce <j.isorce@samsung.com>
Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com>
Reviewed-by: Christian König <christian.koenig@amd.com>
src/gallium/state_trackers/va/buffer.c
src/gallium/state_trackers/va/image.c
src/gallium/state_trackers/va/va_private.h

index f5b9e814c3ab5116b108160d331986d7792f84bf..d3a7c5d6dc41546c6c6593a782aa987924ba477b 100644 (file)
  *
  **************************************************************************/
 
+#include "pipe/p_screen.h"
 #include "util/u_memory.h"
 #include "util/u_handle_table.h"
+#include "util/u_transfer.h"
+#include "vl/vl_winsys.h"
 
 #include "va_private.h"
 
@@ -76,6 +79,9 @@ vlVaBufferSetNumElements(VADriverContextP ctx, VABufferID buf_id,
    if (!buf)
       return VA_STATUS_ERROR_INVALID_BUFFER;
 
+   if (buf->derived_surface.resource)
+      return VA_STATUS_ERROR_INVALID_BUFFER;
+
    buf->data = REALLOC(buf->data, buf->size * buf->num_elements,
                        buf->size * num_elements);
    buf->num_elements = num_elements;
@@ -89,19 +95,34 @@ vlVaBufferSetNumElements(VADriverContextP ctx, VABufferID buf_id,
 VAStatus
 vlVaMapBuffer(VADriverContextP ctx, VABufferID buf_id, void **pbuff)
 {
+   vlVaDriver *drv;
    vlVaBuffer *buf;
 
    if (!ctx)
       return VA_STATUS_ERROR_INVALID_CONTEXT;
 
+   drv = VL_VA_DRIVER(ctx);
+   if (!drv)
+      return VA_STATUS_ERROR_INVALID_CONTEXT;
+
    if (!pbuff)
       return VA_STATUS_ERROR_INVALID_PARAMETER;
 
-   buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id);
+   buf = handle_table_get(drv->htab, buf_id);
    if (!buf)
       return VA_STATUS_ERROR_INVALID_BUFFER;
 
-   *pbuff = buf->data;
+   if (buf->derived_surface.resource) {
+      *pbuff = pipe_buffer_map(drv->pipe, buf->derived_surface.resource,
+                               PIPE_TRANSFER_WRITE,
+                               &buf->derived_surface.transfer);
+
+      if (!buf->derived_surface.transfer || !*pbuff)
+         return VA_STATUS_ERROR_INVALID_BUFFER;
+
+   } else {
+      *pbuff = buf->data;
+   }
 
    return VA_STATUS_SUCCESS;
 }
@@ -109,16 +130,27 @@ vlVaMapBuffer(VADriverContextP ctx, VABufferID buf_id, void **pbuff)
 VAStatus
 vlVaUnmapBuffer(VADriverContextP ctx, VABufferID buf_id)
 {
+   vlVaDriver *drv;
    vlVaBuffer *buf;
 
    if (!ctx)
       return VA_STATUS_ERROR_INVALID_CONTEXT;
 
-   buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id);
+   drv = VL_VA_DRIVER(ctx);
+   if (!drv)
+      return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+   buf = handle_table_get(drv->htab, buf_id);
    if (!buf)
       return VA_STATUS_ERROR_INVALID_BUFFER;
 
-   /* Nothing to do here */
+   if (buf->derived_surface.resource) {
+     if (!buf->derived_surface.transfer)
+        return VA_STATUS_ERROR_INVALID_BUFFER;
+
+     pipe_buffer_unmap(drv->pipe, buf->derived_surface.transfer);
+     buf->derived_surface.transfer = NULL;
+   }
 
    return VA_STATUS_SUCCESS;
 }
@@ -135,6 +167,9 @@ vlVaDestroyBuffer(VADriverContextP ctx, VABufferID buf_id)
    if (!buf)
       return VA_STATUS_ERROR_INVALID_BUFFER;
 
+   if (buf->derived_surface.resource)
+     pipe_resource_reference(&buf->derived_surface.resource, NULL);
+
    FREE(buf->data);
    FREE(buf);
    handle_table_remove(VL_VA_DRIVER(ctx)->htab, buf_id);
index b0c720de1078e1fc2d1170376f8c4dee077faaf1..c6d0c5abf6503feafc06b4f9593449942588556d 100644 (file)
@@ -184,10 +184,97 @@ vlVaCreateImage(VADriverContextP ctx, VAImageFormat *format, int width, int heig
 VAStatus
 vlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image)
 {
+   vlVaDriver *drv;
+   vlVaSurface *surf;
+   vlVaBuffer *img_buf;
+   VAImage *img;
+   struct pipe_surface **surfaces;
+   int w;
+   int h;
+   int i;
+
    if (!ctx)
       return VA_STATUS_ERROR_INVALID_CONTEXT;
 
-   return VA_STATUS_ERROR_UNIMPLEMENTED;
+   drv = VL_VA_DRIVER(ctx);
+
+   if (!drv)
+      return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+   surf = handle_table_get(drv->htab, surface);
+
+   if (!surf || !surf->buffer || surf->buffer->interlaced)
+      return VA_STATUS_ERROR_INVALID_SURFACE;
+
+   surfaces = surf->buffer->get_surfaces(surf->buffer);
+   if (!surfaces || !surfaces[0]->texture)
+      return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+   img = CALLOC(1, sizeof(VAImage));
+   if (!img)
+      return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+   img->format.fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format);
+   img->buf = VA_INVALID_ID;
+   img->width = surf->buffer->width;
+   img->height = surf->buffer->height;
+   img->num_palette_entries = 0;
+   img->entry_bytes = 0;
+   w = align(surf->buffer->width, 2);
+   h = align(surf->buffer->height, 2);
+
+   for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+      if (img->format.fourcc == formats[i].fourcc) {
+         img->format = formats[i];
+         break;
+      }
+   }
+
+   switch (img->format.fourcc) {
+   case VA_FOURCC('U','Y','V','Y'):
+   case VA_FOURCC('Y','U','Y','V'):
+      img->num_planes = 1;
+      img->pitches[0] = w * 2;
+      img->offsets[0] = 0;
+      img->data_size  = w * h * 2;
+      break;
+
+   case VA_FOURCC('B','G','R','A'):
+   case VA_FOURCC('R','G','B','A'):
+   case VA_FOURCC('B','G','R','X'):
+   case VA_FOURCC('R','G','B','X'):
+      img->num_planes = 1;
+      img->pitches[0] = w * 4;
+      img->offsets[0] = 0;
+      img->data_size  = w * h * 4;
+      break;
+
+   default:
+      /* VaDeriveImage is designed for contiguous planes. */
+      FREE(img);
+      return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
+   }
+
+   img_buf = CALLOC(1, sizeof(vlVaBuffer));
+   if (!img_buf) {
+      FREE(img);
+      return VA_STATUS_ERROR_ALLOCATION_FAILED;
+   }
+
+   img->image_id = handle_table_add(drv->htab, img);
+
+   img_buf->type = VAImageBufferType;
+   img_buf->size = image->data_size;
+   img_buf->num_elements = 1;
+   img_buf->derived_surface.fence = surf->fence;
+
+   pipe_resource_reference(&img_buf->derived_surface.resource, surfaces[0]->texture);
+
+   img->buf = handle_table_add(VL_VA_DRIVER(ctx)->htab, img_buf);
+
+   *image = *img;
+
+   return VA_STATUS_SUCCESS;
 }
 
 VAStatus
@@ -342,7 +429,13 @@ vlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image,
    if (!img_buf)
       return VA_STATUS_ERROR_INVALID_BUFFER;
 
+   if (img_buf->derived_surface.resource) {
+      /* Attempting to transfer derived image to surface */
+      return VA_STATUS_ERROR_UNIMPLEMENTED;
+   }
+
    format = VaFourccToPipeFormat(vaimage->format.fourcc);
+
    if (format == PIPE_FORMAT_NONE)
       return VA_STATUS_ERROR_OPERATION_FAILED;
 
index 60e966965e27477dd4f33ff34a9abf0c870c6abe..3ae51a766a02c4958b468b4200182384944e1df5 100644 (file)
@@ -233,6 +233,11 @@ typedef struct {
    unsigned int size;
    unsigned int num_elements;
    void *data;
+   struct {
+      struct pipe_resource *resource;
+      struct pipe_transfer *transfer;
+      struct pipe_fence_handle *fence;
+   } derived_surface;
 } vlVaBuffer;
 
 typedef struct {