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 *    Zeng Li <zeng.li@intel.com>
26 *    Jason Hu <jason.hu@intel.com>
27 *    Shengquan Yuan  <shengquan.yuan@intel.com>
28 */
29
30#include <va/va.h>
31#include <va/va_backend.h>
32#include <va/va_backend_tpi.h>
33#include <va/va_backend_egl.h>
34#include <va/va_drmcommon.h>
35#include "psb_drv_video.h"
36#include "psb_output.h"
37#include "android/psb_android_glue.h"
38#include "psb_drv_debug.h"
39#include "vc1_defs.h"
40#include "pnw_rotate.h"
41#include <stdio.h>
42#include <string.h>
43#include <stdarg.h>
44#include <time.h>
45#include <unistd.h>
46#include <wsbm/wsbm_pool.h>
47#include <wsbm/wsbm_manager.h>
48#include <wsbm/wsbm_util.h>
49#include <wsbm/wsbm_fencemgr.h>
50
51#ifdef ANROID
52#include <system/graphics.h>
53#endif
54
55#define INIT_DRIVER_DATA    psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData
56#define INIT_OUTPUT_PRIV    unsigned char* output = ((psb_driver_data_p)ctx->pDriverData)->ws_priv
57#define SURFACE(id)    ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id ))
58#define CONTEXT(id) ((object_context_p) object_heap_lookup( &driver_data->context_heap, id ))
59#define CONFIG(id)  ((object_config_p) object_heap_lookup( &driver_data->config_heap, id ))
60
61#define CHECK_SURFACE_REALLOC(psb_surface, msvdx_rotate, need)  \
62do {                                                            \
63    int old_rotate = GET_SURFACE_INFO_rotate(psb_surface);      \
64    switch (msvdx_rotate) {                                     \
65    case 2: /* 180 */                                           \
66        if (old_rotate == 2)                                    \
67            need = 0;                                           \
68        else                                                    \
69            need = 1;                                           \
70        break;                                                  \
71    case 1: /* 90 */                                            \
72    case 3: /* 270 */                                           \
73        if (old_rotate == 1 || old_rotate == 3)                 \
74            need = 0;                                           \
75        else                                                    \
76            need = 1;                                           \
77        break;                                                  \
78    }                                                           \
79} while (0)
80
81static int get_surface_stride(int width, int tiling)
82{
83    int stride = 0;
84
85    if (0) {
86        ;
87    } else if (512 >= width) {
88        stride = 512;
89    } else if (1024 >= width) {
90        stride = 1024;
91    } else if (1280 >= width) {
92        stride = 1280;
93#ifdef PSBVIDEO_MSVDX_DEC_TILING
94        if (tiling) {
95            stride = 2048;
96        }
97#endif
98    } else if (2048 >= width) {
99        stride = 2048;
100    } else if (4096 >= width) {
101        stride = 4096;
102    } else {
103        stride = (width + 0x3f) & ~0x3f;
104    }
105
106    return stride;
107}
108//#define OVERLAY_ENABLE_MIRROR
109
110#ifdef PSBVIDEO_MRFL_VPP
111
112static int isVppOn(void __maybe_unused *output) {
113#ifdef TARGET_HAS_MULTIPLE_DISPLAY
114    return psb_android_get_mds_vpp_state(output);
115#else
116    return psb_android_get_vpp_state();
117#endif
118}
119#endif
120
121void psb_InitOutLoop(VADriverContextP ctx)
122{
123    char env_value[64];
124    INIT_DRIVER_DATA;
125
126    /* VA rotate from APP */
127    driver_data->va_rotate = VA_ROTATION_NONE;
128
129    /* window manager rotation from OS */
130    driver_data->mipi0_rotation = VA_ROTATION_NONE;
131    driver_data->mipi1_rotation = VA_ROTATION_NONE;
132    driver_data->hdmi_rotation = VA_ROTATION_NONE;
133
134    /* final rotation of VA rotate+WM rotate */
135    driver_data->local_rotation = VA_ROTATION_NONE;
136    driver_data->extend_rotation = VA_ROTATION_NONE;
137
138    /* MSVDX rotate */
139    driver_data->msvdx_rotate_want = ROTATE_VA2MSVDX(VA_ROTATION_NONE);
140
141    if (psb_parse_config("PSB_VIDEO_NOROTATE", &env_value[0]) == 0) {
142        drv_debug_msg(VIDEO_DEBUG_GENERAL, "MSVDX: disable MSVDX rotation\n");
143        driver_data->disable_msvdx_rotate = 1;
144    }
145    /* FIXME: Disable rotation when VPP enabled, just a workround here*/
146#ifdef PSBVIDEO_MRFL_VPP
147    if (isVppOn((void*)driver_data->ws_priv)) {
148        drv_debug_msg(VIDEO_DEBUG_GENERAL, "For VPP: disable MSVDX rotation\n");
149        driver_data->disable_msvdx_rotate = 1;
150        driver_data->vpp_on = 1;
151    }
152#endif
153
154#ifdef BAYTRAIL
155    driver_data->disable_msvdx_rotate = 1;
156#endif
157
158    driver_data->disable_msvdx_rotate_backup = driver_data->disable_msvdx_rotate;
159}
160
161void psb_RecalcAlternativeOutput(object_context_p obj_context)
162{
163    psb_driver_data_p driver_data = obj_context->driver_data;
164    object_surface_p obj_surface = obj_context->current_render_target;
165    int angle, new_rotate, i;
166    int old_rotate = driver_data->msvdx_rotate_want;
167    int mode = INIT_VALUE;
168#ifdef TARGET_HAS_MULTIPLE_DISPLAY
169    mode = psb_android_get_mds_mode((void*)driver_data->ws_priv);
170#endif
171
172    if (mode != INIT_VALUE) {
173        // clear device rotation info
174        if (driver_data->mipi0_rotation != VA_ROTATION_NONE) {
175            driver_data->mipi0_rotation = VA_ROTATION_NONE;
176            driver_data->hdmi_rotation = VA_ROTATION_NONE;
177        }
178        // Disable msvdx rotation if
179        // WIDI video is play and meta data rotation angle is 0
180        if (mode == WIDI_VIDEO_ISPLAYING) {
181            if (driver_data->va_rotate == VA_ROTATION_NONE)
182                driver_data->disable_msvdx_rotate = 1;
183            else {
184                driver_data->mipi0_rotation = 0;
185                driver_data->hdmi_rotation = 0;
186                driver_data->disable_msvdx_rotate = 0;
187            }
188        } else {
189            if (IS_MOFD(driver_data))
190                driver_data->disable_msvdx_rotate = 1;
191            else
192                driver_data->disable_msvdx_rotate = driver_data->disable_msvdx_rotate_backup;
193        }
194    } else if (IS_MOFD(driver_data)) {
195    /* Moorefield has overlay rotaion, so decoder doesn't generate rotation
196     * output according to windows manager. It is controlled by payload info
197     * in which HWC signal decoder to generate rotation output
198     */
199        long long hwc_timestamp = 0;
200        int index = -1;
201
202        for (i = 0; i < obj_context->num_render_targets; i++) {
203            object_surface_p obj_surface = SURFACE(obj_context->render_targets[i]);
204            /* traverse all surfaces' share info to find out the latest transform info */
205            if (obj_surface && obj_surface->share_info) {
206                if (obj_surface->share_info->hwc_timestamp > hwc_timestamp) {
207                    hwc_timestamp = obj_surface->share_info->hwc_timestamp;
208                    index = i;
209                }
210            }
211        }
212        if (index >= 0) {
213            object_surface_p obj_surface = SURFACE(obj_context->render_targets[index]);
214            if (obj_surface && obj_surface->share_info) {
215                int transform = obj_surface->share_info->layer_transform;
216                driver_data->mipi0_rotation = HAL2VAROTATION(transform);
217                drv_debug_msg(VIDEO_DEBUG_GENERAL, "Signal from HWC to rotate %d\n", driver_data->mipi0_rotation);
218            }
219        }
220    } else if (driver_data->native_window) {
221        int display_rotate = 0;
222        psb_android_surfaceflinger_rotate(driver_data->native_window, &display_rotate);
223        drv_debug_msg(VIDEO_DEBUG_GENERAL, "NativeWindow(0x%x), get surface flinger rotate %d\n", driver_data->native_window, display_rotate);
224
225        if (driver_data->mipi0_rotation != display_rotate) {
226            driver_data->mipi0_rotation = display_rotate;
227        }
228    } else {
229        long long hwc_timestamp = 0;
230        int index = -1;
231
232        for (i = 0; i < obj_context->num_render_targets; i++) {
233            object_surface_p obj_surface = SURFACE(obj_context->render_targets[i]);
234            /* traverse all surfaces' share info to find out the latest transform info */
235            if (obj_surface && obj_surface->share_info) {
236                if (obj_surface->share_info->hwc_timestamp > hwc_timestamp) {
237                    hwc_timestamp = obj_surface->share_info->hwc_timestamp;
238                    index = i;
239                }
240            }
241        }
242        if (index >= 0) {
243            object_surface_p obj_surface = SURFACE(obj_context->render_targets[index]);
244            if (obj_surface && obj_surface->share_info) {
245                int transform = obj_surface->share_info->layer_transform;
246                driver_data->mipi0_rotation = HAL2VAROTATION(transform);
247            }
248        }
249    }
250
251#ifdef PSBVIDEO_MRFL
252    if ((mode == HDMI_VIDEO_ISPLAYING) && driver_data->native_window) {
253        int display_rotate = 0;
254        psb_android_surfaceflinger_rotate(driver_data->native_window, &display_rotate);
255        drv_debug_msg(VIDEO_DEBUG_GENERAL, "NativeWindow(0x%x), get surface flinger rotate %d\n", driver_data->native_window, display_rotate);
256
257        if (driver_data->mipi0_rotation != display_rotate && !IS_MOFD(driver_data)) {
258            driver_data->mipi0_rotation = display_rotate;
259        }
260    }
261#endif
262
263    /* calc VA rotation and WM rotation, and assign to the final rotation degree */
264    angle = Rotation2Angle(driver_data->va_rotate) + Rotation2Angle(driver_data->mipi0_rotation);
265    driver_data->local_rotation = Angle2Rotation(angle);
266    angle = Rotation2Angle(driver_data->va_rotate) + Rotation2Angle(driver_data->hdmi_rotation);
267    driver_data->extend_rotation = Angle2Rotation(angle);
268
269    /* On MOFD, no need to use meta rotation, just use rotation angle signal from HWC */
270    if (IS_MOFD(driver_data)) {
271        driver_data->local_rotation = driver_data->mipi0_rotation;
272        driver_data->extend_rotation = Rotation2Angle(driver_data->hdmi_rotation);
273    }
274
275    /* for any case that local and extened rotation are not same, fallback to GPU */
276    if ((driver_data->mipi1_rotation != VA_ROTATION_NONE) ||
277        ((driver_data->local_rotation != VA_ROTATION_NONE) &&
278         (driver_data->extend_rotation != VA_ROTATION_NONE) &&
279         (driver_data->local_rotation != driver_data->extend_rotation))) {
280        new_rotate = ROTATE_VA2MSVDX(driver_data->local_rotation);
281        if (driver_data->is_android == 0) /*fallback to texblit path*/
282            driver_data->output_method = PSB_PUTSURFACE_CTEXTURE;
283    } else {
284        if (driver_data->local_rotation == VA_ROTATION_NONE)
285            new_rotate = driver_data->extend_rotation;
286        else
287            new_rotate = driver_data->local_rotation;
288
289        if (driver_data->is_android == 0) {
290            if (driver_data->output_method != PSB_PUTSURFACE_FORCE_CTEXTURE)
291                driver_data->output_method = PSB_PUTSURFACE_COVERLAY;
292        }
293    }
294
295    if (old_rotate != new_rotate) {
296        drv_debug_msg(VIDEO_DEBUG_GENERAL, "MSVDX: new rotation %d desired\n", new_rotate);
297        driver_data->msvdx_rotate_want = new_rotate;
298    }
299
300#ifdef TARGET_HAS_MULTIPLE_DISPLAY
301    int scaling_buffer_width = 1920, scaling_buffer_height = 1080 ;
302    int scaling_width = 0, scaling_height = 0;
303    int scaling_offset_x = 0, scaling_offset_y = 0;
304    int old_bufw = 0, old_bufh = 0, old_x = 0, old_y = 0, old_w = 0, old_h = 0;
305    int bScaleChanged = 0, size = 0;
306    unsigned char * surface_data;
307
308    int ret = psb_android_get_mds_decoder_output_resolution(
309                (void*)driver_data->ws_priv,
310                &scaling_width, &scaling_height,
311                &scaling_offset_x, &scaling_offset_y,
312                &scaling_buffer_width, &scaling_buffer_height);
313
314    if ((old_bufw != scaling_buffer_width) || (old_bufh != scaling_buffer_height) ||
315        (old_x != scaling_offset_x) || (old_y != scaling_offset_y) ||
316        (old_w != scaling_width) || (old_h != scaling_height)) {
317        bScaleChanged = 1;
318    }
319
320    old_x = scaling_offset_x;
321    old_y = scaling_offset_y;
322    old_w = scaling_width;
323    old_h = scaling_height;
324    old_bufw = scaling_buffer_width;
325    old_bufh = scaling_buffer_height;
326
327    /* turn off ved downscaling if width and height are 0.
328     * Besides, scaling_width and scaling_height must be a multiple of 2.
329     */
330    if (!ret || (!scaling_width || !scaling_height) ||
331             (scaling_width & 1) || (scaling_height & 1)) {
332        obj_context->msvdx_scaling = 0;
333        obj_context->scaling_width = 0;
334        obj_context->scaling_height = 0;
335        obj_context->scaling_offset_x= 0;
336        obj_context->scaling_offset_y = 0;
337        obj_context->scaling_buffer_width = 0;
338        obj_context->scaling_buffer_height = 0;
339    } else {
340        obj_context->msvdx_scaling = 1;
341        obj_context->scaling_width = scaling_width;
342        obj_context->scaling_height = scaling_height;
343        obj_context->scaling_offset_x= scaling_offset_x;
344        obj_context->scaling_offset_y = scaling_offset_y;
345        obj_context->scaling_buffer_width = scaling_buffer_width;
346        obj_context->scaling_buffer_height = scaling_buffer_height;
347    }
348    if (bScaleChanged) {
349        if ((obj_surface != NULL) &&
350            (obj_surface->out_loop_surface != NULL)) {
351            if (psb_buffer_map(&obj_surface->out_loop_surface->buf, &surface_data)) {
352                drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to map rotation buffer before clear it");
353            }
354            else {
355                size = obj_surface->out_loop_surface->chroma_offset;
356                memset(surface_data, 0, size);
357                memset(surface_data + size, 0x80, obj_surface->out_loop_surface->size - size);
358                psb_buffer_unmap(&obj_context->current_render_target->out_loop_surface->buf);
359            }
360        }
361    }
362#endif
363}
364
365
366void psb_CheckInterlaceRotate(object_context_p obj_context, unsigned char *pic_param_tmp)
367{
368    object_surface_p obj_surface = obj_context->current_render_target;
369
370    switch (obj_context->profile) {
371    case VAProfileMPEG2Simple:
372    case VAProfileMPEG2Main:
373        break;
374    case VAProfileMPEG4Simple:
375    case VAProfileMPEG4AdvancedSimple:
376    case VAProfileMPEG4Main:
377    case VAProfileH263Baseline: {
378        VAPictureParameterBufferMPEG4 *pic_params = (VAPictureParameterBufferMPEG4 *)pic_param_tmp;
379
380        if (pic_params->vol_fields.bits.interlaced)
381            obj_context->interlaced_stream = 1; /* is it the right way to check? */
382        break;
383    }
384    case VAProfileH264Baseline:
385    case VAProfileH264Main:
386    case VAProfileH264High:
387    case VAProfileH264ConstrainedBaseline: {
388        VAPictureParameterBufferH264 *pic_params = (VAPictureParameterBufferH264 *)pic_param_tmp;
389        /* is it the right way to check? */
390        if (pic_params->pic_fields.bits.field_pic_flag || pic_params->seq_fields.bits.mb_adaptive_frame_field_flag)
391            obj_context->interlaced_stream = 1;
392
393        break;
394    }
395    case VAProfileVC1Simple:
396    case VAProfileVC1Main:
397    case VAProfileVC1Advanced: {
398        VAPictureParameterBufferVC1 *pic_params = (VAPictureParameterBufferVC1 *)pic_param_tmp;
399
400        /* is it the right way to check? */
401        if (pic_params->sequence_fields.bits.interlace)
402            obj_context->interlaced_stream = 1;
403
404        break;
405    }
406    default:
407        break;
408    }
409
410    if (obj_surface->share_info) {
411        psb_surface_share_info_p share_info = obj_surface->share_info;
412        if (obj_context->interlaced_stream) {
413            SET_SURFACE_INFO_rotate(obj_surface->psb_surface, 0);
414            obj_context->msvdx_rotate = 0;
415            share_info->bob_deinterlace = 1;
416        } else {
417           share_info->bob_deinterlace = 0;
418       }
419    }
420}
421#if 0
422/*
423 * Detach a surface from obj_surface
424 */
425VAStatus psb_DestroyRotateSurface(
426    VADriverContextP ctx,
427    object_surface_p obj_surface,
428    int rotate
429)
430{
431    INIT_DRIVER_DATA;
432    psb_surface_p psb_surface = obj_surface->out_loop_surface;
433    VAStatus vaStatus = VA_STATUS_SUCCESS;
434
435    /* Allocate alternative output surface */
436    if (psb_surface) {
437        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Try to allocate surface for alternative rotate output\n");
438        psb_surface_destroy(obj_surface->out_loop_surface);
439        free(psb_surface);
440
441        obj_surface->out_loop_surface = NULL;
442        obj_surface->width_r = obj_surface->width;
443        obj_surface->height_r = obj_surface->height;
444    }
445
446    return vaStatus;
447}
448#endif
449#ifdef TARGET_HAS_MULTIPLE_DISPLAY
450/*
451 * Create and attach a downscaling surface to obj_surface
452 */
453static void clearScalingInfo(psb_surface_share_info_p share_info) {
454    if (share_info == NULL)
455        return;
456    share_info->width_s = 0;
457    share_info->height_s = 0;
458    share_info->scaling_khandle = 0;
459
460    share_info->scaling_luma_stride = 0;
461    share_info->scaling_chroma_u_stride = 0;
462    share_info->scaling_chroma_v_stride = 0;
463    return;
464}
465
466VAStatus psb_CreateScalingSurface(
467        object_context_p obj_context,
468        object_surface_p obj_surface
469)
470{
471    psb_surface_p psb_surface;
472    VAStatus vaStatus = VA_STATUS_SUCCESS;
473    psb_surface_share_info_p share_info = obj_surface->share_info;
474    unsigned int set_flags, clear_flags;
475    int ret = 0;
476
477    if (obj_context->driver_data->render_rect.width <= obj_context->scaling_width || obj_context->driver_data->render_rect.height <= obj_context->scaling_height) {
478        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Either downscaling is not required or upscaling is needed for the target resolution\n");
479        obj_context->msvdx_scaling = 0; /* Disable downscaling */
480        clearScalingInfo(share_info);
481        return VA_STATUS_ERROR_OPERATION_FAILED;
482    }
483
484    psb_surface = obj_surface->scaling_surface;
485    /* Check if downscaling resolution has been changed */
486    if (psb_surface) {
487        if (obj_surface->width_s != obj_context->scaling_width || obj_surface->height_s != obj_context->scaling_height) {
488            psb_surface_destroy(psb_surface);
489            free(psb_surface);
490            psb_surface = NULL;
491
492            drv_debug_msg(VIDEO_DEBUG_GENERAL, "downscaling buffer realloc: %d x %d -> %d x %d\n",
493                    obj_surface->width_s, obj_surface->height_s, obj_context->scaling_width, obj_context->scaling_height);
494            clearScalingInfo(share_info);
495        }
496    }
497
498    if (!psb_surface) {
499        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Try to allocate surface for alternative scaling output: %dx%d\n",
500                      obj_context->scaling_width, obj_context->scaling_height);
501        psb_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
502        CHECK_ALLOCATION(psb_surface);
503
504        vaStatus = psb_surface_create(obj_context->driver_data, obj_context->scaling_width,
505                                      (obj_context->scaling_height + 0x1f) & ~0x1f, VA_FOURCC_NV12,
506                                      0, psb_surface);
507
508        //set_flags = WSBM_PL_FLAG_CACHED | DRM_PSB_FLAG_MEM_MMU | WSBM_PL_FLAG_SHARED;
509        //clear_flags = WSBM_PL_FLAG_UNCACHED | WSBM_PL_FLAG_WC;
510        //ret = psb_buffer_setstatus(&psb_surface->buf, set_flags, clear_flags);
511
512        if (VA_STATUS_SUCCESS != vaStatus || ret) {
513            drv_debug_msg(VIDEO_DEBUG_GENERAL, "allocate scaling buffer fail\n");
514            free(psb_surface);
515            obj_surface->scaling_surface = NULL;
516            vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
517            DEBUG_FAILURE;
518            return vaStatus;
519        }
520
521        obj_surface->width_s = obj_context->scaling_width;
522        obj_surface->height_s = obj_context->scaling_height;
523        obj_surface->buffer_width_s = obj_context->scaling_width;
524        obj_surface->buffer_height_s = obj_context->scaling_height;
525        obj_surface->offset_x_s= obj_context->scaling_offset_x;
526        obj_surface->offset_y_s= obj_context->scaling_offset_y;
527        obj_context->scaling_update = 1;
528    }
529    obj_surface->scaling_surface = psb_surface;
530
531    /* derive the protected flag from the primay surface */
532    SET_SURFACE_INFO_protect(psb_surface,
533                             GET_SURFACE_INFO_protect(obj_surface->psb_surface));
534
535    /*notify hwc that rotated buffer is ready to use.
536     * TODO: Do these in psb_SyncSurface()
537     */
538    if (share_info != NULL) {
539        share_info->width_s = obj_surface->width_s;
540        share_info->height_s = obj_surface->height_s;
541        share_info->scaling_khandle =
542        (uint32_t)(wsbmKBufHandle(wsbmKBuf(psb_surface->buf.drm_buf)));
543
544        share_info->scaling_luma_stride = psb_surface->stride;
545        share_info->scaling_chroma_u_stride = psb_surface->stride;
546        share_info->scaling_chroma_v_stride = psb_surface->stride;
547    }
548    return vaStatus;
549}
550#else
551VAStatus psb_CreateScalingSurface(
552        object_context_p __maybe_unused obj_context,
553        object_surface_p __maybe_unused obj_surface
554)
555{
556    return VA_STATUS_ERROR_OPERATION_FAILED;
557}
558#endif
559
560/*
561 * Create and attach a rotate surface to obj_surface
562 */
563VAStatus psb_CreateRotateSurface(
564    object_context_p obj_context,
565    object_surface_p obj_surface,
566    int msvdx_rotate
567)
568{
569    int width, height;
570    psb_surface_p rotate_surface;
571    VAStatus vaStatus = VA_STATUS_SUCCESS;
572    int need_realloc = 0;
573    unsigned int flags = 0;
574    psb_surface_share_info_p share_info = obj_surface->share_info;
575    psb_driver_data_p driver_data = obj_context->driver_data;
576    int rotate_stride = 0, rotate_tiling = 0;
577    object_config_p obj_config = CONFIG(obj_context->config_id);
578    unsigned char * surface_data;
579
580    CHECK_CONFIG(obj_config);
581
582    rotate_surface = obj_surface->out_loop_surface;
583
584    if (msvdx_rotate == 0
585#ifdef OVERLAY_ENABLE_MIRROR
586        /*Bypass 180 degree rotate when overlay enabling mirror*/
587        || msvdx_rotate == VA_ROTATION_180
588#endif
589        )
590        return vaStatus;
591
592    if (rotate_surface) {
593        CHECK_SURFACE_REALLOC(rotate_surface, msvdx_rotate, need_realloc);
594        if (need_realloc == 0) {
595            goto exit;
596        } else { /* free the old rotate surface */
597            /*FIX ME: it is not safe to do that because surfaces may be in use for rendering.*/
598            psb_surface_destroy(obj_surface->out_loop_surface);
599            memset(rotate_surface, 0, sizeof(*rotate_surface));
600        }
601    } else {
602        rotate_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
603        CHECK_ALLOCATION(rotate_surface);
604    }
605
606#ifdef PSBVIDEO_MSVDX_DEC_TILING
607    SET_SURFACE_INFO_tiling(rotate_surface, GET_SURFACE_INFO_tiling(obj_surface->psb_surface));
608#endif
609#ifdef PSBVIDEO_MRFL_VPP_ROTATE
610    SET_SURFACE_INFO_rotate(rotate_surface, msvdx_rotate);
611#endif
612    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Try to allocate surface for alternative rotate output\n");
613
614    flags = IS_ROTATED;
615
616    if (msvdx_rotate == 2 /* VA_ROTATION_180 */) {
617        width = obj_surface->width;
618        height = obj_surface->height;
619
620#ifdef PSBVIDEO_MRFL_VPP_ROTATE
621    if (obj_config->entrypoint == VAEntrypointVideoProc &&
622            share_info && share_info->out_loop_khandle) {
623            vaStatus = psb_surface_create_from_kbuf(driver_data, width, height,
624                                  obj_surface->psb_surface->size, VA_FOURCC_NV12,
625                                  share_info->out_loop_khandle,
626                                  obj_surface->psb_surface->stride,
627                                  obj_surface->psb_surface->stride,
628                                  obj_surface->psb_surface->stride,
629                                  0, 0, 0, rotate_surface);
630    } else
631#endif
632            vaStatus = psb_surface_create(driver_data, width, height, VA_FOURCC_NV12,
633                                      flags, rotate_surface);
634    } else {
635        width = obj_surface->height_origin;
636        height = (obj_surface->width + 0x1f) & ~0x1f;
637
638#ifdef PSBVIDEO_MRFL_VPP_ROTATE
639        if (obj_config->entrypoint == VAEntrypointVideoProc &&
640                share_info && share_info->out_loop_khandle != 0) {
641                drv_debug_msg(VIDEO_DEBUG_GENERAL,"Create the surface from kbuf out_loop_khandle=%x!\n", share_info->out_loop_khandle);
642                rotate_tiling = GET_SURFACE_INFO_tiling(rotate_surface);
643                rotate_stride = get_surface_stride(width, rotate_tiling);
644                vaStatus = psb_surface_create_from_kbuf(driver_data, width, height,
645                                  (rotate_stride * height * 3) / 2, VA_FOURCC_NV12,
646                                  share_info->out_loop_khandle,
647                                  rotate_stride, rotate_stride, rotate_stride,
648                                  0, rotate_stride * height, rotate_stride * height,
649                                  rotate_surface);
650        } else
651#endif
652        {
653            drv_debug_msg(VIDEO_DEBUG_GENERAL,"Create rotated buffer. width=%d, height=%d\n", width, height);
654            if (CONTEXT_SCALING(obj_context)) {
655                width = obj_context->scaling_buffer_height;
656                height = (obj_context->scaling_buffer_width+ 0x1f) & ~0x1f;
657            }
658            vaStatus = psb_surface_create(driver_data, width, height, VA_FOURCC_NV12,
659                                      flags, rotate_surface);
660        }
661    }
662    if (VA_STATUS_SUCCESS != vaStatus) {
663        free(rotate_surface);
664        obj_surface->out_loop_surface = NULL;
665        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
666        DEBUG_FAILURE;
667        return vaStatus;
668    }
669
670    //clear rotation surface
671     if (CONTEXT_SCALING(obj_context)) {
672        if (psb_buffer_map(&rotate_surface->buf, &surface_data)) {
673            drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to map rotation buffer before clear it");
674        }
675        else {
676            memset(surface_data, 0, rotate_surface->chroma_offset);
677            memset(surface_data + rotate_surface->chroma_offset, 0x80,
678                       rotate_surface->size - rotate_surface->chroma_offset);
679            psb_buffer_unmap(&rotate_surface->buf);
680        }
681    }
682    obj_surface->width_r = width;
683    obj_surface->height_r = height;
684
685#ifdef PSBVIDEO_MSVDX_DEC_TILING
686    drv_debug_msg(VIDEO_DEBUG_GENERAL, "attempt to update tile context\n");
687    if (GET_SURFACE_INFO_tiling(rotate_surface) && obj_config->entrypoint != VAEntrypointVideoProc) {
688        drv_debug_msg(VIDEO_DEBUG_GENERAL, "update tile context\n");
689        object_context_p obj_context = CONTEXT(obj_surface->context_id);
690        if (NULL == obj_context) {
691            vaStatus = VA_STATUS_ERROR_INVALID_CONTEXT;
692            DEBUG_FAILURE;
693            return vaStatus;
694        }
695        unsigned long msvdx_tile = psb__tile_stride_log2_256(obj_surface->width_r);
696        obj_context->msvdx_tile &= 0xf; /* clear rotate tile */
697        obj_context->msvdx_tile |= (msvdx_tile << 4);
698        obj_context->ctp_type &= (~PSB_CTX_TILING_MASK); /* clear tile context */
699        obj_context->ctp_type |= ((obj_context->msvdx_tile & 0xff) << 16);
700        psb_update_context(driver_data, obj_context->ctp_type);
701    }
702#endif
703
704exit:
705    obj_surface->out_loop_surface = rotate_surface;
706    SET_SURFACE_INFO_rotate(rotate_surface, msvdx_rotate);
707    /* derive the protected flag from the primay surface */
708    SET_SURFACE_INFO_protect(rotate_surface,
709                             GET_SURFACE_INFO_protect(obj_surface->psb_surface));
710
711    /*notify hwc that rotated buffer is ready to use.
712    * TODO: Do these in psb_SyncSurface()
713    */
714    if (share_info != NULL) {
715	share_info->width_r = rotate_surface->stride;
716        share_info->height_r = obj_surface->height_r;
717        share_info->out_loop_khandle =
718            (uint32_t)(wsbmKBufHandle(wsbmKBuf(rotate_surface->buf.drm_buf)));
719        share_info->metadata_rotate = VAROTATION2HAL(driver_data->va_rotate);
720        share_info->surface_rotate = VAROTATION2HAL(msvdx_rotate);
721
722        share_info->out_loop_luma_stride = rotate_surface->stride;
723        share_info->out_loop_chroma_u_stride = rotate_surface->stride;
724        share_info->out_loop_chroma_v_stride = rotate_surface->stride;
725    }
726
727    return vaStatus;
728}
729
730VAStatus psb_DestroyRotateBuffer(
731    object_context_p obj_context,
732    object_surface_p obj_surface)
733{
734    VAStatus vaStatus = VA_STATUS_SUCCESS;
735    psb_surface_share_info_p share_info = obj_surface->share_info;
736    psb_driver_data_p driver_data = obj_context->driver_data;
737    psb_surface_p rotate_surface = obj_surface->out_loop_surface;
738    struct psb_buffer_s psb_buf;
739
740    if (share_info && share_info->out_loop_khandle) {
741        drv_debug_msg(VIDEO_DEBUG_GENERAL,"psb_DestroyRotateBuffer out_loop_khandle=%x\n", share_info->out_loop_khandle);
742        vaStatus = psb_kbuffer_reference(driver_data, &psb_buf, share_info->out_loop_khandle);
743        if (vaStatus != VA_STATUS_SUCCESS)
744            return vaStatus;
745        psb_buffer_destroy(&psb_buf);
746        share_info->out_loop_khandle = 0;
747    }
748
749    if (rotate_surface)
750        free(rotate_surface);
751
752    return vaStatus;
753}
754
755