xref: /aosp_15_r20/external/mesa3d/src/amd/vpelib/src/core/resource.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /* Copyright 2022 Advanced Micro Devices, Inc.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a
4  * copy of this software and associated documentation files (the "Software"),
5  * to deal in the Software without restriction, including without limitation
6  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7  * and/or sell copies of the Software, and to permit persons to whom the
8  * Software is furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
16  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
17  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19  * OTHER DEALINGS IN THE SOFTWARE.
20  *
21  * Authors: AMD
22  *
23  */
24 #include <math.h>
25 #include "vpe_types.h"
26 #include "vpe_priv.h"
27 #include "vpe_version.h"
28 #include "common.h"
29 
30 #ifdef VPE_BUILD_1_0
31 #include "vpe10_resource.h"
32 #endif
33 
34 #ifdef VPE_BUILD_1_1
35 #include "vpe11_resource.h"
36 #endif
37 
38 static const struct vpe_debug_options debug_defaults = {
39     .flags                                   = {0},
40     .cm_in_bypass                            = 0,
41     .vpcnvc_bypass                           = 0,
42     .mpc_bypass                              = 0,
43     .identity_3dlut                          = 0,
44     .sce_3dlut                               = 0,
45     .disable_reuse_bit                       = 0,
46     .bg_bit_depth                            = 0,
47     .bypass_gamcor                           = 0,
48     .bypass_ogam                             = 0,
49     .bypass_dpp_gamut_remap                  = 0,
50     .bypass_post_csc                         = 0,
51     .bg_color_fill_only                      = 0,
52     .assert_when_not_support                 = 0,
53     .enable_mem_low_power =
54         {
55             .bits =
56                 {
57                     .cm   = false,
58                     .dscl = false,
59                     .mpc  = false,
60                 },
61         },
62     .expansion_mode   = 1,
63     .clamping_setting = 1,
64     .clamping_params =
65         {
66             .r_clamp_component_lower = 0x1000,
67             .g_clamp_component_lower = 0x1000,
68             .b_clamp_component_lower = 0x1000,
69             .r_clamp_component_upper = 0xEB00,
70             .g_clamp_component_upper = 0xEB00,
71             .b_clamp_component_upper = 0xEB00,
72             .clamping_range          = 4,
73         },
74     .bypass_per_pixel_alpha = 0,
75     .opp_pipe_crc_ctrl      = 0,
76     .dpp_crc_ctrl           = 0,
77     .mpc_crc_ctrl           = 0,
78     .visual_confirm_params  = {{{0}}},
79     .skip_optimal_tap_check = 0,
80     .disable_3dlut_cache    = 0,
81     .bypass_blndgam         = 0
82 };
83 
vpe_resource_parse_ip_version(uint8_t major,uint8_t minor,uint8_t rev_id)84 enum vpe_ip_level vpe_resource_parse_ip_version(
85     uint8_t major, uint8_t minor, uint8_t rev_id)
86 {
87     enum vpe_ip_level ip_level = VPE_IP_LEVEL_UNKNOWN;
88     switch (VPE_VERSION(major, minor, rev_id)) {
89 #ifdef VPE_BUILD_1_0
90     case VPE_VERSION(6, 1, 0):
91     case VPE_VERSION(6, 1, 3):
92         ip_level = VPE_IP_LEVEL_1_0;
93         break;
94 #endif
95 #ifdef VPE_BUILD_1_1
96     case VPE_VERSION(6, 1, 1):
97     case VPE_VERSION(6, 1, 2):
98         ip_level = VPE_IP_LEVEL_1_1;
99         break;
100 #endif
101     default:
102         ip_level = VPE_IP_LEVEL_UNKNOWN;
103         break;
104     }
105     return ip_level;
106 }
107 
vpe_construct_resource(struct vpe_priv * vpe_priv,enum vpe_ip_level level,struct resource * res)108 enum vpe_status vpe_construct_resource(
109     struct vpe_priv *vpe_priv, enum vpe_ip_level level, struct resource *res)
110 {
111     enum vpe_status status = VPE_STATUS_OK;
112     switch (level) {
113 #ifdef VPE_BUILD_1_0
114     case VPE_IP_LEVEL_1_0:
115         status = vpe10_construct_resource(vpe_priv, res);
116         break;
117 #endif
118 #ifdef VPE_BUILD_1_1
119     case VPE_IP_LEVEL_1_1:
120         status = vpe11_construct_resource(vpe_priv, res);
121         break;
122 #endif
123     default:
124         status = VPE_STATUS_NOT_SUPPORTED;
125         vpe_log("invalid ip level: %d", (int)level);
126         break;
127     }
128 
129     vpe_priv->init.debug     = debug_defaults;
130     vpe_priv->expansion_mode = vpe_priv->init.debug.expansion_mode;
131     if (res)
132         res->vpe_priv = vpe_priv;
133 
134     return status;
135 }
136 
vpe_destroy_resource(struct vpe_priv * vpe_priv,struct resource * res)137 void vpe_destroy_resource(struct vpe_priv *vpe_priv, struct resource *res)
138 {
139     switch (vpe_priv->pub.level) {
140 #ifdef VPE_BUILD_1_0
141     case VPE_IP_LEVEL_1_0:
142         vpe10_destroy_resource(vpe_priv, res);
143         break;
144 #endif
145 #ifdef VPE_BUILD_1_1
146     case VPE_IP_LEVEL_1_1:
147         vpe11_destroy_resource(vpe_priv, res);
148         break;
149 #endif
150     default:
151         break;
152     }
153 }
154 
vpe_alloc_segment_ctx(struct vpe_priv * vpe_priv,uint16_t num_segments)155 struct segment_ctx *vpe_alloc_segment_ctx(struct vpe_priv *vpe_priv, uint16_t num_segments)
156 {
157     struct segment_ctx *segment_ctx_base;
158 
159     segment_ctx_base = (struct segment_ctx *)vpe_zalloc(sizeof(struct segment_ctx) * num_segments);
160 
161     if (!segment_ctx_base)
162         return NULL;
163 
164     return segment_ctx_base;
165 }
166 
vpe_alloc_stream_ctx(struct vpe_priv * vpe_priv,uint32_t num_streams)167 struct stream_ctx *vpe_alloc_stream_ctx(struct vpe_priv *vpe_priv, uint32_t num_streams)
168 {
169     struct stream_ctx *ctx_base, *ctx;
170     uint32_t           i;
171 
172     ctx_base = (struct stream_ctx *)vpe_zalloc(sizeof(struct stream_ctx) * num_streams);
173     if (!ctx_base)
174         return NULL;
175 
176     for (i = 0; i < num_streams; i++) {
177         ctx           = &ctx_base[i];
178         ctx->cs       = COLOR_SPACE_UNKNOWN;
179         ctx->tf       = TRANSFER_FUNC_UNKNOWN;
180         ctx->vpe_priv = vpe_priv;
181         vpe_color_set_adjustments_to_default(&ctx->color_adjustments);
182         ctx->tf_scaling_factor = vpe_fixpt_one;
183         ctx->stream.flags.geometric_scaling = 0;
184         ctx->stream.tm_params.UID = 0;
185         ctx->uid_3dlut = 0;
186     }
187 
188     return ctx_base;
189 }
190 
vpe_free_stream_ctx(struct vpe_priv * vpe_priv)191 void vpe_free_stream_ctx(struct vpe_priv *vpe_priv)
192 {
193     uint16_t           i;
194     struct stream_ctx *ctx;
195 
196     if (!vpe_priv->stream_ctx || !vpe_priv->num_streams)
197         return;
198 
199     for (i = 0; i < vpe_priv->num_streams; i++) {
200         ctx = &vpe_priv->stream_ctx[i];
201         if (ctx->input_tf) {
202             vpe_free(ctx->input_tf);
203             ctx->input_tf = NULL;
204         }
205 
206         if (ctx->bias_scale) {
207             vpe_free(ctx->bias_scale);
208             ctx->bias_scale = NULL;
209         }
210 
211         if (ctx->input_cs) {
212             vpe_free(ctx->input_cs);
213             ctx->input_cs = NULL;
214         }
215 
216         if (ctx->gamut_remap) {
217             vpe_free(ctx->gamut_remap);
218             ctx->gamut_remap = NULL;
219         }
220 
221         if (ctx->in_shaper_func) {
222             vpe_free(ctx->in_shaper_func);
223             ctx->in_shaper_func = NULL;
224         }
225 
226         if (ctx->blend_tf) {
227             vpe_free(ctx->blend_tf);
228             ctx->blend_tf = NULL;
229         }
230 
231         if (ctx->lut3d_func) {
232             vpe_free(ctx->lut3d_func);
233             ctx->lut3d_func = NULL;
234         }
235 
236         if (ctx->lut3d_cache) {
237             vpe_free(ctx->lut3d_cache);
238             ctx->lut3d_cache = NULL;
239         }
240 
241         if (ctx->segment_ctx) {
242             vpe_free(ctx->segment_ctx);
243             ctx->segment_ctx = NULL;
244         }
245     }
246     vpe_free(vpe_priv->stream_ctx);
247     vpe_priv->stream_ctx  = NULL;
248     vpe_priv->num_streams = 0;
249     vpe_priv->num_virtual_streams = 0;
250 }
251 
vpe_free_output_ctx(struct vpe_priv * vpe_priv)252 void vpe_free_output_ctx(struct vpe_priv *vpe_priv)
253 {
254     if (vpe_priv->output_ctx.gamut_remap)
255         vpe_free(vpe_priv->output_ctx.gamut_remap);
256 
257     if (vpe_priv->output_ctx.output_tf)
258         vpe_free(vpe_priv->output_ctx.output_tf);
259 }
260 
vpe_pipe_reset(struct vpe_priv * vpe_priv)261 void vpe_pipe_reset(struct vpe_priv *vpe_priv)
262 {
263     int              i;
264     struct pipe_ctx *pipe_ctx;
265 
266     for (i = 0; i < vpe_priv->num_pipe; i++) {
267         pipe_ctx               = &vpe_priv->pipe_ctx[i];
268         pipe_ctx->is_top_pipe  = true;
269         pipe_ctx->owner        = PIPE_CTX_NO_OWNER;
270         pipe_ctx->top_pipe_idx = 0xff;
271     }
272 }
273 
vpe_pipe_reclaim(struct vpe_priv * vpe_priv,struct vpe_cmd_info * cmd_info)274 void vpe_pipe_reclaim(struct vpe_priv *vpe_priv, struct vpe_cmd_info *cmd_info)
275 {
276     int              i, j;
277     struct pipe_ctx *pipe_ctx;
278 
279     for (i = 0; i < vpe_priv->num_pipe; i++) {
280         pipe_ctx = &vpe_priv->pipe_ctx[i];
281         if (pipe_ctx->owner != PIPE_CTX_NO_OWNER) {
282             for (j = 0; j < cmd_info->num_inputs; j++)
283                 if (pipe_ctx->owner == cmd_info->inputs[j].stream_idx)
284                     break;
285 
286             if (j == cmd_info->num_inputs) {
287                 // that stream no longer exists
288                 pipe_ctx->is_top_pipe  = true;
289                 pipe_ctx->owner        = PIPE_CTX_NO_OWNER;
290                 pipe_ctx->top_pipe_idx = 0xff;
291             }
292         }
293     }
294 }
295 
vpe_pipe_find_owner(struct vpe_priv * vpe_priv,uint32_t stream_idx,bool * reuse)296 struct pipe_ctx *vpe_pipe_find_owner(struct vpe_priv *vpe_priv, uint32_t stream_idx, bool *reuse)
297 {
298     int              i;
299     struct pipe_ctx *pipe_ctx;
300     struct pipe_ctx *free_pipe = NULL;
301 
302     for (i = 0; i < vpe_priv->num_pipe; i++) {
303         pipe_ctx = &vpe_priv->pipe_ctx[i];
304 
305         if (!free_pipe && (pipe_ctx->owner == PIPE_CTX_NO_OWNER))
306             free_pipe = pipe_ctx;
307         // re-use the same pipe
308         else if (pipe_ctx->owner == stream_idx) {
309             *reuse = true;
310             return pipe_ctx;
311         }
312     }
313 
314     if (free_pipe) {
315         free_pipe->owner = stream_idx;
316     }
317     *reuse = false;
318     return free_pipe;
319 }
320 
calculate_recout(struct segment_ctx * segment)321 static void calculate_recout(struct segment_ctx *segment)
322 {
323     struct stream_ctx  *stream_ctx = segment->stream_ctx;
324     struct scaler_data *data       = &segment->scaler_data;
325     struct vpe_rect    *dst_rect;
326     int32_t             split_count, split_idx;
327 
328     dst_rect = &stream_ctx->stream.scaling_info.dst_rect;
329 
330     split_count = stream_ctx->num_segments - 1;
331     split_idx   = segment->segment_idx;
332 
333     // src & dst rect has been clipped earlier
334     data->recout.x      = 0;
335     data->recout.y      = 0;
336     data->recout.width  = dst_rect->width;
337     data->recout.height = dst_rect->height;
338 
339     if (split_count) {
340         /* extra pixels in the division remainder need to go to pipes after
341          * the extra pixel index minus one(epimo) defined here as:
342          */
343         int32_t epimo = split_count - (int32_t)data->recout.width % (split_count + 1);
344 
345         data->recout.x += ((int32_t)data->recout.width / (split_count + 1)) * split_idx;
346         if (split_idx > epimo)
347             data->recout.x += split_idx - epimo - 1;
348 
349         data->recout.width =
350             data->recout.width / (uint32_t)(split_count + 1) + (split_idx > epimo ? 1 : 0);
351     }
352 }
353 
calculate_scaling_ratios(struct scaler_data * scl_data,struct vpe_rect * src_rect,struct vpe_rect * dst_rect,enum vpe_surface_pixel_format format)354 void calculate_scaling_ratios(struct scaler_data *scl_data, struct vpe_rect *src_rect,
355     struct vpe_rect *dst_rect, enum vpe_surface_pixel_format format)
356 {
357     // no rotation support
358 
359     scl_data->ratios.horz   = vpe_fixpt_from_fraction(src_rect->width, dst_rect->width);
360     scl_data->ratios.vert   = vpe_fixpt_from_fraction(src_rect->height, dst_rect->height);
361     scl_data->ratios.horz_c = scl_data->ratios.horz;
362     scl_data->ratios.vert_c = scl_data->ratios.vert;
363 
364     if (vpe_is_yuv420(format)) {
365         scl_data->ratios.horz_c.value /= 2;
366         scl_data->ratios.vert_c.value /= 2;
367     }
368 
369     scl_data->ratios.horz   = vpe_fixpt_truncate(scl_data->ratios.horz, 19);
370     scl_data->ratios.vert   = vpe_fixpt_truncate(scl_data->ratios.vert, 19);
371     scl_data->ratios.horz_c = vpe_fixpt_truncate(scl_data->ratios.horz_c, 19);
372     scl_data->ratios.vert_c = vpe_fixpt_truncate(scl_data->ratios.vert_c, 19);
373 }
374 
375 /*
376  * This is a preliminary vp size calculation to allow us to check taps support.
377  * The result is completely overridden afterwards.
378  */
calculate_viewport_size(struct segment_ctx * segment_ctx)379 static void calculate_viewport_size(struct segment_ctx *segment_ctx)
380 {
381     struct scaler_data *data = &segment_ctx->scaler_data;
382 
383     data->viewport.width =
384         (uint32_t)vpe_fixpt_ceil(vpe_fixpt_mul_int(data->ratios.horz, (int)data->recout.width));
385     data->viewport.height =
386         (uint32_t)vpe_fixpt_ceil(vpe_fixpt_mul_int(data->ratios.vert, (int)data->recout.height));
387     data->viewport_c.width =
388         (uint32_t)vpe_fixpt_ceil(vpe_fixpt_mul_int(data->ratios.horz_c, (int)data->recout.width));
389     data->viewport_c.height =
390         (uint32_t)vpe_fixpt_ceil(vpe_fixpt_mul_int(data->ratios.vert_c, (int)data->recout.height));
391 }
392 
393 /*
394  * We completely calculate vp offset, size and inits here based entirely on scaling
395  * ratios and recout for pixel perfect pipe combine.
396  */
calculate_init_and_vp(bool flip_scan_dir,int32_t recout_offset,uint32_t recout_size,uint32_t src_size,uint32_t taps,struct fixed31_32 ratio,struct fixed31_32 init_adj,struct fixed31_32 * init,int32_t * vp_offset,uint32_t * vp_size)397 static void calculate_init_and_vp(bool flip_scan_dir, int32_t recout_offset, uint32_t recout_size,
398     uint32_t src_size, uint32_t taps, struct fixed31_32 ratio, struct fixed31_32 init_adj,
399     struct fixed31_32 *init, int32_t *vp_offset, uint32_t *vp_size)
400 {
401 
402     struct fixed31_32 src_offset, temp;
403     int32_t           int_part;
404 
405     /*
406      * First of the taps starts sampling pixel number <init_int_part> corresponding to recout
407      * pixel 1. Next recout pixel samples int part of <init + scaling ratio> and so on.
408      * All following calculations are based on this logic.
409      */
410     src_offset = vpe_fixpt_mul_int(ratio, recout_offset);
411     *vp_offset = vpe_fixpt_floor(src_offset);
412 
413     // calculate the phase
414     init->value = src_offset.value & 0xffffffff; // for phase accumulation
415     *init       = vpe_fixpt_add(*init, init_adj);
416     int_part    = vpe_fixpt_floor(vpe_fixpt_from_fraction(taps, 2)) +
417                1; // middle point of the sampling window
418     *init = vpe_fixpt_add_int(*init, int_part);
419     *init = vpe_fixpt_truncate(*init, 19);
420     /*
421      * If there are more pixels on the left hand side (top for vertical scaling) of the
422      * sampling point which can be covered by the taps, init value needs go get increased
423      * to be able to buffer the pixels as much as taps.
424      */
425     if (int_part < (int32_t)taps) {
426         int32_t left = (int32_t)taps - int_part;
427         if (left > *vp_offset)
428             left = *vp_offset;
429         *vp_offset -= left;
430         *init = vpe_fixpt_add_int(*init, left);
431     }
432     /*
433      * If taps are sampling outside of viewport at end of recout and there are more pixels
434      * available in the surface we should increase the viewport size, regardless set vp to
435      * only what is used.
436      */
437     temp     = vpe_fixpt_add(*init, vpe_fixpt_mul_int(ratio, (int)(recout_size - 1)));
438     *vp_size = (uint32_t)vpe_fixpt_floor(temp);
439     if ((uint32_t)((int32_t)*vp_size + *vp_offset) > src_size)
440         *vp_size = (uint32_t)((int32_t)src_size - *vp_offset);
441     /* We did all the math assuming we are scanning same direction as display does,
442      * however mirror/rotation changes how vp scans vs how it is offset. If scan direction
443      * is flipped we simply need to calculate offset from the other side of plane.
444      * Note that outside of viewport all scaling hardware works in recout space.
445      */
446     if (flip_scan_dir)
447         *vp_offset = (int32_t)src_size - *vp_offset - (int32_t)*vp_size;
448 }
449 
get_vp_scan_direction(enum vpe_rotation_angle rotation,bool horizontal_mirror,bool * orthogonal_rotation,bool * flip_vert_scan_dir,bool * flip_horz_scan_dir)450 static inline void get_vp_scan_direction(enum vpe_rotation_angle rotation, bool horizontal_mirror,
451     bool *orthogonal_rotation, bool *flip_vert_scan_dir, bool *flip_horz_scan_dir)
452 {
453     *orthogonal_rotation = false;
454     *flip_vert_scan_dir  = false;
455     *flip_horz_scan_dir  = false;
456     if (rotation == VPE_ROTATION_ANGLE_180) {
457         *flip_vert_scan_dir = true;
458         *flip_horz_scan_dir = true;
459     } else if (rotation == VPE_ROTATION_ANGLE_90) {
460         *orthogonal_rotation = true;
461         *flip_horz_scan_dir  = true;
462     } else if (rotation == VPE_ROTATION_ANGLE_270) {
463         *orthogonal_rotation = true;
464         *flip_vert_scan_dir  = true;
465     }
466 
467     if (horizontal_mirror)
468         *flip_horz_scan_dir = !*flip_horz_scan_dir;
469 }
470 
calculate_inits_and_viewports(struct segment_ctx * segment_ctx)471 static enum vpe_status calculate_inits_and_viewports(struct segment_ctx *segment_ctx)
472 {
473     struct stream_ctx       *stream_ctx   = segment_ctx->stream_ctx;
474     struct vpe_surface_info *surface_info = &stream_ctx->stream.surface_info;
475     struct vpe_rect          src_rect     = stream_ctx->stream.scaling_info.src_rect;
476     struct vpe_rect         *dst_rect     = &stream_ctx->stream.scaling_info.dst_rect;
477     struct scaler_data      *data         = &segment_ctx->scaler_data;
478     uint32_t                 vpc_h_div    = vpe_is_yuv420(data->format) ? 2 : 1;
479     uint32_t                 vpc_v_div    = vpe_is_yuv420(data->format) ? 2 : 1;
480     bool                     orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir;
481     struct fixed31_32        init_adj_h = vpe_fixpt_zero;
482     struct fixed31_32        init_adj_v = vpe_fixpt_zero;
483 
484     get_vp_scan_direction(stream_ctx->stream.rotation, stream_ctx->stream.horizontal_mirror,
485         &orthogonal_rotation, &flip_vert_scan_dir, &flip_horz_scan_dir);
486 
487     if (orthogonal_rotation) {
488         swap(src_rect.width, src_rect.height);
489         swap(flip_vert_scan_dir, flip_horz_scan_dir);
490     }
491 
492     if (flip_horz_scan_dir) {
493         if (stream_ctx->flip_horizonal_output)
494             // flip at the output instead
495             flip_horz_scan_dir = false;
496     }
497 
498     if (vpe_is_yuv420(data->format)) {
499         int sign = -1; // this gives the direction of the cositing (negative will move left, right
500                        // otherwise)
501         switch (surface_info->cs.cositing) {
502 
503         case VPE_CHROMA_COSITING_LEFT:
504             init_adj_h = vpe_fixpt_zero;
505             init_adj_v = vpe_fixpt_from_fraction(sign, 4);
506             break;
507         case VPE_CHROMA_COSITING_NONE:
508             init_adj_h = vpe_fixpt_from_fraction(sign, 4);
509             init_adj_v = vpe_fixpt_from_fraction(sign, 4);
510             break;
511         case VPE_CHROMA_COSITING_TOPLEFT:
512         default:
513             init_adj_h = vpe_fixpt_zero;
514             init_adj_v = vpe_fixpt_zero;
515             break;
516         }
517     }
518 
519     calculate_init_and_vp(flip_horz_scan_dir, data->recout.x, data->recout.width, src_rect.width,
520         data->taps.h_taps, data->ratios.horz, vpe_fixpt_zero, &data->inits.h, &data->viewport.x,
521         &data->viewport.width);
522     calculate_init_and_vp(flip_horz_scan_dir, data->recout.x, data->recout.width,
523         src_rect.width / vpc_h_div, data->taps.h_taps_c, data->ratios.horz_c, init_adj_h,
524         &data->inits.h_c, &data->viewport_c.x, &data->viewport_c.width);
525     calculate_init_and_vp(flip_vert_scan_dir, data->recout.y, data->recout.height, src_rect.height,
526         data->taps.v_taps, data->ratios.vert, vpe_fixpt_zero, &data->inits.v, &data->viewport.y,
527         &data->viewport.height);
528     calculate_init_and_vp(flip_vert_scan_dir, data->recout.y, data->recout.height,
529         src_rect.height / vpc_v_div, data->taps.v_taps_c, data->ratios.vert_c, init_adj_v,
530         &data->inits.v_c, &data->viewport_c.y, &data->viewport_c.height);
531 
532     // convert to absolute address
533     data->viewport.x += src_rect.x;
534     data->viewport.y += src_rect.y;
535     data->viewport_c.x += src_rect.x / (int32_t)vpc_h_div;
536     data->viewport_c.y += src_rect.y / (int32_t)vpc_v_div;
537 
538     return VPE_STATUS_OK;
539 }
540 
vpe_get_num_segments(struct vpe_priv * vpe_priv,const struct vpe_rect * src,const struct vpe_rect * dst,const uint32_t max_seg_width)541 uint16_t vpe_get_num_segments(struct vpe_priv *vpe_priv, const struct vpe_rect *src,
542     const struct vpe_rect *dst, const uint32_t max_seg_width)
543 {
544     int num_seg_src = (int)(ceil((double)src->width / max_seg_width));
545     int num_seg_dst = (int)(ceil((double)dst->width / max_seg_width));
546     return (uint16_t)(max(max(num_seg_src, num_seg_dst), 1));
547 }
548 
vpe_clip_stream(struct vpe_rect * src_rect,struct vpe_rect * dst_rect,const struct vpe_rect * target_rect)549 void vpe_clip_stream(
550     struct vpe_rect *src_rect, struct vpe_rect *dst_rect, const struct vpe_rect *target_rect)
551 {
552     struct fixed31_32 scaling_ratio_h;
553     struct fixed31_32 scaling_ratio_v;
554 
555     struct vpe_rect clipped_dst_rect, clipped_src_rect;
556     uint32_t        clipped_pixels;
557 
558     clipped_dst_rect = *dst_rect;
559     clipped_src_rect = *src_rect;
560 
561     scaling_ratio_h = vpe_fixpt_from_fraction(src_rect->width, dst_rect->width);
562     scaling_ratio_v = vpe_fixpt_from_fraction(src_rect->height, dst_rect->height);
563 
564     if (dst_rect->x < target_rect->x) {
565         clipped_pixels     = (uint32_t)(target_rect->x - dst_rect->x);
566         clipped_dst_rect.x = target_rect->x;
567         clipped_dst_rect.width -= clipped_pixels;
568         clipped_pixels = (uint32_t)vpe_fixpt_round(
569             vpe_fixpt_mul_int(scaling_ratio_h, (int)(target_rect->x - dst_rect->x)));
570         clipped_src_rect.x += (int32_t)clipped_pixels;
571         clipped_src_rect.width -= clipped_pixels;
572     }
573     if (dst_rect->y < target_rect->y) {
574         clipped_pixels     = (uint32_t)(target_rect->y - dst_rect->y);
575         clipped_dst_rect.y = target_rect->y;
576         clipped_dst_rect.height -= clipped_pixels;
577         clipped_pixels = (uint32_t)vpe_fixpt_round(
578             vpe_fixpt_mul_int(scaling_ratio_v, (int)(target_rect->y - dst_rect->y)));
579         clipped_src_rect.y += (int32_t)clipped_pixels;
580         clipped_src_rect.height -= clipped_pixels;
581     }
582     if (dst_rect->x + (int32_t)dst_rect->width > target_rect->x + (int32_t)target_rect->width) {
583         clipped_dst_rect.width =
584             (uint32_t)(target_rect->x + (int32_t)target_rect->width - clipped_dst_rect.x);
585         clipped_src_rect.width = (uint32_t)vpe_fixpt_round(
586             vpe_fixpt_mul_int(scaling_ratio_h, (int)clipped_dst_rect.width));
587     }
588     if (dst_rect->y + (int32_t)dst_rect->height > target_rect->y + (int32_t)target_rect->height) {
589         clipped_dst_rect.height =
590             (uint32_t)(target_rect->y + (int32_t)target_rect->height - clipped_dst_rect.y);
591         clipped_src_rect.height = (uint32_t)vpe_fixpt_round(
592             vpe_fixpt_mul_int(scaling_ratio_v, (int)clipped_dst_rect.height));
593     }
594 
595     *src_rect = clipped_src_rect;
596     *dst_rect = clipped_dst_rect;
597 }
598 
vpe_resource_build_scaling_params(struct segment_ctx * segment_ctx)599 enum vpe_status vpe_resource_build_scaling_params(struct segment_ctx *segment_ctx)
600 {
601     struct stream_ctx  *stream_ctx = segment_ctx->stream_ctx;
602     struct scaler_data *scl_data   = &segment_ctx->scaler_data;
603     struct dpp         *dpp        = stream_ctx->vpe_priv->resource.dpp[0];
604 
605     scl_data->format             = stream_ctx->stream.surface_info.format;
606     scl_data->lb_params.alpha_en = stream_ctx->per_pixel_alpha;
607 
608     // h/v active will be set later
609 
610     /* recout.x is temporary for viewport calculation,
611      * will be finalized in calculate_dst_viewport_and_active()
612      */
613 
614     calculate_recout(segment_ctx);
615     calculate_viewport_size(segment_ctx);
616 
617     if (scl_data->viewport.height < 1 || scl_data->viewport.width < 1)
618         return VPE_STATUS_VIEWPORT_SIZE_NOT_SUPPORTED;
619 
620     if (!dpp->funcs->validate_number_of_taps(dpp, scl_data)) {
621         return VPE_STATUS_SCALING_RATIO_NOT_SUPPORTED;
622     }
623 
624     calculate_inits_and_viewports(segment_ctx);
625 
626     if (scl_data->viewport.height < VPE_MIN_VIEWPORT_SIZE ||
627         scl_data->viewport.width < VPE_MIN_VIEWPORT_SIZE)
628         return VPE_STATUS_VIEWPORT_SIZE_NOT_SUPPORTED;
629 
630     return VPE_STATUS_OK;
631 }
632 
vpe_handle_output_h_mirror(struct vpe_priv * vpe_priv)633 void vpe_handle_output_h_mirror(struct vpe_priv *vpe_priv)
634 {
635     uint16_t           stream_idx;
636     int                seg_idx;
637     struct stream_ctx *stream_ctx;
638 
639     // swap the stream output location
640     for (stream_idx = 0; stream_idx < vpe_priv->num_streams; stream_idx++) {
641         stream_ctx = &vpe_priv->stream_ctx[stream_idx];
642         if (stream_ctx->flip_horizonal_output) {
643             struct segment_ctx *first_seg, *last_seg;
644 
645             // swap the segment output order, init the last segment first
646             first_seg = &stream_ctx->segment_ctx[0];
647             last_seg  = &stream_ctx->segment_ctx[stream_ctx->num_segments - 1];
648 
649             // last segment becomes first
650             last_seg->scaler_data.dst_viewport.x = first_seg->scaler_data.dst_viewport.x;
651 
652             for (seg_idx = (int)(stream_ctx->num_segments - 2); seg_idx >= 0; seg_idx--) {
653                 struct segment_ctx *prev_seg, *curr_seg;
654 
655                 // set the x in reverse order
656                 prev_seg = &stream_ctx->segment_ctx[seg_idx + 1];
657                 curr_seg = &stream_ctx->segment_ctx[seg_idx];
658 
659                 curr_seg->scaler_data.dst_viewport.x =
660                     prev_seg->scaler_data.dst_viewport.x +
661                     (int32_t)prev_seg->scaler_data.dst_viewport.width;
662 
663                 curr_seg->scaler_data.dst_viewport_c.x =
664                     prev_seg->scaler_data.dst_viewport_c.x +
665                     (int32_t)prev_seg->scaler_data.dst_viewport_c.width;
666             }
667         }
668     }
669 }
670 
vpe_resource_build_bit_depth_reduction_params(struct opp * opp,struct bit_depth_reduction_params * fmt_bit_depth)671 void vpe_resource_build_bit_depth_reduction_params(
672     struct opp *opp, struct bit_depth_reduction_params *fmt_bit_depth)
673 {
674     struct vpe_priv         *vpe_priv    = opp->vpe_priv;
675     struct vpe_surface_info *dst_surface = &vpe_priv->output_ctx.surface;
676     enum color_depth         display_color_depth;
677     memset(fmt_bit_depth, 0, sizeof(*fmt_bit_depth));
678 
679     display_color_depth = vpe_get_color_depth(dst_surface->format);
680 
681     switch (display_color_depth) {
682     case COLOR_DEPTH_888:
683     case COLOR_DEPTH_101010:
684         fmt_bit_depth->flags.TRUNCATE_ENABLED = 1;
685         fmt_bit_depth->flags.TRUNCATE_DEPTH   = (display_color_depth == COLOR_DEPTH_888) ? 1 : 2;
686         fmt_bit_depth->flags.TRUNCATE_MODE    = 1;
687         break;
688     default:
689         break;
690     }
691 }
692 
vpe_frontend_config_callback(void * ctx,uint64_t cfg_base_gpu,uint64_t cfg_base_cpu,uint64_t size)693 void vpe_frontend_config_callback(
694     void *ctx, uint64_t cfg_base_gpu, uint64_t cfg_base_cpu, uint64_t size)
695 {
696     struct config_frontend_cb_ctx *cb_ctx = (struct config_frontend_cb_ctx*)ctx;
697     struct vpe_priv *vpe_priv             = cb_ctx->vpe_priv;
698     struct stream_ctx *stream_ctx         = &vpe_priv->stream_ctx[cb_ctx->stream_idx];
699     enum vpe_cmd_type  cmd_type;
700 
701     if (cb_ctx->stream_sharing) {
702         VPE_ASSERT(stream_ctx->num_configs <
703                 (int)(sizeof(stream_ctx->configs) / sizeof(struct config_record)));
704 
705         stream_ctx->configs[stream_ctx->num_configs].config_base_addr = cfg_base_gpu;
706         stream_ctx->configs[stream_ctx->num_configs].config_size = size;
707         stream_ctx->num_configs++;
708     } else if (cb_ctx->stream_op_sharing) {
709         cmd_type = cb_ctx->cmd_type;
710 
711         VPE_ASSERT(
712             stream_ctx->num_stream_op_configs[cmd_type] <
713                    (int)(sizeof(stream_ctx->stream_op_configs[cmd_type]) / sizeof(struct config_record)));
714 
715         stream_ctx->stream_op_configs[cmd_type][stream_ctx->num_stream_op_configs[cmd_type]]
716             .config_base_addr = cfg_base_gpu;
717         stream_ctx->stream_op_configs[cmd_type][stream_ctx->num_stream_op_configs[cmd_type]]
718             .config_size = size;
719         stream_ctx->num_stream_op_configs[cmd_type]++;
720     }
721 
722     vpe_priv->vpe_desc_writer.add_config_desc(
723         &vpe_priv->vpe_desc_writer, cfg_base_gpu, false, (uint8_t)vpe_priv->config_writer.buf->tmz);
724 }
725 
vpe_backend_config_callback(void * ctx,uint64_t cfg_base_gpu,uint64_t cfg_base_cpu,uint64_t size)726 void vpe_backend_config_callback(
727     void *ctx, uint64_t cfg_base_gpu, uint64_t cfg_base_cpu, uint64_t size)
728 {
729     struct config_backend_cb_ctx *cb_ctx = (struct config_backend_cb_ctx*)ctx;
730     struct vpe_priv *vpe_priv            = cb_ctx->vpe_priv;
731     struct output_ctx *output_ctx        = &vpe_priv->output_ctx;
732 
733     if (cb_ctx->share) {
734         VPE_ASSERT(
735             output_ctx->num_configs < (sizeof(output_ctx->configs) / sizeof(struct config_record)));
736 
737         output_ctx->configs[output_ctx->num_configs].config_base_addr = cfg_base_gpu;
738         output_ctx->configs[output_ctx->num_configs].config_size      = size;
739         output_ctx->num_configs++;
740     }
741 
742     vpe_priv->vpe_desc_writer.add_config_desc(
743         &vpe_priv->vpe_desc_writer, cfg_base_gpu, false, (uint8_t)vpe_priv->config_writer.buf->tmz);
744 }
745