st/va: add support to export a surface as dmabuf
authorJulien Isorce <j.isorce@samsung.com>
Fri, 30 Oct 2015 11:42:53 +0000 (11:42 +0000)
committerChristian König <christian.koenig@amd.com>
Fri, 30 Oct 2015 12:21:20 +0000 (13:21 +0100)
I.e. implements:
VaAcquireBufferHandle
VaReleaseBufferHandle
for memory of type VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME

And apply relatives change to:
vlVaMapBuffer
vlVaUnMapBuffer
vlVaDestroyBuffer

Implementation inspired from cgit.freedesktop.org/vaapi/intel-driver

Tested with gstreamer-vaapi with nouveau 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/context.c
src/gallium/state_trackers/va/va_private.h

index d3a7c5d6dc41546c6c6593a782aa987924ba477b..71a65037757e7fbc58f9d2b22620ee6d3b402db6 100644 (file)
@@ -27,6 +27,7 @@
  **************************************************************************/
 
 #include "pipe/p_screen.h"
+#include "state_tracker/drm_driver.h"
 #include "util/u_memory.h"
 #include "util/u_handle_table.h"
 #include "util/u_transfer.h"
@@ -112,6 +113,9 @@ vlVaMapBuffer(VADriverContextP ctx, VABufferID buf_id, void **pbuff)
    if (!buf)
       return VA_STATUS_ERROR_INVALID_BUFFER;
 
+   if (buf->export_refcount > 0)
+      return VA_STATUS_ERROR_INVALID_BUFFER;
+
    if (buf->derived_surface.resource) {
       *pbuff = pipe_buffer_map(drv->pipe, buf->derived_surface.resource,
                                PIPE_TRANSFER_WRITE,
@@ -144,6 +148,9 @@ vlVaUnmapBuffer(VADriverContextP ctx, VABufferID buf_id)
    if (!buf)
       return VA_STATUS_ERROR_INVALID_BUFFER;
 
+   if (buf->export_refcount > 0)
+      return VA_STATUS_ERROR_INVALID_BUFFER;
+
    if (buf->derived_surface.resource) {
      if (!buf->derived_surface.transfer)
         return VA_STATUS_ERROR_INVALID_BUFFER;
@@ -167,8 +174,12 @@ vlVaDestroyBuffer(VADriverContextP ctx, VABufferID buf_id)
    if (!buf)
       return VA_STATUS_ERROR_INVALID_BUFFER;
 
-   if (buf->derived_surface.resource)
+   if (buf->derived_surface.resource) {
+     if (buf->export_refcount > 0)
+       return VA_STATUS_ERROR_INVALID_BUFFER;
+
      pipe_resource_reference(&buf->derived_surface.resource, NULL);
+   }
 
    FREE(buf->data);
    FREE(buf);
@@ -196,3 +207,126 @@ vlVaBufferInfo(VADriverContextP ctx, VABufferID buf_id, VABufferType *type,
 
    return VA_STATUS_SUCCESS;
 }
+
+VAStatus
+vlVaAcquireBufferHandle(VADriverContextP ctx, VABufferID buf_id,
+                        VABufferInfo *out_buf_info)
+{
+   uint32_t i;
+   uint32_t mem_type;
+   vlVaBuffer *buf ;
+   struct pipe_screen *screen;
+
+   /* List of supported memory types, in preferred order. */
+   static const uint32_t mem_types[] = {
+      VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
+      0
+   };
+
+   if (!ctx)
+      return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+   buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id);
+
+   if (!buf)
+      return VA_STATUS_ERROR_INVALID_BUFFER;
+
+   /* Only VA surface|image like buffers are supported for now .*/
+   if (buf->type != VAImageBufferType)
+      return VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE;
+
+   if (!out_buf_info)
+      return VA_STATUS_ERROR_INVALID_PARAMETER;
+
+   if (!out_buf_info->mem_type)
+      mem_type = mem_types[0];
+   else {
+      mem_type = 0;
+      for (i = 0; mem_types[i] != 0; i++) {
+         if (out_buf_info->mem_type & mem_types[i]) {
+            mem_type = out_buf_info->mem_type;
+            break;
+         }
+      }
+      if (!mem_type)
+         return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
+   }
+
+   if (!buf->derived_surface.resource)
+      return VA_STATUS_ERROR_INVALID_BUFFER;
+
+   screen = VL_VA_PSCREEN(ctx);
+
+   if (buf->derived_surface.fence) {
+      screen->fence_finish(screen, buf->derived_surface.fence, PIPE_TIMEOUT_INFINITE);
+      screen->fence_reference(screen, &buf->derived_surface.fence, NULL);
+   }
+
+   if (buf->export_refcount > 0) {
+      if (buf->export_state.mem_type != mem_type)
+         return VA_STATUS_ERROR_INVALID_PARAMETER;
+   } else {
+      VABufferInfo * const buf_info = &buf->export_state;
+
+      switch (mem_type) {
+      case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME: {
+         struct winsys_handle whandle;
+
+         memset(&whandle, 0, sizeof(whandle));
+         whandle.type = DRM_API_HANDLE_TYPE_FD;
+
+         if (!screen->resource_get_handle(screen, buf->derived_surface.resource, &whandle))
+            return VA_STATUS_ERROR_INVALID_BUFFER;
+
+         buf_info->handle = (intptr_t)whandle.handle;
+         break;
+      default:
+         return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
+      }
+   }
+
+   buf_info->type = buf->type;
+   buf_info->mem_type = mem_type;
+   buf_info->mem_size = buf->num_elements * buf->size;
+
+   }
+
+   buf->export_refcount++;
+
+   *out_buf_info = buf->export_state;
+
+   return VA_STATUS_SUCCESS;
+}
+
+VAStatus
+vlVaReleaseBufferHandle(VADriverContextP ctx, VABufferID buf_id)
+{
+   vlVaBuffer *buf;
+
+   if (!ctx)
+      return VA_STATUS_ERROR_INVALID_CONTEXT;
+
+   buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id);
+
+   if (!buf)
+      return VA_STATUS_ERROR_INVALID_BUFFER;
+
+   if (buf->export_refcount == 0)
+      return VA_STATUS_ERROR_INVALID_BUFFER;
+
+   if (--buf->export_refcount == 0) {
+      VABufferInfo * const buf_info = &buf->export_state;
+
+      switch (buf_info->mem_type) {
+      case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
+         close((intptr_t)buf_info->handle);
+         break;
+      default:
+         return VA_STATUS_ERROR_INVALID_BUFFER;
+      }
+
+      buf_info->mem_type = 0;
+   }
+
+   return VA_STATUS_SUCCESS;
+}
index bd533c4d061389c6ee7c754036ff7e8b006f17b2..ec9e0488d8549121c08fa2d7d2e1079dd8419396 100644 (file)
@@ -87,7 +87,9 @@ static struct VADriverVTable vtable =
    &vlVaUnlockSurface,
    NULL, /* DEPRECATED VaGetSurfaceAttributes */
    &vlVaCreateSurfaces2,
-   &vlVaQuerySurfaceAttributes
+   &vlVaQuerySurfaceAttributes,
+   &vlVaAcquireBufferHandle,
+   &vlVaReleaseBufferHandle
 };
 
 static struct VADriverVTableVPP vtable_vpp =
index 3ae51a766a02c4958b468b4200182384944e1df5..2b645d08a03534b095d7b5b5e29d5f10544c06bf 100644 (file)
@@ -34,6 +34,7 @@
 #include <va/va.h>
 #include <va/va_backend.h>
 #include <va/va_backend_vpp.h>
+#include <va/va_drmcommon.h>
 
 #include "pipe/p_video_enums.h"
 #include "pipe/p_video_codec.h"
@@ -238,6 +239,8 @@ typedef struct {
       struct pipe_transfer *transfer;
       struct pipe_fence_handle *fence;
    } derived_surface;
+   unsigned int export_refcount;
+   VABufferInfo export_state;
 } vlVaBuffer;
 
 typedef struct {
@@ -328,6 +331,9 @@ VAStatus vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format, unsigned
 VAStatus vlVaQuerySurfaceAttributes(VADriverContextP ctx, VAConfigID config, VASurfaceAttrib *attrib_list,
                                     unsigned int *num_attribs);
 
+VAStatus vlVaAcquireBufferHandle(VADriverContextP ctx, VABufferID buf_id, VABufferInfo *out_buf_info);
+VAStatus vlVaReleaseBufferHandle(VADriverContextP ctx, VABufferID buf_id);
+
 VAStatus vlVaQueryVideoProcFilters(VADriverContextP ctx, VAContextID context, VAProcFilterType *filters,
                                    unsigned int *num_filters);
 VAStatus vlVaQueryVideoProcFilterCaps(VADriverContextP ctx, VAContextID context, VAProcFilterType type,