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 *    Zhaohan Ren  <zhaohan.ren@intel.com>
26 *    Shengquan Yuan  <shengquan.yuan@intel.com>
27 *    Jiang Fei <jiang.fei@intel.com>
28 *    Binglin Chen <binglin.chen@intel.com>
29 *
30 */
31#include <va/va_backend.h>
32#include "psb_output.h"
33#include "psb_surface.h"
34#include "psb_buffer.h"
35#include "psb_overlay.h"
36#include "psb_texture.h"
37#include <stdio.h>
38#include <string.h>
39#include <stdarg.h>
40#include "psb_android_glue.h"
41#include "psb_output_android.h"
42#ifndef BAYTRAIL
43#include "psb_HDMIExtMode.h"
44#endif
45#include "pnw_rotate.h"
46#include "psb_drv_debug.h"
47#include <wsbm/wsbm_manager.h>
48#include <hardware.h>
49
50#define INIT_DRIVER_DATA    psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData;
51#define INIT_OUTPUT_PRIV    psb_android_output_p output = (psb_android_output_p)(((psb_driver_data_p)ctx->pDriverData)->ws_priv)
52
53#define SURFACE(id) ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id ))
54#define BUFFER(id)  ((object_buffer_p) object_heap_lookup( &driver_data->buffer_heap, id ))
55#define IMAGE(id)  ((object_image_p) object_heap_lookup( &driver_data->image_heap, id ))
56#define SUBPIC(id)  ((object_subpic_p) object_heap_lookup( &driver_data->subpic_heap, id ))
57#define CONTEXT(id) ((object_context_p) object_heap_lookup( &driver_data->context_heap, id ))
58
59#define GET_SURFACE_INFO_rotate(psb_surface) ((int) psb_surface->extra_info[5])
60#define GET_SURFACE_INFO_protect(psb_surface) ((int) psb_surface->extra_info[6])
61#define MAX_OVERLAY_IDLE_FRAME 4
62
63enum {
64    eWidiOff             = 1,
65    eWidiClone           = 2,
66    eWidiExtendedVideo   = 3,
67};
68extern unsigned int update_forced;
69
70inline int va2hw_rotation(int va_rotate)
71{
72    switch (va_rotate) {
73    case VA_ROTATION_90:
74        return HAL_TRANSFORM_ROT_270;
75    case VA_ROTATION_180:
76        return HAL_TRANSFORM_ROT_180;
77    case VA_ROTATION_270:
78        return HAL_TRANSFORM_ROT_90;
79    defaut:
80        return 0;
81    }
82
83    return 0;
84}
85
86unsigned char *psb_android_output_init(VADriverContextP ctx)
87{
88    INIT_DRIVER_DATA;
89    char put_surface[1024];
90    psb_android_output_p output = calloc(1, sizeof(psb_android_output_s));
91    struct fb_var_screeninfo vinfo;
92    int fbfd = -1;
93
94    if (output == NULL) {
95        drv_debug_msg(VIDEO_DEBUG_ERROR, "Can't malloc memory\n");
96        return NULL;
97    }
98    memset(output, 0, sizeof(psb_android_output_s));
99
100    /* Guess the screen size */
101    output->screen_width = 800;
102    output->screen_height = 480;
103
104    // Open the frame buffer for reading
105    memset(&vinfo, 0, sizeof(vinfo));
106    fbfd = open("/dev/graphics/fb0", O_RDONLY);
107    if (fbfd) {
108        if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))
109            drv_debug_msg(VIDEO_DEBUG_GENERAL, "Error reading screen information.\n");
110    }
111    close(fbfd);
112    output->screen_width = vinfo.xres;
113    output->screen_height = vinfo.yres;
114
115    /* TS by default */
116    driver_data->output_method = PSB_PUTSURFACE_OVERLAY;
117    driver_data->color_key = 0x000001; /*light blue*/
118
119    if (psb_parse_config("PSB_VIDEO_CTEXTURES", &put_surface[0]) == 0) {
120        drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB_VIDEO_CTEXTURES is enabled for vaPutSurfaceBuf\n");
121        driver_data->ctexture = 1; /* Init CTEXTURE for vaPutSurfaceBuf */
122    }
123
124    if (psb_parse_config("PSB_VIDEO_COVERLAY", &put_surface[0]) == 0) {
125        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Putsurface use client overlay\n");
126        driver_data->output_method = PSB_PUTSURFACE_FORCE_COVERLAY;
127    }
128
129    driver_data->coverlay = 1;
130
131    return (unsigned char *)output;
132}
133
134VAStatus psb_android_output_deinit(VADriverContextP ctx)
135{
136    INIT_DRIVER_DATA;
137    INIT_OUTPUT_PRIV;
138    //psb_android_output_p output = GET_OUTPUT_DATA(ctx);
139#ifdef TARGET_HAS_MULTIPLE_DISPLAY
140    if (output->mds != NULL) {
141        deinit_mds_listener(output);
142    }
143#endif
144    return VA_STATUS_SUCCESS;
145}
146
147#ifndef BAYTRAIL
148static VAStatus psb_putsurface_ctexture(
149    VADriverContextP ctx,
150    VASurfaceID surface,
151    unsigned char* data,
152    short srcx,
153    short srcy,
154    unsigned short srcw,
155    unsigned short srch,
156    short destx,
157    short desty,
158    unsigned short destw,
159    unsigned short desth,
160    unsigned int __maybe_unused flags /* de-interlacing flags */
161)
162{
163    INIT_DRIVER_DATA;
164    INIT_OUTPUT_PRIV;
165    object_surface_p obj_surface;
166    int offset = 0;
167    psb_surface_p psb_surface;
168    VAStatus vaStatus = VA_STATUS_SUCCESS;
169
170    obj_surface = SURFACE(surface);
171    CHECK_SURFACE(obj_surface);
172    psb_surface = obj_surface->psb_surface;
173
174    //    psb_surface->buf.drm_buf;
175    //    psb_surface->buf.pl_flags;
176    psb_putsurface_textureblit(ctx, data, surface, srcx, srcy, srcw, srch,
177                               destx, desty, destw, desth, 0, /* no subtitle */
178                               obj_surface->width, obj_surface->height,
179                               psb_surface->stride, psb_surface->buf.drm_buf,
180                               psb_surface->buf.pl_flags, 1 /* need wrap dst */);
181
182    psb_android_postBuffer(offset);
183
184    return VA_STATUS_SUCCESS;
185}
186#endif
187
188#if 0
189VAStatus psb_putsurface_coverlay(
190    VADriverContextP ctx,
191    VASurfaceID surface,
192    short srcx,
193    short srcy,
194    unsigned short srcw,
195    unsigned short srch,
196    short destx, /* screen cooridination */
197    short desty,
198    unsigned short destw,
199    unsigned short desth,
200    unsigned int flags /* de-interlacing flags */
201)
202{
203    INIT_OUTPUT_PRIV;
204    VAStatus vaStatus = VA_STATUS_SUCCESS;
205
206    /* USE_FIT_SCR_SIZE */
207    /* calculate fit screen size of frame */
208    unsigned short _scr_x = output->screen_width;
209    unsigned short _scr_y = output->screen_height;
210    float _slope_xy = (float)srch / srcw;
211    unsigned short _destw = (short)(_scr_y / _slope_xy);
212    unsigned short _desth = (short)(_scr_x * _slope_xy);
213    short _pos_x, _pos_y;
214
215    if (_destw <= _scr_x) {
216        _desth = _scr_y;
217        _pos_x = (_scr_x - _destw) >> 1;
218        _pos_y = 0;
219    } else {
220        _destw = _scr_x;
221        _pos_x = 0;
222        _pos_y = (_scr_y - _desth) >> 1;
223    }
224    destx += _pos_x;
225    desty += _pos_y;
226    destw = _destw;
227    desth = _desth;
228
229    drv_debug_msg(VIDEO_DEBUG_GENERAL, "psb_putsurface_overlay: src (%d, %d, %d, %d), destx (%d, %d, %d, %d).\n",
230                             srcx, srcy, srcw, srch, destx, desty, destw, desth);
231    /* display by overlay */
232    vaStatus = psb_putsurface_overlay(
233                   ctx, surface, srcx, srcy, srcw, srch,
234                   destx, desty, destw, desth, /* screen coordinate */
235                   flags, OVERLAY_A, PIPEA);
236
237    return vaStatus;
238}
239#endif
240
241#if 0
242static int psb_update_destbox(
243    VADriverContextP ctx
244)
245{
246    INIT_DRIVER_DATA;
247    INIT_OUTPUT_PRIV;
248    short destx;
249    short desty;
250    unsigned short destw;
251    unsigned short desth;
252    VAStatus vaStatus = VA_STATUS_SUCCESS;
253
254    psb_android_get_destbox(&destx, &desty, &destw, &desth);
255    /*drv_debug_msg(VIDEO_DEBUG_GENERAL, "destbox = (%d,%d,%d,%d)\n", destx, desty, destw, desth);*/
256    if ((destx >= 0) && (desty >= 0) &&
257        ((destx + destw) <= output->screen_width) &&
258        ((desty + desth) <= output->screen_height) &&
259        (output->destx != destx ||
260         output->desty != desty ||
261         output->destw != destw ||
262         output->desth != desth)) {
263        output->destx = destx;
264        output->desty = desty;
265        output->destw = destw;
266        output->desth = desth;
267        output->new_destbox = 1;
268
269        LOGD("==========New Destbox=============\n");
270        LOGD("output->destbox = (%d,%d,%d,%d)\n", output->destx, output->desty, output->destw, output->desth);
271    }
272
273    return vaStatus;
274}
275#endif
276
277#if 0
278static int psb_check_outputmethod(
279    VADriverContextP ctx,
280    VASurfaceID surface,
281    unsigned short srcw,
282    unsigned short srch,
283    void *android_isurface,
284    psb_hdmi_mode *hdmi_mode
285)
286{
287    INIT_DRIVER_DATA;
288    INIT_OUTPUT_PRIV;
289    psb_HDMIExt_info_p psb_HDMIExt_info = (psb_HDMIExt_info_p)output->psb_HDMIExt_info;
290    object_surface_p obj_surface;
291    int rotation = 0, widi = 0;
292    int delta_rotation = 0;
293    int srf_rotate; /* primary surface rotation */
294    psb_surface_p rotate_surface; /* rotate surface */
295    int rotate_srf_rotate = -1; /* degree of the rotate surface */
296
297    if ((srcw >= 2048) || (srch >= 2048)) {
298        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Clip size extend overlay hw limit, use texstreaming\n");
299        driver_data->output_method = PSB_PUTSURFACE_TEXSTREAMING;
300        return 0;
301    }
302
303    /* use saved status to avoid per-frame checking */
304    if ((driver_data->frame_count % driver_data->outputmethod_checkinterval) != 0) {
305        *hdmi_mode = psb_HDMIExt_get_mode(output);
306        return 0;
307    }
308
309    /* check the status at outputmethod_checkinterval frequency */
310    /* at first check HDMI status */
311    if (psb_HDMIExt_update(ctx, psb_HDMIExt_info)) {
312        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to update HDMIExt info.\n", __FUNCTION__);
313        return -1;
314    }
315
316    obj_surface = SURFACE(surface);
317    if (obj_surface == NULL) {
318        drv_debug_msg(VIDEO_DEBUG_ERROR, "Invalid surface\n");
319        return -1;
320    }
321
322    *hdmi_mode = psb_HDMIExt_get_mode(output);
323    if ((*hdmi_mode == EXTENDED_VIDEO) || (*hdmi_mode == CLONE)) {
324        unsigned short _destw, _desth;
325        short _pos_x, _pos_y;
326        unsigned short crtc_width = 0, crtc_height = 0;
327        float _slope_xy;
328
329        /* need to handle VA rotation, and set WM rotate to 0
330         * for Android, MIPI0/HDMI has the same WM rotation always
331         */
332        if (driver_data->mipi0_rotation != 0 || driver_data->rotation_dirty != 0) {
333            driver_data->mipi0_rotation = 0;
334            driver_data->hdmi_rotation = 0;
335            driver_data->rotation_dirty = 0;
336            output->new_destbox = 1;
337            psb_RecalcRotate(ctx, CONTEXT(obj_surface->context_id));
338        }
339
340        psb_HDMIExt_get_prop(output, &crtc_width, &crtc_height);
341
342        /*recalculate the render box to fit the ratio of height/width*/
343        if ((driver_data->extend_rotation == VA_ROTATION_90) ||
344            (driver_data->extend_rotation == VA_ROTATION_270))
345            _slope_xy = (float)srcw / srch;
346        else
347            _slope_xy = (float)srch / srcw;
348
349        _destw = (short)(crtc_height / _slope_xy);
350        _desth = (short)(crtc_width * _slope_xy);
351        if (_destw <= crtc_width) {
352            _desth = crtc_height;
353            _pos_x = (crtc_width - _destw) >> 1;
354            _pos_y = 0;
355        } else {
356            _destw = crtc_width;
357            _pos_x = 0;
358            _pos_y = (crtc_height - _desth) >> 1;
359        }
360        driver_data->render_rect.x = _pos_x;
361        driver_data->render_rect.y = _pos_y;
362        driver_data->render_rect.width = _destw;
363        driver_data->render_rect.height = _desth;
364        drv_debug_msg(VIDEO_DEBUG_GENERAL, "HDMI mode is on (%d), Render Rect: (%d,%d,%d,%d)\n",
365                                 *hdmi_mode,
366                                 driver_data->render_rect.x, driver_data->render_rect.y,
367                                 driver_data->render_rect.width, driver_data->render_rect.height);
368        return 0;
369    }
370
371    /* HDMI is not enabled */
372    psb_android_surfaceflinger_status(android_isurface, &output->sf_composition, &rotation, &widi);
373    /*Update output destbox using layerbuffer's visible region*/
374    psb_update_destbox(ctx);
375
376    if ((driver_data->output_method == PSB_PUTSURFACE_FORCE_COVERLAY)
377        || (driver_data->output_method == PSB_PUTSURFACE_FORCE_TEXSTREAMING))
378        return 0;
379
380    /*If overlay can not get correct destbox, use texstreaming.*/
381    if (output->destw == 0 || output->desth == 0 ||
382        ((output->destw == srcw) && (output->desth == srch))) {
383        drv_debug_msg(VIDEO_DEBUG_GENERAL, "No proper destbox, use texstreaming (%dx%d+%d+%d)\n",
384                                 output->destw, output->desth, output->destx, output->desty);
385        driver_data->output_method = PSB_PUTSURFACE_TEXSTREAMING;
386        return 0;
387    }
388
389    /* only care local rotation */
390    delta_rotation = Rotation2Angle(driver_data->mipi0_rotation) - Rotation2Angle(rotation);
391    if ((((abs(delta_rotation) == 90) || (abs(delta_rotation) == 270)) && output->new_destbox) ||
392        (abs(delta_rotation) == 180)) {
393        drv_debug_msg(VIDEO_DEBUG_GENERAL, "New rotation degree %d of MIPI0 WM, Need to recalc rotation\n", rotation);
394        driver_data->mipi0_rotation = rotation;
395        driver_data->hdmi_rotation = rotation;
396        driver_data->rotation_dirty |= PSB_NEW_WM_ROTATION;
397    }
398    output->new_destbox = 0;
399
400    if (driver_data->rotation_dirty != 0) {
401        psb_RecalcRotate(ctx, CONTEXT(obj_surface->context_id));
402        driver_data->rotation_dirty = 0;
403    }
404
405    if (GET_SURFACE_INFO_protect(obj_surface->psb_surface)) {
406        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Protected surface, use overlay\n");
407        driver_data->output_method = PSB_PUTSURFACE_COVERLAY;
408
409        return 0;
410    }
411
412    if (widi == eWidiClone) {
413        drv_debug_msg(VIDEO_DEBUG_GENERAL, "WIDI in clone mode, use texstreaming\n");
414        driver_data->output_method = PSB_PUTSURFACE_TEXSTREAMING;
415        driver_data->msvdx_rotate_want = 0;/* disable msvdx rotae */
416
417        return 0;
418    }
419    if (widi == eWidiExtendedVideo) {
420        drv_debug_msg(VIDEO_DEBUG_GENERAL, "WIDI in extend video mode, disable local displaying\n");
421        driver_data->output_method = PSB_PUTSURFACE_NONE;
422        driver_data->msvdx_rotate_want = 0;/* disable msvdx rotae */
423
424        return 0;
425    }
426
427    if (output->sf_composition) {
428        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Composition is detected, use texstreaming\n");
429        driver_data->output_method = PSB_PUTSURFACE_TEXSTREAMING;
430        return 0;
431    }
432
433    srf_rotate = GET_SURFACE_INFO_rotate(obj_surface->psb_surface);
434    rotate_surface = obj_surface->out_loop_surface;
435    if (rotate_surface != NULL)
436        rotate_srf_rotate = GET_SURFACE_INFO_rotate(rotate_surface);
437
438    drv_debug_msg(VIDEO_DEBUG_GENERAL, "SF rotation %d, VA rotation %d, final MSVDX rotation %d\n",
439                             rotation, driver_data->va_rotate, driver_data->local_rotation);
440    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Primary surface rotation %d, rotated surface rotation %d\n",
441                             srf_rotate, rotate_srf_rotate);
442
443    /* The surface rotation is not same with the final rotation */
444    if ((driver_data->local_rotation != 0) &&
445        ((srf_rotate != driver_data->local_rotation) || (rotate_srf_rotate != driver_data->local_rotation))) {
446        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Use texstreaming due to different VA surface rotation and final rotaion\n",
447                                 srf_rotate, rotate_srf_rotate);
448        driver_data->output_method = PSB_PUTSURFACE_TEXSTREAMING;
449        return 0;
450    }
451
452    driver_data->output_method = PSB_PUTSURFACE_COVERLAY;
453
454    return 0;
455}
456#endif
457
458VAStatus psb_PutSurface(
459    VADriverContextP ctx,
460    VASurfaceID surface,
461    void __maybe_unused * android_isurface,
462    short srcx,
463    short srcy,
464    unsigned short srcw,
465    unsigned short srch,
466    short destx,
467    short desty,
468    unsigned short destw,
469    unsigned short desth,
470    VARectangle *cliprects, /* client supplied clip list */
471    unsigned int number_cliprects, /* number of clip rects in the clip list */
472    unsigned int flags /* de-interlacing flags */
473)
474{
475    INIT_DRIVER_DATA;
476    INIT_OUTPUT_PRIV;
477    object_surface_p obj_surface;
478    VAStatus vaStatus = VA_STATUS_SUCCESS;
479    PsbPortPrivPtr pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv);
480    int ret = 0;
481
482#ifndef BAYTRAIL
483
484    obj_surface = SURFACE(surface);
485
486//    psb__dump_NV_buffers(obj_surface,srcx,srcy,srcw,srch);
487    CHECK_SURFACE(obj_surface);
488    CHECK_INVALID_PARAM((NULL == cliprects) && (0 != number_cliprects));
489
490    if ((srcx < 0) || (srcx > obj_surface->width) || (srcw > (obj_surface->width - srcx)) ||
491        (srcy < 0) || (srcy > obj_surface->height_origin) || (srch > (obj_surface->height_origin - srcy))) {
492        drv_debug_msg(VIDEO_DEBUG_ERROR, "vaPutSurface: source rectangle passed from upper layer is not correct.\n");
493        return VA_STATUS_ERROR_UNKNOWN;
494    }
495    if ((destx < 0) || (desty < 0)) {
496        drv_debug_msg(VIDEO_DEBUG_ERROR, "vaPutSurface: dest rectangle passed from upper layer is not correct.\n");
497        return VA_STATUS_ERROR_UNKNOWN;
498    }
499
500    if (driver_data->dummy_putsurface) {
501        drv_debug_msg(VIDEO_DEBUG_GENERAL, "vaPutSurface: dummy mode, return directly\n");
502        return VA_STATUS_SUCCESS;
503    }
504
505    /* init overlay */
506    if (!driver_data->coverlay_init) {
507        ret = psb_coverlay_init(ctx);
508        if (ret != 0) {
509            drv_debug_msg(VIDEO_DEBUG_GENERAL, "vaPutSurface: psb_coverlay_init failed. Fallback to texture streaming.\n");
510            driver_data->coverlay_init = 0;
511        } else
512            driver_data->coverlay_init = 1;
513    }
514
515    /* set the current displaying video frame into kernel */
516    psb_surface_set_displaying(driver_data, obj_surface->width,
517                               obj_surface->height_origin,
518                               obj_surface->psb_surface);
519
520    /* local video playback */
521    drv_debug_msg(VIDEO_DEBUG_GENERAL, "MIPI: Use overlay to display.\n");
522
523    /*initialize output destbox using default destbox if it has not been initialized until here.*/
524    if (output->destw == 0 || output->desth == 0) {
525        output->destx = (destx > 0) ? destx : 0;
526        output->desty = (desty > 0) ? desty : 0;
527        output->destw = ((output->destx + destw) > output->screen_width) ? (output->screen_width - output->destx) : destw;
528        output->desth = ((output->desty + desth) > output->screen_height) ? (output->screen_height - output->desty) : desth;
529    }
530
531    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Overlay position = (%d,%d,%d,%d)\n", output->destx, output->desty, output->destw, output->desth);
532    srcw = srcw <= 2047? srcw : 2047;
533    vaStatus = psb_putsurface_overlay(ctx, surface,
534                                      srcx, srcy, srcw, srch,
535                                      output->destx, output->desty, output->destw, output->desth,
536                                      flags, OVERLAY_A, PIPEA);
537
538    driver_data->frame_count++;
539#endif
540    return vaStatus;
541}
542