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  */
psb_surface_create_from_ub(psb_driver_data_p driver_data,int width,int height,int fourcc,VASurfaceAttributeTPI * graphic_buffers,psb_surface_p psb_surface,void * vaddr,int fd,unsigned flags)53 VAStatus 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
130 VAStatus 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 
psb_CreateSurfacesForUserPtr(VADriverContextP ctx,int Width,int Height,int format,int num_surfaces,VASurfaceID * surface_list,unsigned size,unsigned int fourcc,unsigned int luma_stride,unsigned int chroma_u_stride,unsigned int chroma_v_stride,unsigned int luma_offset,unsigned int chroma_u_offset,unsigned int chroma_v_offset,unsigned int tiling)256 VAStatus 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 
psb_CreateSurfaceFromKBuf(VADriverContextP ctx,int _width,int _height,int format,VASurfaceID * surface,unsigned int kbuf_handle,unsigned size,unsigned int kBuf_fourcc,unsigned int luma_stride,unsigned int chroma_u_stride,unsigned int chroma_v_stride,unsigned int luma_offset,unsigned int chroma_u_offset,unsigned int chroma_v_offset,unsigned int tiling)410 VAStatus  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 
psb_CreateSurfaceFromUserspace(VADriverContextP ctx,int width,int height,int format,int num_surfaces,VASurfaceID * surface_list,VASurfaceAttributeTPI * attribute_tpi)543 VAStatus  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 
psb_CreateSurfaceFromION(VADriverContextP ctx,int width,int height,int format,int num_surfaces,VASurfaceID * surface_list,VASurfaceAttributeTPI * attribute_tpi)635 VAStatus  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 
psb_CreateSurfacesWithAttribute(VADriverContextP ctx,int width,int height,int format,int num_surfaces,VASurfaceID * surface_list,VASurfaceAttributeTPI * attribute_tpi)759 VAStatus 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