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