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