diff --git a/NEWS b/NEWS index 9b31f4c51..d5c75a68f 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ Copyright (C) 2009-2023 Intel Corporation Version 2.4.6 - XX.XX.XXXX (IRQL fork) +* Add support for VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 in vaCreateSurfaces. * Remove support for VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_3 in vaExportSurfaceHandle. It was using an ugly memory hack to work and there isn't much support or use case for this variant. diff --git a/src/i965_drv_video.c b/src/i965_drv_video.c index e98628e05..93fe4a7f5 100644 --- a/src/i965_drv_video.c +++ b/src/i965_drv_video.c @@ -2047,6 +2047,266 @@ i965_surface_external_memory(VADriverContextP ctx, return VA_STATUS_SUCCESS; } +static VAStatus +i965_surface_external_memory2(VADriverContextP ctx, + struct object_surface *obj_surface, + int external_memory_type, + VADRMPRIMESurfaceDescriptor *memory_attribute, + int index) +{ + assert(external_memory_type != I965_SURFACE_MEM_DRM_PRIME_2); + + struct i965_driver_data *i965 = i965_driver_data(ctx); + unsigned int tiling, swizzle; + + if (!memory_attribute || + !memory_attribute->num_objects || + index >= memory_attribute->num_objects) + return VA_STATUS_ERROR_INVALID_PARAMETER; + + if (memory_attribute->num_objects > 1) + { + i965_log_error(ctx, "i965_surface_external_memory2: Driver does not support more than one object."); + return VA_STATUS_ERROR_INVALID_PARAMETER; + } + + obj_surface->size = memory_attribute->objects[0].size; + obj_surface->bo = drm_intel_bo_gem_create_from_prime(i965->intel.bufmgr, + memory_attribute->objects[0].fd, + obj_surface->size); + + if (!obj_surface->bo) + return VA_STATUS_ERROR_INVALID_PARAMETER; + + dri_bo_get_tiling(obj_surface->bo, &tiling, &swizzle); + + ASSERT_RET(obj_surface->orig_width == memory_attribute->width, VA_STATUS_ERROR_INVALID_PARAMETER); + ASSERT_RET(obj_surface->orig_height == memory_attribute->height, VA_STATUS_ERROR_INVALID_PARAMETER); + + obj_surface->fourcc = memory_attribute->fourcc; + obj_surface->width = memory_attribute->width; + + int bpp_1stplane = bpp_1stplane_by_fourcc(obj_surface->fourcc); + ASSERT_RET(IS_ALIGNED(obj_surface->width, 16), VA_STATUS_ERROR_INVALID_PARAMETER); + ASSERT_RET(obj_surface->width >= obj_surface->orig_width * bpp_1stplane, VA_STATUS_ERROR_INVALID_PARAMETER); + + if (memory_attribute->num_layers == 1) + obj_surface->height = memory_attribute->objects[0].size / obj_surface->width; + else + obj_surface->height = memory_attribute->layers[1].offset[0] / obj_surface->width; + + if (memory_attribute->num_layers > 1) { + ASSERT_RET(obj_surface->height >= obj_surface->orig_height, VA_STATUS_ERROR_INVALID_PARAMETER); + } + + if (tiling) { + ASSERT_RET(IS_ALIGNED(obj_surface->width, 128), VA_STATUS_ERROR_INVALID_PARAMETER); + + if (memory_attribute->num_layers > 1) + ASSERT_RET(IS_ALIGNED(obj_surface->height, 32), VA_STATUS_ERROR_INVALID_PARAMETER); + } else { + ASSERT_RET(IS_ALIGNED(obj_surface->width, i965->codec_info->min_linear_wpitch), VA_STATUS_ERROR_INVALID_PARAMETER); + + if (memory_attribute->num_layers > 1) + ASSERT_RET(IS_ALIGNED(obj_surface->height, i965->codec_info->min_linear_hpitch), VA_STATUS_ERROR_INVALID_PARAMETER); + } + + obj_surface->x_cb_offset = 0; /* X offset is always 0 */ + obj_surface->x_cr_offset = 0; + if ((obj_surface->fourcc == VA_FOURCC_I420 || + obj_surface->fourcc == VA_FOURCC_IYUV || + obj_surface->fourcc == VA_FOURCC_I010 || + obj_surface->fourcc == VA_FOURCC_YV12 || + obj_surface->fourcc == VA_FOURCC_YV16) && tiling) + return VA_STATUS_ERROR_INVALID_PARAMETER; + + switch (obj_surface->fourcc) { + case VA_FOURCC_NV12: + case VA_FOURCC_P010: + ASSERT_RET(memory_attribute->num_layers == 2, VA_STATUS_ERROR_INVALID_PARAMETER); + ASSERT_RET(memory_attribute->layers[0].pitch[0] == memory_attribute->layers[1].pitch[0], VA_STATUS_ERROR_INVALID_PARAMETER); + + obj_surface->subsampling = SUBSAMPLE_YUV420; + obj_surface->y_cb_offset = obj_surface->height; + obj_surface->y_cr_offset = obj_surface->height; + obj_surface->cb_cr_width = ALIGN(obj_surface->orig_width, 2) / 2; + obj_surface->cb_cr_height = ALIGN(obj_surface->orig_height, 2) / 2; + obj_surface->cb_cr_pitch = memory_attribute->layers[1].pitch[0]; + if (tiling) + ASSERT_RET(IS_ALIGNED(obj_surface->cb_cr_pitch, 128), VA_STATUS_ERROR_INVALID_PARAMETER); + else + ASSERT_RET(IS_ALIGNED(obj_surface->cb_cr_pitch, i965->codec_info->min_linear_wpitch), VA_STATUS_ERROR_INVALID_PARAMETER); + + break; + + case VA_FOURCC_YV12: + case VA_FOURCC_IMC1: + ASSERT_RET(memory_attribute->num_layers == 3, VA_STATUS_ERROR_INVALID_PARAMETER); + ASSERT_RET(memory_attribute->layers[1].pitch[0] == memory_attribute->layers[2].pitch[0], VA_STATUS_ERROR_INVALID_PARAMETER); + + obj_surface->subsampling = SUBSAMPLE_YUV420; + obj_surface->y_cr_offset = obj_surface->height; + obj_surface->y_cb_offset = memory_attribute->layers[2].offset[0] / obj_surface->width; + obj_surface->cb_cr_width = ALIGN(obj_surface->orig_width, 2) / 2; + obj_surface->cb_cr_height = ALIGN(obj_surface->orig_height, 2) / 2; + obj_surface->cb_cr_pitch = memory_attribute->layers[1].pitch[0]; + + if (tiling) + ASSERT_RET(IS_ALIGNED(obj_surface->cb_cr_pitch, 128), VA_STATUS_ERROR_INVALID_PARAMETER); + else + ASSERT_RET(IS_ALIGNED(obj_surface->cb_cr_pitch, i965->codec_info->min_linear_wpitch), VA_STATUS_ERROR_INVALID_PARAMETER); + + break; + + case VA_FOURCC_I420: + case VA_FOURCC_IYUV: + case VA_FOURCC_IMC3: + case VA_FOURCC_I010: + ASSERT_RET(memory_attribute->num_layers == 3, VA_STATUS_ERROR_INVALID_PARAMETER); + ASSERT_RET(memory_attribute->layers[1].pitch[0] == memory_attribute->layers[2].pitch[0], VA_STATUS_ERROR_INVALID_PARAMETER); + + obj_surface->subsampling = SUBSAMPLE_YUV420; + obj_surface->y_cb_offset = obj_surface->height; + obj_surface->y_cr_offset = memory_attribute->layers[2].offset[0] / obj_surface->width; + obj_surface->cb_cr_width = ALIGN(obj_surface->orig_width, 2) / 2; + obj_surface->cb_cr_height = ALIGN(obj_surface->orig_height, 2) / 2; + obj_surface->cb_cr_pitch = memory_attribute->layers[1].pitch[0]; + if (tiling) + ASSERT_RET(IS_ALIGNED(obj_surface->cb_cr_pitch, 128), VA_STATUS_ERROR_INVALID_PARAMETER); + else + ASSERT_RET(IS_ALIGNED(obj_surface->cb_cr_pitch, i965->codec_info->min_linear_wpitch), VA_STATUS_ERROR_INVALID_PARAMETER); + + break; + + case VA_FOURCC_YUY2: + case VA_FOURCC_UYVY: + ASSERT_RET(memory_attribute->num_layers == 1, VA_STATUS_ERROR_INVALID_PARAMETER); + + obj_surface->subsampling = SUBSAMPLE_YUV422H; + obj_surface->y_cb_offset = 0; + obj_surface->y_cr_offset = 0; + obj_surface->cb_cr_width = obj_surface->orig_width / 2; + obj_surface->cb_cr_height = obj_surface->orig_height; + obj_surface->cb_cr_pitch = memory_attribute->layers[0].pitch[0]; + + break; + + case VA_FOURCC_RGBA: + case VA_FOURCC_RGBX: + case VA_FOURCC_BGRA: + case VA_FOURCC_BGRX: + case VA_FOURCC_ARGB: + ASSERT_RET(memory_attribute->num_layers == 1, VA_STATUS_ERROR_INVALID_PARAMETER); + + obj_surface->subsampling = SUBSAMPLE_RGBX; + obj_surface->y_cb_offset = 0; + obj_surface->y_cr_offset = 0; + obj_surface->cb_cr_width = 0; + obj_surface->cb_cr_height = 0; + obj_surface->cb_cr_pitch = 0; + + break; + + case VA_FOURCC_Y800: /* monochrome surface */ + ASSERT_RET(memory_attribute->num_layers == 1, VA_STATUS_ERROR_INVALID_PARAMETER); + + obj_surface->subsampling = SUBSAMPLE_YUV400; + obj_surface->y_cb_offset = 0; + obj_surface->y_cr_offset = 0; + obj_surface->cb_cr_width = 0; + obj_surface->cb_cr_height = 0; + obj_surface->cb_cr_pitch = 0; + + break; + + case VA_FOURCC_411P: + ASSERT_RET(memory_attribute->num_layers == 3, VA_STATUS_ERROR_INVALID_PARAMETER); + ASSERT_RET(memory_attribute->layers[1].pitch[0] == memory_attribute->layers[2].pitch[0], VA_STATUS_ERROR_INVALID_PARAMETER); + + obj_surface->subsampling = SUBSAMPLE_YUV411; + obj_surface->y_cb_offset = obj_surface->height; + obj_surface->y_cr_offset = memory_attribute->layers[2].offset[0] / obj_surface->width; + obj_surface->cb_cr_width = obj_surface->orig_width / 4; + obj_surface->cb_cr_height = obj_surface->orig_height; + obj_surface->cb_cr_pitch = memory_attribute->layers[1].pitch[0]; + if (tiling) + ASSERT_RET(IS_ALIGNED(obj_surface->cb_cr_pitch, 128), VA_STATUS_ERROR_INVALID_PARAMETER); + else + ASSERT_RET(IS_ALIGNED(obj_surface->cb_cr_pitch, i965->codec_info->min_linear_wpitch), VA_STATUS_ERROR_INVALID_PARAMETER); + break; + + case VA_FOURCC_422H: + ASSERT_RET(memory_attribute->num_layers == 3, VA_STATUS_ERROR_INVALID_PARAMETER); + ASSERT_RET(memory_attribute->layers[1].pitch[0] == memory_attribute->layers[2].pitch[0], VA_STATUS_ERROR_INVALID_PARAMETER); + + obj_surface->subsampling = SUBSAMPLE_YUV422H; + obj_surface->y_cb_offset = obj_surface->height; + obj_surface->y_cr_offset = memory_attribute->layers[2].offset[0] / obj_surface->width; + obj_surface->cb_cr_width = ALIGN(obj_surface->orig_width, 2) / 2; + obj_surface->cb_cr_height = obj_surface->orig_height; + obj_surface->cb_cr_pitch = memory_attribute->layers[1].pitch[0]; + if (tiling) + ASSERT_RET(IS_ALIGNED(obj_surface->cb_cr_pitch, 128), VA_STATUS_ERROR_INVALID_PARAMETER); + else + ASSERT_RET(IS_ALIGNED(obj_surface->cb_cr_pitch, i965->codec_info->min_linear_wpitch), VA_STATUS_ERROR_INVALID_PARAMETER); + + break; + + case VA_FOURCC_YV16: + ASSERT_RET(memory_attribute->num_layers == 3, VA_STATUS_ERROR_INVALID_PARAMETER); + ASSERT_RET(memory_attribute->layers[1].pitch[0] == memory_attribute->layers[2].pitch[0], VA_STATUS_ERROR_INVALID_PARAMETER); + + obj_surface->subsampling = SUBSAMPLE_YUV422H; + obj_surface->y_cr_offset = memory_attribute->layers[1].offset[0] / obj_surface->width; + obj_surface->y_cb_offset = memory_attribute->layers[2].offset[0] / obj_surface->width; + obj_surface->cb_cr_width = ALIGN(obj_surface->orig_width, 2) / 2; + obj_surface->cb_cr_height = obj_surface->orig_height; + obj_surface->cb_cr_pitch = memory_attribute->layers[1].pitch[0]; + ASSERT_RET(IS_ALIGNED(obj_surface->cb_cr_pitch, i965->codec_info->min_linear_wpitch), VA_STATUS_ERROR_INVALID_PARAMETER); + + break; + + case VA_FOURCC_422V: + ASSERT_RET(memory_attribute->num_layers == 3, VA_STATUS_ERROR_INVALID_PARAMETER); + ASSERT_RET(memory_attribute->layers[1].pitch[0] == memory_attribute->layers[2].pitch[0], VA_STATUS_ERROR_INVALID_PARAMETER); + + obj_surface->subsampling = SUBSAMPLE_YUV422H; + obj_surface->y_cb_offset = obj_surface->height; + obj_surface->y_cr_offset = memory_attribute->layers[2].offset[0] / obj_surface->width; + obj_surface->cb_cr_width = obj_surface->orig_width; + obj_surface->cb_cr_height = ALIGN(obj_surface->orig_height, 2) / 2; + obj_surface->cb_cr_pitch = memory_attribute->layers[1].pitch[0]; + if (tiling) + ASSERT_RET(IS_ALIGNED(obj_surface->cb_cr_pitch, 128), VA_STATUS_ERROR_INVALID_PARAMETER); + else + ASSERT_RET(IS_ALIGNED(obj_surface->cb_cr_pitch, i965->codec_info->min_linear_wpitch), VA_STATUS_ERROR_INVALID_PARAMETER); + + break; + + case VA_FOURCC_444P: + ASSERT_RET(memory_attribute->num_layers == 3, VA_STATUS_ERROR_INVALID_PARAMETER); + ASSERT_RET(memory_attribute->layers[1].pitch[0] == memory_attribute->layers[2].pitch[0], VA_STATUS_ERROR_INVALID_PARAMETER); + + obj_surface->subsampling = SUBSAMPLE_YUV444; + obj_surface->y_cb_offset = obj_surface->height; + obj_surface->y_cr_offset = memory_attribute->layers[2].offset[0] / obj_surface->width; + obj_surface->cb_cr_width = obj_surface->orig_width; + obj_surface->cb_cr_height = obj_surface->orig_height; + obj_surface->cb_cr_pitch = memory_attribute->layers[1].pitch[0]; + if (tiling) + ASSERT_RET(IS_ALIGNED(obj_surface->cb_cr_pitch, 128), VA_STATUS_ERROR_INVALID_PARAMETER); + else + ASSERT_RET(IS_ALIGNED(obj_surface->cb_cr_pitch, i965->codec_info->min_linear_wpitch), VA_STATUS_ERROR_INVALID_PARAMETER); + + break; + + default: + return VA_STATUS_ERROR_INVALID_PARAMETER; + } + + return VA_STATUS_SUCCESS; +} + static VAStatus i965_CreateSurfaces2( VADriverContextP ctx, @@ -2071,6 +2331,7 @@ i965_CreateSurfaces2( int memory_type = I965_SURFACE_MEM_NATIVE; /* native */ int surface_usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC; VASurfaceAttribExternalBuffers *memory_attribute = NULL; + VADRMPRIMESurfaceDescriptor *prime_descriptor = NULL; for (i = 0; i < num_attribs && attrib_list; i++) { if ((attrib_list[i].type == VASurfaceAttribPixelFormat) && @@ -2096,7 +2357,11 @@ i965_CreateSurfaces2( } else if (attrib_list[i].value.value.i == VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME) { - memory_type = I965_SURFACE_MEM_DRM_PRIME; /* drm prime fd */ + memory_type = I965_SURFACE_MEM_DRM_PRIME; /* VASurfaceAttribExternalBuffers (using DRM PRIME fd) */ + } + else if (attrib_list[i].value.value.i == VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2) + { + memory_type = I965_SURFACE_MEM_DRM_PRIME_2; /* VADRMPRIMESurfaceDescriptor (using DRM PRIME fd) */ } else if (attrib_list[i].value.value.i == VA_SURFACE_ATTRIB_MEM_TYPE_VA) { @@ -2108,14 +2373,27 @@ i965_CreateSurfaces2( } else { - i965_log_debug(ctx, "i965_CreateSurfaces2: Unknown VA_SURFACE_TYPE: %i\n", attrib_list[i].value.value.i); + if (attrib_list[i].value.value.i != VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR) + { + i965_log_debug(ctx, "i965_CreateSurfaces2: Unknown VA_SURFACE_TYPE: %i\n", attrib_list[i].value.value.i); + } + + return VA_STATUS_ERROR_INVALID_PARAMETER; } } if ((attrib_list[i].type == VASurfaceAttribExternalBufferDescriptor) && (attrib_list[i].flags == VA_SURFACE_ATTRIB_SETTABLE)) { ASSERT_RET(attrib_list[i].value.type == VAGenericValueTypePointer, VA_STATUS_ERROR_INVALID_PARAMETER); - memory_attribute = (VASurfaceAttribExternalBuffers *)attrib_list[i].value.value.p; + + if (memory_type == I965_SURFACE_MEM_DRM_PRIME_2) + { + prime_descriptor = (VADRMPRIMESurfaceDescriptor *)attrib_list[i].value.value.p; + } + else + { + memory_attribute = (VASurfaceAttribExternalBuffers *)attrib_list[i].value.value.p; + } } } @@ -2247,6 +2525,14 @@ i965_CreateSurfaces2( i); break; + case I965_SURFACE_MEM_DRM_PRIME_2: + vaStatus = i965_surface_external_memory2(ctx, + obj_surface, + memory_type, + prime_descriptor, + i); + break; + default: i965_log_debug(ctx, "i965_CreateSurfaces2: Unknown memory type %d, expect explosion?\n", memory_type); break; @@ -6448,7 +6734,8 @@ i965_QuerySurfaceAttributes(VADriverContextP ctx, attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE; attribs[i].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA | VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM | - VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME; + VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME | + VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2; i++; attribs[i].type = VASurfaceAttribExternalBufferDescriptor; diff --git a/src/i965_drv_video.h b/src/i965_drv_video.h index d675fd06c..c44c76741 100644 --- a/src/i965_drv_video.h +++ b/src/i965_drv_video.h @@ -676,6 +676,7 @@ extern VAStatus i965_CreateSurfaces(VADriverContextP ctx, #define I965_SURFACE_MEM_NATIVE 0 #define I965_SURFACE_MEM_GEM_FLINK 1 #define I965_SURFACE_MEM_DRM_PRIME 2 +#define I965_SURFACE_MEM_DRM_PRIME_2 3 void i965_destroy_surface_storage(struct object_surface *obj_surface);