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