/*
* Copyright (c) 2011 Intel Corporation. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <malloc.h>
#ifdef ANDROID
#include <linux/ion.h>
#endif
#include <va/va_tpi.h>
#include "psb_drv_video.h"
#include "psb_drv_debug.h"
#include "psb_surface.h"
#include "psb_surface_attrib.h"
#define INIT_DRIVER_DATA psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData;
#define CONFIG(id) ((object_config_p) object_heap_lookup( &driver_data->config_heap, id ))
#define CONTEXT(id) ((object_context_p) object_heap_lookup( &driver_data->context_heap, id ))
#define SURFACE(id) ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id ))
#define BUFFER(id) ((object_buffer_p) object_heap_lookup( &driver_data->buffer_heap, id ))
/*
* Create surface
*/
VAStatus psb_surface_create_from_ub(
psb_driver_data_p driver_data,
int width, int height, int fourcc,
VASurfaceAttributeTPI *graphic_buffers,
psb_surface_p psb_surface, /* out */
void *vaddr,
int fd,
unsigned flags
)
{
int ret = 0;
if ((fourcc == VA_FOURCC_NV12) || (fourcc == VA_FOURCC_YV16) || (fourcc == VA_FOURCC_IYUV) || (fourcc == VA_FOURCC_RGBA)) {
if ((width <= 0) || (width * height > 5120 * 5120) || (height <= 0)) {
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
psb_surface->stride = graphic_buffers->luma_stride;
if (0) {
;
} else if (512 == graphic_buffers->luma_stride) {
psb_surface->stride_mode = STRIDE_512;
} else if (1024 == graphic_buffers->luma_stride) {
psb_surface->stride_mode = STRIDE_1024;
} else if (1280 == graphic_buffers->luma_stride) {
psb_surface->stride_mode = STRIDE_1280;
} else if (2048 == graphic_buffers->luma_stride) {
psb_surface->stride_mode = STRIDE_2048;
} else if (4096 == graphic_buffers->luma_stride) {
psb_surface->stride_mode = STRIDE_4096;
} else {
psb_surface->stride_mode = STRIDE_NA;
}
if (psb_surface->stride != graphic_buffers->luma_stride) {
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
psb_surface->luma_offset = 0;
psb_surface->chroma_offset = psb_surface->stride * height;
if (VA_FOURCC_NV12 == fourcc) {
psb_surface->size = ((psb_surface->stride * height) * 3) / 2;
psb_surface->extra_info[4] = VA_FOURCC_NV12;
}
else if (VA_FOURCC_YV16 == fourcc) {
psb_surface->size = (psb_surface->stride * height) * 2;
psb_surface->extra_info[4] = VA_FOURCC_YV16;
}
else if (VA_FOURCC_IYUV == fourcc) {
psb_surface->size = ((psb_surface->stride * height) * 3) / 2;
psb_surface->extra_info[4] = VA_FOURCC_IYUV;
}
else if (VA_FOURCC_RGBA == fourcc) {
psb_surface->size = (psb_surface->stride * height) * 4;
psb_surface->extra_info[4] = VA_FOURCC_RGBA;
}
psb_surface->extra_info[8] = psb_surface->extra_info[4];
} else {
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
#ifdef PSBVIDEO_MSVDX_DEC_TILING
if (graphic_buffers->tiling)
ret = psb_buffer_create_from_ub(driver_data, psb_surface->size,
psb_bt_mmu_tiling, &psb_surface->buf,
vaddr, fd, 0);
else
#endif
ret = psb_buffer_create_from_ub(driver_data, psb_surface->size,
psb_bt_surface, &psb_surface->buf,
vaddr, fd, flags);
return ret ? VA_STATUS_ERROR_ALLOCATION_FAILED : VA_STATUS_SUCCESS;
}
#if 0
VAStatus psb_CreateSurfaceFromV4L2Buf(
VADriverContextP ctx,
int v4l2_fd, /* file descriptor of V4L2 device */
struct v4l2_format *v4l2_fmt, /* format of V4L2 */
struct v4l2_buffer *v4l2_buf, /* V4L2 buffer */
VASurfaceID *surface /* out */
)
{
INIT_DRIVER_DATA;
VAStatus vaStatus = VA_STATUS_SUCCESS;
int surfaceID;
object_surface_p obj_surface;
psb_surface_p psb_surface;
int width, height, buf_stride, buf_offset, size;
unsigned long *user_ptr = NULL;
if (IS_MRST(driver_data) == 0 && IS_MFLD(driver_data) == 0) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "CreateSurfaceFromV4L2Buf isn't supported on non-MRST platform\n");
return VA_STATUS_ERROR_UNKNOWN;
}
/* Todo:
* sanity check if the v4l2 device on MRST is supported
*/
if (V4L2_MEMORY_USERPTR == v4l2_buf->memory) {
unsigned long tmp = (unsigned long)(v4l2_buf->m.userptr);
if (tmp & 0xfff) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "The buffer address 0x%08x must be page aligned\n", tmp);
return VA_STATUS_ERROR_UNKNOWN;
}
}
surfaceID = object_heap_allocate(&driver_data->surface_heap);
obj_surface = SURFACE(surfaceID);
CHECK_ALLOCATION(obj_surface);
MEMSET_OBJECT(obj_surface, struct object_surface_s);
width = v4l2_fmt->fmt.pix.width;
height = v4l2_fmt->fmt.pix.height;
buf_stride = width; /* ? */
buf_offset = v4l2_buf->m.offset;
size = v4l2_buf->length;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Create Surface from V4L2 buffer: %dx%d, stride=%d, buffer offset=0x%08x, size=%d\n",
width, height, buf_stride, buf_offset, size);
obj_surface->surface_id = surfaceID;
*surface = surfaceID;
obj_surface->context_id = -1;
obj_surface->width = width;
obj_surface->height = height;
obj_surface->subpictures = NULL;
obj_surface->subpic_count = 0;
obj_surface->derived_imgcnt = 0;
obj_surface->display_timestamp = 0;
psb_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
if (NULL == psb_surface) {
object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
obj_surface->surface_id = VA_INVALID_SURFACE;
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
DEBUG_FAILURE;
return vaStatus;
}
#if PSB_MFLD_DUMMY_CODE
/* current assume it is NV12 */
if (IS_MRST(driver_data))
vaStatus = psb_surface_create_camera(driver_data, width, height, buf_stride, size, psb_surface, 1, buf_offset);
else {
if (V4L2_MEMORY_USERPTR == v4l2_buf->memory)
user_ptr = (unsigned long *)(v4l2_buf->m.userptr);
else {
user_ptr = mmap(NULL /* start anywhere */ ,
v4l2_buf->length,
PROT_READ ,
MAP_SHARED /* recommended */ ,
v4l2_fd, v4l2_buf->m.offset);
}
if (NULL != user_ptr && MAP_FAILED != user_ptr)
vaStatus = psb_surface_create_camera_from_ub(driver_data, width, height,
buf_stride, size, psb_surface, 1, buf_offset, user_ptr);
else {
DEBUG_FAILURE;
vaStatus = VA_STATUS_ERROR_UNKNOWN;
}
}
#else
vaStatus = VA_STATUS_ERROR_UNKNOWN;
#endif
if (VA_STATUS_SUCCESS != vaStatus) {
free(psb_surface);
object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
obj_surface->surface_id = VA_INVALID_SURFACE;
DEBUG_FAILURE;
return vaStatus;
}
memset(psb_surface->extra_info, 0, sizeof(psb_surface->extra_info));
psb_surface->extra_info[4] = VA_FOURCC_NV12; /* temp treat is as IYUV */
obj_surface->psb_surface = psb_surface;
/* Error recovery */
if (VA_STATUS_SUCCESS != vaStatus) {
object_surface_p obj_surface = SURFACE(*surface);
psb__destroy_surface(driver_data, obj_surface);
*surface = VA_INVALID_SURFACE;
}
return vaStatus;
}
#endif
VAStatus psb_CreateSurfacesForUserPtr(
VADriverContextP ctx,
int Width,
int Height,
int format,
int num_surfaces,
VASurfaceID *surface_list, /* out */
unsigned size, /* total buffer size need to be allocated */
unsigned int fourcc, /* expected fourcc */
unsigned int luma_stride, /* luma stride, could be width aligned with a special value */
unsigned int chroma_u_stride, /* chroma stride */
unsigned int chroma_v_stride,
unsigned int luma_offset, /* could be 0 */
unsigned int chroma_u_offset, /* UV offset from the beginning of the memory */
unsigned int chroma_v_offset,
unsigned int tiling
)
{
INIT_DRIVER_DATA
VAStatus vaStatus = VA_STATUS_SUCCESS;
int i, height_origin;
unsigned long buffer_stride;
/* silient compiler warning */
unsigned int width = (unsigned int)Width;
unsigned int height = (unsigned int)Height;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Create surface: width %d, height %d, format 0x%08x"
"\n\t\t\t\t\tnum_surface %d, buffer size %d, fourcc 0x%08x"
"\n\t\t\t\t\tluma_stride %d, chroma u stride %d, chroma v stride %d"
"\n\t\t\t\t\tluma_offset %d, chroma u offset %d, chroma v offset %d\n",
width, height, format,
num_surfaces, size, fourcc,
luma_stride, chroma_u_stride, chroma_v_stride,
luma_offset, chroma_u_offset, chroma_v_offset);
CHECK_INVALID_PARAM(num_surfaces <= 0);
CHECK_SURFACE(surface_list);
/* We only support one format */
if ((VA_RT_FORMAT_YUV420 != format) && (VA_RT_FORMAT_RGB32 != format)) {
vaStatus = VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
DEBUG_FAILURE;
return vaStatus;
}
/* We only support NV12 */
if ((VA_RT_FORMAT_YUV420 == format) && (fourcc != VA_FOURCC_NV12)) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "Only support NV12 format\n");
return VA_STATUS_ERROR_UNKNOWN;
}
vaStatus = psb__checkSurfaceDimensions(driver_data, width, height);
CHECK_VASTATUS();
if (VA_RT_FORMAT_YUV420 == format) {
CHECK_INVALID_PARAM((size < width * height * 1.5) ||
(luma_stride < width) ||
(chroma_u_stride * 2 < width) ||
(chroma_v_stride * 2 < width) ||
(chroma_u_offset < luma_offset + width * height) ||
(chroma_v_offset < luma_offset + width * height));
} else if (VA_RT_FORMAT_RGB32 == format) {
CHECK_INVALID_PARAM((size < width * height * 4) ||
(luma_stride < width) ||
(chroma_u_stride * 2 < width) ||
(chroma_v_stride * 2 < width) ||
(chroma_u_offset < luma_offset + width * height) ||
(chroma_v_offset < luma_offset + width * height));
}
height_origin = height;
for (i = 0; i < num_surfaces; i++) {
int surfaceID;
object_surface_p obj_surface;
psb_surface_p psb_surface;
surfaceID = object_heap_allocate(&driver_data->surface_heap);
obj_surface = SURFACE(surfaceID);
if (NULL == obj_surface) {
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
DEBUG_FAILURE;
break;
}
MEMSET_OBJECT(obj_surface, struct object_surface_s);
obj_surface->surface_id = surfaceID;
surface_list[i] = surfaceID;
obj_surface->context_id = -1;
obj_surface->width = width;
obj_surface->height = height;
obj_surface->width_r = width;
obj_surface->height_r = height;
obj_surface->height_origin = height_origin;
obj_surface->is_ref_surface = 0;
psb_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
if (NULL == psb_surface) {
object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
obj_surface->surface_id = VA_INVALID_SURFACE;
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
DEBUG_FAILURE;
break;
}
vaStatus = psb_surface_create_for_userptr(driver_data, width, height,
size,
fourcc,
luma_stride,
chroma_u_stride,
chroma_v_stride,
luma_offset,
chroma_u_offset,
chroma_v_offset,
psb_surface
);
if (VA_STATUS_SUCCESS != vaStatus) {
free(psb_surface);
object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
obj_surface->surface_id = VA_INVALID_SURFACE;
DEBUG_FAILURE;
break;
}
buffer_stride = psb_surface->stride;
/* by default, surface fourcc is NV12 */
memset(psb_surface->extra_info, 0, sizeof(psb_surface->extra_info));
psb_surface->extra_info[4] = fourcc;
psb_surface->extra_info[8] = fourcc;
#ifdef PSBVIDEO_MSVDX_DEC_TILING
psb_surface->extra_info[7] = tiling;
#endif
obj_surface->psb_surface = psb_surface;
}
/* Error recovery */
if (VA_STATUS_SUCCESS != vaStatus) {
/* surface_list[i-1] was the last successful allocation */
for (; i--;) {
object_surface_p obj_surface = SURFACE(surface_list[i]);
psb__destroy_surface(driver_data, obj_surface);
surface_list[i] = VA_INVALID_SURFACE;
}
}
return vaStatus;
}
VAStatus psb_CreateSurfaceFromKBuf(
VADriverContextP ctx,
int _width,
int _height,
int format,
VASurfaceID *surface, /* out */
unsigned int kbuf_handle, /* kernel buffer handle*/
unsigned size, /* kernel buffer size */
unsigned int kBuf_fourcc, /* expected fourcc */
unsigned int luma_stride, /* luma stride, could be width aligned with a special value */
unsigned int chroma_u_stride, /* chroma stride */
unsigned int chroma_v_stride,
unsigned int luma_offset, /* could be 0 */
unsigned int chroma_u_offset, /* UV offset from the beginning of the memory */
unsigned int chroma_v_offset,
unsigned int tiling
)
{
INIT_DRIVER_DATA
VAStatus vaStatus = VA_STATUS_SUCCESS;
unsigned long buffer_stride;
/* silient compiler warning */
unsigned int width = (unsigned int)_width;
unsigned int height = (unsigned int)_height;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Create surface: width %d, height %d, format 0x%08x"
"\n\t\t\t\t\tnum_surface %d, buffer size %d, fourcc 0x%08x"
"\n\t\t\t\t\tluma_stride %d, chroma u stride %d, chroma v stride %d"
"\n\t\t\t\t\tluma_offset %d, chroma u offset %d, chroma v offset %d\n",
width, height, format,
size, kBuf_fourcc,
luma_stride, chroma_u_stride, chroma_v_stride,
luma_offset, chroma_u_offset, chroma_v_offset);
CHECK_SURFACE(surface);
/* We only support one format */
if (VA_RT_FORMAT_YUV420 != format) {
vaStatus = VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
DEBUG_FAILURE;
return vaStatus;
}
/* We only support NV12/YV12 */
if ((VA_RT_FORMAT_YUV420 == format) && (kBuf_fourcc != VA_FOURCC_NV12)) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "Only support NV12 format\n");
return VA_STATUS_ERROR_UNKNOWN;
}
/*
vaStatus = psb__checkSurfaceDimensions(driver_data, width, height);
CHECK_VASTATUS();
*/
CHECK_INVALID_PARAM((size < width * height * 1.5) ||
(luma_stride < width) ||
(chroma_u_stride * 2 < width) ||
(chroma_v_stride * 2 < width) ||
(chroma_u_offset < luma_offset + width * height) ||
(chroma_v_offset < luma_offset + width * height));
int surfaceID;
object_surface_p obj_surface;
psb_surface_p psb_surface;
surfaceID = object_heap_allocate(&driver_data->surface_heap);
obj_surface = SURFACE(surfaceID);
CHECK_ALLOCATION(obj_surface);
MEMSET_OBJECT(obj_surface, struct object_surface_s);
obj_surface->surface_id = surfaceID;
*surface = surfaceID;
obj_surface->context_id = -1;
obj_surface->width = width;
obj_surface->height = height;
obj_surface->width_r = width;
obj_surface->height_r = height;
obj_surface->height_origin = height;
obj_surface->is_ref_surface = 0;
psb_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
if (NULL == psb_surface) {
object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
obj_surface->surface_id = VA_INVALID_SURFACE;
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
DEBUG_FAILURE;
return vaStatus;
}
vaStatus = psb_surface_create_from_kbuf(driver_data, width, height,
size,
kBuf_fourcc,
kbuf_handle,
luma_stride,
chroma_u_stride,
chroma_v_stride,
luma_offset,
chroma_u_offset,
chroma_v_offset,
psb_surface);
if (VA_STATUS_SUCCESS != vaStatus) {
free(psb_surface);
object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
obj_surface->surface_id = VA_INVALID_SURFACE;
DEBUG_FAILURE;
return vaStatus;
}
buffer_stride = psb_surface->stride;
/* by default, surface fourcc is NV12 */
memset(psb_surface->extra_info, 0, sizeof(psb_surface->extra_info));
psb_surface->extra_info[4] = kBuf_fourcc;
psb_surface->extra_info[8] = kBuf_fourcc;
#ifdef PSBVIDEO_MSVDX_DEC_TILING
psb_surface->extra_info[7] = tiling;
#endif
obj_surface->psb_surface = psb_surface;
/* Error recovery */
if (VA_STATUS_SUCCESS != vaStatus) {
object_surface_p obj_surface = SURFACE(surfaceID);
psb__destroy_surface(driver_data, obj_surface);
*surface = VA_INVALID_SURFACE;
}
return vaStatus;
}
VAStatus psb_CreateSurfaceFromUserspace(
VADriverContextP ctx,
int width,
int height,
int format,
int num_surfaces,
VASurfaceID *surface_list, /* out */
VASurfaceAttributeTPI *attribute_tpi
)
{
INIT_DRIVER_DATA;
VAStatus vaStatus = VA_STATUS_SUCCESS;
#ifdef ANDROID
unsigned int *vaddr;
unsigned long fourcc;
int surfaceID;
object_surface_p obj_surface;
psb_surface_p psb_surface;
int i;
switch (format) {
case VA_RT_FORMAT_YUV422:
fourcc = VA_FOURCC_YV16;
break;
case VA_RT_FORMAT_YUV420:
default:
fourcc = VA_FOURCC_NV12;
break;
}
for (i=0; i < num_surfaces; i++) {
vaddr = (unsigned int *)(attribute_tpi->buffers[i]);
surfaceID = object_heap_allocate(&driver_data->surface_heap);
obj_surface = SURFACE(surfaceID);
if (NULL == obj_surface) {
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
DEBUG_FAILURE;
break;
}
MEMSET_OBJECT(obj_surface, struct object_surface_s);
obj_surface->surface_id = surfaceID;
surface_list[i] = surfaceID;
obj_surface->context_id = -1;
obj_surface->width = attribute_tpi->width;
obj_surface->height = attribute_tpi->height;
obj_surface->width_r = attribute_tpi->width;
obj_surface->height_r = attribute_tpi->height;
obj_surface->is_ref_surface = 0;
psb_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
if (NULL == psb_surface) {
object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
obj_surface->surface_id = VA_INVALID_SURFACE;
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
DEBUG_FAILURE;
break;
}
if (attribute_tpi->type == VAExternalMemoryNoneCacheUserPointer)
vaStatus = psb_surface_create_from_ub(driver_data, width, height, fourcc,
attribute_tpi, psb_surface, vaddr, -1, PSB_USER_BUFFER_UNCACHED);
else {
vaStatus = psb_surface_create_from_ub(driver_data, width, height, fourcc,
attribute_tpi, psb_surface, vaddr, -1, 0);
psb_surface->buf.unfence_flag = 2;
}
obj_surface->psb_surface = psb_surface;
if (VA_STATUS_SUCCESS != vaStatus) {
free(psb_surface);
object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
obj_surface->surface_id = VA_INVALID_SURFACE;
DEBUG_FAILURE;
break;
}
/* by default, surface fourcc is NV12 */
memset(psb_surface->extra_info, 0, sizeof(psb_surface->extra_info));
psb_surface->extra_info[4] = fourcc;
psb_surface->extra_info[8] = fourcc;
obj_surface->psb_surface = psb_surface;
/* Error recovery */
if (VA_STATUS_SUCCESS != vaStatus) {
object_surface_p obj_surface = SURFACE(surfaceID);
psb__destroy_surface(driver_data, obj_surface);
}
}
#endif
return vaStatus;
}
VAStatus psb_CreateSurfaceFromION(
VADriverContextP ctx,
int width,
int height,
int format,
int num_surfaces,
VASurfaceID *surface_list, /* out */
VASurfaceAttributeTPI *attribute_tpi
)
{
INIT_DRIVER_DATA;
VAStatus vaStatus = VA_STATUS_SUCCESS;
#ifdef ANDROID
unsigned int *vaddr = NULL;
unsigned long fourcc;
int surfaceID;
object_surface_p obj_surface;
psb_surface_p psb_surface;
int i;
unsigned int source_size = 0;
int ion_fd = 0;
int ion_ret = 0;
struct ion_fd_data ion_source_share;
switch (format) {
case VA_RT_FORMAT_YUV422:
fourcc = VA_FOURCC_YV16;
break;
case VA_RT_FORMAT_YUV420:
default:
fourcc = VA_FOURCC_NV12;
break;
}
ion_fd = open("/dev/ion", O_RDWR);
if (ion_fd < 0) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Fail to open the ion device!\n", __FUNCTION__);
return VA_STATUS_ERROR_UNKNOWN;
}
for (i=0; i < num_surfaces; i++) {
ion_source_share.handle = 0;
ion_source_share.fd = (int)(attribute_tpi->buffers[i]);
ion_ret = ioctl(ion_fd, ION_IOC_IMPORT, &ion_source_share);
if ((ion_ret < 0) || (0 == ion_source_share.handle)) {
close(ion_fd);
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Fail to import the ion fd!\n", __FUNCTION__);
return VA_STATUS_ERROR_UNKNOWN;
}
if (VA_FOURCC_NV12 == fourcc)
source_size = attribute_tpi->width * attribute_tpi->height * 1.5;
else
source_size = attribute_tpi->width * attribute_tpi->height * 2;
vaddr = mmap(NULL, source_size, PROT_READ|PROT_WRITE, MAP_SHARED, ion_source_share.fd, 0);
if (MAP_FAILED == vaddr) {
close(ion_fd);
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Fail to mmap the ion buffer!\n", __FUNCTION__);
return VA_STATUS_ERROR_UNKNOWN;
}
surfaceID = object_heap_allocate(&driver_data->surface_heap);
obj_surface = SURFACE(surfaceID);
if (NULL == obj_surface) {
close(ion_fd);
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
DEBUG_FAILURE;
break;
}
MEMSET_OBJECT(obj_surface, struct object_surface_s);
obj_surface->surface_id = surfaceID;
surface_list[i] = surfaceID;
obj_surface->context_id = -1;
obj_surface->width = attribute_tpi->width;
obj_surface->height = attribute_tpi->height;
obj_surface->width_r = attribute_tpi->width;
obj_surface->height_r = attribute_tpi->height;
obj_surface->is_ref_surface = 0;
psb_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
if (NULL == psb_surface) {
object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
obj_surface->surface_id = VA_INVALID_SURFACE;
close(ion_fd);
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
DEBUG_FAILURE;
break;
}
vaStatus = psb_surface_create_from_ub(driver_data, width, height, fourcc,
attribute_tpi, psb_surface, vaddr, ion_source_share.fd, 0);
obj_surface->psb_surface = psb_surface;
if (VA_STATUS_SUCCESS != vaStatus) {
free(psb_surface);
object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
obj_surface->surface_id = VA_INVALID_SURFACE;
close(ion_fd);
DEBUG_FAILURE;
break;
}
/* by default, surface fourcc is NV12 */
memset(psb_surface->extra_info, 0, sizeof(psb_surface->extra_info));
psb_surface->extra_info[4] = fourcc;
psb_surface->extra_info[8] = fourcc;
obj_surface->psb_surface = psb_surface;
/* Error recovery */
if (VA_STATUS_SUCCESS != vaStatus) {
object_surface_p obj_surface = SURFACE(surfaceID);
psb__destroy_surface(driver_data, obj_surface);
close(ion_fd);
}
vaddr = NULL;
}
close(ion_fd);
#endif
return vaStatus;
}
VAStatus psb_CreateSurfacesWithAttribute(
VADriverContextP ctx,
int width,
int height,
int format,
int num_surfaces,
VASurfaceID *surface_list, /* out */
VASurfaceAttributeTPI *attribute_tpi
)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
int i;
int tiling;
CHECK_INVALID_PARAM(attribute_tpi == NULL);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Create %d surface(%dx%d) with type %d, tiling is %d\n",
num_surfaces, width, height, attribute_tpi->type, attribute_tpi->tiling);
tiling = attribute_tpi->tiling;
switch (attribute_tpi->type) {
case VAExternalMemoryNULL:
vaStatus = psb_CreateSurfacesForUserPtr(ctx, width, height, format, num_surfaces, surface_list,
attribute_tpi->size, attribute_tpi->pixel_format,
attribute_tpi->luma_stride, attribute_tpi->chroma_u_stride,
attribute_tpi->chroma_v_stride, attribute_tpi->luma_offset,
attribute_tpi->chroma_u_offset, attribute_tpi->chroma_v_offset,
attribute_tpi->tiling);
return vaStatus;
#ifdef ANDROID
case VAExternalMemoryNoneCacheUserPointer:
#endif
case VAExternalMemoryUserPointer:
vaStatus = psb_CreateSurfaceFromUserspace(ctx, width, height,
format, num_surfaces, surface_list,
attribute_tpi);
return vaStatus;
case VAExternalMemoryKernelDRMBufffer:
for (i=0; i < num_surfaces; i++) {
vaStatus = psb_CreateSurfaceFromKBuf(
ctx, width, height, format, &surface_list[i],
attribute_tpi->buffers[i],
attribute_tpi->size, attribute_tpi->pixel_format,
attribute_tpi->luma_stride, attribute_tpi->chroma_u_stride,
attribute_tpi->chroma_v_stride, attribute_tpi->luma_offset,
attribute_tpi->chroma_u_offset, attribute_tpi->chroma_v_offset, tiling);
CHECK_VASTATUS();
}
return vaStatus;
case VAExternalMemoryAndroidGrallocBuffer:
vaStatus = psb_CreateSurfacesFromGralloc(ctx, width, height,
format, num_surfaces, surface_list,
(PsbSurfaceAttributeTPI *)attribute_tpi);
return vaStatus;
#ifdef ANDROID
case VAExternalMemoryIONSharedFD:
vaStatus = psb_CreateSurfaceFromION(ctx, width, height,
format, num_surfaces, surface_list,
attribute_tpi);
return vaStatus;
#endif
default:
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
return VA_STATUS_ERROR_INVALID_PARAMETER;
}