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 * Authors:
25 *    Shengquan Yuan  <shengquan.yuan@intel.com>
26 *    Zhaohan Ren  <zhaohan.ren@intel.com>
27 *    Jason Hu <jason.hu@intel.com>
28 *
29 */
30
31#ifndef ANDROID
32#include <X11/Xutil.h>
33#include <X11/extensions/Xrandr.h>
34#include <va/va_dricommon.h>
35#include "x11/psb_x11.h"
36#include "x11/psb_xrandr.h"
37#endif
38#include <va/va_backend.h>
39#include <dlfcn.h>
40#include <stdlib.h>
41#include "psb_output.h"
42#include "psb_surface.h"
43#include "psb_buffer.h"
44#include "psb_surface_ext.h"
45#include "pnw_rotate.h"
46#include <stdio.h>
47#include <string.h>
48#include <stdarg.h>
49#include <wsbm/wsbm_manager.h>
50#include "psb_drv_debug.h"
51#include <string.h>
52#include <unistd.h>
53#include <sys/ioctl.h>
54#include <math.h>
55
56#define INIT_DRIVER_DATA        psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData;
57
58#define SURFACE(id)     ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id ))
59#define BUFFER(id)  ((object_buffer_p) object_heap_lookup( &driver_data->buffer_heap, id ))
60#define IMAGE(id)  ((object_image_p) object_heap_lookup( &driver_data->image_heap, id ))
61#define SUBPIC(id)  ((object_subpic_p) object_heap_lookup( &driver_data->subpic_heap, id ))
62#define CONTEXT(id) ((object_context_p) object_heap_lookup( &driver_data->context_heap, id ))
63
64
65/* surfaces link list associated with a subpicture */
66typedef struct _subpic_surface {
67    VASurfaceID surface_id;
68    struct _subpic_surface *next;
69} subpic_surface_s, *subpic_surface_p;
70
71
72static VAImageFormat psb__SubpicFormat[] = {
73    psb__ImageRGBA,
74    //psb__ImageAYUV,
75    //psb__ImageAI44
76};
77
78static VAImageFormat psb__CreateImageFormat[] = {
79    psb__ImageNV12,
80    psb__ImageRGBA,
81    //psb__ImageAYUV,
82    //psb__ImageAI44,
83    psb__ImageYV16,
84    psb__ImageYV32
85};
86
87unsigned char *psb_x11_output_init(VADriverContextP ctx);
88VAStatus psb_x11_output_deinit(VADriverContextP ctx);
89unsigned char *psb_android_output_init(VADriverContextP ctx);
90VAStatus psb_android_output_deinit(VADriverContextP ctx);
91
92int psb_coverlay_init(VADriverContextP ctx);
93int psb_coverlay_deinit(VADriverContextP ctx);
94
95VAStatus psb_initOutput(VADriverContextP ctx)
96{
97    INIT_DRIVER_DATA;
98    unsigned char *ws_priv = NULL;
99    char env_value[1024];
100
101    pthread_mutex_init(&driver_data->output_mutex, NULL);
102
103    if (psb_parse_config("PSB_VIDEO_PUTSURFACE_DUMMY", &env_value[0]) == 0) {
104        drv_debug_msg(VIDEO_DEBUG_GENERAL, "vaPutSurface: dummy mode, return directly\n");
105        driver_data->dummy_putsurface = 0;
106
107        return VA_STATUS_SUCCESS;
108    }
109
110    if (psb_parse_config("PSB_VIDEO_FPS", &env_value[0]) == 0) {
111        driver_data->fixed_fps = atoi(env_value);
112        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Throttling at FPS=%d\n", driver_data->fixed_fps);
113    } else
114        driver_data->fixed_fps = 0;
115
116    driver_data->outputmethod_checkinterval = 1;
117    if (psb_parse_config("PSB_VIDEO_INTERVAL", &env_value[0]) == 0) {
118        driver_data->outputmethod_checkinterval = atoi(env_value);
119        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Check output method at %d frames interval\n",
120                                 driver_data->outputmethod_checkinterval);
121    }
122
123    driver_data->cur_displaying_surface = VA_INVALID_SURFACE;
124    driver_data->last_displaying_surface = VA_INVALID_SURFACE;
125
126    psb_InitOutLoop(ctx);
127
128#ifdef ANDROID
129    ws_priv = psb_android_output_init(ctx);
130    driver_data->is_android = 1;
131#else
132    ws_priv = psb_x11_output_init(ctx);
133    driver_data->is_android = 0;
134#endif
135    driver_data->ws_priv = ws_priv;
136
137
138#if 0
139    //use client textureblit
140    if (driver_data->ctexture == 1) {
141        int ret = psb_ctexture_init(ctx);
142        if (ret != 0)
143            driver_data->ctexture = 0;
144    }
145#endif
146
147    /*
148    //use texture streaming
149    if (driver_data->ctexstreaming == 1)
150    psb_ctexstreaing_init(ctx);
151    */
152
153    return VA_STATUS_SUCCESS;
154}
155
156VAStatus psb_deinitOutput(
157    VADriverContextP ctx
158)
159{
160    INIT_DRIVER_DATA;
161
162#if 0
163    //use client textureblit
164    if (driver_data->ctexture == 1)
165        psb_ctexture_deinit(ctx);
166#endif
167
168    if (driver_data->coverlay_init) {
169        psb_coverlay_deinit(ctx);
170        driver_data->coverlay_init = 0;
171    }
172
173#ifndef ANDROID
174    psb_x11_output_deinit(ctx);
175#else
176    psb_android_output_deinit(ctx);
177#endif
178    /* free here, but allocate in window system specific */
179    free(driver_data->ws_priv);
180    /*
181    //use texture streaming
182    if (driver_data->ctexstreaming == 1)
183        psb_ctexstreaing_deinit(ctx);
184    */
185    /* clean the displaying surface information in kernel */
186#ifndef _FOR_FPGA_
187    psb_surface_set_displaying(driver_data, 0, 0, NULL);
188#endif
189    pthread_mutex_destroy(&driver_data->output_mutex);
190
191    return VA_STATUS_SUCCESS;
192}
193
194#ifndef VA_STATUS_ERROR_INVALID_IMAGE_FORMAT
195#define VA_STATUS_ERROR_INVALID_IMAGE_FORMAT VA_STATUS_ERROR_UNKNOWN
196#endif
197
198static VAImageFormat *psb__VAImageCheckFourCC(
199    VAImageFormat       *src_format,
200    VAImageFormat       *dst_format,
201    int                 dst_num
202)
203{
204    int i;
205    if (NULL == src_format || dst_format == NULL) {
206        return NULL;
207    }
208
209    /* check VAImage at first */
210    for (i = 0; i < dst_num; i++) {
211        if (dst_format[i].fourcc == src_format->fourcc)
212            return &dst_format[i];
213    }
214
215    drv_debug_msg(VIDEO_DEBUG_ERROR, "Unsupport fourcc 0x%x\n", src_format->fourcc);
216    return NULL;
217}
218
219static void psb__VAImageCheckRegion(
220    object_surface_p surface,
221    VAImage *image,
222    int *src_x,
223    int *src_y,
224    int *dest_x,
225    int *dest_y,
226    int *width,
227    int *height
228)
229{
230    /* check for image */
231    if (*src_x < 0) *src_x = 0;
232    if (*src_x > image->width) *src_x = image->width - 1;
233    if (*src_y < 0) *src_y = 0;
234    if (*src_y > image->height) *src_y = image->height - 1;
235
236    if (((*width) + (*src_x)) > image->width) *width = image->width - *src_x;
237    if (((*height) + (*src_y)) > image->height) *height = image->height - *src_x;
238
239    /* check for surface */
240    if (*dest_x < 0) *dest_x = 0;
241    if (*dest_x > surface->width) *dest_x = surface->width - 1;
242    if (*dest_y < 0) *dest_y = 0;
243    if (*dest_y > surface->height) *dest_y = surface->height - 1;
244
245    if (((*width) + (*dest_x)) > surface->width) *width = surface->width - *dest_x;
246    if (((*height) + (*dest_y)) > surface->height) *height = surface->height - *dest_x;
247}
248
249
250VAStatus psb_QueryImageFormats(
251    VADriverContextP __maybe_unused ctx,
252    VAImageFormat *format_list,        /* out */
253    int *num_formats           /* out */
254)
255{
256    VAStatus vaStatus = VA_STATUS_SUCCESS;
257
258    CHECK_INVALID_PARAM(format_list == NULL);
259    CHECK_INVALID_PARAM(num_formats == NULL);
260
261    memcpy(format_list, psb__CreateImageFormat, sizeof(psb__CreateImageFormat));
262    *num_formats = PSB_MAX_IMAGE_FORMATS;
263
264    return VA_STATUS_SUCCESS;
265}
266
267inline int min_POT(int n)
268{
269    if ((n & (n - 1)) == 0) /* already POT */
270        return n;
271
272    return n |= n >> 16, n |= n >> 8, n |= n >> 4, n |= n >> 2, n |= n >> 1, n + 1;
273    /* return ((((n |= n>>16) |= n>>8) |= n>>4) |= n>>2) |= n>>1, n + 1; */
274}
275
276VAStatus psb_CreateImage(
277    VADriverContextP ctx,
278    VAImageFormat *format,
279    int width,
280    int height,
281    VAImage *image     /* out */
282)
283{
284    INIT_DRIVER_DATA;
285    VAImageID imageID;
286    object_image_p obj_image;
287    VAStatus vaStatus = VA_STATUS_SUCCESS;
288    VAImageFormat *img_fmt;
289    int pitch_pot;
290
291    (void)driver_data;
292
293    img_fmt = psb__VAImageCheckFourCC(format, psb__CreateImageFormat,
294                                      sizeof(psb__CreateImageFormat) / sizeof(VAImageFormat));
295    if (img_fmt == NULL)
296        return VA_STATUS_ERROR_UNKNOWN;
297
298    CHECK_INVALID_PARAM(image == NULL);
299
300    imageID = object_heap_allocate(&driver_data->image_heap);
301    obj_image = IMAGE(imageID);
302    CHECK_ALLOCATION(obj_image);
303
304    MEMSET_OBJECT(obj_image, struct object_image_s);
305
306    obj_image->image.image_id = imageID;
307    obj_image->image.format = *img_fmt;
308    obj_image->subpic_ref = 0;
309
310    pitch_pot = min_POT(width);
311
312    switch (format->fourcc) {
313    case VA_FOURCC_NV12: {
314        obj_image->image.width = width;
315        obj_image->image.height = height;
316        obj_image->image.data_size = pitch_pot * height /*Y*/ + 2 * (pitch_pot / 2) * (height / 2);/*UV*/
317        obj_image->image.num_planes = 2;
318        obj_image->image.pitches[0] = pitch_pot;
319        obj_image->image.pitches[1] = pitch_pot;
320        obj_image->image.offsets[0] = 0;
321        obj_image->image.offsets[1] = pitch_pot * height;
322        obj_image->image.num_palette_entries = 0;
323        obj_image->image.entry_bytes = 0;
324        obj_image->image.component_order[0] = 'Y';
325        obj_image->image.component_order[1] = 'U';/* fixed me: packed UV packed here! */
326        obj_image->image.component_order[2] = 'V';
327        obj_image->image.component_order[3] = '\0';
328        break;
329    }
330    case VA_FOURCC_AYUV: {
331        obj_image->image.width = width;
332        obj_image->image.height = height;
333        obj_image->image.data_size = 4 * pitch_pot * height;
334        obj_image->image.num_planes = 1;
335        obj_image->image.pitches[0] = 4 * pitch_pot;
336        obj_image->image.num_palette_entries = 0;
337        obj_image->image.entry_bytes = 0;
338        obj_image->image.component_order[0] = 'V';
339        obj_image->image.component_order[1] = 'U';
340        obj_image->image.component_order[2] = 'Y';
341        obj_image->image.component_order[3] = 'A';
342        break;
343    }
344    case VA_FOURCC_RGBA: {
345        obj_image->image.width = width;
346        obj_image->image.height = height;
347        obj_image->image.data_size = 4 * pitch_pot * height;
348        obj_image->image.num_planes = 1;
349        obj_image->image.pitches[0] = 4 * pitch_pot;
350        obj_image->image.num_palette_entries = 0;
351        obj_image->image.entry_bytes = 0;
352        obj_image->image.component_order[0] = 'R';
353        obj_image->image.component_order[1] = 'G';
354        obj_image->image.component_order[2] = 'B';
355        obj_image->image.component_order[3] = 'A';
356        break;
357    }
358    case VA_FOURCC_AI44: {
359        obj_image->image.width = width;
360        obj_image->image.height = height;
361        obj_image->image.data_size = pitch_pot * height;/* one byte one element */
362        obj_image->image.num_planes = 1;
363        obj_image->image.pitches[0] = pitch_pot;
364        obj_image->image.num_palette_entries = 16;
365        obj_image->image.entry_bytes = 4; /* AYUV */
366        obj_image->image.component_order[0] = 'I';
367        obj_image->image.component_order[1] = 'A';
368        obj_image->image.component_order[2] = '\0';
369        obj_image->image.component_order[3] = '\0';
370        break;
371    }
372    case VA_FOURCC_IYUV: {
373        obj_image->image.width = width;
374        obj_image->image.height = height;
375        obj_image->image.data_size = pitch_pot * height /*Y*/ + 2 * (pitch_pot / 2) * (height / 2);/*UV*/
376        obj_image->image.num_planes = 3;
377        obj_image->image.pitches[0] = pitch_pot;
378        obj_image->image.pitches[1] = pitch_pot / 2;
379        obj_image->image.pitches[2] = pitch_pot / 2;
380        obj_image->image.offsets[0] = 0;
381        obj_image->image.offsets[1] = pitch_pot * height;
382        obj_image->image.offsets[2] = pitch_pot * height + (pitch_pot / 2) * (height / 2);
383        obj_image->image.num_palette_entries = 0;
384        obj_image->image.entry_bytes = 0;
385        obj_image->image.component_order[0] = 'Y';
386        obj_image->image.component_order[1] = 'U';
387        obj_image->image.component_order[2] = 'V';
388        obj_image->image.component_order[3] = '\0';
389        break;
390    }
391    case VA_FOURCC_YV32: {
392        obj_image->image.width = width;
393        obj_image->image.height = height;
394        obj_image->image.data_size = 4 * pitch_pot * height;
395        obj_image->image.num_planes = 4;
396        obj_image->image.pitches[0] = pitch_pot;
397        obj_image->image.pitches[1] = pitch_pot;
398        obj_image->image.pitches[2] = pitch_pot;
399        obj_image->image.extra_pitch = pitch_pot;
400        obj_image->image.offsets[0] = 0;
401        obj_image->image.offsets[1] = pitch_pot * height;
402        obj_image->image.offsets[2] = pitch_pot * height * 2;
403        obj_image->image.extra_offset = pitch_pot * height * 3;
404        obj_image->image.num_palette_entries = 0;
405        obj_image->image.entry_bytes = 0;
406        obj_image->image.component_order[0] = 'V';
407        obj_image->image.component_order[1] = 'U';
408        obj_image->image.component_order[2] = 'Y';
409        obj_image->image.component_order[3] = 'A';
410        break;
411    }
412    default: {
413        vaStatus = VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
414        break;
415    }
416    }
417
418    if (VA_STATUS_SUCCESS == vaStatus) {
419        /* create the buffer */
420        vaStatus = psb__CreateBuffer(driver_data, NULL, VAImageBufferType,
421                                     obj_image->image.data_size, 1, NULL, &obj_image->image.buf);
422    }
423
424    obj_image->derived_surface = 0;
425
426    if (VA_STATUS_SUCCESS != vaStatus) {
427        object_heap_free(&driver_data->image_heap, (object_base_p) obj_image);
428    } else {
429        memcpy(image, &obj_image->image, sizeof(VAImage));
430    }
431
432    return vaStatus;
433}
434
435static int psb_CheckIEDStatus(VADriverContextP ctx)
436{
437    INIT_DRIVER_DATA;
438    struct drm_lnc_video_getparam_arg arg;
439    unsigned long temp;
440    int ret = 0;
441
442    /* not settled, we get it from current HW FRAMESKIP flag */
443    arg.key = IMG_VIDEO_IED_STATE;
444    arg.value = (uint64_t)((unsigned long) & temp);
445    ret = drmCommandWriteRead(driver_data->drm_fd, driver_data->getParamIoctlOffset,
446                              &arg, sizeof(arg));
447    if (ret == 0) {
448        if (temp == 1) {
449            drv_debug_msg(VIDEO_DEBUG_ERROR, "IED is enabled, image is encrypted.\n");
450            return 1;
451        } else {
452            return 0;
453        }
454    } else {
455        drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to call IMG_VIDEO_IED_STATE.\n");
456        return -1;
457    }
458}
459
460VAStatus psb_DeriveImage(
461    VADriverContextP ctx,
462    VASurfaceID surface,
463    VAImage *image     /* out */
464)
465{
466    INIT_DRIVER_DATA;
467    VAStatus vaStatus = VA_STATUS_SUCCESS;
468    VABufferID bufferID;
469    object_buffer_p obj_buffer;
470    VAImageID imageID;
471    object_image_p obj_image;
472    object_surface_p obj_surface = SURFACE(surface);
473    unsigned int fourcc, fourcc_index = ~0, i;
474    uint32_t srf_buf_ofs = 0;
475
476    CHECK_SURFACE(obj_surface);
477    CHECK_INVALID_PARAM(image == NULL);
478    /* Can't derive image from reconstrued frame which is in tiled format */
479    if (obj_surface->is_ref_surface == 1 || obj_surface->is_ref_surface == 2) {
480	if (getenv("PSB_VIDEO_IGNORE_TILED_FORMAT")) {
481	    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Ignore tiled memory format" \
482			"of rec-frames\n");
483	} else {
484	    drv_debug_msg(VIDEO_DEBUG_ERROR, "Can't derive reference surface" \
485			"which is tiled format\n");
486	    return VA_STATUS_ERROR_OPERATION_FAILED;
487	}
488    }
489
490    if (IS_MFLD(driver_data) && (psb_CheckIEDStatus(ctx) == 1)) {
491        vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
492        return vaStatus;
493    }
494
495    fourcc = obj_surface->psb_surface->extra_info[4];
496    for (i = 0; i < PSB_MAX_IMAGE_FORMATS; i++) {
497        if (psb__CreateImageFormat[i].fourcc == fourcc) {
498            fourcc_index = i;
499            break;
500        }
501    }
502    if (i == PSB_MAX_IMAGE_FORMATS) {
503        drv_debug_msg(VIDEO_DEBUG_ERROR, "Can't support the Fourcc\n");
504        vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
505        return vaStatus;
506    }
507
508    /* create the image */
509    imageID = object_heap_allocate(&driver_data->image_heap);
510    obj_image = IMAGE(imageID);
511    CHECK_ALLOCATION(obj_image);
512
513    MEMSET_OBJECT(obj_image, struct object_image_s);
514
515    /* create a buffer to represent surface buffer */
516    bufferID = object_heap_allocate(&driver_data->buffer_heap);
517    obj_buffer = BUFFER(bufferID);
518    if (NULL == obj_buffer) {
519        object_heap_free(&driver_data->image_heap, (object_base_p) obj_image);
520        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
521        DEBUG_FAILURE;
522        return vaStatus;
523    }
524    MEMSET_OBJECT(obj_buffer, struct object_buffer_s);
525
526    obj_buffer->type = VAImageBufferType;
527    obj_buffer->buffer_data = NULL;
528    obj_buffer->psb_buffer = &obj_surface->psb_surface->buf;
529    obj_buffer->size = obj_surface->psb_surface->size;
530    obj_buffer->max_num_elements = 0;
531    obj_buffer->alloc_size = obj_buffer->size;
532
533    /* fill obj_image data structure */
534    obj_image->image.image_id = imageID;
535    obj_image->image.format = psb__CreateImageFormat[fourcc_index];
536    obj_image->subpic_ref = 0;
537
538    obj_image->image.buf = bufferID;
539    obj_image->image.width = obj_surface->width;
540    obj_image->image.height = obj_surface->height;
541    obj_image->image.data_size = obj_surface->psb_surface->size;
542
543    srf_buf_ofs = obj_surface->psb_surface->buf.buffer_ofs;
544
545    switch (fourcc) {
546    case VA_FOURCC_NV12: {
547        obj_image->image.num_planes = 2;
548        obj_image->image.pitches[0] = obj_surface->psb_surface->stride;
549        obj_image->image.pitches[1] = obj_surface->psb_surface->stride;
550
551        obj_image->image.offsets[0] = srf_buf_ofs;
552        obj_image->image.offsets[1] = srf_buf_ofs + obj_surface->height * obj_surface->psb_surface->stride;
553        obj_image->image.num_palette_entries = 0;
554        obj_image->image.entry_bytes = 0;
555        obj_image->image.component_order[0] = 'Y';
556        obj_image->image.component_order[1] = 'U';/* fixed me: packed UV packed here! */
557        obj_image->image.component_order[2] = 'V';
558        obj_image->image.component_order[3] = '\0';
559        break;
560    }
561    case VA_FOURCC_YV16: {
562        obj_image->image.num_planes = 3;
563        obj_image->image.pitches[0] = obj_surface->psb_surface->stride;
564        obj_image->image.pitches[1] = obj_surface->psb_surface->stride / 2;
565        obj_image->image.pitches[2] = obj_surface->psb_surface->stride / 2;
566
567        obj_image->image.offsets[0] = srf_buf_ofs;
568        obj_image->image.offsets[1] = srf_buf_ofs + obj_surface->height * obj_surface->psb_surface->stride;
569        obj_image->image.offsets[2] = srf_buf_ofs + obj_surface->height * obj_surface->psb_surface->stride * 3 / 2;
570        obj_image->image.num_palette_entries = 0;
571        obj_image->image.entry_bytes = 0;
572        obj_image->image.component_order[0] = 'Y';
573        obj_image->image.component_order[1] = 'V';/* fixed me: packed UV packed here! */
574        obj_image->image.component_order[2] = 'U';
575        obj_image->image.component_order[3] = '\0';
576        break;
577    }
578    case VA_FOURCC_YV32: {
579        obj_image->image.num_planes = 3;
580        obj_image->image.pitches[0] = obj_surface->psb_surface->stride;
581        obj_image->image.pitches[1] = obj_surface->psb_surface->stride;
582        obj_image->image.pitches[2] = obj_surface->psb_surface->stride;
583
584        obj_image->image.offsets[0] = srf_buf_ofs;
585        obj_image->image.offsets[1] = srf_buf_ofs + obj_surface->height * obj_surface->psb_surface->stride;
586        obj_image->image.offsets[2] = srf_buf_ofs + obj_surface->height * obj_surface->psb_surface->stride * 2;
587        obj_image->image.num_palette_entries = 0;
588        obj_image->image.entry_bytes = 0;
589        obj_image->image.component_order[0] = 'Y';
590        obj_image->image.component_order[1] = 'U';/* fixed me: packed UV packed here! */
591        obj_image->image.component_order[2] = 'V';
592        obj_image->image.component_order[3] = '\0';
593        break;
594    }
595    default:
596        break;
597    }
598
599    obj_image->derived_surface = surface; /* this image is derived from a surface */
600    obj_surface->derived_imgcnt++;
601
602    memcpy(image, &obj_image->image, sizeof(VAImage));
603
604    return vaStatus;
605}
606
607VAStatus psb__destroy_image(psb_driver_data_p driver_data, object_image_p obj_image)
608{
609    VAStatus vaStatus = VA_STATUS_SUCCESS;
610
611    if (obj_image->subpic_ref > 0) {
612        vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
613        return vaStatus;
614    }
615
616    object_surface_p obj_surface = SURFACE(obj_image->derived_surface);
617
618    if (obj_surface == NULL) { /* destroy the buffer */
619        object_buffer_p obj_buffer = BUFFER(obj_image->image.buf);
620        CHECK_BUFFER(obj_buffer);
621        psb__suspend_buffer(driver_data, obj_buffer);
622    } else {
623        object_buffer_p obj_buffer = BUFFER(obj_image->image.buf);
624        object_heap_free(&driver_data->buffer_heap, &obj_buffer->base);
625        obj_surface->derived_imgcnt--;
626    }
627    object_heap_free(&driver_data->image_heap, (object_base_p) obj_image);
628
629    return VA_STATUS_SUCCESS;
630}
631
632VAStatus psb_DestroyImage(
633    VADriverContextP ctx,
634    VAImageID image
635)
636{
637    INIT_DRIVER_DATA
638    VAStatus vaStatus = VA_STATUS_SUCCESS;
639    object_image_p obj_image;
640
641    obj_image = IMAGE(image);
642    CHECK_IMAGE(obj_image);
643    return psb__destroy_image(driver_data, obj_image);
644}
645
646VAStatus psb_SetImagePalette(
647    VADriverContextP ctx,
648    VAImageID image,
649    /*
650     * pointer to an array holding the palette data.  The size of the array is
651     * num_palette_entries * entry_bytes in size.  The order of the components
652     * in the palette is described by the component_order in VAImage struct
653     */
654    unsigned char *palette
655)
656{
657    INIT_DRIVER_DATA;
658    VAStatus vaStatus = VA_STATUS_SUCCESS;
659
660    object_image_p obj_image = IMAGE(image);
661    CHECK_IMAGE(obj_image);
662
663    if (obj_image->image.format.fourcc != VA_FOURCC_AI44) {
664        /* only support AI44 palette */
665        vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
666        return vaStatus;
667    }
668
669    if (obj_image->image.num_palette_entries > 16) {
670        drv_debug_msg(VIDEO_DEBUG_ERROR, "image.num_palette_entries(%d) is too big\n", obj_image->image.num_palette_entries);
671        memcpy(obj_image->palette, palette, 16);
672    } else
673        memcpy(obj_image->palette, palette, obj_image->image.num_palette_entries * sizeof(unsigned int));
674
675    return vaStatus;
676}
677
678static VAStatus lnc_unpack_topaz_rec(int src_width, int src_height,
679                                     unsigned char *p_srcY, unsigned char *p_srcUV,
680                                     unsigned char *p_dstY, unsigned char *p_dstU, unsigned char *p_dstV,
681                                     int dstY_stride, int dstU_stride, int dstV_stride,
682                                     int surface_height)
683{
684    unsigned char *tmp_dstY = NULL;
685    unsigned char *tmp_dstUV = NULL;
686
687    int n, i, index;
688
689    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Unpack reconstructed frame to image\n");
690
691    /* do this one column at a time. */
692    tmp_dstY = (unsigned char *)calloc(1, 16 * src_height);
693    if (tmp_dstY == NULL)
694        return  VA_STATUS_ERROR_ALLOCATION_FAILED;
695
696    tmp_dstUV = (unsigned char*)calloc(1, 16 * src_height / 2);
697    if (tmp_dstUV == NULL) {
698        free(tmp_dstY);
699        return VA_STATUS_ERROR_ALLOCATION_FAILED;
700    }
701
702    /*  Copy Y data */
703    for (n = 0; n < src_width / 16; n++) {
704        memcpy((void*)tmp_dstY, p_srcY, 16 * src_height);
705        p_srcY += (16 * surface_height);
706        for (i = 0; i < src_height; i++) {
707            memcpy(p_dstY + dstY_stride * i + n * 16, tmp_dstY + 16 * i, 16);
708        }
709    }
710
711    /* Copy U/V data */
712    for (n = 0; n < src_width / 16; n++) {
713        memcpy((void*)tmp_dstUV, p_srcUV, 16 * src_height / 2);
714        p_srcUV += (16 * surface_height / 2);
715        for (i = 0; i < src_height / 2; i++) {
716            for (index = 0; index < 8; index++) {
717                p_dstU[i*dstU_stride + n*8 + index] = tmp_dstUV[index*2 + i*16];
718                p_dstV[i*dstV_stride + n*8 + index] = tmp_dstUV[index*2 + i*16+1];
719            }
720        }
721    }
722    if (tmp_dstY)
723        free(tmp_dstY);
724    if (tmp_dstUV)
725        free(tmp_dstUV);
726
727    return VA_STATUS_SUCCESS;
728}
729
730/*
731* Convert the memroy format from tiled to linear
732*/
733static VAStatus tng_unpack_vsp_rec(
734    int src_width, int src_height,
735    unsigned char *p_srcY, unsigned char *p_srcUV,
736    unsigned char *p_dstY, unsigned char *p_dstU,
737    int dstY_stride, int dstU_stride, int __maybe_unused dstV_stride,
738    int __maybe_unused surface_height)
739{
740    unsigned char *tmp_dstY = p_dstY;
741    unsigned char *tmp_dstU = p_dstU;
742
743    int n, t,x,y;
744
745   //"	Y_address(x,y) =    Y_base + (((H            +64+63)/64) * (x/64) + (y/64))*4096 + (y%64)*64 + (x%64)
746   //"	U_address(x,y) = UV_base + ((((H+1)/2+32+63)/64) * (x/32) + (y/64))*4096 + (y%64)*64 + (x%32)*2
747   //"	V_address(x,y) = UV_base + ((((H+1)/2+32+63)/64) * (x/32) + (y/64))*4096 + (y%64)*64 + (x%32)*2 + 1
748
749    /*  Copy Y data */
750    for (y = 32; y < src_height + 32; y++) {
751        for (x= 32;x < src_width + 32; x++) {
752            * tmp_dstY++ =  *(p_srcY + (((src_height+64+63)/64) * (x/64) + (y/64))*4096 + (y%64)*64 + (x%64));
753            }
754            tmp_dstY += dstY_stride - src_width;
755    }
756
757    /*  Copy UV data */
758    for (y = 16; y < 16 + ((src_height+1)>>1) ; y++) {
759        for (x= 16;x < 16 + ( (src_width+1)>>1); x++) {
760            * tmp_dstU++ = * (p_srcUV + ((((src_height+1)/2+32+63)/64) * (x/32) + (y/64))*4096 + (y%64)*64 + (x%32)*2);
761            * tmp_dstU++ = * (p_srcUV + ((((src_height+1)/2+32+63)/64) * (x/32) + (y/64))*4096 + (y%64)*64 + (x%32)*2 +1);
762            }
763           tmp_dstU += dstU_stride - ((src_width));
764    }
765
766    return VA_STATUS_SUCCESS;
767}
768/*
769* Convert the memroy format from tiled to linear
770*/
771static VAStatus tng_unpack_topaz_rec(
772    int src_width, int src_height,
773    unsigned char *p_srcY, unsigned char *p_srcUV,
774    unsigned char *p_dstY, unsigned char *p_dstU, unsigned char *p_dstV,
775    int dstY_stride, int __maybe_unused dstU_stride, int __maybe_unused dstV_stride,
776    int __maybe_unused surface_height)
777{
778    unsigned char *tmp_dstY = p_dstY;
779    unsigned char *tmp_dstU = p_dstU;
780    unsigned char *tmp_dstV = p_dstV;
781    unsigned char *tmp_srcY = p_srcY;
782    unsigned char *tmp_srcX = p_srcUV;
783
784    int i, j, n, t;
785    int mb_src_y_w = src_width >> 4;
786    int mb_src_y_h = src_height >> 5;
787    int mb_src_y_p = src_height - (mb_src_y_h << 5);
788
789    /*  Copy Y data */
790    for (j = 0; j < mb_src_y_h; j++) {
791        tmp_dstY = p_dstY + j * dstY_stride * 32;
792        for (i = 0; i < mb_src_y_w; i++) {
793            for (n = 0; n < 32; n++) {
794                memcpy(tmp_dstY + dstY_stride * n, tmp_srcY,16);
795                tmp_srcY += 16;
796            }
797            tmp_dstY += 16;
798        }
799    }
800
801    if(mb_src_y_p != 0) {
802        tmp_dstY = p_dstY + j * dstY_stride * 32;
803        for (i = 0; i < mb_src_y_w; i++) {
804            for (n = 0; n < mb_src_y_p; n++) {
805                memcpy(tmp_dstY + dstY_stride * n, tmp_srcY,16);
806                tmp_srcY += 16;
807            }
808            for (; n < 32; n++) {
809                tmp_srcY += 16;
810            }
811            tmp_dstY += 16;
812        }
813    }
814
815    for (j = 0; j < mb_src_y_h; j++) {
816        tmp_dstU = p_dstU + j * dstY_stride * 16;
817        for (i = 0; i < mb_src_y_w; i++) {
818            for (n = 0; n < 16; n++) {
819                for (t = 0; t < 16; t++) {
820                    tmp_dstU[(n * dstY_stride) + t] = tmp_srcX[t];
821                }
822                tmp_srcX += 16;
823            }
824            tmp_dstU += 16;
825        }
826    }
827    mb_src_y_p >>= 1;
828    if(mb_src_y_p != 0) {
829        tmp_dstU = p_dstU + j * dstY_stride * 16;
830        for (i = 0; i < mb_src_y_w; i++) {
831            for (n = 0; n < mb_src_y_p; n++) {
832                for (t = 0; t < 16; t++) {
833                   tmp_dstU[(n * dstY_stride) + t] = tmp_srcX[t];
834                }
835                tmp_srcX += 16;
836            }
837
838            for (; n < 16; n++) {
839                tmp_srcX += 16;
840            }
841
842            tmp_dstU += 16;
843        }
844    }
845
846    return VA_STATUS_SUCCESS;
847}
848
849VAStatus psb_GetImage(
850    VADriverContextP ctx,
851    VASurfaceID surface,
852    int x,     /* coordinates of the upper left source pixel */
853    int y,
854    unsigned int width, /* width and height of the region */
855    unsigned int height,
856    VAImageID image_id
857)
858{
859    INIT_DRIVER_DATA;
860    VAStatus vaStatus = VA_STATUS_SUCCESS;
861    int ret, src_x = 0, src_y = 0, dest_x = 0, dest_y = 0;
862
863    (void)driver_data;
864    (void)lnc_unpack_topaz_rec;
865
866    object_image_p obj_image = IMAGE(image_id);
867    CHECK_IMAGE(obj_image);
868
869    if (IS_MFLD(driver_data) && (psb_CheckIEDStatus(ctx) == 1)) {
870        vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
871        return vaStatus;
872    }
873
874    if (obj_image->image.format.fourcc != VA_FOURCC_NV12) {
875        drv_debug_msg(VIDEO_DEBUG_ERROR, "target VAImage fourcc should be NV12 or IYUV\n");
876        vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
877        return vaStatus;
878    }
879
880    object_surface_p obj_surface = SURFACE(surface);
881    CHECK_SURFACE(obj_surface);
882
883    psb__VAImageCheckRegion(obj_surface, &obj_image->image, &src_x, &src_y, &dest_x, &dest_y,
884                            (int *)&width, (int *)&height);
885
886    psb_surface_p psb_surface = obj_surface->psb_surface;
887    unsigned char *surface_data;
888    ret = psb_buffer_map(&psb_surface->buf, &surface_data);
889    if (ret) {
890        return VA_STATUS_ERROR_UNKNOWN;
891    }
892
893    object_buffer_p obj_buffer = BUFFER(obj_image->image.buf);
894    CHECK_BUFFER(obj_buffer);
895
896    unsigned char *image_data;
897    ret = psb_buffer_map(obj_buffer->psb_buffer, &image_data);
898    if (ret) {
899        drv_debug_msg(VIDEO_DEBUG_ERROR, "Map buffer failed\n");
900
901        psb_buffer_unmap(&psb_surface->buf);
902        return VA_STATUS_ERROR_UNKNOWN;
903    }
904
905
906    image_data += obj_surface->psb_surface->buf.buffer_ofs;
907
908
909    switch (obj_image->image.format.fourcc) {
910    case VA_FOURCC_NV12: {
911        unsigned char *src_y, *src_uv, *dst_y, *dst_uv;
912	unsigned char *dst_u, *dst_v;
913        unsigned int i;
914
915	/*
916	 * For reconstructed frame, tiled to linear conversion
917	 * must be done.
918	*/
919	if (obj_surface->is_ref_surface == 1) {
920	    src_y = surface_data + y * psb_surface->stride + x;
921	    src_uv = surface_data + ((height + 0x1f) & (~0x1f)) * width;
922
923	    dst_y = image_data;
924	    dst_u = image_data + obj_image->image.offsets[1],
925	    dst_v = dst_u + (height * width) / 4;
926
927	    tng_unpack_topaz_rec(width, height, \
928				 src_y, src_uv, \
929			         dst_y, dst_u, dst_v, \
930			         obj_image->image.pitches[0], \
931			         obj_image->image.width / 2, \
932			         obj_image->image.width / 2, \
933			         obj_surface->height);
934	} else if (obj_surface->is_ref_surface == 2) {
935	    src_y = surface_data + y * psb_surface->stride + x;
936	    src_uv = surface_data + ((height + 2*32 + 63)/64*64) * ((width  + 2*32 + 63)/64*64);
937	    dst_y = image_data;
938	    dst_u = image_data +  obj_image->image.offsets[1];
939
940	    tng_unpack_vsp_rec(width, height, \
941				 src_y, src_uv, \
942			         dst_y, dst_u, \
943			         obj_image->image.pitches[0], \
944			         obj_image->image.pitches[1], \
945			         obj_image->image.pitches[1], \
946			         obj_surface->height);
947	} else{
948            /* copy Y plane */
949            dst_y = image_data;
950            src_y = surface_data + y * psb_surface->stride + x;
951            for (i = 0; i < height; i++)  {
952		memcpy(dst_y, src_y, width);
953		dst_y += obj_image->image.pitches[0];
954		src_y += psb_surface->stride;
955            }
956
957	    /* copy UV plane */
958	    dst_uv = image_data + obj_image->image.offsets[1];
959            src_uv = surface_data + psb_surface->stride * obj_surface->height + (y / 2) * psb_surface->stride + x;;
960            for (i = 0; i < obj_image->image.height / 2; i++) {
961		memcpy(dst_uv, src_uv, width);
962		dst_uv += obj_image->image.pitches[1];
963		src_uv += psb_surface->stride;
964	    }
965	}
966        break;
967    }
968#if 0
969    case VA_FOURCC_IYUV: {
970        unsigned char *source_y, *dst_y;
971        unsigned char *source_uv, *source_u, *source_v, *dst_u, *dst_v;
972        unsigned int i;
973
974        if (psb_surface->extra_info[4] == VA_FOURCC_IREC) {
975            /* copy Y plane */
976            dst_y = image_data + obj_image->image.offsets[0] + src_y * obj_image->image.pitches[0] + src_x;
977            dst_u = image_data + obj_image->image.offsets[1] + src_y * obj_image->image.pitches[1] + src_x;
978            dst_v = image_data + obj_image->image.offsets[2] + src_y * obj_image->image.pitches[2] + src_x;
979
980            source_y = surface_data + dest_y * psb_surface->stride + dest_x;
981            source_uv = surface_data + obj_surface->height * psb_surface->stride
982                        + dest_y * (psb_surface->stride / 2) + dest_x;
983
984            vaStatus = lnc_unpack_topaz_rec(width, height, source_y, source_uv,
985                                            dst_y, dst_u, dst_v,
986                                            obj_image->image.pitches[0],
987                                            obj_image->image.pitches[1],
988                                            obj_image->image.pitches[2],
989                                            obj_surface->height);
990        }
991
992        break;
993    }
994#endif
995    default:
996        break;
997    }
998    psb_buffer_unmap(obj_buffer->psb_buffer);
999    psb_buffer_unmap(&psb_surface->buf);
1000
1001    return vaStatus;
1002}
1003
1004static VAStatus psb_PutImage2(
1005    VADriverContextP ctx,
1006    VASurfaceID surface,
1007    VAImageID image_id,
1008    int src_x,
1009    int src_y,
1010    unsigned int width,
1011    unsigned int height,
1012    int dest_x,
1013    int dest_y
1014)
1015{
1016    INIT_DRIVER_DATA;
1017    VAStatus vaStatus = VA_STATUS_SUCCESS;
1018    int ret;
1019
1020    object_image_p obj_image = IMAGE(image_id);
1021    CHECK_IMAGE(obj_image);
1022
1023    object_surface_p obj_surface = SURFACE(surface);
1024    CHECK_SURFACE(obj_surface);
1025
1026    if (obj_image->image.format.fourcc != VA_FOURCC_NV12) {
1027        drv_debug_msg(VIDEO_DEBUG_ERROR, "target VAImage fourcc should be NV12 or IYUV\n");
1028        vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
1029        return vaStatus;
1030    }
1031
1032    psb__VAImageCheckRegion(obj_surface, &obj_image->image, &src_x, &src_y, &dest_x, &dest_y,
1033                            (int *)&width, (int *)&height);
1034
1035    psb_surface_p psb_surface = obj_surface->psb_surface;
1036    unsigned char *surface_data;
1037    ret = psb_buffer_map(&psb_surface->buf, &surface_data);
1038    if (ret) {
1039        return VA_STATUS_ERROR_UNKNOWN;
1040    }
1041
1042    object_buffer_p obj_buffer = BUFFER(obj_image->image.buf);
1043    CHECK_BUFFER(obj_buffer);
1044
1045    unsigned char *image_data;
1046    ret = psb_buffer_map(obj_buffer->psb_buffer, &image_data);
1047    if (ret) {
1048        psb_buffer_unmap(&psb_surface->buf);
1049        return VA_STATUS_ERROR_UNKNOWN;
1050    }
1051
1052    image_data += obj_surface->psb_surface->buf.buffer_ofs;
1053
1054    switch (obj_image->image.format.fourcc) {
1055    case VA_FOURCC_NV12: {
1056        unsigned char *source_y, *src_uv, *dst_y, *dst_uv;
1057        unsigned int i;
1058
1059        /* copy Y plane */
1060        source_y = image_data + obj_image->image.offsets[0] + src_y * obj_image->image.pitches[0] + src_x;
1061        dst_y = surface_data + dest_y * psb_surface->stride + dest_x;
1062        for (i = 0; i < height; i++)  {
1063            memcpy(dst_y, source_y, width);
1064            source_y += obj_image->image.pitches[0];
1065            dst_y += psb_surface->stride;
1066        }
1067
1068        /* copy UV plane */
1069        src_uv = image_data + obj_image->image.offsets[1] + (src_y / 2) * obj_image->image.pitches[1] + src_x;
1070        dst_uv = surface_data + psb_surface->stride * obj_surface->height + (dest_y / 2) * psb_surface->stride + dest_x;
1071        for (i = 0; i < obj_image->image.height / 2; i++) {
1072            memcpy(dst_uv, src_uv, width);
1073            src_uv += obj_image->image.pitches[1];
1074            dst_uv += psb_surface->stride;
1075        }
1076        break;
1077    }
1078#if 0
1079    case VA_FOURCC_IYUV: {
1080        char *source_y, *dst_y;
1081        char *source_u, *source_v, *dst_u, *dst_v;
1082        unsigned int i;
1083
1084        /* copy Y plane */
1085        source_y = image_data + obj_image->image.offsets[0] + src_y * obj_image->image.pitches[0] + src_x;
1086        source_u = image_data + obj_image->image.offsets[1] + src_y * obj_image->image.pitches[1] + src_x;
1087        source_v = image_data + obj_image->image.offsets[2] + src_y * obj_image->image.pitches[2] + src_x;
1088
1089        dst_y = surface_data + dest_y * psb_surface->stride + dest_x;
1090        dst_u = surface_data + obj_surface->height * psb_surface->stride
1091                + dest_y * (psb_surface->stride / 2) + dest_x;
1092        dst_v = surface_data + obj_surface->height * psb_surface->stride
1093                + (obj_surface->height / 2) * (psb_surface->stride / 2)
1094                + dest_y * (psb_surface->stride / 2) + dest_x;
1095
1096        for (i = 0; i < height; i++)  {
1097            memcpy(dst_y, source_y, width);
1098            source_y += obj_image->image.pitches[0];
1099            dst_y += psb_surface->stride;
1100        }
1101
1102        /* copy UV plane */
1103        for (i = 0; i < obj_image->image.height / 2; i++) {
1104            memcpy(dst_u, source_u, width);
1105            memcpy(dst_v, source_v, width);
1106
1107            source_u += obj_image->image.pitches[1];
1108            source_v += obj_image->image.pitches[2];
1109
1110            dst_u += psb_surface->stride / 2;
1111            dst_v += psb_surface->stride / 2;
1112        }
1113        break;
1114    }
1115#endif
1116    default:
1117        break;
1118    }
1119
1120    psb_buffer_unmap(obj_buffer->psb_buffer);
1121    psb_buffer_unmap(&psb_surface->buf);
1122
1123    return VA_STATUS_SUCCESS;
1124}
1125
1126
1127static void psb__VAImageCheckRegion2(
1128    object_surface_p surface,
1129    VAImage *image,
1130    int *src_x,
1131    int *src_y,
1132    unsigned int *src_width,
1133    unsigned int *src_height,
1134    int *dest_x,
1135    int *dest_y,
1136    int *dest_width,
1137    int *dest_height
1138)
1139{
1140    /* check for image */
1141    if (*src_x < 0) *src_x = 0;
1142    if (*src_x > image->width) *src_x = image->width - 1;
1143    if (*src_y < 0) *src_y = 0;
1144    if (*src_y > image->height) *src_y = image->height - 1;
1145
1146    if (((*src_width) + (*src_x)) > image->width) *src_width = image->width - *src_x;
1147    if (((*src_height) + (*src_y)) > image->height) *src_height = image->height - *src_x;
1148
1149    /* check for surface */
1150    if (*dest_x < 0) *dest_x = 0;
1151    if (*dest_x > surface->width) *dest_x = surface->width - 1;
1152    if (*dest_y < 0) *dest_y = 0;
1153    if (*dest_y > surface->height) *dest_y = surface->height - 1;
1154
1155    if (((*dest_width) + (*dest_x)) > (int)surface->width) *dest_width = surface->width - *dest_x;
1156    if (((*dest_height) + (*dest_y)) > (int)surface->height) *dest_height = surface->height - *dest_x;
1157}
1158
1159VAStatus psb_PutImage(
1160    VADriverContextP ctx,
1161    VASurfaceID surface,
1162    VAImageID image_id,
1163    int src_x,
1164    int src_y,
1165    unsigned int src_width,
1166    unsigned int src_height,
1167    int dest_x,
1168    int dest_y,
1169    unsigned int dest_width,
1170    unsigned int dest_height
1171)
1172{
1173    INIT_DRIVER_DATA;
1174    VAStatus vaStatus = VA_STATUS_SUCCESS;
1175    int ret;
1176    CHECK_INVALID_PARAM(((int)src_width == -1) ||
1177                        ((int)src_height == -1) ||
1178                        ((int)dest_width == ~0) ||
1179                        ((int)dest_height == ~0));
1180
1181    if ((src_width == dest_width) && (src_height == dest_height)) {
1182        /* Shortcut if scaling is not required */
1183        return psb_PutImage2(ctx, surface, image_id, src_x, src_y, src_width, src_height, dest_x, dest_y);
1184    }
1185
1186    object_image_p obj_image = IMAGE(image_id);
1187    CHECK_IMAGE(obj_image);
1188
1189    if (obj_image->image.format.fourcc != VA_FOURCC_NV12) {
1190        /* only support NV12 getImage/putImage */
1191        vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
1192        return vaStatus;
1193    }
1194
1195    object_surface_p obj_surface = SURFACE(surface);
1196    CHECK_SURFACE(obj_surface);
1197
1198    psb__VAImageCheckRegion2(obj_surface, &obj_image->image,
1199                             &src_x, &src_y, &src_width, &src_height,
1200                             &dest_x, &dest_y, (int *)&dest_width, (int *)&dest_height);
1201
1202    psb_surface_p psb_surface = obj_surface->psb_surface;
1203    unsigned char *surface_data;
1204    ret = psb_buffer_map(&psb_surface->buf, &surface_data);
1205    if (ret) {
1206        return VA_STATUS_ERROR_UNKNOWN;
1207    }
1208
1209    object_buffer_p obj_buffer = BUFFER(obj_image->image.buf);
1210    CHECK_BUFFER(obj_buffer);
1211
1212    unsigned char *image_data;
1213    ret = psb_buffer_map(obj_buffer->psb_buffer, &image_data);
1214    if (ret) {
1215        psb_buffer_unmap(&psb_surface->buf);
1216        return VA_STATUS_ERROR_UNKNOWN;
1217    }
1218
1219    /* just a prototype, the algorithm is ugly and not optimized */
1220    switch (obj_image->image.format.fourcc) {
1221    case VA_FOURCC_NV12: {
1222        unsigned char *source_y, *dst_y;
1223        unsigned short *source_uv, *dst_uv;
1224        unsigned int i, j;
1225        float xratio = (float) src_width / dest_width;
1226        float yratio = (float) src_height / dest_height;
1227
1228        /* dst_y/dst_uv: Y/UV plane of destination */
1229        dst_y = (unsigned char *)(surface_data + dest_y * psb_surface->stride + dest_x);
1230        dst_uv = (unsigned short *)(surface_data + psb_surface->stride * obj_surface->height
1231                                    + (dest_y / 2) * psb_surface->stride + dest_x);
1232
1233        for (j = 0; j < dest_height; j++)  {
1234            unsigned char *dst_y_tmp = dst_y;
1235            unsigned short *dst_uv_tmp = dst_uv;
1236
1237            for (i = 0; i < dest_width; i++)  {
1238                int x = (int)(i * xratio);
1239                int y = (int)(j * yratio);
1240
1241                source_y = image_data + obj_image->image.offsets[0]
1242                           + (src_y + y) * obj_image->image.pitches[0]
1243                           + (src_x + x);
1244                *dst_y_tmp = *source_y;
1245                dst_y_tmp++;
1246
1247                if (((i & 1) == 0)) {
1248                    source_uv = (unsigned short *)(image_data + obj_image->image.offsets[1]
1249                                                   + ((src_y + y) / 2) * obj_image->image.pitches[1])
1250                                + ((src_x + x) / 2);
1251                    *dst_uv_tmp = *source_uv;
1252                    dst_uv_tmp++;
1253                }
1254            }
1255            dst_y += psb_surface->stride;
1256
1257            if (j & 1)
1258                dst_uv = (unsigned short *)((unsigned char *)dst_uv + psb_surface->stride);
1259        }
1260        break;
1261    }
1262    default:/* will not reach here */
1263        break;
1264    }
1265
1266    psb_buffer_unmap(obj_buffer->psb_buffer);
1267    psb_buffer_unmap(&psb_surface->buf);
1268
1269    return VA_STATUS_SUCCESS;
1270}
1271
1272/*
1273 * Link supbicture into one surface, when update is zero, not need to
1274 * update the location information
1275 * The image informatio and its BO of subpicture will copied to surface
1276 * so need to update it when a vaSetSubpictureImage is called
1277 */
1278static VAStatus psb__LinkSubpictIntoSurface(
1279    psb_driver_data_p driver_data,
1280    object_surface_p obj_surface,
1281    object_subpic_p obj_subpic,
1282    short src_x,
1283    short src_y,
1284    unsigned short src_w,
1285    unsigned short src_h,
1286    short dest_x,
1287    short dest_y,
1288    unsigned short dest_w,
1289    unsigned short dest_h,
1290    int update /* update subpicture location */
1291)
1292{
1293    PsbVASurfaceRec *surface_subpic;
1294    object_image_p obj_image = IMAGE(obj_subpic->image_id);
1295    if (NULL == obj_image) {
1296        return VA_STATUS_ERROR_INVALID_IMAGE;
1297    }
1298
1299    VAImage *image = &obj_image->image;
1300    object_buffer_p obj_buffer = BUFFER(image->buf);
1301    if (NULL == obj_buffer) {
1302        return VA_STATUS_ERROR_INVALID_BUFFER;
1303    }
1304
1305    int found = 0;
1306
1307    if (obj_surface->subpictures != NULL) {
1308        surface_subpic = (PsbVASurfaceRec *)obj_surface->subpictures;
1309        do {
1310            if (surface_subpic->subpic_id == obj_subpic->subpic_id) {
1311                found = 1;
1312                break;
1313            } else
1314                surface_subpic = surface_subpic->next;
1315        } while (surface_subpic);
1316    }
1317
1318    if (found == 0) { /* new node */
1319        if (obj_surface->subpic_count >= PSB_SUBPIC_MAX_NUM) {
1320            drv_debug_msg(VIDEO_DEBUG_ERROR, "can't support so many sub-pictures for the surface\n");
1321            return VA_STATUS_ERROR_UNKNOWN;
1322        }
1323
1324        surface_subpic = (PsbVASurfaceRec *)calloc(1, sizeof(*surface_subpic));
1325        if (NULL == surface_subpic)
1326            return VA_STATUS_ERROR_ALLOCATION_FAILED;
1327    }
1328
1329    surface_subpic->subpic_id = obj_subpic->subpic_id;
1330    surface_subpic->fourcc = image->format.fourcc;
1331    surface_subpic->size = image->data_size;
1332    surface_subpic->bo = obj_buffer->psb_buffer->drm_buf;
1333    surface_subpic->bufid = wsbmKBufHandle(wsbmKBuf(obj_buffer->psb_buffer->drm_buf));
1334    surface_subpic->pl_flags = obj_buffer->psb_buffer->pl_flags;
1335    surface_subpic->subpic_flags = obj_subpic->flags;
1336
1337    surface_subpic->width = image->width;
1338    surface_subpic->height = image->height;
1339    switch (surface_subpic->fourcc) {
1340    case VA_FOURCC_AYUV:
1341        surface_subpic->stride = image->pitches[0] / 4;
1342        break;
1343    case VA_FOURCC_RGBA:
1344        surface_subpic->stride = image->pitches[0] / 4;
1345        break;
1346    case VA_FOURCC_AI44:
1347        surface_subpic->stride = image->pitches[0];
1348        /* point to Image palette */
1349        surface_subpic->palette_ptr = (PsbAYUVSample8 *) & obj_image->palette[0];
1350        break;
1351    }
1352
1353    if (update) {
1354        surface_subpic->subpic_srcx = src_x;
1355        surface_subpic->subpic_srcy = src_y;
1356        surface_subpic->subpic_dstx = dest_x;
1357        surface_subpic->subpic_dsty = dest_y;
1358        surface_subpic->subpic_srcw = src_w;
1359        surface_subpic->subpic_srch = src_h;
1360        surface_subpic->subpic_dstw = dest_w;
1361        surface_subpic->subpic_dsth = dest_h;
1362    }
1363
1364    if (found == 0) { /* new node, link into the list */
1365        if (NULL == obj_surface->subpictures) {
1366            obj_surface->subpictures = (void *)surface_subpic;
1367        } else { /* insert as the head */
1368            surface_subpic->next = (PsbVASurfacePtr)obj_surface->subpictures;
1369            obj_surface->subpictures = (void *)surface_subpic;
1370        }
1371        obj_surface->subpic_count++;
1372    }
1373
1374    return VA_STATUS_SUCCESS;
1375}
1376
1377
1378static VAStatus psb__LinkSurfaceIntoSubpict(
1379    object_subpic_p obj_subpic,
1380    VASurfaceID surface_id
1381)
1382{
1383    subpic_surface_s *subpic_surface;
1384    int found = 0;
1385
1386    if (obj_subpic->surfaces != NULL) {
1387        subpic_surface = (subpic_surface_s *)obj_subpic->surfaces;
1388        do  {
1389            if (subpic_surface->surface_id == surface_id) {
1390                found = 1;
1391                return VA_STATUS_SUCCESS; /* reture directly */
1392            } else
1393                subpic_surface = subpic_surface->next;
1394        } while (subpic_surface);
1395    }
1396
1397    /* not found */
1398    subpic_surface = (subpic_surface_s *)calloc(1, sizeof(*subpic_surface));
1399    if (NULL == subpic_surface)
1400        return VA_STATUS_ERROR_ALLOCATION_FAILED;
1401
1402    subpic_surface->surface_id = surface_id;
1403    subpic_surface->next = NULL;
1404
1405    if (NULL == obj_subpic->surfaces) {
1406        obj_subpic->surfaces = (void *)subpic_surface;
1407    } else { /* insert as the head */
1408        subpic_surface->next = (subpic_surface_p)obj_subpic->surfaces;
1409        obj_subpic->surfaces = (void *)subpic_surface;
1410    }
1411
1412    return VA_STATUS_SUCCESS;
1413}
1414
1415static VAStatus psb__DelinkSubpictFromSurface(
1416    object_surface_p obj_surface,
1417    VASubpictureID subpic_id
1418)
1419{
1420    PsbVASurfaceRec *surface_subpic, *pre_surface_subpic = NULL;
1421    int found = 0;
1422
1423    if (obj_surface->subpictures != NULL) {
1424        surface_subpic = (PsbVASurfaceRec *)obj_surface->subpictures;
1425        do  {
1426            if (surface_subpic->subpic_id == subpic_id) {
1427                found = 1;
1428                break;
1429            } else {
1430                pre_surface_subpic = surface_subpic;
1431                surface_subpic = surface_subpic->next;
1432            }
1433        } while (surface_subpic);
1434    }
1435
1436    if (found == 1) {
1437        if (pre_surface_subpic == NULL) { /* remove the first node */
1438            obj_surface->subpictures = (void *)surface_subpic->next;
1439        } else {
1440            pre_surface_subpic->next = surface_subpic->next;
1441        }
1442        free(surface_subpic);
1443        obj_surface->subpic_count--;
1444    }
1445
1446    return VA_STATUS_SUCCESS;
1447}
1448
1449
1450static VAStatus psb__DelinkSurfaceFromSubpict(
1451    object_subpic_p obj_subpic,
1452    VASurfaceID surface_id
1453)
1454{
1455    subpic_surface_s *subpic_surface, *pre_subpic_surface = NULL;
1456    int found = 0;
1457
1458    if (obj_subpic->surfaces != NULL) {
1459        subpic_surface = (subpic_surface_s *)obj_subpic->surfaces;
1460        do {
1461            if (subpic_surface->surface_id == surface_id) {
1462                found = 1;
1463                break;
1464            } else {
1465                pre_subpic_surface = subpic_surface;
1466                subpic_surface = subpic_surface->next;
1467            }
1468        } while (subpic_surface);
1469    }
1470
1471    if (found == 1) {
1472        if (pre_subpic_surface == NULL) { /* remove the first node */
1473            obj_subpic->surfaces = (void *)subpic_surface->next;
1474        } else {
1475            pre_subpic_surface->next = subpic_surface->next;
1476        }
1477        free(subpic_surface);
1478    }
1479
1480    return VA_STATUS_SUCCESS;
1481}
1482
1483
1484VAStatus psb_QuerySubpictureFormats(
1485    VADriverContextP __maybe_unused ctx,
1486    VAImageFormat *format_list,        /* out */
1487    unsigned int *flags,       /* out */
1488    unsigned int *num_formats  /* out */
1489)
1490{
1491    VAStatus vaStatus = VA_STATUS_SUCCESS;
1492
1493    CHECK_INVALID_PARAM(format_list == NULL);
1494    CHECK_INVALID_PARAM(flags == NULL);
1495    CHECK_INVALID_PARAM(num_formats == NULL);
1496
1497    memcpy(format_list, psb__SubpicFormat, sizeof(psb__SubpicFormat));
1498    *num_formats = PSB_MAX_SUBPIC_FORMATS;
1499    *flags = PSB_SUPPORTED_SUBPIC_FLAGS;
1500
1501    return VA_STATUS_SUCCESS;
1502}
1503
1504
1505VAStatus psb_CreateSubpicture(
1506    VADriverContextP ctx,
1507    VAImageID image,
1508    VASubpictureID *subpicture   /* out */
1509)
1510{
1511    INIT_DRIVER_DATA;
1512    VASubpictureID subpicID;
1513    object_subpic_p obj_subpic;
1514    object_image_p obj_image;
1515    VAStatus vaStatus = VA_STATUS_SUCCESS;
1516    VAImageFormat *img_fmt;
1517
1518    obj_image = IMAGE(image);
1519    CHECK_IMAGE(obj_image);
1520    CHECK_SUBPICTURE(subpicture);
1521
1522    img_fmt = psb__VAImageCheckFourCC(&obj_image->image.format, psb__SubpicFormat,
1523                                      sizeof(psb__SubpicFormat) / sizeof(VAImageFormat));
1524    if (img_fmt == NULL)
1525        return VA_STATUS_ERROR_UNKNOWN;
1526
1527    subpicID = object_heap_allocate(&driver_data->subpic_heap);
1528    obj_subpic = SUBPIC(subpicID);
1529    CHECK_ALLOCATION(obj_subpic);
1530
1531    MEMSET_OBJECT(obj_subpic, struct object_subpic_s);
1532
1533    obj_subpic->subpic_id = subpicID;
1534    obj_subpic->image_id = obj_image->image.image_id;
1535    obj_subpic->surfaces = NULL;
1536    obj_subpic->global_alpha = 255;
1537
1538    obj_image->subpic_ref ++;
1539
1540    *subpicture = subpicID;
1541
1542    return VA_STATUS_SUCCESS;
1543}
1544
1545
1546
1547VAStatus psb__destroy_subpicture(psb_driver_data_p driver_data, object_subpic_p obj_subpic)
1548{
1549    subpic_surface_s *subpic_surface = (subpic_surface_s *)obj_subpic->surfaces;
1550    VASubpictureID subpicture = obj_subpic->subpic_id;
1551
1552    if (subpic_surface) {
1553        do {
1554            subpic_surface_s *tmp = subpic_surface;
1555            object_surface_p obj_surface = SURFACE(subpic_surface->surface_id);
1556
1557            if (obj_surface) { /* remove subpict from surface */
1558                psb__DelinkSubpictFromSurface(obj_surface, subpicture);
1559            }
1560            subpic_surface = subpic_surface->next;
1561            free(tmp);
1562        } while (subpic_surface);
1563    }
1564
1565    object_heap_free(&driver_data->subpic_heap, (object_base_p) obj_subpic);
1566    return VA_STATUS_SUCCESS;
1567}
1568
1569
1570VAStatus psb_DestroySubpicture(
1571    VADriverContextP ctx,
1572    VASubpictureID subpicture
1573)
1574{
1575    INIT_DRIVER_DATA;
1576    object_subpic_p obj_subpic;
1577    VAStatus vaStatus = VA_STATUS_SUCCESS;
1578
1579    obj_subpic = SUBPIC(subpicture);
1580    CHECK_SUBPICTURE(obj_subpic);
1581
1582    return psb__destroy_subpicture(driver_data, obj_subpic);
1583}
1584
1585VAStatus psb_SetSubpictureImage(
1586    VADriverContextP ctx,
1587    VASubpictureID subpicture,
1588    VAImageID image
1589)
1590{
1591    INIT_DRIVER_DATA;
1592    object_subpic_p obj_subpic;
1593    object_image_p obj_image;
1594    VAStatus vaStatus = VA_STATUS_SUCCESS;
1595    subpic_surface_s *subpic_surface;
1596    VAImageFormat *img_fmt;
1597
1598    obj_image = IMAGE(image);
1599    CHECK_IMAGE(obj_image);
1600
1601    img_fmt = psb__VAImageCheckFourCC(&obj_image->image.format,
1602                                      psb__SubpicFormat,
1603                                      sizeof(psb__SubpicFormat) / sizeof(VAImageFormat));
1604    CHECK_IMAGE(img_fmt);
1605
1606    obj_subpic = SUBPIC(subpicture);
1607    CHECK_SUBPICTURE(obj_subpic);
1608
1609    object_image_p old_obj_image = IMAGE(obj_subpic->image_id);
1610    if (old_obj_image) {
1611        old_obj_image->subpic_ref--;/* decrease reference count */
1612    }
1613
1614    /* reset the image */
1615    obj_subpic->image_id = obj_image->image.image_id;
1616    obj_image->subpic_ref ++;
1617
1618    /* relink again */
1619    if (obj_subpic->surfaces != NULL) {
1620        /* the subpicture already linked into surfaces
1621         * so not check the return value of psb__LinkSubpictIntoSurface
1622         */
1623        subpic_surface = (subpic_surface_s *)obj_subpic->surfaces;
1624        do {
1625            object_surface_p obj_surface = SURFACE(subpic_surface->surface_id);
1626            CHECK_SURFACE(obj_surface);
1627
1628            psb__LinkSubpictIntoSurface(driver_data, obj_surface, obj_subpic,
1629                                        0, 0, 0, 0, 0, 0, 0, 0,
1630                                        0 /* not update location */
1631                                       );
1632            subpic_surface = subpic_surface->next;
1633        } while (subpic_surface);
1634    }
1635
1636
1637    return VA_STATUS_SUCCESS;
1638}
1639
1640
1641VAStatus psb_SetSubpictureChromakey(
1642    VADriverContextP ctx,
1643    VASubpictureID subpicture,
1644    unsigned int chromakey_min,
1645    unsigned int chromakey_max,
1646    unsigned int chromakey_mask
1647)
1648{
1649    INIT_DRIVER_DATA;
1650    (void)driver_data;
1651    /* TODO */
1652    if ((chromakey_mask < chromakey_min) || (chromakey_mask > chromakey_max)) {
1653        drv_debug_msg(VIDEO_DEBUG_ERROR, "Invalid chromakey value %d, chromakey value should between min and max\n", chromakey_mask);
1654        return VA_STATUS_ERROR_INVALID_PARAMETER;
1655    }
1656    object_subpic_p obj_subpic = SUBPIC(subpicture);
1657    if (NULL == obj_subpic) {
1658        drv_debug_msg(VIDEO_DEBUG_ERROR, "Invalid subpicture value %d\n", subpicture);
1659        return VA_STATUS_ERROR_INVALID_SUBPICTURE;
1660    }
1661
1662    return VA_STATUS_SUCCESS;
1663}
1664
1665VAStatus psb_SetSubpictureGlobalAlpha(
1666    VADriverContextP ctx,
1667    VASubpictureID subpicture,
1668    float global_alpha
1669)
1670{
1671    INIT_DRIVER_DATA;
1672
1673    if (global_alpha < 0 || global_alpha > 1) {
1674        drv_debug_msg(VIDEO_DEBUG_ERROR, "Invalid global alpha value %07f, global alpha value should between 0 and 1\n", global_alpha);
1675        return VA_STATUS_ERROR_INVALID_PARAMETER;
1676    }
1677
1678    object_subpic_p obj_subpic = SUBPIC(subpicture);
1679    if (NULL == obj_subpic) {
1680        drv_debug_msg(VIDEO_DEBUG_ERROR, "Invalid subpicture value %d\n", subpicture);
1681        return VA_STATUS_ERROR_INVALID_SUBPICTURE;
1682    }
1683
1684    obj_subpic->global_alpha = global_alpha * 255;
1685
1686    return VA_STATUS_SUCCESS;
1687}
1688
1689
1690VAStatus psb__AssociateSubpicture(
1691    VADriverContextP ctx,
1692    VASubpictureID subpicture,
1693    VASurfaceID *target_surfaces,
1694    int num_surfaces,
1695    short src_x, /* upper left offset in subpicture */
1696    short src_y,
1697    unsigned short src_w,
1698    unsigned short src_h,
1699    short dest_x, /* upper left offset in surface */
1700    short dest_y,
1701    unsigned short dest_w,
1702    unsigned short dest_h,
1703    /*
1704     * whether to enable chroma-keying or global-alpha
1705     * see VA_SUBPICTURE_XXX values
1706     */
1707    unsigned int flags
1708)
1709{
1710    INIT_DRIVER_DATA;
1711
1712    object_subpic_p obj_subpic;
1713    VAStatus vaStatus = VA_STATUS_SUCCESS;
1714    int i;
1715
1716    CHECK_INVALID_PARAM(num_surfaces <= 0);
1717
1718    obj_subpic = SUBPIC(subpicture);
1719    CHECK_SUBPICTURE(obj_subpic);
1720    CHECK_SURFACE(target_surfaces);
1721
1722    if (flags & ~PSB_SUPPORTED_SUBPIC_FLAGS) {
1723#ifdef VA_STATUS_ERROR_FLAG_NOT_SUPPORTED
1724        vaStatus = VA_STATUS_ERROR_FLAG_NOT_SUPPORTED;
1725#else
1726        vaStatus = VA_STATUS_ERROR_UNKNOWN;
1727#endif
1728        DEBUG_FAILURE;
1729        return vaStatus;
1730    } else {
1731
1732        /* If flags are ok, copy them to the subpicture object */
1733        obj_subpic->flags = flags;
1734
1735    }
1736
1737    /* Validate input params */
1738    for (i = 0; i < num_surfaces; i++) {
1739        object_surface_p obj_surface = SURFACE(target_surfaces[i]);
1740        CHECK_SURFACE(obj_surface);
1741    }
1742
1743    VASurfaceID *surfaces = target_surfaces;
1744    for (i = 0; i < num_surfaces; i++) {
1745        object_surface_p obj_surface = SURFACE(*surfaces);
1746        if (obj_surface) {
1747            vaStatus = psb__LinkSubpictIntoSurface(driver_data, obj_surface, obj_subpic,
1748                                                   src_x, src_y, src_w, src_h,
1749                                                   dest_x, dest_y, dest_w, dest_h, 1);
1750            if (VA_STATUS_SUCCESS == vaStatus) {
1751                vaStatus = psb__LinkSurfaceIntoSubpict(obj_subpic, *surfaces);
1752            }
1753            CHECK_VASTATUS();/* failed with malloc */
1754        } else {
1755            /* Should never get here */
1756            drv_debug_msg(VIDEO_DEBUG_ERROR, "Invalid surfaces,SurfaceID=0x%x\n", *surfaces);
1757        }
1758
1759        surfaces++;
1760    }
1761
1762    return VA_STATUS_SUCCESS;
1763}
1764
1765
1766VAStatus psb_AssociateSubpicture(
1767    VADriverContextP ctx,
1768    VASubpictureID subpicture,
1769    VASurfaceID *target_surfaces,
1770    int num_surfaces,
1771    short src_x, /* upper left offset in subpicture */
1772    short src_y,
1773    unsigned short src_width,
1774    unsigned short src_height,
1775    short dest_x, /* upper left offset in surface */
1776    short dest_y,
1777    unsigned short dest_width,
1778    unsigned short dest_height,
1779    /*
1780     * whether to enable chroma-keying or global-alpha
1781     * see VA_SUBPICTURE_XXX values
1782     */
1783    unsigned int flags
1784)
1785{
1786    return psb__AssociateSubpicture(ctx, subpicture, target_surfaces, num_surfaces,
1787                                    src_x, src_y, src_width, src_height,
1788                                    dest_x, dest_y, dest_width, dest_height,
1789                                    flags
1790                                   );
1791}
1792
1793
1794VAStatus psb_DeassociateSubpicture(
1795    VADriverContextP ctx,
1796    VASubpictureID subpicture,
1797    VASurfaceID *target_surfaces,
1798    int num_surfaces
1799)
1800{
1801    INIT_DRIVER_DATA;
1802
1803    object_subpic_p obj_subpic;
1804    VAStatus vaStatus = VA_STATUS_SUCCESS;
1805    object_image_p obj_image;
1806    int i;
1807
1808    CHECK_INVALID_PARAM(num_surfaces <= 0);
1809
1810    obj_subpic = SUBPIC(subpicture);
1811    CHECK_SUBPICTURE(obj_subpic);
1812    CHECK_SURFACE(target_surfaces);
1813
1814    VASurfaceID *surfaces = target_surfaces;
1815    for (i = 0; i < num_surfaces; i++) {
1816        object_surface_p obj_surface = SURFACE(*surfaces);
1817
1818        if (obj_surface) {
1819            psb__DelinkSubpictFromSurface(obj_surface, subpicture);
1820            psb__DelinkSurfaceFromSubpict(obj_subpic, obj_surface->surface_id);
1821        } else {
1822            drv_debug_msg(VIDEO_DEBUG_ERROR, "vaDeassociateSubpicture: Invalid surface, VASurfaceID=0x%08x\n", *surfaces);
1823        }
1824
1825        surfaces++;
1826    }
1827
1828    obj_image = IMAGE(obj_subpic->image_id);
1829    if (obj_image)
1830        obj_image->subpic_ref--;/* decrease reference count */
1831
1832    return VA_STATUS_SUCCESS;
1833}
1834
1835
1836void psb_SurfaceDeassociateSubpict(
1837    psb_driver_data_p driver_data,
1838    object_surface_p obj_surface
1839)
1840{
1841    PsbVASurfaceRec *surface_subpic = (PsbVASurfaceRec *)obj_surface->subpictures;
1842
1843    if (surface_subpic != NULL) {
1844        do  {
1845            PsbVASurfaceRec *tmp = surface_subpic;
1846            object_subpic_p obj_subpic = SUBPIC(surface_subpic->subpic_id);
1847            if (obj_subpic)
1848                psb__DelinkSurfaceFromSubpict(obj_subpic, obj_surface->surface_id);
1849            surface_subpic = surface_subpic->next;
1850            free(tmp);
1851        } while (surface_subpic);
1852    }
1853}
1854
1855
1856static  VADisplayAttribute psb__DisplayAttribute[] = {
1857    {
1858        VADisplayAttribBrightness,
1859        BRIGHTNESS_MIN,
1860        BRIGHTNESS_MAX,
1861        BRIGHTNESS_DEFAULT_VALUE,
1862        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE,
1863        NULL
1864    },
1865
1866    {
1867        VADisplayAttribContrast,
1868        CONTRAST_MIN,
1869        CONTRAST_MAX,
1870        CONTRAST_DEFAULT_VALUE,
1871        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE,
1872        NULL
1873    },
1874
1875    {
1876        VADisplayAttribHue,
1877        HUE_MIN,
1878        HUE_MAX,
1879        HUE_DEFAULT_VALUE,
1880        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE,
1881        NULL
1882    },
1883
1884    {
1885        VADisplayAttribSaturation,
1886        SATURATION_MIN,
1887        SATURATION_MAX,
1888        SATURATION_DEFAULT_VALUE,
1889        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE,
1890        NULL
1891    },
1892    {
1893        VADisplayAttribBackgroundColor,
1894        0x00000000,
1895        0xffffffff,
1896        0x00000000,
1897        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE,
1898        NULL
1899    },
1900    {
1901        VADisplayAttribRotation,
1902        VA_ROTATION_NONE,
1903        VA_ROTATION_270,
1904        VA_ROTATION_NONE,
1905        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE,
1906        NULL
1907    },
1908    {
1909        VADisplayAttribOutofLoopDeblock,
1910        VA_OOL_DEBLOCKING_FALSE,
1911        VA_OOL_DEBLOCKING_TRUE,
1912        VA_OOL_DEBLOCKING_FALSE,
1913        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE,
1914        NULL
1915    },
1916    {
1917        VADisplayAttribBlendColor,
1918        0x00000000,
1919        0xffffffff,
1920        0x00000000,
1921        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE,
1922        NULL
1923    },
1924    {
1925        VADisplayAttribOverlayColorKey,
1926        0x00000000,
1927        0xffffffff,
1928        0x00000000,
1929        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE,
1930        NULL
1931    },
1932    {
1933        VADisplayAttribOverlayAutoPaintColorKey,
1934        0x00000000,
1935        0xffffffff,
1936        0x00000000,
1937        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE,
1938        NULL
1939    },
1940    {
1941        VADisplayAttribCSCMatrix,
1942        0x00000000,
1943        0xffffffff,
1944        0x00000000,
1945        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE,
1946        NULL
1947    },
1948    {
1949        VADisplayAttribRenderDevice,
1950        0x00000000,
1951        0xffffffff,
1952        0x00000000,
1953        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE,
1954        NULL
1955    },
1956    {
1957        VADisplayAttribRenderMode,
1958        0x00000000,
1959        0xffffffff,
1960        0x00000000,
1961        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE,
1962        NULL
1963    },
1964    {
1965        VADisplayAttribRenderRect,
1966        0x00000000,
1967        0xffffffff,
1968        0x00000000,
1969        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE,
1970        NULL
1971    }
1972};
1973
1974/*
1975 * Query display attributes
1976 * The caller must provide a "attr_list" array that can hold at
1977 * least vaMaxNumDisplayAttributes() entries. The actual number of attributes
1978 * returned in "attr_list" is returned in "num_attributes".
1979 */
1980VAStatus psb_QueryDisplayAttributes(
1981    VADriverContextP __maybe_unused ctx,
1982    VADisplayAttribute *attr_list,      /* out */
1983    int *num_attributes         /* out */
1984)
1985{
1986    VAStatus vaStatus = VA_STATUS_SUCCESS;
1987
1988    CHECK_INVALID_PARAM(attr_list == NULL);
1989    CHECK_INVALID_PARAM(num_attributes == NULL);
1990
1991    *num_attributes = min(*num_attributes, PSB_MAX_DISPLAY_ATTRIBUTES);
1992    memcpy(attr_list, psb__DisplayAttribute, (*num_attributes)*sizeof(VADisplayAttribute));
1993    return VA_STATUS_SUCCESS;
1994}
1995
1996/*
1997 * Get display attributes
1998 * This function returns the current attribute values in "attr_list".
1999 * Only attributes returned with VA_DISPLAY_ATTRIB_GETTABLE set in the "flags" field
2000 * from vaQueryDisplayAttributes() can have their values retrieved.
2001 */
2002VAStatus psb_GetDisplayAttributes(
2003    VADriverContextP ctx,
2004    VADisplayAttribute *attr_list,      /* in/out */
2005    int num_attributes
2006)
2007{
2008    INIT_DRIVER_DATA;
2009    VADisplayAttribute *p = attr_list;
2010    int i;
2011    VAStatus vaStatus = VA_STATUS_SUCCESS;
2012
2013    CHECK_INVALID_PARAM(attr_list == NULL);
2014    CHECK_INVALID_PARAM(num_attributes <= 0);
2015
2016    for (i = 0; i < num_attributes; i++) {
2017        switch (p->type) {
2018        case VADisplayAttribBrightness:
2019            /* -50*(1<<10) ~ 50*(1<<10) ==> 0~100*/
2020            p->value = (driver_data->brightness.value / (1 << 10)) + 50;
2021            p->min_value = 0;
2022            p->max_value = 100;
2023            break;
2024        case VADisplayAttribContrast:
2025            /* 0 ~ 2*(1<<25) ==> 0~100 */
2026            p->value = (driver_data->contrast.value / (1 << 25)) * 50;
2027            p->min_value = 0;
2028            p->max_value = 100;
2029            break;
2030        case VADisplayAttribHue:
2031            /* -30*(1<<25) ~ 30*(1<<25) ==> 0~100*/
2032            p->value = ((driver_data->hue.value / (1 << 25)) + 30) * 10 / 6;
2033            p->min_value = 0;
2034            p->max_value = 100;
2035            break;
2036        case VADisplayAttribSaturation:
2037            /* 0 ~ 2*(1<<25) ==> 0~100 */
2038            p->value = (driver_data->saturation.value / (1 << 25)) * 50;
2039            p->min_value = 0;
2040            p->max_value = 100;
2041            break;
2042        case VADisplayAttribBackgroundColor:
2043            p->value = driver_data->clear_color;
2044            break;
2045        case VADisplayAttribBlendColor:
2046            p->value = driver_data->blend_color;
2047            break;
2048        case VADisplayAttribOverlayColorKey:
2049            p->value = driver_data->color_key;
2050            p->min_value = 0;
2051            p->max_value = 0xFFFFFF;
2052            break;
2053        case VADisplayAttribOverlayAutoPaintColorKey:
2054            p->value = driver_data->overlay_auto_paint_color_key;
2055            p->min_value = 0;
2056            p->max_value = 1;
2057            break;
2058        case VADisplayAttribRotation:
2059            p->value = driver_data->va_rotate = p->value;
2060            p->min_value = VA_ROTATION_NONE;
2061            p->max_value = VA_ROTATION_270;
2062            break;
2063        case VADisplayAttribOutofLoopDeblock:
2064            p->value = driver_data->is_oold = p->value;
2065            p->min_value = VA_OOL_DEBLOCKING_FALSE;
2066            p->max_value = VA_OOL_DEBLOCKING_TRUE;
2067            break;
2068        case VADisplayAttribCSCMatrix:
2069            p->value = driver_data->load_csc_matrix = p->value;
2070            p->min_value = 0;
2071            p->max_value = 255;
2072            break;
2073        case VADisplayAttribRenderDevice:
2074            p->value = driver_data->render_device = p->value;
2075            p->min_value = 0;
2076            p->max_value = 255;
2077            break;
2078        case VADisplayAttribRenderMode:
2079            p->value = driver_data->render_mode = p->value;
2080            p->min_value = 0;
2081            p->max_value = 255;
2082            break;
2083        case VADisplayAttribRenderRect:
2084            ((VARectangle *)(p->value))->x = driver_data->render_rect.x = ((VARectangle *)(p->value))->x;
2085            ((VARectangle *)(p->value))->y = driver_data->render_rect.y = ((VARectangle *)(p->value))->y;
2086            ((VARectangle *)(p->value))->width = driver_data->render_rect.width = ((VARectangle *)(p->value))->width;
2087            ((VARectangle *)(p->value))->height = driver_data->render_rect.height = ((VARectangle *)(p->value))->height;
2088            p->min_value = 0;
2089            p->max_value = 255;
2090            break;
2091
2092        default:
2093            break;
2094        }
2095        p++;
2096    }
2097
2098    return VA_STATUS_SUCCESS;
2099}
2100
2101/*
2102 * Set display attributes
2103 * Only attributes returned with VA_DISPLAY_ATTRIB_SETTABLE set in the "flags" field
2104 * from vaQueryDisplayAttributes() can be set.  If the attribute is not settable or
2105 * the value is out of range, the function returns VA_STATUS_ERROR_ATTR_NOT_SUPPORTED
2106 */
2107#define CLAMP_ATTR(a,max,min) (a>max?max:(a<min?min:a))
2108VAStatus psb_SetDisplayAttributes(
2109    VADriverContextP ctx,
2110    VADisplayAttribute *attr_list,
2111    int num_attributes
2112)
2113{
2114    INIT_DRIVER_DATA;
2115    VAStatus vaStatus = VA_STATUS_SUCCESS;
2116    struct psb_texture_s *texture_priv = &driver_data->ctexture_priv;
2117    PsbPortPrivPtr overlay_priv = (PsbPortPrivPtr)(&driver_data->coverlay_priv);
2118    int j, k;
2119
2120    CHECK_INVALID_PARAM(attr_list == NULL);
2121
2122    VADisplayAttribute *p = attr_list;
2123    int i, update_coeffs = 0;
2124    float *p_tmp;
2125
2126    if (num_attributes <= 0) {
2127        return VA_STATUS_ERROR_INVALID_PARAMETER;
2128    }
2129
2130    for (i = 0; i < num_attributes; i++) {
2131        switch (p->type) {
2132        case VADisplayAttribBrightness:
2133            /* 0~100 ==> -50*(1<<10) ~ 50*(1<<10)*/
2134            driver_data->brightness.value = (p->value - 50) * (1 << 10);
2135            /* 0~100 ==> -50~50 */
2136            overlay_priv->brightness.Value = texture_priv->brightness.Value = p->value - 50;
2137            update_coeffs = 1;
2138            break;
2139        case VADisplayAttribContrast:
2140            /* 0~100 ==> 0 ~ 2*(1<<25) */
2141            driver_data->contrast.value = (p->value / 50) * (1 << 25);
2142            /* 0~100 ==> -100~100 */
2143            overlay_priv->contrast.Value = texture_priv->contrast.Value = p->value * 2 - 100;
2144            update_coeffs = 1;
2145            break;
2146        case VADisplayAttribHue:
2147            /* 0~100 ==> -30*(1<<25) ~ 30*(1<<25) */
2148            driver_data->hue.value = ((p->value * 2 - 100) * 3 / 10) * (1 << 25);
2149            /* 0~100 ==> -30~30 */
2150            overlay_priv->hue.Value = texture_priv->hue.Value = (p->value * 2 - 100) * 3 / 10;
2151            update_coeffs = 1;
2152            break;
2153        case VADisplayAttribSaturation:
2154            /* 0~100 ==> 0 ~ 2*(1<<25) */
2155            driver_data->contrast.value = (p->value / 50) * (1 << 25);
2156            /* 0~100 ==> 100~200 */
2157            overlay_priv->saturation.Value = texture_priv->saturation.Value = p->value + 100;
2158            update_coeffs = 1;
2159            break;
2160        case VADisplayAttribBackgroundColor:
2161            driver_data->clear_color = p->value;
2162            break;
2163        case VADisplayAttribOutofLoopDeblock:
2164            driver_data->is_oold = p->value;
2165            break;
2166        case VADisplayAttribRotation:
2167            driver_data->va_rotate = p->value;
2168            driver_data->rotation_dirty |= PSB_NEW_VA_ROTATION;
2169            break;
2170
2171        case VADisplayAttribCSCMatrix:
2172            driver_data->load_csc_matrix = 1;
2173            p_tmp = (float *)(p->attrib_ptr);
2174            for (j = 0; j < CSC_MATRIX_Y; j++)
2175                for (k = 0; k < CSC_MATRIX_X; k++) {
2176                    if (p_tmp)
2177                        driver_data->csc_matrix[j][k] = *p_tmp;
2178                   p_tmp++;
2179                }
2180
2181            for (j = 0; j < CSC_MATRIX_Y; j++)
2182                for (k = 0; k < CSC_MATRIX_X; k++) {
2183                    if (fabs(s601[j*CSC_MATRIX_X+k] - driver_data->csc_matrix[j][k]) > 1e-6) {
2184                        break;
2185                    }
2186                    if (k < CSC_MATRIX_X) {
2187                        break;
2188                    }
2189                }
2190
2191            if (j == CSC_MATRIX_Y && k == CSC_MATRIX_X) {
2192                driver_data->is_BT601 = 1;
2193            }
2194            break;
2195
2196        case VADisplayAttribColorRange:
2197            driver_data->set_video_range = 1;
2198            driver_data->video_range = (p->value == VA_SOURCE_RANGE_FULL);
2199            break;
2200
2201        case VADisplayAttribBlendColor:
2202            driver_data->blend_color = p->value;
2203            break;
2204        case VADisplayAttribOverlayColorKey:
2205            overlay_priv->colorKey = driver_data->color_key = p->value;
2206            break;
2207        case VADisplayAttribOverlayAutoPaintColorKey:
2208            driver_data->overlay_auto_paint_color_key = p->value;
2209            break;
2210
2211        case VADisplayAttribRenderDevice:
2212            driver_data->render_device = p->value & VA_RENDER_DEVICE_MASK;
2213        case VADisplayAttribRenderMode:
2214#ifndef ANDROID
2215            if (p->value & VA_RENDER_MODE_EXTERNAL_GPU) {
2216                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s:Invalid parameter.VARenderModeExternalGPU is not supported.\n", __FUNCTION__);
2217                return VA_STATUS_ERROR_INVALID_PARAMETER;
2218            }
2219            if (((p->value & VA_RENDER_MODE_LOCAL_OVERLAY) && (p->value & VA_RENDER_MODE_LOCAL_GPU)) ||
2220                ((p->value & VA_RENDER_MODE_EXTERNAL_OVERLAY) && (p->value & VA_RENDER_MODE_EXTERNAL_GPU))) {
2221                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s:Invalid parameter. Conflict setting for VADisplayAttribRenderMode.\n", __FUNCTION__);
2222                return VA_STATUS_ERROR_INVALID_PARAMETER;
2223            }
2224#endif
2225            driver_data->render_mode = p->value & VA_RENDER_MODE_MASK;
2226            break;
2227        case VADisplayAttribRenderRect:
2228            driver_data->render_rect.x = ((VARectangle *)(p->attrib_ptr))->x;
2229            driver_data->render_rect.y = ((VARectangle *)(p->attrib_ptr))->y;
2230            driver_data->render_rect.width = ((VARectangle *)(p->attrib_ptr))->width;
2231            driver_data->render_rect.height = ((VARectangle *)(p->attrib_ptr))->height;
2232            break;
2233
2234        default:
2235            break;
2236        }
2237        p++;
2238    }
2239
2240    if (update_coeffs) {
2241        /* TODO */
2242#ifndef ANDROID
2243        texture_priv->update_coeffs = 1;
2244#endif
2245    }
2246
2247    return VA_STATUS_SUCCESS;
2248}
2249
2250