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)  \
67 do {                                                            \
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 
get_surface_stride(int width,int tiling)86 static 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 
isVppOn(void __maybe_unused * output)117 static 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 
psb_InitOutLoop(VADriverContextP ctx)126 void 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 
psb_RecalcAlternativeOutput(object_context_p obj_context)166 void 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 
psb_CheckInterlaceRotate(object_context_p obj_context,unsigned char * pic_param_tmp)371 void 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  */
439 VAStatus 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  */
clearScalingInfo(psb_surface_share_info_p share_info)467 static 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 
psb_CreateScalingSurface(object_context_p obj_context,object_surface_p obj_surface)480 VAStatus 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
psb_CreateScalingSurface(object_context_p __maybe_unused obj_context,object_surface_p __maybe_unused obj_surface)565 VAStatus 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  */
psb_CreateRotateSurface(object_context_p obj_context,object_surface_p obj_surface,int msvdx_rotate)577 VAStatus 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 = NULL;
585     bool rotate_surfaceAlloc = false;
586     VAStatus vaStatus = VA_STATUS_SUCCESS;
587     int need_realloc = 0;
588     unsigned int flags = 0;
589     psb_surface_share_info_p share_info = obj_surface->share_info;
590     psb_driver_data_p driver_data = obj_context->driver_data;
591     int rotate_stride = 0, rotate_tiling = 0;
592     object_config_p obj_config = CONFIG(obj_context->config_id);
593     unsigned char * surface_data;
594 
595     CHECK_CONFIG(obj_config);
596 
597     rotate_surface = obj_surface->out_loop_surface;
598 
599     if (msvdx_rotate == 0
600 #ifdef OVERLAY_ENABLE_MIRROR
601         /*Bypass 180 degree rotate when overlay enabling mirror*/
602         || msvdx_rotate == VA_ROTATION_180
603 #endif
604         )
605         return vaStatus;
606 
607     if (rotate_surface) {
608         CHECK_SURFACE_REALLOC(rotate_surface, msvdx_rotate, need_realloc);
609         if (need_realloc == 0) {
610             goto exit;
611         } else { /* free the old rotate surface */
612             /*FIX ME: it is not safe to do that because surfaces may be in use for rendering.*/
613             psb_surface_destroy(obj_surface->out_loop_surface);
614             memset(rotate_surface, 0, sizeof(*rotate_surface));
615         }
616     } else {
617         rotate_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
618         CHECK_ALLOCATION(rotate_surface);
619         rotate_surfaceAlloc = true;
620     }
621 
622 #ifdef PSBVIDEO_MSVDX_DEC_TILING
623     SET_SURFACE_INFO_tiling(rotate_surface, GET_SURFACE_INFO_tiling(obj_surface->psb_surface));
624 #endif
625 #ifdef PSBVIDEO_MRFL_VPP_ROTATE
626     SET_SURFACE_INFO_rotate(rotate_surface, msvdx_rotate);
627 #endif
628     drv_debug_msg(VIDEO_DEBUG_GENERAL, "Try to allocate surface for alternative rotate output\n");
629 
630     flags = IS_ROTATED;
631 
632     if (msvdx_rotate == 2 /* VA_ROTATION_180 */) {
633         width = obj_surface->width;
634         height = obj_surface->height;
635 
636 #ifdef PSBVIDEO_MRFL_VPP_ROTATE
637     if (obj_config->entrypoint == VAEntrypointVideoProc &&
638             share_info && share_info->out_loop_khandle) {
639             vaStatus = psb_surface_create_from_kbuf(driver_data, width, height,
640                                   obj_surface->psb_surface->size, VA_FOURCC_NV12,
641                                   share_info->out_loop_khandle,
642                                   obj_surface->psb_surface->stride,
643                                   obj_surface->psb_surface->stride,
644                                   obj_surface->psb_surface->stride,
645                                   0, 0, 0, rotate_surface);
646     } else
647 #endif
648             vaStatus = psb_surface_create(driver_data, width, height, VA_FOURCC_NV12,
649                                       flags, rotate_surface);
650     } else {
651         width = obj_surface->height_origin;
652         height = (obj_surface->width + 0x1f) & ~0x1f;
653 
654 #ifdef PSBVIDEO_MRFL_VPP_ROTATE
655         if (obj_config->entrypoint == VAEntrypointVideoProc &&
656                 share_info && share_info->out_loop_khandle != 0) {
657                 drv_debug_msg(VIDEO_DEBUG_GENERAL,"Create the surface from kbuf out_loop_khandle=%x!\n", share_info->out_loop_khandle);
658                 rotate_tiling = GET_SURFACE_INFO_tiling(rotate_surface);
659                 rotate_stride = get_surface_stride(width, rotate_tiling);
660                 vaStatus = psb_surface_create_from_kbuf(driver_data, width, height,
661                                   (rotate_stride * height * 3) / 2, VA_FOURCC_NV12,
662                                   share_info->out_loop_khandle,
663                                   rotate_stride, rotate_stride, rotate_stride,
664                                   0, rotate_stride * height, rotate_stride * height,
665                                   rotate_surface);
666         } else
667 #endif
668         {
669             drv_debug_msg(VIDEO_DEBUG_GENERAL,"Create rotated buffer. width=%d, height=%d\n", width, height);
670             if (CONTEXT_SCALING(obj_context)) {
671                 width = obj_context->scaling_buffer_height;
672                 height = (obj_context->scaling_buffer_width+ 0x1f) & ~0x1f;
673             }
674             vaStatus = psb_surface_create(driver_data, width, height, VA_FOURCC_NV12,
675                                       flags, rotate_surface);
676         }
677     }
678     if (VA_STATUS_SUCCESS != vaStatus) {
679         free(rotate_surface);
680         obj_surface->out_loop_surface = NULL;
681         vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
682         DEBUG_FAILURE;
683         return vaStatus;
684     }
685 
686     //clear rotation surface
687      if (CONTEXT_SCALING(obj_context)) {
688         if (psb_buffer_map(&rotate_surface->buf, &surface_data)) {
689             drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to map rotation buffer before clear it");
690         }
691         else {
692             memset(surface_data, 0, rotate_surface->chroma_offset);
693             memset(surface_data + rotate_surface->chroma_offset, 0x80,
694                        rotate_surface->size - rotate_surface->chroma_offset);
695             psb_buffer_unmap(&rotate_surface->buf);
696         }
697     }
698     obj_surface->width_r = width;
699     obj_surface->height_r = height;
700 
701 #ifdef PSBVIDEO_MSVDX_DEC_TILING
702     drv_debug_msg(VIDEO_DEBUG_GENERAL, "attempt to update tile context\n");
703     if (GET_SURFACE_INFO_tiling(rotate_surface) && obj_config->entrypoint != VAEntrypointVideoProc) {
704         drv_debug_msg(VIDEO_DEBUG_GENERAL, "update tile context\n");
705         object_context_p obj_context = CONTEXT(obj_surface->context_id);
706         if (NULL == obj_context) {
707             vaStatus = VA_STATUS_ERROR_INVALID_CONTEXT;
708             DEBUG_FAILURE;
709             if (rotate_surface != NULL && rotate_surfaceAlloc) {
710                 free(rotate_surface);
711                 rotate_surface = NULL;
712             }
713             return vaStatus;
714         }
715         unsigned long msvdx_tile = psb__tile_stride_log2_256(obj_surface->width_r);
716         obj_context->msvdx_tile &= 0xf; /* clear rotate tile */
717         obj_context->msvdx_tile |= (msvdx_tile << 4);
718         obj_context->ctp_type &= (~PSB_CTX_TILING_MASK); /* clear tile context */
719         obj_context->ctp_type |= ((obj_context->msvdx_tile & 0xff) << 16);
720         psb_update_context(driver_data, obj_context->ctp_type);
721     }
722 #endif
723 
724 exit:
725     obj_surface->out_loop_surface = rotate_surface;
726     SET_SURFACE_INFO_rotate(rotate_surface, msvdx_rotate);
727     /* derive the protected flag from the primay surface */
728     SET_SURFACE_INFO_protect(rotate_surface,
729                              GET_SURFACE_INFO_protect(obj_surface->psb_surface));
730 
731     /*notify hwc that rotated buffer is ready to use.
732     * TODO: Do these in psb_SyncSurface()
733     */
734     if (share_info != NULL) {
735 	share_info->width_r = rotate_surface->stride;
736         share_info->height_r = obj_surface->height_r;
737         share_info->out_loop_khandle =
738             (uint32_t)(wsbmKBufHandle(wsbmKBuf(rotate_surface->buf.drm_buf)));
739         share_info->metadata_rotate = VAROTATION2HAL(driver_data->va_rotate);
740         share_info->surface_rotate = VAROTATION2HAL(msvdx_rotate);
741 
742         share_info->out_loop_luma_stride = rotate_surface->stride;
743         share_info->out_loop_chroma_u_stride = rotate_surface->stride;
744         share_info->out_loop_chroma_v_stride = rotate_surface->stride;
745     }
746 
747     return vaStatus;
748 }
749 
psb_DestroyRotateBuffer(object_context_p obj_context,object_surface_p obj_surface)750 VAStatus psb_DestroyRotateBuffer(
751     object_context_p obj_context,
752     object_surface_p obj_surface)
753 {
754     VAStatus vaStatus = VA_STATUS_SUCCESS;
755     psb_surface_share_info_p share_info = obj_surface->share_info;
756     psb_driver_data_p driver_data = obj_context->driver_data;
757     psb_surface_p rotate_surface = obj_surface->out_loop_surface;
758     struct psb_buffer_s psb_buf;
759 
760     if (share_info && share_info->out_loop_khandle) {
761         drv_debug_msg(VIDEO_DEBUG_GENERAL,"psb_DestroyRotateBuffer out_loop_khandle=%x\n", share_info->out_loop_khandle);
762         vaStatus = psb_kbuffer_reference(driver_data, &psb_buf, share_info->out_loop_khandle);
763         if (vaStatus != VA_STATUS_SUCCESS)
764             return vaStatus;
765         psb_buffer_destroy(&psb_buf);
766         share_info->out_loop_khandle = 0;
767     }
768 
769     if (rotate_surface)
770         free(rotate_surface);
771 
772     return vaStatus;
773 }
774 
775