hwcontext_opencl: Add support for mapping DRM objects to Beignet

Also use that to support mapping VAAPI to Beignet.
This commit is contained in:
Mark Thompson 2018-03-11 21:19:20 +00:00
parent ca9f13bbce
commit ac993e73de
2 changed files with 138 additions and 141 deletions

16
configure vendored
View File

@ -2156,6 +2156,7 @@ HAVE_LIST="
makeinfo_html makeinfo_html
opencl_d3d11 opencl_d3d11
opencl_drm_arm opencl_drm_arm
opencl_drm_beignet
opencl_dxva2 opencl_dxva2
opencl_vaapi_beignet opencl_vaapi_beignet
opencl_vaapi_intel_media opencl_vaapi_intel_media
@ -6241,9 +6242,15 @@ enabled vaapi &&
enabled vaapi && enabled vaapi &&
check_cpp_condition vaapi_1 "va/va.h" "VA_CHECK_VERSION(1, 0, 0)" check_cpp_condition vaapi_1 "va/va.h" "VA_CHECK_VERSION(1, 0, 0)"
if enabled_all opencl vaapi ; then if enabled_all opencl libdrm ; then
check_type "CL/cl_intel.h" "clCreateImageFromFdINTEL_fn" && check_type "CL/cl_intel.h" "clCreateImageFromFdINTEL_fn" &&
enable opencl_vaapi_beignet enable opencl_drm_beignet
check_func_headers "CL/cl_ext.h" clImportMemoryARM &&
enable opencl_drm_arm
fi
if enabled_all opencl vaapi ; then
enabled opencl_drm_beignet && enable opencl_vaapi_beignet
if enabled libmfx ; then if enabled libmfx ; then
check_type "CL/cl.h CL/va_ext.h" "clCreateFromVA_APIMediaSurfaceINTEL_fn" && check_type "CL/cl.h CL/va_ext.h" "clCreateFromVA_APIMediaSurfaceINTEL_fn" &&
enable opencl_vaapi_intel_media enable opencl_vaapi_intel_media
@ -6260,11 +6267,6 @@ if enabled_all opencl d3d11va ; then
enable opencl_d3d11 enable opencl_d3d11
fi fi
if enabled_all opencl libdrm ; then
check_func_headers "CL/cl_ext.h" clImportMemoryARM &&
enable opencl_drm_arm
fi
enabled vdpau && enabled vdpau &&
check_cpp_condition vdpau vdpau/vdpau.h "defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP" check_cpp_condition vdpau vdpau/vdpau.h "defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP"

View File

@ -39,6 +39,12 @@
#include "hwcontext_vaapi.h" #include "hwcontext_vaapi.h"
#endif #endif
#if HAVE_OPENCL_DRM_BEIGNET
#include <unistd.h>
#include <CL/cl_intel.h>
#include "hwcontext_drm.h"
#endif
#if HAVE_OPENCL_VAAPI_INTEL_MEDIA #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
#include <mfx/mfxstructures.h> #include <mfx/mfxstructures.h>
#include <va/va.h> #include <va/va.h>
@ -76,9 +82,9 @@ typedef struct OpenCLDeviceContext {
cl_platform_id platform_id; cl_platform_id platform_id;
// Platform/device-specific functions. // Platform/device-specific functions.
#if HAVE_OPENCL_VAAPI_BEIGNET #if HAVE_OPENCL_DRM_BEIGNET
int vaapi_mapping_usable; int beignet_drm_mapping_usable;
clCreateImageFromFdINTEL_fn clCreateImageFromFdINTEL; clCreateImageFromFdINTEL_fn clCreateImageFromFdINTEL;
#endif #endif
#if HAVE_OPENCL_VAAPI_INTEL_MEDIA #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
@ -687,19 +693,19 @@ static int opencl_device_init(AVHWDeviceContext *hwdev)
} \ } \
} while (0) } while (0)
#if HAVE_OPENCL_VAAPI_BEIGNET #if HAVE_OPENCL_DRM_BEIGNET
{ {
int fail = 0; int fail = 0;
CL_FUNC(clCreateImageFromFdINTEL, CL_FUNC(clCreateImageFromFdINTEL,
"Intel DRM to OpenCL image mapping"); "Beignet DRM to OpenCL image mapping");
if (fail) { if (fail) {
av_log(hwdev, AV_LOG_WARNING, "VAAPI to OpenCL mapping " av_log(hwdev, AV_LOG_WARNING, "Beignet DRM to OpenCL "
"not usable.\n"); "mapping not usable.\n");
priv->vaapi_mapping_usable = 0; priv->beignet_drm_mapping_usable = 0;
} else { } else {
priv->vaapi_mapping_usable = 1; priv->beignet_drm_mapping_usable = 1;
} }
} }
#endif #endif
@ -1189,7 +1195,8 @@ static int opencl_device_derive(AVHWDeviceContext *hwdev,
int err; int err;
switch (src_ctx->type) { switch (src_ctx->type) {
#if HAVE_OPENCL_VAAPI_BEIGNET #if HAVE_OPENCL_DRM_BEIGNET
case AV_HWDEVICE_TYPE_DRM:
case AV_HWDEVICE_TYPE_VAAPI: case AV_HWDEVICE_TYPE_VAAPI:
{ {
// Surface mapping works via DRM PRIME fds with no special // Surface mapping works via DRM PRIME fds with no special
@ -2030,175 +2037,152 @@ fail:
return err; return err;
} }
#if HAVE_OPENCL_VAAPI_BEIGNET #if HAVE_OPENCL_DRM_BEIGNET
typedef struct VAAPItoOpenCLMapping { typedef struct DRMBeignetToOpenCLMapping {
VAImage va_image; AVFrame *drm_frame;
VABufferInfo va_buffer_info; AVDRMFrameDescriptor *drm_desc;
AVOpenCLFrameDescriptor frame; AVOpenCLFrameDescriptor frame;
} VAAPItoOpenCLMapping; } DRMBeignetToOpenCLMapping;
static void opencl_unmap_from_vaapi(AVHWFramesContext *src_fc, static void opencl_unmap_from_drm_beignet(AVHWFramesContext *dst_fc,
HWMapDescriptor *hwmap) HWMapDescriptor *hwmap)
{ {
VAAPItoOpenCLMapping *mapping = hwmap->priv; DRMBeignetToOpenCLMapping *mapping = hwmap->priv;
AVVAAPIDeviceContext *src_dev = src_fc->device_ctx->hwctx;
VASurfaceID surface_id;
VAStatus vas;
cl_int cle; cl_int cle;
int i; int i;
surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
av_log(src_fc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from OpenCL.\n",
surface_id);
for (i = 0; i < mapping->frame.nb_planes; i++) { for (i = 0; i < mapping->frame.nb_planes; i++) {
cle = clReleaseMemObject(mapping->frame.planes[i]); cle = clReleaseMemObject(mapping->frame.planes[i]);
if (cle != CL_SUCCESS) { if (cle != CL_SUCCESS) {
av_log(src_fc, AV_LOG_ERROR, "Failed to release CL " av_log(dst_fc, AV_LOG_ERROR, "Failed to release CL image "
"buffer of plane %d of VA image %#x (derived " "of plane %d of DRM frame: %d.\n", i, cle);
"from surface %#x): %d.\n", i,
mapping->va_image.buf, surface_id, cle);
} }
} }
vas = vaReleaseBufferHandle(src_dev->display,
mapping->va_image.buf);
if (vas != VA_STATUS_SUCCESS) {
av_log(src_fc, AV_LOG_ERROR, "Failed to release buffer "
"handle of image %#x (derived from surface %#x): "
"%d (%s).\n", mapping->va_image.buf, surface_id,
vas, vaErrorStr(vas));
}
vas = vaDestroyImage(src_dev->display,
mapping->va_image.image_id);
if (vas != VA_STATUS_SUCCESS) {
av_log(src_fc, AV_LOG_ERROR, "Failed to destroy image "
"derived from surface %#x: %d (%s).\n",
surface_id, vas, vaErrorStr(vas));
}
av_free(mapping); av_free(mapping);
} }
static int opencl_map_from_vaapi(AVHWFramesContext *dst_fc, AVFrame *dst, static int opencl_map_from_drm_beignet(AVHWFramesContext *dst_fc,
const AVFrame *src, int flags) AVFrame *dst, const AVFrame *src,
int flags)
{ {
AVHWFramesContext *src_fc = AVOpenCLDeviceContext *hwctx = dst_fc->device_ctx->hwctx;
(AVHWFramesContext*)src->hw_frames_ctx->data; OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv;
AVVAAPIDeviceContext *src_dev = src_fc->device_ctx->hwctx; DRMBeignetToOpenCLMapping *mapping;
AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; const AVDRMFrameDescriptor *desc;
OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv;
VAAPItoOpenCLMapping *mapping = NULL;
VASurfaceID surface_id;
VAStatus vas;
cl_int cle; cl_int cle;
int err, p; int err, i, j, p;
surface_id = (VASurfaceID)(uintptr_t)src->data[3]; desc = (const AVDRMFrameDescriptor*)src->data[0];
av_log(src_fc, AV_LOG_DEBUG, "Map VAAPI surface %#x to OpenCL.\n",
surface_id);
mapping = av_mallocz(sizeof(*mapping)); mapping = av_mallocz(sizeof(*mapping));
if (!mapping) if (!mapping)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
vas = vaDeriveImage(src_dev->display, surface_id, p = 0;
&mapping->va_image); for (i = 0; i < desc->nb_layers; i++) {
if (vas != VA_STATUS_SUCCESS) { const AVDRMLayerDescriptor *layer = &desc->layers[i];
av_log(src_fc, AV_LOG_ERROR, "Failed to derive image from " for (j = 0; j < layer->nb_planes; j++) {
"surface %#x: %d (%s).\n", const AVDRMPlaneDescriptor *plane = &layer->planes[j];
surface_id, vas, vaErrorStr(vas)); const AVDRMObjectDescriptor *object =
err = AVERROR(EIO); &desc->objects[plane->object_index];
goto fail;
}
mapping->va_buffer_info.mem_type = cl_import_image_info_intel image_info = {
VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME; .fd = object->fd,
.size = object->size,
.type = CL_MEM_OBJECT_IMAGE2D,
.offset = plane->offset,
.row_pitch = plane->pitch,
};
cl_image_desc image_desc;
vas = vaAcquireBufferHandle(src_dev->display, err = opencl_get_plane_format(dst_fc->sw_format, p,
mapping->va_image.buf, src->width, src->height,
&mapping->va_buffer_info); &image_info.fmt,
if (vas != VA_STATUS_SUCCESS) { &image_desc);
av_log(src_fc, AV_LOG_ERROR, "Failed to get buffer " if (err < 0) {
"handle from image %#x (derived from surface %#x): " av_log(dst_fc, AV_LOG_ERROR, "DRM frame layer %d "
"%d (%s).\n", mapping->va_image.buf, surface_id, "plane %d is not representable in OpenCL: %d.\n",
vas, vaErrorStr(vas)); i, j, err);
vaDestroyImage(src_dev->display, mapping->va_image.buf); goto fail;
err = AVERROR(EIO); }
goto fail_derived; image_info.width = image_desc.image_width;
} image_info.height = image_desc.image_height;
av_log(dst_fc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n", mapping->frame.planes[p] =
mapping->va_buffer_info.handle); priv->clCreateImageFromFdINTEL(hwctx->context,
&image_info, &cle);
if (!mapping->frame.planes[p]) {
av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL image "
"from layer %d plane %d of DRM frame: %d.\n",
i, j, cle);
err = AVERROR(EIO);
goto fail;
}
mapping->frame.nb_planes = mapping->va_image.num_planes; dst->data[p] = (uint8_t*)mapping->frame.planes[p];
for (p = 0; p < mapping->frame.nb_planes; p++) { mapping->frame.nb_planes = ++p;
cl_import_image_info_intel image_info = {
.fd = mapping->va_buffer_info.handle,
.size = mapping->va_buffer_info.mem_size,
.type = CL_MEM_OBJECT_IMAGE2D,
.offset = mapping->va_image.offsets[p],
.row_pitch = mapping->va_image.pitches[p],
};
cl_image_desc image_desc;
err = opencl_get_plane_format(src_fc->sw_format, p,
mapping->va_image.width,
mapping->va_image.height,
&image_info.fmt,
&image_desc);
if (err < 0) {
av_log(dst_fc, AV_LOG_ERROR, "VA %#x (derived from "
"surface %#x) has invalid parameters: %d.\n",
mapping->va_image.buf, surface_id, err);
goto fail_mapped;
} }
image_info.width = image_desc.image_width;
image_info.height = image_desc.image_height;
mapping->frame.planes[p] =
priv->clCreateImageFromFdINTEL(dst_dev->context,
&image_info, &cle);
if (!mapping->frame.planes[p]) {
av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL image "
"from plane %d of VA image %#x (derived from "
"surface %#x): %d.\n", p,
mapping->va_image.buf, surface_id, cle);
err = AVERROR(EIO);
goto fail_mapped;
}
dst->data[p] = (uint8_t*)mapping->frame.planes[p];
} }
err = ff_hwframe_map_create(src->hw_frames_ctx, err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
dst, src, &opencl_unmap_from_vaapi, &opencl_unmap_from_drm_beignet,
mapping); mapping);
if (err < 0) if (err < 0)
goto fail_mapped; goto fail;
dst->width = src->width; dst->width = src->width;
dst->height = src->height; dst->height = src->height;
return 0; return 0;
fail_mapped: fail:
for (p = 0; p < mapping->frame.nb_planes; p++) { for (p = 0; p < mapping->frame.nb_planes; p++) {
if (mapping->frame.planes[p]) if (mapping->frame.planes[p])
clReleaseMemObject(mapping->frame.planes[p]); clReleaseMemObject(mapping->frame.planes[p]);
} }
vaReleaseBufferHandle(src_dev->display, mapping->va_image.buf); av_free(mapping);
fail_derived:
vaDestroyImage(src_dev->display, mapping->va_image.image_id);
fail:
av_freep(&mapping);
return err; return err;
} }
#endif #if HAVE_OPENCL_VAAPI_BEIGNET
static int opencl_map_from_vaapi(AVHWFramesContext *dst_fc,
AVFrame *dst, const AVFrame *src,
int flags)
{
HWMapDescriptor *hwmap;
AVFrame *tmp;
int err;
tmp = av_frame_alloc();
if (!tmp)
return AVERROR(ENOMEM);
tmp->format = AV_PIX_FMT_DRM_PRIME;
err = av_hwframe_map(tmp, src, flags);
if (err < 0)
goto fail;
err = opencl_map_from_drm_beignet(dst_fc, dst, tmp, flags);
if (err < 0)
goto fail;
// Adjust the map descriptor so that unmap works correctly.
hwmap = (HWMapDescriptor*)dst->buf[0]->data;
av_frame_unref(hwmap->source);
err = av_frame_ref(hwmap->source, src);
fail:
av_frame_free(&tmp);
return err;
}
#endif /* HAVE_OPENCL_VAAPI_BEIGNET */
#endif /* HAVE_OPENCL_DRM_BEIGNET */
static inline cl_mem_flags opencl_mem_flags_for_mapping(int map_flags) static inline cl_mem_flags opencl_mem_flags_for_mapping(int map_flags)
{ {
@ -2828,9 +2812,14 @@ static int opencl_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
OpenCLDeviceContext *priv = hwfc->device_ctx->internal->priv; OpenCLDeviceContext *priv = hwfc->device_ctx->internal->priv;
av_assert0(dst->format == AV_PIX_FMT_OPENCL); av_assert0(dst->format == AV_PIX_FMT_OPENCL);
switch (src->format) { switch (src->format) {
#if HAVE_OPENCL_DRM_BEIGNET
case AV_PIX_FMT_DRM_PRIME:
if (priv->beignet_drm_mapping_usable)
return opencl_map_from_drm_beignet(hwfc, dst, src, flags);
#endif
#if HAVE_OPENCL_VAAPI_BEIGNET #if HAVE_OPENCL_VAAPI_BEIGNET
case AV_PIX_FMT_VAAPI: case AV_PIX_FMT_VAAPI:
if (priv->vaapi_mapping_usable) if (priv->beignet_drm_mapping_usable)
return opencl_map_from_vaapi(hwfc, dst, src, flags); return opencl_map_from_vaapi(hwfc, dst, src, flags);
#endif #endif
#if HAVE_OPENCL_VAAPI_INTEL_MEDIA #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
@ -2863,9 +2852,15 @@ static int opencl_frames_derive_to(AVHWFramesContext *dst_fc,
{ {
OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv; OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv;
switch (src_fc->device_ctx->type) { switch (src_fc->device_ctx->type) {
#if HAVE_OPENCL_DRM_BEIGNET
case AV_HWDEVICE_TYPE_DRM:
if (!priv->beignet_drm_mapping_usable)
return AVERROR(ENOSYS);
break;
#endif
#if HAVE_OPENCL_VAAPI_BEIGNET #if HAVE_OPENCL_VAAPI_BEIGNET
case AV_HWDEVICE_TYPE_VAAPI: case AV_HWDEVICE_TYPE_VAAPI:
if (!priv->vaapi_mapping_usable) if (!priv->beignet_drm_mapping_usable)
return AVERROR(ENOSYS); return AVERROR(ENOSYS);
break; break;
#endif #endif