#include "sysdeps.h"
#include <unistd.h>
#include <dlfcn.h>
+#include <drm_fourcc.h>
#ifdef HAVE_VA_X11
# include "i965_output_dri.h"
if (HAS_H264_DECODING(i965) ||
HAS_H264_ENCODING(i965) ||
- HAS_LP_H264_ENCODING(i965)) {
+ HAS_LP_H264_ENCODING(i965) ||
+ HAS_FEI_H264_ENCODING(i965)) {
profile_list[i++] = VAProfileH264ConstrainedBaseline;
profile_list[i++] = VAProfileH264Main;
profile_list[i++] = VAProfileH264High;
if (HAS_LP_H264_ENCODING(i965))
entrypoint_list[n++] = VAEntrypointEncSliceLP;
+ if (HAS_FEI_H264_ENCODING(i965))
+ entrypoint_list[n++] = VAEntrypointFEI;
+
break;
case VAProfileH264MultiviewHigh:
case VAProfileH264StereoHigh:
case VAProfileH264High:
if ((HAS_H264_DECODING(i965) && entrypoint == VAEntrypointVLD) ||
(HAS_H264_ENCODING(i965) && entrypoint == VAEntrypointEncSlice) ||
- (HAS_LP_H264_ENCODING(i965) && entrypoint == VAEntrypointEncSliceLP)) {
+ (HAS_LP_H264_ENCODING(i965) && entrypoint == VAEntrypointEncSliceLP) ||
+ (HAS_FEI_H264_ENCODING(i965) && entrypoint == VAEntrypointFEI)) {
va_status = VA_STATUS_SUCCESS;
} else if (!HAS_H264_DECODING(i965) && !HAS_H264_ENCODING(i965) &&
- !HAS_LP_H264_ENCODING(i965)) {
+ !HAS_LP_H264_ENCODING(i965) && !HAS_FEI_H264_ENCODING(i965)) {
va_status = VA_STATUS_ERROR_UNSUPPORTED_PROFILE;
} else {
va_status = VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT;
attrib_list[i].value = i965->codec_info->lp_h264_brc_mode;
else
attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
+ } else if (entrypoint == VAEntrypointFEI) {
+ /* Only CQP is supported in FEI Entrypoint */
+ if (profile == VAProfileH264ConstrainedBaseline ||
+ profile == VAProfileH264Main ||
+ profile == VAProfileH264High)
+ attrib_list[i].value = VA_RC_CQP;
+ else
+ attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
} else
attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
case VAConfigAttribEncPackedHeaders:
if (entrypoint == VAEntrypointEncSlice ||
- entrypoint == VAEntrypointEncSliceLP) {
+ entrypoint == VAEntrypointEncSliceLP ||
+ entrypoint == VAEntrypointFEI) {
attrib_list[i].value = VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_PICTURE | VA_ENC_PACKED_HEADER_MISC;
if (profile == VAProfileH264ConstrainedBaseline ||
profile == VAProfileH264Main ||
break;
case VAConfigAttribEncMaxRefFrames:
- if (entrypoint == VAEntrypointEncSlice) {
+ if (entrypoint == VAEntrypointEncSlice || entrypoint == VAEntrypointFEI) {
attrib_list[i].value = (1 << 16) | (1 << 0);
if (profile == VAProfileH264ConstrainedBaseline ||
profile == VAProfileH264Main ||
case VAConfigAttribEncQualityRange:
if (entrypoint == VAEntrypointEncSlice ||
- entrypoint == VAEntrypointEncSliceLP) {
+ entrypoint == VAEntrypointEncSliceLP ||
+ entrypoint == VAEntrypointFEI) {
attrib_list[i].value = 1;
if (profile == VAProfileH264ConstrainedBaseline ||
profile == VAProfileH264Main ||
case VAConfigAttribEncROI:
if (entrypoint == VAEntrypointEncSlice ||
- entrypoint == VAEntrypointEncSliceLP) {
+ entrypoint == VAEntrypointEncSliceLP ||
+ entrypoint == VAEntrypointFEI) {
VAConfigAttribValEncROI *roi_config =
(VAConfigAttribValEncROI *) & (attrib_list[i].value);
profile == VAProfileH264High) {
if (IS_GEN9(i965->intel.device_info) &&
- entrypoint == VAEntrypointEncSlice)
+ (entrypoint == VAEntrypointEncSlice || entrypoint == VAEntrypointFEI))
attrib_list[i].value = 0;
else {
if (entrypoint == VAEntrypointEncSliceLP) {
roi_config->bits.num_roi_regions = 3;
roi_config->bits.roi_rc_priority_support = 0;
- roi_config->bits.roi_rc_qp_delat_support = 0;
+ roi_config->bits.roi_rc_qp_delta_support = 0;
} else {
roi_config->bits.num_roi_regions =
I965_MAX_NUM_ROI_REGIONS;
roi_config->bits.roi_rc_priority_support = 0;
- roi_config->bits.roi_rc_qp_delat_support = 1;
+ roi_config->bits.roi_rc_qp_delta_support = 1;
}
}
} else if (profile == VAProfileHEVCMain ||
roi_config->bits.num_roi_regions =
I965_MAX_NUM_ROI_REGIONS;
roi_config->bits.roi_rc_priority_support = 1;
- roi_config->bits.roi_rc_qp_delat_support = 1;
+ roi_config->bits.roi_rc_qp_delta_support = 1;
} else {
attrib_list[i].value = 0;
}
profile == VAProfileHEVCMain10) {
attrib_list[i].value = I965_MAX_NUM_SLICE;
}
- } else if (entrypoint == VAEntrypointEncSliceLP) {
+ } else if (entrypoint == VAEntrypointEncSliceLP || entrypoint == VAEntrypointFEI) {
if ((profile == VAProfileH264ConstrainedBaseline ||
profile == VAProfileH264Main ||
profile == VAProfileH264High) ||
}
break;
+
+ case VAConfigAttribFEIFunctionType:
+ /* Supporing all possible modes of FEI */
+ attrib_list[i].value = VA_FEI_FUNCTION_ENC |
+ VA_FEI_FUNCTION_PAK | VA_FEI_FUNCTION_ENC_PAK;
+ break;
+
+ case VAConfigAttribFEIMVPredictors:
+ attrib_list[i].value = 4;
+ break;
+
default:
/* Do nothing */
attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
else if ((entrypoint == VAEntrypointEncSliceLP) && attrib_found &&
!(attrib_found->value & i965->codec_info->lp_h264_brc_mode))
vaStatus = VA_STATUS_ERROR_INVALID_CONFIG;
+ else if ((entrypoint == VAEntrypointFEI) && attrib_found &&
+ !(attrib_found->value == VA_RC_CQP))
+ vaStatus = VA_STATUS_ERROR_INVALID_CONFIG;
break;
default:
break;
} else if (profile == VAProfileHEVCMain ||
profile == VAProfileHEVCMain10)
attrib.value = I965_MAX_NUM_SLICE;
- } else if (entrypoint == VAEntrypointEncSliceLP) {
+ } else if (entrypoint == VAEntrypointEncSliceLP || entrypoint == VAEntrypointFEI) {
if ((profile == VAProfileH264ConstrainedBaseline ||
profile == VAProfileH264Main ||
profile == VAProfileH264High) ||
obj_surface->height = memory_attibute->offsets[1] / obj_surface->width;
if (memory_attibute->num_planes > 1) {
- ASSERT_RET(IS_ALIGNED(obj_surface->height, 16), VA_STATUS_ERROR_INVALID_PARAMETER);
ASSERT_RET(obj_surface->height >= obj_surface->orig_height, VA_STATUS_ERROR_INVALID_PARAMETER);
}
obj_context->hw_context = i965->codec_info->proc_hw_context_init(ctx, obj_config);
} else if ((VAEntrypointEncSlice == obj_config->entrypoint) ||
(VAEntrypointEncPicture == obj_config->entrypoint) ||
- (VAEntrypointEncSliceLP == obj_config->entrypoint)) {
+ (VAEntrypointEncSliceLP == obj_config->entrypoint) ||
+ (VAEntrypointFEI == obj_config->entrypoint)) {
VAConfigAttrib *packed_attrib;
obj_context->codec_type = CODEC_ENC;
memset(&obj_context->codec_state.encode, 0, sizeof(obj_context->codec_state.encode));
case VAHuffmanTableBufferType:
case VAProbabilityBufferType:
case VAEncMacroblockMapBufferType:
+ case VAEncQPBufferType:
+ case VAEncFEIMVBufferType:
+ case VAEncFEIMBCodeBufferType:
+ case VAEncFEIDistortionBufferType:
+ case VAEncFEIMBControlBufferType:
+ case VAEncFEIMVPredictorBufferType:
/* Ok */
break;
type == VAImageBufferType ||
type == VAEncCodedBufferType ||
type == VAEncMacroblockMapBufferType ||
- type == VAProbabilityBufferType) {
+ type == VAProbabilityBufferType ||
+ type == VAEncQPBufferType ||
+ type == VAEncFEIMVBufferType ||
+ type == VAEncFEIMBCodeBufferType ||
+ type == VAEncFEIDistortionBufferType ||
+ type == VAEncFEIMBControlBufferType ||
+ type == VAEncFEIMVPredictorBufferType) {
/* If the buffer is wrapped, the bo/buffer of buffer_store is bogus.
* So it is enough to allocate one 64 byte bo
vaStatus = i965_proc_render_picture(ctx, context, buffers, num_buffers);
} else if ((VAEntrypointEncSlice == obj_config->entrypoint) ||
(VAEntrypointEncPicture == obj_config->entrypoint) ||
- (VAEntrypointEncSliceLP == obj_config->entrypoint)) {
+ (VAEntrypointEncSliceLP == obj_config->entrypoint) ||
+ (VAEntrypointFEI == obj_config->entrypoint)) {
vaStatus = i965_encoder_render_picture(ctx, context, buffers, num_buffers);
} else {
vaStatus = i965_decoder_render_picture(ctx, context, buffers, num_buffers);
} else if (obj_context->codec_type == CODEC_ENC) {
ASSERT_RET(((VAEntrypointEncSlice == obj_config->entrypoint) ||
(VAEntrypointEncPicture == obj_config->entrypoint) ||
- (VAEntrypointEncSliceLP == obj_config->entrypoint)),
+ (VAEntrypointEncSliceLP == obj_config->entrypoint) ||
+ (VAEntrypointFEI == obj_config->entrypoint)),
VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT);
if (obj_context->codec_state.encode.num_packed_header_params_ext !=
IS_GEN9(i965->intel.device_info)) {
if (obj_config->entrypoint == VAEntrypointEncSlice ||
obj_config->entrypoint == VAEntrypointVideoProc ||
- obj_config->entrypoint == VAEntrypointEncSliceLP) {
+ obj_config->entrypoint == VAEntrypointEncSliceLP ||
+ obj_config->entrypoint == VAEntrypointFEI) {
switch (attrib_list[i].value.value.i) {
case VA_FOURCC_NV12:
case VA_FOURCC_I420:
attribs[i].type = VASurfaceAttribPixelFormat;
attribs[i].value.type = VAGenericValueTypeInteger;
attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
+ attribs[i].value.value.i = VA_FOURCC_UYVY;
+ i++;
+
+ attribs[i].type = VASurfaceAttribPixelFormat;
+ attribs[i].value.type = VAGenericValueTypeInteger;
+ attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
attribs[i].value.value.i = VA_FOURCC_RGBA;
i++;
} else if (obj_config->entrypoint == VAEntrypointEncSlice || /* encode */
obj_config->entrypoint == VAEntrypointVideoProc ||
obj_config->entrypoint == VAEntrypointEncSliceLP ||
- obj_config->entrypoint == VAEntrypointEncPicture) {
+ obj_config->entrypoint == VAEntrypointEncPicture ||
+ obj_config->entrypoint == VAEntrypointFEI) {
if (obj_config->profile == VAProfileHEVCMain10) {
attribs[i].type = VASurfaceAttribPixelFormat;
attribs[i].type = VASurfaceAttribPixelFormat;
attribs[i].value.type = VAGenericValueTypeInteger;
attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
+ attribs[i].value.value.i = VA_FOURCC_UYVY;
+ i++;
+
+ attribs[i].type = VASurfaceAttribPixelFormat;
+ attribs[i].value.type = VAGenericValueTypeInteger;
+ attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
attribs[i].value.value.i = VA_FOURCC_RGBA;
i++;
return i965_release_buffer_handle(obj_buffer);
}
+// Locally define DRM_FORMAT values not available in older but still
+// supported versions of libdrm.
+#ifndef DRM_FORMAT_R8
+#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ')
+#endif
+#ifndef DRM_FORMAT_R16
+#define DRM_FORMAT_R16 fourcc_code('R', '1', '6', ' ')
+#endif
+#ifndef DRM_FORMAT_GR88
+#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8')
+#endif
+#ifndef DRM_FORMAT_GR1616
+#define DRM_FORMAT_GR1616 fourcc_code('G', 'R', '3', '2')
+#endif
+
+static uint32_t drm_format_of_separate_plane(uint32_t fourcc, int plane)
+{
+ if (plane == 0) {
+ switch (fourcc) {
+ case VA_FOURCC_NV12:
+ case VA_FOURCC_I420:
+ case VA_FOURCC_YV12:
+ case VA_FOURCC_YV16:
+ case VA_FOURCC_Y800:
+ return DRM_FORMAT_R8;
+ case VA_FOURCC_P010:
+ case VA_FOURCC_I010:
+ return DRM_FORMAT_R16;
+
+ case VA_FOURCC_YUY2:
+ case VA_FOURCC_UYVY:
+ // These are not representable as separate planes.
+ return 0;
+
+ case VA_FOURCC_RGBA:
+ return DRM_FORMAT_ABGR8888;
+ case VA_FOURCC_RGBX:
+ return DRM_FORMAT_XBGR8888;
+ case VA_FOURCC_BGRA:
+ return DRM_FORMAT_ARGB8888;
+ case VA_FOURCC_BGRX:
+ return DRM_FORMAT_XRGB8888;
+ case VA_FOURCC_ARGB:
+ return DRM_FORMAT_BGRA8888;
+ case VA_FOURCC_ABGR:
+ return DRM_FORMAT_RGBA8888;
+ }
+ } else {
+ switch (fourcc) {
+ case VA_FOURCC_NV12:
+ return DRM_FORMAT_GR88;
+ case VA_FOURCC_I420:
+ case VA_FOURCC_YV12:
+ case VA_FOURCC_YV16:
+ return DRM_FORMAT_R8;
+ case VA_FOURCC_P010:
+ return DRM_FORMAT_GR1616;
+ case VA_FOURCC_I010:
+ return DRM_FORMAT_R16;
+ }
+ }
+ return 0;
+}
+
+static uint32_t drm_format_of_composite_object(uint32_t fourcc)
+{
+ switch (fourcc) {
+ case VA_FOURCC_NV12:
+ return DRM_FORMAT_NV12;
+ case VA_FOURCC_I420:
+ return DRM_FORMAT_YUV420;
+ case VA_FOURCC_YV12:
+ return DRM_FORMAT_YVU420;
+ case VA_FOURCC_YV16:
+ return DRM_FORMAT_YVU422;
+ case VA_FOURCC_YUY2:
+ return DRM_FORMAT_YUYV;
+ case VA_FOURCC_UYVY:
+ return DRM_FORMAT_UYVY;
+ case VA_FOURCC_Y800:
+ return DRM_FORMAT_R8;
+
+ case VA_FOURCC_P010:
+ case VA_FOURCC_I010:
+ // These currently have no composite DRM format - they are usable
+ // only as separate planes.
+ return 0;
+
+ case VA_FOURCC_RGBA:
+ return DRM_FORMAT_ABGR8888;
+ case VA_FOURCC_RGBX:
+ return DRM_FORMAT_XBGR8888;
+ case VA_FOURCC_BGRA:
+ return DRM_FORMAT_ARGB8888;
+ case VA_FOURCC_BGRX:
+ return DRM_FORMAT_XRGB8888;
+ case VA_FOURCC_ARGB:
+ return DRM_FORMAT_BGRA8888;
+ case VA_FOURCC_ABGR:
+ return DRM_FORMAT_RGBA8888;
+ }
+ return 0;
+}
+
+static VAStatus
+i965_ExportSurfaceHandle(VADriverContextP ctx, VASurfaceID surface_id,
+ uint32_t mem_type, uint32_t flags,
+ void *descriptor)
+{
+ struct i965_driver_data *const i965 = i965_driver_data(ctx);
+ struct object_surface *obj_surface = SURFACE(surface_id);
+ const i965_fourcc_info *info;
+ VADRMPRIMESurfaceDescriptor *desc;
+ unsigned int tiling, swizzle;
+ uint32_t formats[4], pitch, height, offset;
+ int fd, p;
+ int composite_object =
+ flags & VA_EXPORT_SURFACE_COMPOSED_LAYERS;
+
+ if (!obj_surface || !obj_surface->bo)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ if (mem_type != VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2) {
+ i965_log_info(ctx, "vaExportSurfaceHandle: memory type %08x "
+ "is not supported.\n", mem_type);
+ return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
+ }
+
+ info = get_fourcc_info(obj_surface->fourcc);
+ if (!info)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+ if (composite_object) {
+ formats[0] =
+ drm_format_of_composite_object(obj_surface->fourcc);
+ if (!formats[0]) {
+ i965_log_info(ctx, "vaExportSurfaceHandle: fourcc %08x "
+ "is not supported for export as a composite "
+ "object.\n", obj_surface->fourcc);
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+ }
+ } else {
+ for (p = 0; p < info->num_planes; p++) {
+ formats[p] =
+ drm_format_of_separate_plane(obj_surface->fourcc, p);
+ if (!formats[p]) {
+ i965_log_info(ctx, "vaExportSurfaceHandle: fourcc %08x "
+ "is not supported for export as separate "
+ "planes.\n", obj_surface->fourcc);
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+ }
+ }
+ }
+
+ if (drm_intel_bo_gem_export_to_prime(obj_surface->bo, &fd))
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ if (drm_intel_bo_get_tiling(obj_surface->bo, &tiling, &swizzle))
+ tiling = I915_TILING_NONE;
+
+ desc = descriptor;
+
+ desc->fourcc = obj_surface->fourcc;
+ desc->width = obj_surface->width;
+ desc->height = obj_surface->height;
+
+ desc->num_objects = 1;
+ desc->objects[0].fd = fd;
+ desc->objects[0].size = obj_surface->size;
+ switch (tiling) {
+ case I915_TILING_X:
+ desc->objects[0].drm_format_modifier = I915_FORMAT_MOD_X_TILED;
+ break;
+ case I915_TILING_Y:
+ desc->objects[0].drm_format_modifier = I915_FORMAT_MOD_Y_TILED;
+ break;
+ case I915_TILING_NONE:
+ default:
+ desc->objects[0].drm_format_modifier = DRM_FORMAT_MOD_NONE;
+ }
+
+ if (composite_object) {
+ desc->num_layers = 1;
+
+ desc->layers[0].drm_format = formats[0];
+ desc->layers[0].num_planes = info->num_planes;
+
+ offset = 0;
+ for (p = 0; p < info->num_planes; p++) {
+ desc->layers[0].object_index[p] = 0;
+
+ if (p == 0) {
+ pitch = obj_surface->width;
+ height = obj_surface->height;
+ } else {
+ pitch = obj_surface->cb_cr_pitch;
+ height = obj_surface->cb_cr_height;
+ }
+
+ desc->layers[0].offset[p] = offset;
+ desc->layers[0].pitch[p] = pitch;
+
+ offset += pitch * height;
+ }
+ } else {
+ desc->num_layers = info->num_planes;
+
+ offset = 0;
+ for (p = 0; p < info->num_planes; p++) {
+ desc->layers[p].drm_format = formats[p];
+ desc->layers[p].num_planes = 1;
+
+ desc->layers[p].object_index[0] = 0;
+
+ if (p == 0) {
+ pitch = obj_surface->width;
+ height = obj_surface->height;
+ } else {
+ pitch = obj_surface->cb_cr_pitch;
+ height = obj_surface->cb_cr_height;
+ }
+
+ desc->layers[p].offset[0] = offset;
+ desc->layers[p].pitch[0] = pitch;
+
+ offset += pitch * height;
+ }
+ }
+
+ return VA_STATUS_SUCCESS;
+}
+
static int
i965_os_has_ring_support(VADriverContextP ctx,
int ring)
return VA_STATUS_SUCCESS;
}
+void i965_log_error(VADriverContextP ctx, const char *format, ...)
+{
+ va_list vl;
+
+ va_start(vl, format);
+
+ if (!ctx->error_callback) {
+ // No error callback: this is a error message which should be
+ // user-visible, so print it to stderr instead.
+ vfprintf(stderr, format, vl);
+ } else {
+ // Put the message on the stack. If it overruns the size of the
+ // then it will just be truncated - callers shouldn't be sending
+ // messages which are too long.
+ char tmp[1024];
+ int ret;
+ ret = vsnprintf(tmp, sizeof(tmp), format, vl);
+ if (ret > 0)
+ ctx->error_callback(ctx, tmp);
+ }
+
+ va_end(vl);
+}
+
+void i965_log_info(VADriverContextP ctx, const char *format, ...)
+{
+ va_list vl;
+
+ va_start(vl, format);
+
+ if (!ctx->info_callback) {
+ // No info callback: this message is only useful for developers,
+ // so just discard it.
+ } else {
+ // Put the message on the stack. If it overruns the size of the
+ // then it will just be truncated - callers shouldn't be sending
+ // messages which are too long.
+ char tmp[1024];
+ int ret;
+ ret = vsnprintf(tmp, sizeof(tmp), format, vl);
+ if (ret > 0)
+ ctx->info_callback(ctx, tmp);
+ }
+
+ va_end(vl);
+}
+
extern struct hw_codec_info *i965_get_codec_info(int devid);
static bool
vtable->vaAcquireBufferHandle = i965_AcquireBufferHandle;
vtable->vaReleaseBufferHandle = i965_ReleaseBufferHandle;
+ /* 1.0.0 */
+ vtable->vaExportSurfaceHandle = i965_ExportSurfaceHandle;
+
vtable_vpp->vaQueryVideoProcFilters = i965_QueryVideoProcFilters;
vtable_vpp->vaQueryVideoProcFilterCaps = i965_QueryVideoProcFilterCaps;
vtable_vpp->vaQueryVideoProcPipelineCaps = i965_QueryVideoProcPipelineCaps;