1/*
2 * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sub license, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
19 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
20 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 */
25
26#include <sys/mman.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/ioctl.h>
30#include <fcntl.h>
31#ifdef ANDROID
32#include <linux/ion.h>
33#endif
34#include <va/va_tpi.h>
35#include "psb_drv_video.h"
36#include "psb_drv_debug.h"
37#include "psb_surface.h"
38#include "psb_surface_attrib.h"
39
40
41#define INIT_DRIVER_DATA    psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData;
42
43#define CONFIG(id)  ((object_config_p) object_heap_lookup( &driver_data->config_heap, id ))
44#define CONTEXT(id) ((object_context_p) object_heap_lookup( &driver_data->context_heap, id ))
45#define SURFACE(id)    ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id ))
46#define BUFFER(id)  ((object_buffer_p) object_heap_lookup( &driver_data->buffer_heap, id ))
47
48
49/*
50 * Create surface
51 */
52VAStatus psb_surface_create_from_ub(
53    psb_driver_data_p driver_data,
54    int width, int height, int fourcc,
55    VASurfaceAttributeTPI *graphic_buffers,
56    psb_surface_p psb_surface, /* out */
57    void *vaddr,
58    unsigned flags
59)
60{
61    int ret = 0;
62
63    if ((fourcc == VA_FOURCC_NV12) || (fourcc == VA_FOURCC_YV16) || (fourcc == VA_FOURCC_IYUV) || (fourcc == VA_FOURCC_RGBA)) {
64        if ((width <= 0) || (width * height > 5120 * 5120) || (height <= 0)) {
65            return VA_STATUS_ERROR_ALLOCATION_FAILED;
66        }
67
68        psb_surface->stride = graphic_buffers->luma_stride;
69        if (0) {
70            ;
71        } else if (512 == graphic_buffers->luma_stride) {
72            psb_surface->stride_mode = STRIDE_512;
73        } else if (1024 == graphic_buffers->luma_stride) {
74            psb_surface->stride_mode = STRIDE_1024;
75        } else if (1280 == graphic_buffers->luma_stride) {
76            psb_surface->stride_mode = STRIDE_1280;
77#ifdef PSBVIDEO_MSVDX_DEC_TILING
78            if (graphic_buffers->tiling) {
79                psb_surface->stride_mode = STRIDE_2048;
80                psb_surface->stride = 2048;
81            }
82#endif
83        } else if (2048 == graphic_buffers->luma_stride) {
84            psb_surface->stride_mode = STRIDE_2048;
85        } else if (4096 == graphic_buffers->luma_stride) {
86            psb_surface->stride_mode = STRIDE_4096;
87        } else {
88            psb_surface->stride_mode = STRIDE_NA;
89        }
90        if (psb_surface->stride != graphic_buffers->luma_stride) {
91            return VA_STATUS_ERROR_ALLOCATION_FAILED;
92        }
93
94        psb_surface->luma_offset = 0;
95        psb_surface->chroma_offset = psb_surface->stride * height;
96
97        if (VA_FOURCC_NV12 == fourcc) {
98            psb_surface->size = ((psb_surface->stride * height) * 3) / 2;
99            psb_surface->extra_info[4] = VA_FOURCC_NV12;
100        }
101        else if (VA_FOURCC_YV16 == fourcc) {
102            psb_surface->size = (psb_surface->stride * height) * 2;
103            psb_surface->extra_info[4] = VA_FOURCC_YV16;
104        }
105        else if (VA_FOURCC_IYUV == fourcc) {
106            psb_surface->size = ((psb_surface->stride * height) * 3) / 2;
107            psb_surface->extra_info[4] = VA_FOURCC_IYUV;
108        }
109	else if (VA_FOURCC_RGBA == fourcc) {
110            psb_surface->size = (psb_surface->stride * height) * 4;
111            psb_surface->extra_info[4] = VA_FOURCC_RGBA;
112        }
113
114        psb_surface->extra_info[8] = psb_surface->extra_info[4];
115
116    } else {
117        return VA_STATUS_ERROR_ALLOCATION_FAILED;
118    }
119#ifdef PSBVIDEO_MSVDX_DEC_TILING
120    if (graphic_buffers->tiling)
121        ret = psb_buffer_create_from_ub(driver_data, psb_surface->size,
122                psb_bt_mmu_tiling, &psb_surface->buf,
123                vaddr, 0);
124    else
125#endif
126        ret = psb_buffer_create_from_ub(driver_data, psb_surface->size,
127                psb_bt_surface, &psb_surface->buf,
128                vaddr, flags);
129
130    return ret ? VA_STATUS_ERROR_ALLOCATION_FAILED : VA_STATUS_SUCCESS;
131}
132
133#if 0
134VAStatus psb_CreateSurfaceFromV4L2Buf(
135    VADriverContextP ctx,
136    int v4l2_fd,         /* file descriptor of V4L2 device */
137    struct v4l2_format *v4l2_fmt,       /* format of V4L2 */
138    struct v4l2_buffer *v4l2_buf,       /* V4L2 buffer */
139    VASurfaceID *surface        /* out */
140)
141{
142    INIT_DRIVER_DATA;
143    VAStatus vaStatus = VA_STATUS_SUCCESS;
144    int surfaceID;
145    object_surface_p obj_surface;
146    psb_surface_p psb_surface;
147    int width, height, buf_stride, buf_offset, size;
148    unsigned long *user_ptr = NULL;
149
150    if (IS_MRST(driver_data) == 0 && IS_MFLD(driver_data) == 0) {
151        drv_debug_msg(VIDEO_DEBUG_ERROR, "CreateSurfaceFromV4L2Buf isn't supported on non-MRST platform\n");
152        return VA_STATUS_ERROR_UNKNOWN;
153    }
154
155    /* Todo:
156     * sanity check if the v4l2 device on MRST is supported
157     */
158    if (V4L2_MEMORY_USERPTR == v4l2_buf->memory) {
159        unsigned long tmp = (unsigned long)(v4l2_buf->m.userptr);
160
161        if (tmp & 0xfff) {
162            drv_debug_msg(VIDEO_DEBUG_ERROR, "The buffer address 0x%08x must be page aligned\n", tmp);
163            return VA_STATUS_ERROR_UNKNOWN;
164        }
165    }
166
167    surfaceID = object_heap_allocate(&driver_data->surface_heap);
168    obj_surface = SURFACE(surfaceID);
169    CHECK_ALLOCATION(obj_surface);
170
171    MEMSET_OBJECT(obj_surface, struct object_surface_s);
172
173    width = v4l2_fmt->fmt.pix.width;
174    height = v4l2_fmt->fmt.pix.height;
175
176    buf_stride = width; /* ? */
177    buf_offset = v4l2_buf->m.offset;
178    size = v4l2_buf->length;
179
180    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Create Surface from V4L2 buffer: %dx%d, stride=%d, buffer offset=0x%08x, size=%d\n",
181                             width, height, buf_stride, buf_offset, size);
182
183    obj_surface->surface_id = surfaceID;
184    *surface = surfaceID;
185    obj_surface->context_id = -1;
186    obj_surface->width = width;
187    obj_surface->height = height;
188    obj_surface->subpictures = NULL;
189    obj_surface->subpic_count = 0;
190    obj_surface->derived_imgcnt = 0;
191    obj_surface->display_timestamp = 0;
192
193    psb_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
194    if (NULL == psb_surface) {
195        object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
196        obj_surface->surface_id = VA_INVALID_SURFACE;
197
198        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
199
200        DEBUG_FAILURE;
201
202        return vaStatus;
203    }
204
205#if PSB_MFLD_DUMMY_CODE
206    /* current assume it is NV12 */
207    if (IS_MRST(driver_data))
208        vaStatus = psb_surface_create_camera(driver_data, width, height, buf_stride, size, psb_surface, 1, buf_offset);
209    else {
210        if (V4L2_MEMORY_USERPTR == v4l2_buf->memory)
211            user_ptr = (unsigned long *)(v4l2_buf->m.userptr);
212        else {
213            user_ptr = mmap(NULL /* start anywhere */ ,
214                            v4l2_buf->length,
215                            PROT_READ ,
216                            MAP_SHARED /* recommended */ ,
217                            v4l2_fd, v4l2_buf->m.offset);
218        }
219
220        if (NULL != user_ptr && MAP_FAILED != user_ptr)
221            vaStatus = psb_surface_create_camera_from_ub(driver_data, width, height,
222                       buf_stride, size, psb_surface, 1, buf_offset, user_ptr);
223        else {
224            DEBUG_FAILURE;
225            vaStatus = VA_STATUS_ERROR_UNKNOWN;
226        }
227    }
228#else
229        vaStatus = VA_STATUS_ERROR_UNKNOWN;
230#endif
231
232
233    if (VA_STATUS_SUCCESS != vaStatus) {
234        free(psb_surface);
235        object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
236        obj_surface->surface_id = VA_INVALID_SURFACE;
237
238        DEBUG_FAILURE;
239
240        return vaStatus;
241    }
242
243    memset(psb_surface->extra_info, 0, sizeof(psb_surface->extra_info));
244    psb_surface->extra_info[4] = VA_FOURCC_NV12; /* temp treat is as IYUV */
245
246    obj_surface->psb_surface = psb_surface;
247
248    /* Error recovery */
249    if (VA_STATUS_SUCCESS != vaStatus) {
250        object_surface_p obj_surface = SURFACE(*surface);
251        psb__destroy_surface(driver_data, obj_surface);
252        *surface = VA_INVALID_SURFACE;
253    }
254
255    return vaStatus;
256}
257#endif
258
259
260VAStatus psb_CreateSurfacesForUserPtr(
261    VADriverContextP ctx,
262    int Width,
263    int Height,
264    int format,
265    int num_surfaces,
266    VASurfaceID *surface_list,       /* out */
267    unsigned size, /* total buffer size need to be allocated */
268    unsigned int fourcc, /* expected fourcc */
269    unsigned int luma_stride, /* luma stride, could be width aligned with a special value */
270    unsigned int chroma_u_stride, /* chroma stride */
271    unsigned int chroma_v_stride,
272    unsigned int luma_offset, /* could be 0 */
273    unsigned int chroma_u_offset, /* UV offset from the beginning of the memory */
274    unsigned int chroma_v_offset,
275    unsigned int tiling
276)
277{
278    INIT_DRIVER_DATA
279    VAStatus vaStatus = VA_STATUS_SUCCESS;
280    int i, height_origin;
281    unsigned long buffer_stride;
282
283    /* silient compiler warning */
284    unsigned int width = (unsigned int)Width;
285    unsigned int height = (unsigned int)Height;
286
287    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Create surface: width %d, height %d, format 0x%08x"
288                             "\n\t\t\t\t\tnum_surface %d, buffer size %d, fourcc 0x%08x"
289                             "\n\t\t\t\t\tluma_stride %d, chroma u stride %d, chroma v stride %d"
290                             "\n\t\t\t\t\tluma_offset %d, chroma u offset %d, chroma v offset %d\n",
291                             width, height, format,
292                             num_surfaces, size, fourcc,
293                             luma_stride, chroma_u_stride, chroma_v_stride,
294                             luma_offset, chroma_u_offset, chroma_v_offset);
295
296    CHECK_INVALID_PARAM(num_surfaces <= 0);
297    CHECK_SURFACE(surface_list);
298
299    /* We only support one format */
300    if ((VA_RT_FORMAT_YUV420 != format) && (VA_RT_FORMAT_RGB32 != format)) {
301        vaStatus = VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
302        DEBUG_FAILURE;
303        return vaStatus;
304    }
305
306    /* We only support NV12 */
307    if ((VA_RT_FORMAT_YUV420 == format) && (fourcc != VA_FOURCC_NV12)) {
308        drv_debug_msg(VIDEO_DEBUG_ERROR, "Only support NV12 format\n");
309        return VA_STATUS_ERROR_UNKNOWN;
310    }
311
312    vaStatus = psb__checkSurfaceDimensions(driver_data, width, height);
313    CHECK_VASTATUS();
314
315    if (VA_RT_FORMAT_YUV420 == format) {
316    CHECK_INVALID_PARAM((size < width * height * 1.5) ||
317        (luma_stride < width) ||
318        (chroma_u_stride * 2 < width) ||
319        (chroma_v_stride * 2 < width) ||
320        (chroma_u_offset < luma_offset + width * height) ||
321        (chroma_v_offset < luma_offset + width * height));
322    } else if (VA_RT_FORMAT_RGB32 == format) {
323    CHECK_INVALID_PARAM((size < width * height * 4) ||
324        (luma_stride < width) ||
325        (chroma_u_stride * 2 < width) ||
326        (chroma_v_stride * 2 < width) ||
327        (chroma_u_offset < luma_offset + width * height) ||
328        (chroma_v_offset < luma_offset + width * height));
329    }
330
331    height_origin = height;
332
333    for (i = 0; i < num_surfaces; i++) {
334        int surfaceID;
335        object_surface_p obj_surface;
336        psb_surface_p psb_surface;
337
338        surfaceID = object_heap_allocate(&driver_data->surface_heap);
339        obj_surface = SURFACE(surfaceID);
340        if (NULL == obj_surface) {
341            vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
342            DEBUG_FAILURE;
343            break;
344        }
345        MEMSET_OBJECT(obj_surface, struct object_surface_s);
346
347        obj_surface->surface_id = surfaceID;
348        surface_list[i] = surfaceID;
349        obj_surface->context_id = -1;
350        obj_surface->width = width;
351        obj_surface->height = height;
352        obj_surface->width_r = width;
353        obj_surface->height_r = height;
354        obj_surface->height_origin = height_origin;
355	obj_surface->is_ref_surface = 0;
356
357        psb_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
358        if (NULL == psb_surface) {
359            object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
360            obj_surface->surface_id = VA_INVALID_SURFACE;
361
362            vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
363
364            DEBUG_FAILURE;
365            break;
366        }
367
368
369        vaStatus = psb_surface_create_for_userptr(driver_data, width, height,
370                   size,
371                   fourcc,
372                   luma_stride,
373                   chroma_u_stride,
374                   chroma_v_stride,
375                   luma_offset,
376                   chroma_u_offset,
377                   chroma_v_offset,
378                   psb_surface
379                                                 );
380
381        if (VA_STATUS_SUCCESS != vaStatus) {
382            free(psb_surface);
383            object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
384            obj_surface->surface_id = VA_INVALID_SURFACE;
385
386            DEBUG_FAILURE;
387            break;
388        }
389        buffer_stride = psb_surface->stride;
390        /* by default, surface fourcc is NV12 */
391        memset(psb_surface->extra_info, 0, sizeof(psb_surface->extra_info));
392        psb_surface->extra_info[4] = fourcc;
393        psb_surface->extra_info[8] = fourcc;
394#ifdef PSBVIDEO_MSVDX_DEC_TILING
395	psb_surface->extra_info[7] = tiling;
396#endif
397        obj_surface->psb_surface = psb_surface;
398    }
399
400    /* Error recovery */
401    if (VA_STATUS_SUCCESS != vaStatus) {
402        /* surface_list[i-1] was the last successful allocation */
403        for (; i--;) {
404            object_surface_p obj_surface = SURFACE(surface_list[i]);
405            psb__destroy_surface(driver_data, obj_surface);
406            surface_list[i] = VA_INVALID_SURFACE;
407        }
408    }
409
410
411    return vaStatus;
412}
413
414VAStatus  psb_CreateSurfaceFromKBuf(
415    VADriverContextP ctx,
416    int _width,
417    int _height,
418    int format,
419    VASurfaceID *surface,       /* out */
420    unsigned int kbuf_handle, /* kernel buffer handle*/
421    unsigned size, /* kernel buffer size */
422    unsigned int kBuf_fourcc, /* expected fourcc */
423    unsigned int luma_stride, /* luma stride, could be width aligned with a special value */
424    unsigned int chroma_u_stride, /* chroma stride */
425    unsigned int chroma_v_stride,
426    unsigned int luma_offset, /* could be 0 */
427    unsigned int chroma_u_offset, /* UV offset from the beginning of the memory */
428    unsigned int chroma_v_offset,
429    unsigned int tiling
430)
431{
432    INIT_DRIVER_DATA
433    VAStatus vaStatus = VA_STATUS_SUCCESS;
434    unsigned long buffer_stride;
435
436    /* silient compiler warning */
437    unsigned int width = (unsigned int)_width;
438    unsigned int height = (unsigned int)_height;
439
440    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Create surface: width %d, height %d, format 0x%08x"
441                             "\n\t\t\t\t\tnum_surface %d, buffer size %d, fourcc 0x%08x"
442                             "\n\t\t\t\t\tluma_stride %d, chroma u stride %d, chroma v stride %d"
443                             "\n\t\t\t\t\tluma_offset %d, chroma u offset %d, chroma v offset %d\n",
444                             width, height, format,
445                             size, kBuf_fourcc,
446                             luma_stride, chroma_u_stride, chroma_v_stride,
447                             luma_offset, chroma_u_offset, chroma_v_offset);
448
449    CHECK_SURFACE(surface);
450
451    /* We only support one format */
452    if (VA_RT_FORMAT_YUV420 != format) {
453        vaStatus = VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
454        DEBUG_FAILURE;
455        return vaStatus;
456    }
457
458    /* We only support NV12/YV12 */
459
460    if ((VA_RT_FORMAT_YUV420 == format) && (kBuf_fourcc != VA_FOURCC_NV12)) {
461        drv_debug_msg(VIDEO_DEBUG_ERROR, "Only support NV12 format\n");
462        return VA_STATUS_ERROR_UNKNOWN;
463    }
464    /*
465    vaStatus = psb__checkSurfaceDimensions(driver_data, width, height);
466    CHECK_VASTATUS();
467    */
468
469    CHECK_INVALID_PARAM((size < width * height * 1.5) ||
470        (luma_stride < width) ||
471        (chroma_u_stride * 2 < width) ||
472        (chroma_v_stride * 2 < width) ||
473        (chroma_u_offset < luma_offset + width * height) ||
474        (chroma_v_offset < luma_offset + width * height));
475
476    int surfaceID;
477    object_surface_p obj_surface;
478    psb_surface_p psb_surface;
479
480    surfaceID = object_heap_allocate(&driver_data->surface_heap);
481    obj_surface = SURFACE(surfaceID);
482    CHECK_ALLOCATION(obj_surface);
483
484    MEMSET_OBJECT(obj_surface, struct object_surface_s);
485
486    obj_surface->surface_id = surfaceID;
487    *surface = surfaceID;
488    obj_surface->context_id = -1;
489    obj_surface->width = width;
490    obj_surface->height = height;
491    obj_surface->width_r = width;
492    obj_surface->height_r = height;
493    obj_surface->height_origin = height;
494    obj_surface->is_ref_surface = 0;
495
496    psb_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
497    if (NULL == psb_surface) {
498        object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
499        obj_surface->surface_id = VA_INVALID_SURFACE;
500
501        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
502
503        DEBUG_FAILURE;
504        return vaStatus;
505    }
506
507    vaStatus = psb_surface_create_from_kbuf(driver_data, width, height,
508                                            size,
509                                            kBuf_fourcc,
510                                            kbuf_handle,
511                                            luma_stride,
512                                            chroma_u_stride,
513                                            chroma_v_stride,
514                                            luma_offset,
515                                            chroma_u_offset,
516                                            chroma_v_offset,
517                                            psb_surface);
518
519    if (VA_STATUS_SUCCESS != vaStatus) {
520        free(psb_surface);
521        object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
522        obj_surface->surface_id = VA_INVALID_SURFACE;
523
524        DEBUG_FAILURE;
525        return vaStatus;
526    }
527    buffer_stride = psb_surface->stride;
528    /* by default, surface fourcc is NV12 */
529    memset(psb_surface->extra_info, 0, sizeof(psb_surface->extra_info));
530    psb_surface->extra_info[4] = kBuf_fourcc;
531    psb_surface->extra_info[8] = kBuf_fourcc;
532#ifdef PSBVIDEO_MSVDX_DEC_TILING
533    psb_surface->extra_info[7] = tiling;
534#endif
535    obj_surface->psb_surface = psb_surface;
536
537    /* Error recovery */
538    if (VA_STATUS_SUCCESS != vaStatus) {
539        object_surface_p obj_surface = SURFACE(surfaceID);
540        psb__destroy_surface(driver_data, obj_surface);
541        *surface = VA_INVALID_SURFACE;
542    }
543
544    return vaStatus;
545}
546
547VAStatus  psb_CreateSurfaceFromUserspace(
548        VADriverContextP ctx,
549        int width,
550        int height,
551        int format,
552        int num_surfaces,
553        VASurfaceID *surface_list,        /* out */
554        VASurfaceAttributeTPI *attribute_tpi
555)
556{
557    INIT_DRIVER_DATA;
558    VAStatus vaStatus = VA_STATUS_SUCCESS;
559#ifdef ANDROID
560    unsigned int *vaddr;
561    unsigned long fourcc;
562    int surfaceID;
563    object_surface_p obj_surface;
564    psb_surface_p psb_surface;
565    int i;
566
567    switch (format) {
568    case VA_RT_FORMAT_YUV422:
569        fourcc = VA_FOURCC_YV16;
570        break;
571    case VA_RT_FORMAT_YUV420:
572    default:
573        fourcc = VA_FOURCC_NV12;
574        break;
575    }
576
577    for (i=0; i < num_surfaces; i++) {
578        vaddr = (unsigned int *)(attribute_tpi->buffers[i]);
579        surfaceID = object_heap_allocate(&driver_data->surface_heap);
580        obj_surface = SURFACE(surfaceID);
581        if (NULL == obj_surface) {
582            vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
583            DEBUG_FAILURE;
584            break;
585        }
586        MEMSET_OBJECT(obj_surface, struct object_surface_s);
587
588        obj_surface->surface_id = surfaceID;
589        surface_list[i] = surfaceID;
590        obj_surface->context_id = -1;
591        obj_surface->width = attribute_tpi->width;
592        obj_surface->height = attribute_tpi->height;
593        obj_surface->width_r = attribute_tpi->width;
594        obj_surface->height_r = attribute_tpi->height;
595	obj_surface->is_ref_surface = 0;
596
597        psb_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
598        if (NULL == psb_surface) {
599            object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
600            obj_surface->surface_id = VA_INVALID_SURFACE;
601            vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
602            DEBUG_FAILURE;
603            break;
604        }
605
606        if (attribute_tpi->type == VAExternalMemoryNoneCacheUserPointer)
607            vaStatus = psb_surface_create_from_ub(driver_data, width, height, fourcc,
608                    attribute_tpi, psb_surface, vaddr, PSB_USER_BUFFER_UNCACHED);
609        else
610            vaStatus = psb_surface_create_from_ub(driver_data, width, height, fourcc,
611                    attribute_tpi, psb_surface, vaddr, 0);
612        obj_surface->psb_surface = psb_surface;
613
614        if (VA_STATUS_SUCCESS != vaStatus) {
615            free(psb_surface);
616            object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
617            obj_surface->surface_id = VA_INVALID_SURFACE;
618            DEBUG_FAILURE;
619            break;
620        }
621        /* by default, surface fourcc is NV12 */
622        memset(psb_surface->extra_info, 0, sizeof(psb_surface->extra_info));
623        psb_surface->extra_info[4] = fourcc;
624        psb_surface->extra_info[8] = fourcc;
625        obj_surface->psb_surface = psb_surface;
626
627        /* Error recovery */
628        if (VA_STATUS_SUCCESS != vaStatus) {
629            object_surface_p obj_surface = SURFACE(surfaceID);
630            psb__destroy_surface(driver_data, obj_surface);
631        }
632    }
633#endif
634    return vaStatus;
635}
636
637VAStatus  psb_CreateSurfaceFromION(
638        VADriverContextP ctx,
639        int width,
640        int height,
641        int format,
642        int num_surfaces,
643        VASurfaceID *surface_list,        /* out */
644        VASurfaceAttributeTPI *attribute_tpi
645)
646{
647    INIT_DRIVER_DATA;
648    VAStatus vaStatus = VA_STATUS_SUCCESS;
649#ifdef ANDROID
650    unsigned int *vaddr = NULL;
651    unsigned long fourcc;
652    int surfaceID;
653    object_surface_p obj_surface;
654    psb_surface_p psb_surface;
655    int i;
656    unsigned int source_size = 0;
657    int ion_fd = 0;
658    int ion_ret = 0;
659    struct ion_fd_data ion_source_share;
660
661    switch (format) {
662    case VA_RT_FORMAT_YUV422:
663        fourcc = VA_FOURCC_YV16;
664        break;
665    case VA_RT_FORMAT_YUV420:
666    default:
667        fourcc = VA_FOURCC_NV12;
668        break;
669    }
670
671    ion_fd = open("/dev/ion", O_RDWR);
672    if (ion_fd < 0) {
673        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Fail to open the ion device!\n", __FUNCTION__);
674        return VA_STATUS_ERROR_UNKNOWN;
675    }
676
677    for (i=0; i < num_surfaces; i++) {
678        ion_source_share.handle = 0;
679        ion_source_share.fd = (int)(attribute_tpi->buffers[i]);
680        ion_ret = ioctl(ion_fd, ION_IOC_IMPORT, &ion_source_share);
681            if ((ion_ret < 0) || (0 == ion_source_share.handle)) {
682            close(ion_fd);
683            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Fail to import the ion fd!\n", __FUNCTION__);
684            return VA_STATUS_ERROR_UNKNOWN;
685        }
686
687        if (VA_FOURCC_NV12 == fourcc)
688            source_size = attribute_tpi->width * attribute_tpi->height * 1.5;
689        else
690            source_size = attribute_tpi->width * attribute_tpi->height * 2;
691
692        vaddr = mmap(NULL, source_size, PROT_READ|PROT_WRITE, MAP_SHARED, ion_source_share.fd, 0);
693        if (MAP_FAILED == vaddr) {
694            close(ion_fd);
695            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Fail to mmap the ion buffer!\n", __FUNCTION__);
696            return VA_STATUS_ERROR_UNKNOWN;
697        }
698
699        surfaceID = object_heap_allocate(&driver_data->surface_heap);
700        obj_surface = SURFACE(surfaceID);
701        if (NULL == obj_surface) {
702            close(ion_fd);
703            vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
704            DEBUG_FAILURE;
705            break;
706        }
707        MEMSET_OBJECT(obj_surface, struct object_surface_s);
708
709        obj_surface->surface_id = surfaceID;
710        surface_list[i] = surfaceID;
711        obj_surface->context_id = -1;
712        obj_surface->width = attribute_tpi->width;
713        obj_surface->height = attribute_tpi->height;
714        obj_surface->width_r = attribute_tpi->width;
715        obj_surface->height_r = attribute_tpi->height;
716	obj_surface->is_ref_surface = 0;
717
718        psb_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
719        if (NULL == psb_surface) {
720            object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
721            obj_surface->surface_id = VA_INVALID_SURFACE;
722            close(ion_fd);
723            vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
724            DEBUG_FAILURE;
725            break;
726        }
727
728        vaStatus = psb_surface_create_from_ub(driver_data, width, height, fourcc,
729                attribute_tpi, psb_surface, vaddr, 0);
730        obj_surface->psb_surface = psb_surface;
731
732        if (VA_STATUS_SUCCESS != vaStatus) {
733            free(psb_surface);
734            object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
735            obj_surface->surface_id = VA_INVALID_SURFACE;
736            close(ion_fd);
737            DEBUG_FAILURE;
738            break;
739        }
740        /* by default, surface fourcc is NV12 */
741        memset(psb_surface->extra_info, 0, sizeof(psb_surface->extra_info));
742        psb_surface->extra_info[4] = fourcc;
743        psb_surface->extra_info[8] = fourcc;
744        obj_surface->psb_surface = psb_surface;
745
746        /* Error recovery */
747        if (VA_STATUS_SUCCESS != vaStatus) {
748            object_surface_p obj_surface = SURFACE(surfaceID);
749            psb__destroy_surface(driver_data, obj_surface);
750            close(ion_fd);
751        }
752
753        vaddr = NULL;
754    }
755
756    close(ion_fd);
757#endif
758    return vaStatus;
759}
760
761VAStatus psb_CreateSurfacesWithAttribute(
762    VADriverContextP ctx,
763    int width,
764    int height,
765    int format,
766    int num_surfaces,
767    VASurfaceID *surface_list,        /* out */
768    VASurfaceAttributeTPI *attribute_tpi
769)
770{
771    VAStatus vaStatus = VA_STATUS_SUCCESS;
772    int i;
773    int tiling;
774
775    CHECK_INVALID_PARAM(attribute_tpi == NULL);
776
777    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Create %d surface(%dx%d) with type %d, tiling is %d\n",
778            num_surfaces, width, height, attribute_tpi->type, attribute_tpi->tiling);
779
780    tiling = attribute_tpi->tiling;
781    switch (attribute_tpi->type) {
782    case VAExternalMemoryNULL:
783        vaStatus = psb_CreateSurfacesForUserPtr(ctx, width, height, format, num_surfaces, surface_list,
784                                     attribute_tpi->size, attribute_tpi->pixel_format,
785                                     attribute_tpi->luma_stride, attribute_tpi->chroma_u_stride,
786                                     attribute_tpi->chroma_v_stride, attribute_tpi->luma_offset,
787                                     attribute_tpi->chroma_u_offset, attribute_tpi->chroma_v_offset,
788                                     attribute_tpi->tiling);
789        return vaStatus;
790#ifdef ANDROID
791    case VAExternalMemoryNoneCacheUserPointer:
792#endif
793    case VAExternalMemoryUserPointer:
794        vaStatus = psb_CreateSurfaceFromUserspace(ctx, width, height,
795                                                 format, num_surfaces, surface_list,
796                                                 attribute_tpi);
797        return vaStatus;
798    case VAExternalMemoryKernelDRMBufffer:
799        for (i=0; i < num_surfaces; i++) {
800            vaStatus = psb_CreateSurfaceFromKBuf(
801                ctx, width, height, format, &surface_list[i],
802                attribute_tpi->buffers[i],
803                attribute_tpi->size, attribute_tpi->pixel_format,
804                attribute_tpi->luma_stride, attribute_tpi->chroma_u_stride,
805                attribute_tpi->chroma_v_stride, attribute_tpi->luma_offset,
806                attribute_tpi->chroma_u_offset, attribute_tpi->chroma_v_offset, tiling);
807            CHECK_VASTATUS();
808        }
809        return vaStatus;
810    case VAExternalMemoryAndroidGrallocBuffer:
811        vaStatus = psb_CreateSurfacesFromGralloc(ctx, width, height,
812                                                 format, num_surfaces, surface_list,
813                                                 (PsbSurfaceAttributeTPI *)attribute_tpi);
814        return vaStatus;
815#ifdef ANDROID
816    case VAExternalMemoryIONSharedFD:
817        vaStatus = psb_CreateSurfaceFromION(ctx, width, height,
818                                                 format, num_surfaces, surface_list,
819                                                 attribute_tpi);
820        return vaStatus;
821#endif
822    default:
823        return VA_STATUS_ERROR_INVALID_PARAMETER;
824    }
825
826    return VA_STATUS_ERROR_INVALID_PARAMETER;
827}
828