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