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)  \
62 do {                                                            \
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 
get_surface_stride(int width,int tiling)81 static 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 
isVppOn(void __maybe_unused * output)112 static 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 
psb_InitOutLoop(VADriverContextP ctx)121 void 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 
psb_RecalcAlternativeOutput(object_context_p obj_context)161 void 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 
psb_CheckInterlaceRotate(object_context_p obj_context,unsigned char * pic_param_tmp)366 void 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  */
425 VAStatus 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  */
clearScalingInfo(psb_surface_share_info_p share_info)453 static 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 
psb_CreateScalingSurface(object_context_p obj_context,object_surface_p obj_surface)466 VAStatus 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
psb_CreateScalingSurface(object_context_p __maybe_unused obj_context,object_surface_p __maybe_unused obj_surface)551 VAStatus 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  */
psb_CreateRotateSurface(object_context_p obj_context,object_surface_p obj_surface,int msvdx_rotate)563 VAStatus 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 
704 exit:
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 
psb_DestroyRotateBuffer(object_context_p obj_context,object_surface_p obj_surface)730 VAStatus 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