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