From e7ed3963ed33134cc214f0a8b8e4b8cb6029887d Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Fri, 30 Oct 2015 11:42:53 +0000 Subject: [PATCH] st/va: add support to export a surface as dmabuf MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Emil Velikov Reviewed-by: Christian König --- src/gallium/state_trackers/va/buffer.c | 136 ++++++++++++++++++++- src/gallium/state_trackers/va/context.c | 4 +- src/gallium/state_trackers/va/va_private.h | 6 + 3 files changed, 144 insertions(+), 2 deletions(-) diff --git a/src/gallium/state_trackers/va/buffer.c b/src/gallium/state_trackers/va/buffer.c index d3a7c5d6dc4..71a65037757 100644 --- a/src/gallium/state_trackers/va/buffer.c +++ b/src/gallium/state_trackers/va/buffer.c @@ -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; +} diff --git a/src/gallium/state_trackers/va/context.c b/src/gallium/state_trackers/va/context.c index bd533c4d061..ec9e0488d85 100644 --- a/src/gallium/state_trackers/va/context.c +++ b/src/gallium/state_trackers/va/context.c @@ -87,7 +87,9 @@ static struct VADriverVTable vtable = &vlVaUnlockSurface, NULL, /* DEPRECATED VaGetSurfaceAttributes */ &vlVaCreateSurfaces2, - &vlVaQuerySurfaceAttributes + &vlVaQuerySurfaceAttributes, + &vlVaAcquireBufferHandle, + &vlVaReleaseBufferHandle }; static struct VADriverVTableVPP vtable_vpp = diff --git a/src/gallium/state_trackers/va/va_private.h b/src/gallium/state_trackers/va/va_private.h index 3ae51a766a0..2b645d08a03 100644 --- a/src/gallium/state_trackers/va/va_private.h +++ b/src/gallium/state_trackers/va/va_private.h @@ -34,6 +34,7 @@ #include #include #include +#include #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, -- 2.30.2