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