• 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 <string.h>
25 #include "vpe_priv.h"
26 #include "common.h"
27 #include "vpe10_resource.h"
28 #include "vpe10_cmd_builder.h"
29 #include "vpe10_vpec.h"
30 #include "vpe10_cdc_fe.h"
31 #include "vpe10_cdc_be.h"
32 #include "vpe10_dpp.h"
33 #include "vpe10_mpc.h"
34 #include "vpe10_opp.h"
35 #include "vpe10_background.h"
36 #include "vpe10_vpe_desc_writer.h"
37 #include "vpe10_plane_desc_writer.h"
38 #include "vpe10_config_writer.h"
39 #include "vpe10/inc/asic/bringup_vpe_6_1_0_offset.h"
40 #include "vpe10/inc/asic/bringup_vpe_6_1_0_sh_mask.h"
41 #include "vpe10/inc/asic/bringup_vpe_6_1_0_default.h"
42 #include "vpe10/inc/asic/vpe_1_0_offset.h"
43 #include "custom_fp16.h"
44 #include "custom_float.h"
45 #include "background.h"
46 #include "vpe_visual_confirm.h"
47 #include "color_bg.h"
48 
49 #define LUT_NUM_ENTRIES   (17 * 17 * 17)
50 #define LUT_ENTRY_SIZE    (2)
51 #define LUT_NUM_COMPONENT (3)
52 #define LUT_BUFFER_SIZE   (LUT_NUM_ENTRIES * LUT_ENTRY_SIZE * LUT_NUM_COMPONENT)
53 // set field/register/bitfield name
54 #define SFRB(field_name, reg_name, post_fix) .field_name = reg_name##__##field_name##post_fix
55 
56 #define BASE_INNER(seg_id) VPE_BASE__INST0_SEG##seg_id
57 
58 #define BASE(seg_id) BASE_INNER(seg_id)
59 
60 // set register with block id and default val, init lastWrittenVal as default while isWritten set to
61 // false
62 #define SRIDFVL(reg_name, block, id)                                                               \
63     .reg_name = {BASE(reg##reg_name##_BASE_IDX) + reg##reg_name, reg##reg_name##_##DEFAULT,        \
64         reg##reg_name##_##DEFAULT, false}
65 
66 #define SRIDFVL1(reg_name)                                                                          \
67     .reg_name = {BASE(reg##reg_name##_BASE_IDX) + reg##reg_name, reg##reg_name##_##DEFAULT,         \
68         reg##reg_name##_##DEFAULT, false}
69 
70 #define SRIDFVL2(reg_name, block, id)                                                                  \
71     .block##_##reg_name = {BASE(reg##block##id##_##reg_name##_BASE_IDX) + reg##block##id##_##reg_name, \
72         reg##block##id##_##reg_name##_##DEFAULT, reg##block##id##_##reg_name##_##DEFAULT, false}
73 
74 #define SRIDFVL3(reg_name, block, id)                                                                  \
75     .block##_##reg_name = {BASE(reg##block##_##reg_name##_BASE_IDX) + reg##block##_##reg_name,         \
76         reg##block##_##reg_name##_##DEFAULT, reg##block##_##reg_name##_##DEFAULT, false}
77 
78 /***************** CDC FE registers ****************/
79 #define cdc_fe_regs(id) [id] = {CDC_FE_REG_LIST_VPE10(id)}
80 
81 static struct vpe10_cdc_fe_registers cdc_fe_regs[] = {cdc_fe_regs(0)};
82 
83 static const struct vpe10_cdc_fe_shift cdc_fe_shift = {CDC_FE_FIELD_LIST_VPE10(__SHIFT)};
84 
85 static const struct vpe10_cdc_fe_mask cdc_fe_mask = {CDC_FE_FIELD_LIST_VPE10(_MASK)};
86 
87 /***************** CDC BE registers ****************/
88 #define cdc_be_regs(id) [id] = {CDC_BE_REG_LIST_VPE10(id)}
89 
90 static struct vpe10_cdc_be_registers cdc_be_regs[] = {cdc_be_regs(0)};
91 
92 static const struct vpe10_cdc_be_shift cdc_be_shift = {CDC_BE_FIELD_LIST_VPE10(__SHIFT)};
93 
94 static const struct vpe10_cdc_be_mask cdc_be_mask = {CDC_BE_FIELD_LIST_VPE10(_MASK)};
95 
96 /***************** DPP registers ****************/
97 #define dpp_regs(id) [id] = {DPP_REG_LIST_VPE10(id)}
98 
99 static struct vpe10_dpp_registers dpp_regs[] = {dpp_regs(0)};
100 
101 static const struct vpe10_dpp_shift dpp_shift = {DPP_FIELD_LIST_VPE10(__SHIFT)};
102 
103 static const struct vpe10_dpp_mask dpp_mask = {DPP_FIELD_LIST_VPE10(_MASK)};
104 
105 /***************** MPC registers ****************/
106 #define mpc_regs(id) [id] = {MPC_REG_LIST_VPE10(id)}
107 
108 static struct vpe10_mpc_registers mpc_regs[] = {mpc_regs(0)};
109 
110 static const struct vpe10_mpc_shift mpc_shift = {MPC_FIELD_LIST_VPE10(__SHIFT)};
111 
112 static const struct vpe10_mpc_mask mpc_mask = {MPC_FIELD_LIST_VPE10(_MASK)};
113 
114 /***************** OPP registers ****************/
115 #define opp_regs(id) [id] = {OPP_REG_LIST_VPE10(id)}
116 
117 static struct vpe10_opp_registers opp_regs[] = {opp_regs(0)};
118 
119 static const struct vpe10_opp_shift opp_shift = {OPP_FIELD_LIST_VPE10(__SHIFT)};
120 
121 static const struct vpe10_opp_mask opp_mask = {OPP_FIELD_LIST_VPE10(_MASK)};
122 
123 static struct vpe_caps caps = {
124     .lut_size               = LUT_BUFFER_SIZE,
125     .rotation_support       = 0,
126     .h_mirror_support       = 1,
127     .v_mirror_support       = 0,
128     .is_apu                 = 1,
129     .bg_color_check_support = 0,
130     .resource_caps =
131         {
132             .num_dpp       = 1,
133             .num_opp       = 1,
134             .num_mpc_3dlut = 1,
135             .num_queue     = 8,
136             .num_cdc_be    = 1,
137         },
138     .color_caps = {.dpp =
139                        {
140                            .pre_csc    = 1,
141                            .luma_key   = 0,
142                            .color_key  = 1,
143                            .dgam_ram   = 0,
144                            .post_csc   = 1,
145                            .gamma_corr = 1,
146                            .hw_3dlut   = 1,
147                            .ogam_ram   = 1, /**< programmable gam in output -> gamma_corr */
148                            .ocsc       = 0,
149                            .dgam_rom_caps =
150                                {
151                                    .srgb     = 1,
152                                    .bt2020   = 1,
153                                    .gamma2_2 = 1,
154                                    .pq       = 1,
155                                    .hlg      = 1,
156                                },
157                        },
158         .mpc =
159             {
160                 .gamut_remap         = 1,
161                 .ogam_ram            = 1,
162                 .ocsc                = 1,
163                 .shared_3d_lut       = 1,
164                 .global_alpha        = 1,
165                 .top_bottom_blending = 0,
166             }},
167     .plane_caps =
168         {
169             .per_pixel_alpha = 1,
170             .input_pixel_format_support =
171                 {
172                     .argb_packed_32b = 1,
173                     .nv12            = 1,
174                     .fp16            = 0,
175                     .p010            = 1, /**< planar 4:2:0 10-bit */
176                     .p016            = 0, /**< planar 4:2:0 16-bit */
177                     .ayuv            = 0, /**< packed 4:4:4 */
178                     .yuy2 = 0
179                 },
180             .output_pixel_format_support =
181                 {
182                     .argb_packed_32b = 1,
183                     .nv12            = 0,
184                     .fp16            = 1,
185                     .p010            = 0, /**< planar 4:2:0 10-bit */
186                     .p016            = 0, /**< planar 4:2:0 16-bit */
187                     .ayuv            = 0, /**< packed 4:4:4 */
188                     .yuy2 = 0
189                 },
190             .max_upscale_factor = 64000,
191 
192             /*
193              * 4:1 downscaling ratio : 1000 / 4 = 250
194              * vpelib does not support more than 4:1 to preserve quality
195              * due to the limitation of using maximum number of 8 taps
196              */
197             .max_downscale_factor = 250,
198 
199             .pitch_alignment    = 256,
200             .addr_alignment     = 256,
201             .max_viewport_width = 1024,
202         },
203 };
204 
vpe10_init_scaler_data(struct vpe_priv * vpe_priv,struct stream_ctx * stream_ctx,struct scaler_data * scl_data,struct vpe_rect * src_rect,struct vpe_rect * dst_rect)205 static bool vpe10_init_scaler_data(struct vpe_priv *vpe_priv, struct stream_ctx *stream_ctx,
206     struct scaler_data *scl_data, struct vpe_rect *src_rect, struct vpe_rect *dst_rect)
207 {
208     struct dpp *dpp;
209     dpp = vpe_priv->resource.dpp[0];
210 
211     calculate_scaling_ratios(scl_data, src_rect, dst_rect, stream_ctx->stream.surface_info.format);
212 
213     scl_data->taps.v_taps   = stream_ctx->stream.scaling_info.taps.v_taps;
214     scl_data->taps.h_taps   = stream_ctx->stream.scaling_info.taps.h_taps;
215     scl_data->taps.v_taps_c = stream_ctx->stream.scaling_info.taps.v_taps_c;
216     scl_data->taps.h_taps_c = stream_ctx->stream.scaling_info.taps.h_taps_c;
217     if (!vpe_priv->init.debug.skip_optimal_tap_check) {
218         if (!dpp->funcs->get_optimal_number_of_taps(src_rect, dst_rect, &scl_data->taps)) {
219             return false;
220         }
221     }
222 
223     if ((stream_ctx->stream.use_external_scaling_coeffs ==
224             false) || /* don't try to optimize is the scaler is configured externally*/
225         (stream_ctx->stream.polyphase_scaling_coeffs.taps.h_taps == 0) ||
226         (stream_ctx->stream.polyphase_scaling_coeffs.taps.v_taps == 0)) {
227         scl_data->polyphase_filter_coeffs = 0;
228     } else {
229         if ((stream_ctx->stream.polyphase_scaling_coeffs.taps.h_taps !=
230                 stream_ctx->stream.scaling_info.taps.h_taps) ||
231             (stream_ctx->stream.polyphase_scaling_coeffs.taps.v_taps !=
232                 stream_ctx->stream.scaling_info.taps.v_taps)) {
233             return false; // sanity check to make sure the taps structures are the same
234         }
235         scl_data->taps = stream_ctx->stream.polyphase_scaling_coeffs
236                              .taps; /* use the extenally provided tap configuration*/
237         scl_data->polyphase_filter_coeffs = &stream_ctx->stream.polyphase_scaling_coeffs;
238     }
239     // bypass scaler if all ratios are 1
240     if (IDENTITY_RATIO(scl_data->ratios.horz))
241         scl_data->taps.h_taps = 1;
242     if (IDENTITY_RATIO(scl_data->ratios.vert))
243         scl_data->taps.v_taps = 1;
244 
245     return true;
246 }
247 
vpe10_set_num_segments(struct vpe_priv * vpe_priv,struct stream_ctx * stream_ctx,struct scaler_data * scl_data,struct vpe_rect * src_rect,struct vpe_rect * dst_rect,uint32_t * max_seg_width)248 enum vpe_status vpe10_set_num_segments(struct vpe_priv *vpe_priv, struct stream_ctx *stream_ctx,
249     struct scaler_data *scl_data, struct vpe_rect *src_rect, struct vpe_rect *dst_rect,
250     uint32_t *max_seg_width)
251 {
252 
253     uint16_t       num_segs;
254     struct dpp    *dpp         = vpe_priv->resource.dpp[0];
255     const uint32_t max_lb_size = dpp->funcs->get_line_buffer_size();
256 
257     *max_seg_width = min(*max_seg_width, max_lb_size / scl_data->taps.v_taps);
258 
259     num_segs = vpe_get_num_segments(vpe_priv, src_rect, dst_rect, *max_seg_width);
260 
261     stream_ctx->segment_ctx = vpe_alloc_segment_ctx(vpe_priv, num_segs);
262     if (!stream_ctx->segment_ctx)
263         return VPE_STATUS_NO_MEMORY;
264 
265     stream_ctx->num_segments = num_segs;
266 
267     return VPE_STATUS_OK;
268 }
269 
vpe10_get_dcc_compression_output_cap(const struct vpe * vpe,const struct vpe_dcc_surface_param * params,struct vpe_surface_dcc_cap * cap)270 bool vpe10_get_dcc_compression_output_cap(const struct vpe *vpe, const struct vpe_dcc_surface_param *params, struct vpe_surface_dcc_cap *cap)
271 {
272     cap->capable = false;
273     return cap->capable;
274 }
275 
vpe10_get_dcc_compression_input_cap(const struct vpe * vpe,const struct vpe_dcc_surface_param * params,struct vpe_surface_dcc_cap * cap)276 bool vpe10_get_dcc_compression_input_cap(const struct vpe *vpe, const struct vpe_dcc_surface_param *params, struct vpe_surface_dcc_cap *cap)
277 {
278     cap->capable = false;
279     return cap->capable;
280 }
281 
282 static struct vpe_cap_funcs cap_funcs =
283 {
284     .get_dcc_compression_output_cap = vpe10_get_dcc_compression_output_cap,
285     .get_dcc_compression_input_cap  = vpe10_get_dcc_compression_input_cap
286 };
287 
vpe10_cdc_fe_create(struct vpe_priv * vpe_priv,int inst)288 struct cdc_fe *vpe10_cdc_fe_create(struct vpe_priv *vpe_priv, int inst)
289 {
290     struct vpe10_cdc_fe *vpe10_cdc_fe = vpe_zalloc(sizeof(struct vpe10_cdc_fe));
291 
292     if (!vpe10_cdc_fe)
293         return NULL;
294 
295     vpe10_construct_cdc_fe(vpe_priv, &vpe10_cdc_fe->base);
296 
297     vpe10_cdc_fe->regs  = &cdc_fe_regs[inst];
298     vpe10_cdc_fe->mask  = &cdc_fe_mask;
299     vpe10_cdc_fe->shift = &cdc_fe_shift;
300 
301     return &vpe10_cdc_fe->base;
302 }
303 
vpe10_cdc_be_create(struct vpe_priv * vpe_priv,int inst)304 struct cdc_be *vpe10_cdc_be_create(struct vpe_priv *vpe_priv, int inst)
305 {
306     struct vpe10_cdc_be *vpe10_cdc_be = vpe_zalloc(sizeof(struct vpe10_cdc_be));
307 
308     if (!vpe10_cdc_be)
309         return NULL;
310 
311     vpe10_construct_cdc_be(vpe_priv, &vpe10_cdc_be->base);
312 
313     vpe10_cdc_be->regs  = &cdc_be_regs[inst];
314     vpe10_cdc_be->mask  = &cdc_be_mask;
315     vpe10_cdc_be->shift = &cdc_be_shift;
316 
317     return &vpe10_cdc_be->base;
318 }
319 
vpe10_dpp_create(struct vpe_priv * vpe_priv,int inst)320 struct dpp *vpe10_dpp_create(struct vpe_priv *vpe_priv, int inst)
321 {
322     struct vpe10_dpp *vpe10_dpp = vpe_zalloc(sizeof(struct vpe10_dpp));
323 
324     if (!vpe10_dpp)
325         return NULL;
326 
327     vpe10_construct_dpp(vpe_priv, &vpe10_dpp->base);
328 
329     vpe10_dpp->regs  = &dpp_regs[inst];
330     vpe10_dpp->mask  = &dpp_mask;
331     vpe10_dpp->shift = &dpp_shift;
332 
333     return &vpe10_dpp->base;
334 }
335 
vpe10_mpc_create(struct vpe_priv * vpe_priv,int inst)336 struct mpc *vpe10_mpc_create(struct vpe_priv *vpe_priv, int inst)
337 {
338     struct vpe10_mpc *vpe10_mpc = vpe_zalloc(sizeof(struct vpe10_mpc));
339 
340     if (!vpe10_mpc)
341         return NULL;
342 
343     vpe10_construct_mpc(vpe_priv, &vpe10_mpc->base);
344 
345     vpe10_mpc->regs  = &mpc_regs[inst];
346     vpe10_mpc->mask  = &mpc_mask;
347     vpe10_mpc->shift = &mpc_shift;
348 
349     return &vpe10_mpc->base;
350 }
351 
vpe10_opp_create(struct vpe_priv * vpe_priv,int inst)352 struct opp *vpe10_opp_create(struct vpe_priv *vpe_priv, int inst)
353 {
354     struct vpe10_opp *vpe10_opp = vpe_zalloc(sizeof(struct vpe10_opp));
355 
356     if (!vpe10_opp)
357         return NULL;
358 
359     vpe10_construct_opp(vpe_priv, &vpe10_opp->base);
360 
361     vpe10_opp->regs  = &opp_regs[inst];
362     vpe10_opp->mask  = &opp_mask;
363     vpe10_opp->shift = &opp_shift;
364 
365     return &vpe10_opp->base;
366 }
367 
vpe10_construct_resource(struct vpe_priv * vpe_priv,struct resource * res)368 enum vpe_status vpe10_construct_resource(struct vpe_priv *vpe_priv, struct resource *res)
369 {
370     struct vpe *vpe = &vpe_priv->pub;
371 
372     vpe->caps      = &caps;
373     vpe->cap_funcs = &cap_funcs;
374 
375     vpe10_construct_vpec(vpe_priv, &res->vpec);
376 
377     res->cdc_fe[0] = vpe10_cdc_fe_create(vpe_priv, 0);
378     if (!res->cdc_fe[0])
379         goto err;
380 
381     res->dpp[0] = vpe10_dpp_create(vpe_priv, 0);
382     if (!res->dpp[0])
383         goto err;
384 
385     res->mpc[0] = vpe10_mpc_create(vpe_priv, 0);
386     if (!res->mpc[0])
387         goto err;
388 
389     res->cdc_be[0] = vpe10_cdc_be_create(vpe_priv, 0);
390     if (!res->cdc_be[0])
391         goto err;
392 
393     res->opp[0] = vpe10_opp_create(vpe_priv, 0);
394     if (!res->opp[0])
395         goto err;
396 
397     vpe10_construct_cmd_builder(vpe_priv, &res->cmd_builder);
398     vpe10_construct_vpe_desc_writer(&vpe_priv->vpe_desc_writer);
399     vpe10_construct_plane_desc_writer(&vpe_priv->plane_desc_writer);
400     vpe10_config_writer_init(&vpe_priv->config_writer);
401 
402     vpe_priv->num_pipe = 1;
403 
404     res->internal_hdr_normalization = 1;
405 
406     res->check_input_color_space           = vpe10_check_input_color_space;
407     res->check_output_color_space          = vpe10_check_output_color_space;
408     res->check_h_mirror_support            = vpe10_check_h_mirror_support;
409     res->calculate_segments                = vpe10_calculate_segments;
410     res->set_num_segments                  = vpe10_set_num_segments;
411     res->split_bg_gap                      = vpe10_split_bg_gap;
412     res->calculate_dst_viewport_and_active = vpe10_calculate_dst_viewport_and_active;
413     res->find_bg_gaps                      = vpe_find_bg_gaps;
414     res->create_bg_segments                = vpe_create_bg_segments;
415     res->populate_cmd_info                 = vpe10_populate_cmd_info;
416     res->program_frontend                  = vpe10_program_frontend;
417     res->program_backend                   = vpe10_program_backend;
418     res->get_bufs_req                      = vpe10_get_bufs_req;
419     res->check_bg_color_support            = vpe10_check_bg_color_support;
420     res->check_mirror_rotation_support     = vpe10_check_mirror_rotation_support;
421     res->update_blnd_gamma                 = vpe10_update_blnd_gamma;
422 
423     return VPE_STATUS_OK;
424 err:
425     vpe10_destroy_resource(vpe_priv, res);
426     return VPE_STATUS_ERROR;
427 }
428 
vpe10_destroy_resource(struct vpe_priv * vpe_priv,struct resource * res)429 void vpe10_destroy_resource(struct vpe_priv *vpe_priv, struct resource *res)
430 {
431     if (res->cdc_fe[0] != NULL) {
432         vpe_free(container_of(res->cdc_fe[0], struct vpe10_cdc_fe, base));
433         res->cdc_fe[0] = NULL;
434     }
435 
436     if (res->dpp[0] != NULL) {
437         vpe_free(container_of(res->dpp[0], struct vpe10_dpp, base));
438         res->dpp[0] = NULL;
439     }
440 
441     if (res->mpc[0] != NULL) {
442         vpe_free(container_of(res->mpc[0], struct vpe10_mpc, base));
443         res->mpc[0] = NULL;
444     }
445 
446     if (res->cdc_be[0] != NULL) {
447         vpe_free(container_of(res->cdc_be[0], struct vpe10_cdc_be, base));
448         res->cdc_be[0] = NULL;
449     }
450 
451     if (res->opp[0] != NULL) {
452         vpe_free(container_of(res->opp[0], struct vpe10_opp, base));
453         res->opp[0] = NULL;
454     }
455 }
456 
vpe10_check_input_color_space(struct vpe_priv * vpe_priv,enum vpe_surface_pixel_format format,const struct vpe_color_space * vcs)457 bool vpe10_check_input_color_space(struct vpe_priv *vpe_priv, enum vpe_surface_pixel_format format,
458     const struct vpe_color_space *vcs)
459 {
460     enum color_space         cs;
461     enum color_transfer_func tf;
462 
463     vpe_color_get_color_space_and_tf(vcs, &cs, &tf);
464     if (cs == COLOR_SPACE_UNKNOWN || tf == TRANSFER_FUNC_UNKNOWN)
465         return false;
466 
467     return true;
468 }
469 
vpe10_check_output_color_space(struct vpe_priv * vpe_priv,enum vpe_surface_pixel_format format,const struct vpe_color_space * vcs)470 bool vpe10_check_output_color_space(struct vpe_priv *vpe_priv, enum vpe_surface_pixel_format format,
471     const struct vpe_color_space *vcs)
472 {
473     enum color_space         cs;
474     enum color_transfer_func tf;
475 
476     // packed 32bit rgb
477     if (vcs->encoding != VPE_PIXEL_ENCODING_RGB)
478         return false;
479 
480     vpe_color_get_color_space_and_tf(vcs, &cs, &tf);
481     if (cs == COLOR_SPACE_UNKNOWN || tf == TRANSFER_FUNC_UNKNOWN)
482         return false;
483 
484     if (vpe_is_fp16(format) && tf != TRANSFER_FUNC_LINEAR)
485         return false;
486 
487     return true;
488 }
489 
vpe10_check_h_mirror_support(bool * input_mirror,bool * output_mirror)490 bool vpe10_check_h_mirror_support(bool *input_mirror, bool *output_mirror)
491 {
492     *input_mirror  = false;
493     *output_mirror = true;
494     return true;
495 }
496 
vpe10_calculate_dst_viewport_and_active(struct segment_ctx * segment_ctx,uint32_t max_seg_width)497 void vpe10_calculate_dst_viewport_and_active(
498     struct segment_ctx *segment_ctx, uint32_t max_seg_width)
499 {
500     struct scaler_data *data        = &segment_ctx->scaler_data;
501     struct stream_ctx  *stream_ctx  = segment_ctx->stream_ctx;
502     struct vpe_priv    *vpe_priv    = stream_ctx->vpe_priv;
503     struct vpe_rect    *dst_rect    = &stream_ctx->stream.scaling_info.dst_rect;
504     struct vpe_rect    *target_rect = &vpe_priv->output_ctx.target_rect;
505 
506     uint32_t vpc_div = vpe_is_yuv420(vpe_priv->output_ctx.surface.format) ? 2 : 1;
507 
508     data->dst_viewport.x     = data->recout.x + dst_rect->x;
509     data->dst_viewport.width = data->recout.width;
510 
511     // 1st stream will cover the background
512     // extends the v_active to cover the full target_rect's height
513     if (stream_ctx->stream_idx == 0) {
514         data->recout.x            = 0;
515         data->recout.y            = dst_rect->y - target_rect->y;
516         data->dst_viewport.y      = target_rect->y;
517         data->dst_viewport.height = target_rect->height;
518 
519         if (!stream_ctx->flip_horizonal_output) {
520             /* first segment :
521              * if the dst_viewport.width is not 1024,
522              * and we need background on the left, extend the active to cover as much as it can
523              */
524             if (segment_ctx->segment_idx == 0) {
525                 uint32_t remain_gap = min(max_seg_width - data->dst_viewport.width,
526                     (uint32_t)(data->dst_viewport.x - target_rect->x));
527                 data->recout.x      = (int32_t)remain_gap;
528 
529                 data->dst_viewport.x -= (int32_t)remain_gap;
530                 data->dst_viewport.width += remain_gap;
531             }
532             // last segment
533             if (segment_ctx->segment_idx == stream_ctx->num_segments - 1) {
534                 uint32_t remain_gap = min(max_seg_width - data->dst_viewport.width,
535                     (uint32_t)((target_rect->x + (int32_t)target_rect->width) -
536                                (data->dst_viewport.x + (int32_t)data->dst_viewport.width)));
537 
538                 data->dst_viewport.width += remain_gap;
539             }
540         }
541     } else {
542         data->dst_viewport.y      = data->recout.y + dst_rect->y;
543         data->dst_viewport.height = data->recout.height;
544         data->recout.y            = 0;
545         data->recout.x            = 0;
546     }
547 
548     data->dst_viewport_c.x      = data->dst_viewport.x / (int32_t)vpc_div;
549     data->dst_viewport_c.y      = data->dst_viewport.y / (int32_t)vpc_div;
550     data->dst_viewport_c.width  = data->dst_viewport.width / vpc_div;
551     data->dst_viewport_c.height = data->dst_viewport.height / vpc_div;
552 
553     // [h/v]_active
554     data->h_active = data->dst_viewport.width;
555     data->v_active = data->dst_viewport.height;
556 }
557 
558 
get_max_gap_num(struct vpe_priv * vpe_priv,const struct vpe_build_param * params,uint32_t max_seg_width)559 static uint16_t get_max_gap_num(
560     struct vpe_priv* vpe_priv, const struct vpe_build_param* params, uint32_t max_seg_width)
561 {
562     const uint16_t num_multiple = vpe_priv->vpe_num_instance ? vpe_priv->vpe_num_instance : 1;
563     bool is_color_fill = (vpe_priv->num_streams == 1) && (vpe_priv->stream_ctx[0].stream_type == VPE_STREAM_TYPE_BG_GEN);
564 
565     uint16_t max_gaps =
566         (uint16_t)(max((params->target_rect.width + max_seg_width - 1) / max_seg_width, 1));
567 
568     /* If the stream width is less than max_seg_width - 1024, and it
569     * lies inside a max_seg_width window of the background, vpe needs
570     * an extra bg segment to store that.
571        1    2  3  4   5
572     |....|....|.**.|....|
573     |....|....|.**.|....|
574     |....|....|.**.|....|
575 
576      (*: stream
577       .: background
578       |: 1k separator)
579 
580     */
581 
582     if (!is_color_fill) {
583         // full colorfillOnly case, no need to + 1 as the gap won't be seaprated by stream dst
584         // for non-colorfillOnly case, +1 for worst case the gap is separated by stream dst
585         max_gaps += 1;
586     }
587 
588     if (max_gaps % num_multiple > 0) {
589         max_gaps += num_multiple - (max_gaps % num_multiple);
590     }
591 
592     return max_gaps;
593 }
594 
vpe10_calculate_segments(struct vpe_priv * vpe_priv,const struct vpe_build_param * params)595 enum vpe_status vpe10_calculate_segments(
596     struct vpe_priv *vpe_priv, const struct vpe_build_param *params)
597 {
598     enum vpe_status     res;
599     struct vpe_rect    *gaps;
600     uint16_t            gaps_cnt, max_gaps;
601     uint16_t            stream_idx, seg_idx;
602     struct stream_ctx  *stream_ctx;
603     struct segment_ctx *segment_ctx;
604     uint32_t            max_seg_width = vpe_priv->pub.caps->plane_caps.max_viewport_width;
605     struct scaler_data  scl_data;
606     struct vpe_rect    *src_rect;
607     struct vpe_rect    *dst_rect;
608     uint32_t            factor;
609     const uint32_t      max_upscale_factor   = vpe_priv->pub.caps->plane_caps.max_upscale_factor;
610     const uint32_t      max_downscale_factor = vpe_priv->pub.caps->plane_caps.max_downscale_factor;
611     struct dpp         *dpp                  = vpe_priv->resource.dpp[0];
612     const uint32_t      max_lb_size          = dpp->funcs->get_line_buffer_size();
613 
614     for (stream_idx = 0; stream_idx < vpe_priv->num_streams; stream_idx++) {
615         stream_ctx = &vpe_priv->stream_ctx[stream_idx];
616         src_rect   = &stream_ctx->stream.scaling_info.src_rect;
617         dst_rect   = &stream_ctx->stream.scaling_info.dst_rect;
618 
619         if (stream_ctx->stream_type == VPE_STREAM_TYPE_BG_GEN)
620             continue;
621 
622         if (src_rect->width < VPE_MIN_VIEWPORT_SIZE || src_rect->height < VPE_MIN_VIEWPORT_SIZE ||
623             dst_rect->width < VPE_MIN_VIEWPORT_SIZE || dst_rect->height < VPE_MIN_VIEWPORT_SIZE) {
624             return VPE_STATUS_VIEWPORT_SIZE_NOT_SUPPORTED;
625         }
626 
627         vpe_clip_stream(src_rect, dst_rect, &params->target_rect);
628 
629         if (src_rect->width <= 0 || src_rect->height <= 0 || dst_rect->width <= 0 ||
630             dst_rect->height <= 0) {
631             vpe_log("calculate_segments: after clipping, src or dst rect contains no area. Skip "
632                     "this stream.\n");
633             stream_ctx->num_segments = 0;
634             continue;
635         }
636 
637         /* If the source frame size in either dimension is 1 then the scaling ratio becomes 0
638          * in that dimension. If destination frame size in any dimesnion is 1 the scaling ratio
639          * is NAN.
640          */
641         if (src_rect->width < VPE_MIN_VIEWPORT_SIZE || src_rect->height < VPE_MIN_VIEWPORT_SIZE ||
642             dst_rect->width < VPE_MIN_VIEWPORT_SIZE || dst_rect->height < VPE_MIN_VIEWPORT_SIZE) {
643             return VPE_STATUS_VIEWPORT_SIZE_NOT_SUPPORTED;
644         }
645         factor = (uint32_t)vpe_fixpt_ceil(
646             vpe_fixpt_from_fraction((1000 * dst_rect->width), src_rect->width));
647         if (factor > max_upscale_factor || factor < max_downscale_factor)
648             return VPE_STATUS_SCALING_RATIO_NOT_SUPPORTED;
649 
650         // initialize scaling data
651         if (!vpe10_init_scaler_data(vpe_priv, stream_ctx, &scl_data, src_rect, dst_rect))
652             return VPE_STATUS_SCALING_RATIO_NOT_SUPPORTED;
653 
654         res = vpe_priv->resource.set_num_segments(
655             vpe_priv, stream_ctx, &scl_data, src_rect, dst_rect, &max_seg_width);
656         if (res != VPE_STATUS_OK)
657             return res;
658 
659         for (seg_idx = 0; seg_idx < stream_ctx->num_segments; seg_idx++) {
660             segment_ctx              = &stream_ctx->segment_ctx[seg_idx];
661             segment_ctx->segment_idx = seg_idx;
662             segment_ctx->stream_ctx  = stream_ctx;
663 
664             segment_ctx->scaler_data.ratios = scl_data.ratios;
665             segment_ctx->scaler_data.taps   = scl_data.taps;
666             if (stream_ctx->stream.use_external_scaling_coeffs) {
667                 segment_ctx->scaler_data.polyphase_filter_coeffs =
668                     &stream_ctx->stream.polyphase_scaling_coeffs;
669             } else {
670                 segment_ctx->scaler_data.polyphase_filter_coeffs = 0;
671             }
672             res = vpe_resource_build_scaling_params(segment_ctx);
673             if (res != VPE_STATUS_OK)
674                 return res;
675 
676             vpe_priv->resource.calculate_dst_viewport_and_active(segment_ctx, max_seg_width);
677         }
678     }
679 
680     max_seg_width = vpe_priv->pub.caps->plane_caps.max_viewport_width;
681 
682     max_gaps = get_max_gap_num(vpe_priv, params, max_seg_width);
683 
684     gaps = vpe_zalloc(sizeof(struct vpe_rect) * max_gaps);
685     if (!gaps)
686         return VPE_STATUS_NO_MEMORY;
687 
688     gaps_cnt = vpe_priv->resource.find_bg_gaps(vpe_priv, &(params->target_rect), gaps, max_gaps);
689 
690     if (gaps_cnt > 0)
691         vpe_priv->resource.create_bg_segments(vpe_priv, gaps, gaps_cnt, VPE_CMD_OPS_BG);
692 
693     if (gaps != NULL) {
694         vpe_free(gaps);
695         gaps = NULL;
696     }
697 
698     vpe_handle_output_h_mirror(vpe_priv);
699 
700     res = vpe_priv->resource.populate_cmd_info(vpe_priv);
701 
702     if (res == VPE_STATUS_OK)
703         res = vpe_create_visual_confirm_segs(vpe_priv, params, max_seg_width);
704 
705     return res;
706 }
707 
build_clamping_params(struct opp * opp,struct clamping_and_pixel_encoding_params * clamping)708 static void build_clamping_params(
709     struct opp *opp, struct clamping_and_pixel_encoding_params *clamping)
710 {
711     struct vpe_priv         *vpe_priv     = opp->vpe_priv;
712     struct vpe_surface_info *dst_surface  = &vpe_priv->output_ctx.surface;
713     enum vpe_color_range     output_range = dst_surface->cs.range;
714 
715     memset(clamping, 0, sizeof(*clamping));
716     clamping->clamping_level = CLAMPING_FULL_RANGE;
717     clamping->c_depth        = vpe_get_color_depth(dst_surface->format);
718     if (output_range == VPE_COLOR_RANGE_STUDIO) {
719         if (!vpe_priv->init.debug.clamping_setting) {
720             switch (clamping->c_depth) {
721             case COLOR_DEPTH_888:
722                 clamping->clamping_level = CLAMPING_LIMITED_RANGE_8BPC;
723                 break;
724             case COLOR_DEPTH_101010:
725                 clamping->clamping_level = CLAMPING_LIMITED_RANGE_10BPC;
726                 break;
727             case COLOR_DEPTH_121212:
728                 clamping->clamping_level = CLAMPING_LIMITED_RANGE_12BPC;
729                 break;
730             default:
731                 clamping->clamping_level =
732                     CLAMPING_FULL_RANGE; // for all the others bit depths set the full range
733                 break;
734             }
735         } else {
736             switch (vpe_priv->init.debug.clamping_params.clamping_range) {
737             case VPE_CLAMPING_LIMITED_RANGE_8BPC:
738                 clamping->clamping_level = CLAMPING_LIMITED_RANGE_8BPC;
739                 break;
740             case VPE_CLAMPING_LIMITED_RANGE_10BPC:
741                 clamping->clamping_level = CLAMPING_LIMITED_RANGE_10BPC;
742                 break;
743             case VPE_CLAMPING_LIMITED_RANGE_12BPC:
744                 clamping->clamping_level = CLAMPING_LIMITED_RANGE_12BPC;
745                 break;
746             default:
747                 clamping->clamping_level =
748                     CLAMPING_LIMITED_RANGE_PROGRAMMABLE; // for all the others set to programmable
749                                                          // range
750                 clamping->r_clamp_component_lower =
751                     vpe_priv->output_ctx.clamping_params.r_clamp_component_lower;
752                 clamping->g_clamp_component_lower =
753                     vpe_priv->output_ctx.clamping_params.g_clamp_component_lower;
754                 clamping->b_clamp_component_lower =
755                     vpe_priv->output_ctx.clamping_params.b_clamp_component_lower;
756                 clamping->r_clamp_component_upper =
757                     vpe_priv->output_ctx.clamping_params.r_clamp_component_upper;
758                 clamping->g_clamp_component_upper =
759                     vpe_priv->output_ctx.clamping_params.g_clamp_component_upper;
760                 clamping->b_clamp_component_upper =
761                     vpe_priv->output_ctx.clamping_params.b_clamp_component_upper;
762                 break;
763             }
764         }
765     }
766 }
767 
vpe10_program_frontend(struct vpe_priv * vpe_priv,uint32_t pipe_idx,uint32_t cmd_idx,uint32_t cmd_input_idx,bool seg_only)768 int32_t vpe10_program_frontend(struct vpe_priv *vpe_priv, uint32_t pipe_idx, uint32_t cmd_idx,
769     uint32_t cmd_input_idx, bool seg_only)
770 {
771     struct vpe_cmd_info *cmd_info = vpe_vector_get(vpe_priv->vpe_cmd_vector, cmd_idx);
772     VPE_ASSERT(cmd_info);
773 
774     struct vpe_cmd_input      *cmd_input    = &cmd_info->inputs[cmd_input_idx];
775     struct stream_ctx         *stream_ctx   = &vpe_priv->stream_ctx[cmd_input->stream_idx];
776     struct vpe_surface_info   *surface_info = &stream_ctx->stream.surface_info;
777     struct cdc_fe             *cdc_fe       = vpe_priv->resource.cdc_fe[pipe_idx];
778     struct dpp                *dpp          = vpe_priv->resource.dpp[pipe_idx];
779     struct mpc                *mpc          = vpe_priv->resource.mpc[pipe_idx];
780     enum input_csc_select      select       = INPUT_CSC_SELECT_BYPASS;
781     uint32_t                   hw_mult      = 0;
782     struct cnv_keyer_params    keyer_params;
783     struct custom_float_format fmt;
784 
785     vpe_priv->fe_cb_ctx.stream_idx = cmd_input->stream_idx;
786     vpe_priv->fe_cb_ctx.vpe_priv   = vpe_priv;
787 
788     config_writer_set_callback(
789         &vpe_priv->config_writer, &vpe_priv->fe_cb_ctx, vpe_frontend_config_callback);
790 
791     config_writer_set_type(&vpe_priv->config_writer, CONFIG_TYPE_DIRECT, pipe_idx);
792 
793     if (!seg_only) {
794         /* start front-end programming that can be shared among segments */
795         vpe_priv->fe_cb_ctx.stream_sharing = true;
796 
797         cdc_fe->funcs->program_surface_config(cdc_fe, surface_info->format,
798             stream_ctx->stream.rotation,
799             // set to false as h_mirror is not supported by input, only supported in output
800             false, surface_info->swizzle);
801         cdc_fe->funcs->program_crossbar_config(cdc_fe, surface_info->format);
802 
803         dpp->funcs->program_cnv(dpp, surface_info->format, vpe_priv->expansion_mode);
804         if (stream_ctx->bias_scale)
805             dpp->funcs->program_cnv_bias_scale(dpp, stream_ctx->bias_scale);
806 
807         dpp->funcs->build_keyer_params(dpp, stream_ctx, &keyer_params);
808         dpp->funcs->program_alpha_keyer(dpp, &keyer_params);
809 
810         /* If input adjustment exists, program the ICSC with those values. */
811         if (stream_ctx->input_cs) {
812             select = INPUT_CSC_SELECT_ICSC;
813             dpp->funcs->program_post_csc(dpp, stream_ctx->cs, select, stream_ctx->input_cs);
814         } else {
815             dpp->funcs->program_post_csc(dpp, stream_ctx->cs, select, NULL);
816         }
817         dpp->funcs->program_input_transfer_func(dpp, stream_ctx->input_tf);
818         dpp->funcs->program_gamut_remap(dpp, stream_ctx->gamut_remap);
819 
820         // for not bypass mode, we always are in single layer coming from DPP and output to OPP
821         mpc->funcs->program_mpcc_mux(mpc, MPC_MPCCID_0, MPC_MUX_TOPSEL_DPP0, MPC_MUX_BOTSEL_DISABLE,
822             MPC_MUX_OUTMUX_MPCC0, MPC_MUX_OPPID_OPP0);
823 
824         // program shaper, 3dlut and 1dlut in MPC for stream before blend
825         mpc->funcs->program_movable_cm(
826             mpc, stream_ctx->in_shaper_func, stream_ctx->lut3d_func, stream_ctx->blend_tf, false);
827 
828         // program hdr_mult
829         fmt.exponenta_bits = 6;
830         fmt.mantissa_bits  = 12;
831         fmt.sign           = true;
832         if (stream_ctx->stream.tm_params.UID || stream_ctx->stream.tm_params.enable_3dlut) {
833             if (!vpe_convert_to_custom_float_format(
834                     stream_ctx->lut3d_func->hdr_multiplier, &fmt, &hw_mult)) {
835                 VPE_ASSERT(0);
836             }
837         } else {
838             if (!vpe_convert_to_custom_float_format(stream_ctx->white_point_gain, &fmt, &hw_mult)) {
839                 VPE_ASSERT(0);
840             }
841         }
842         dpp->funcs->set_hdr_multiplier(dpp, hw_mult);
843 
844         if (vpe_priv->init.debug.dpp_crc_ctrl)
845             dpp->funcs->program_crc(dpp, true);
846 
847         if (vpe_priv->init.debug.mpc_crc_ctrl)
848             mpc->funcs->program_crc(mpc, true);
849 
850         // put other hw programming for stream specific that can be shared here
851 
852         config_writer_complete(&vpe_priv->config_writer);
853     }
854 
855     vpe10_create_stream_ops_config(vpe_priv, pipe_idx, stream_ctx, cmd_input, cmd_info->ops);
856 
857     /* start segment specific programming */
858     vpe_priv->fe_cb_ctx.stream_sharing    = false;
859     vpe_priv->fe_cb_ctx.stream_op_sharing = false;
860     vpe_priv->fe_cb_ctx.cmd_type          = VPE_CMD_TYPE_COMPOSITING;
861 
862     cdc_fe->funcs->program_viewport(
863         cdc_fe, &cmd_input->scaler_data.viewport, &cmd_input->scaler_data.viewport_c);
864 
865     dpp->funcs->set_segment_scaler(dpp, &cmd_input->scaler_data);
866 
867     config_writer_complete(&vpe_priv->config_writer);
868 
869     return 0;
870 }
871 
vpe10_program_backend(struct vpe_priv * vpe_priv,uint32_t pipe_idx,uint32_t cmd_idx,bool seg_only)872 int32_t vpe10_program_backend(
873     struct vpe_priv *vpe_priv, uint32_t pipe_idx, uint32_t cmd_idx, bool seg_only)
874 {
875     struct output_ctx       *output_ctx   = &vpe_priv->output_ctx;
876     struct vpe_surface_info *surface_info = &vpe_priv->output_ctx.surface;
877 
878     struct cdc_be *cdc_be = vpe_priv->resource.cdc_be[pipe_idx];
879     struct opp *opp = vpe_priv->resource.opp[pipe_idx];
880     struct mpc *mpc = vpe_priv->resource.mpc[pipe_idx];
881 
882     struct bit_depth_reduction_params         fmt_bit_depth;
883     struct clamping_and_pixel_encoding_params clamp_param;
884     enum color_depth                          display_color_depth;
885     uint16_t                                  alpha_16;
886     bool                                      opp_dig_bypass = false;
887 
888     vpe_priv->be_cb_ctx.vpe_priv = vpe_priv;
889     config_writer_set_callback(
890         &vpe_priv->config_writer, &vpe_priv->be_cb_ctx, vpe_backend_config_callback);
891 
892     config_writer_set_type(&vpe_priv->config_writer, CONFIG_TYPE_DIRECT, pipe_idx);
893 
894     if (!seg_only) {
895         /* start back-end programming that can be shared among segments */
896         vpe_priv->be_cb_ctx.share = true;
897 
898         cdc_be->funcs->program_p2b_config(
899             cdc_be, surface_info->format, surface_info->swizzle, &output_ctx->target_rect, NULL);
900         cdc_be->funcs->program_global_sync(cdc_be, VPE10_CDC_VUPDATE_OFFSET_DEFAULT,
901             VPE10_CDC_VUPDATE_WIDTH_DEFAULT, VPE10_CDC_VREADY_OFFSET_DEFAULT);
902 
903         mpc->funcs->set_output_transfer_func(mpc, output_ctx);
904         // program shaper, 3dlut and 1dlut in MPC for after blend
905         // Note: cannot program both before and after blend CM
906         // caller should ensure only one is programmed
907         // mpc->funcs->program_movable_cm(mpc, output_ctx->in_shaper_func,
908         //    output_ctx->lut3d_func, output_ctx->blend_tf, true);
909         mpc->funcs->program_mpc_out(mpc, surface_info->format);
910 
911         // Post blend gamut remap
912         mpc->funcs->set_gamut_remap(mpc, output_ctx->gamut_remap);
913 
914         if (vpe_is_fp16(surface_info->format)) {
915             if (vpe_priv->output_ctx.alpha_mode == VPE_ALPHA_BGCOLOR)
916                 vpe_convert_from_float_to_fp16(
917                     (double)vpe_priv->output_ctx.mpc_bg_color.rgba.a, &alpha_16);
918             else
919                 vpe_convert_from_float_to_fp16(1.0, &alpha_16);
920 
921             opp_dig_bypass = true;
922         } else {
923             if (vpe_priv->output_ctx.alpha_mode == VPE_ALPHA_BGCOLOR)
924                 alpha_16 = (uint16_t)(vpe_priv->output_ctx.mpc_bg_color.rgba.a * 0xffff);
925             else
926                 alpha_16 = 0xffff;
927         }
928 
929         opp->funcs->program_pipe_alpha(opp, alpha_16);
930         opp->funcs->program_pipe_bypass(opp, opp_dig_bypass);
931 
932         display_color_depth = vpe_get_color_depth(surface_info->format);
933         build_clamping_params(opp, &clamp_param);
934         vpe_resource_build_bit_depth_reduction_params(opp, &fmt_bit_depth);
935 
936         // disable dynamic expansion for now as no use case
937         opp->funcs->set_dyn_expansion(opp, false, display_color_depth);
938         opp->funcs->program_fmt(opp, &fmt_bit_depth, &clamp_param);
939         if (vpe_priv->init.debug.opp_pipe_crc_ctrl)
940             opp->funcs->program_pipe_crc(opp, true);
941 
942         config_writer_complete(&vpe_priv->config_writer);
943     }
944 
945     return 0;
946 }
947 
vpe10_populate_cmd_info(struct vpe_priv * vpe_priv)948 enum vpe_status vpe10_populate_cmd_info(struct vpe_priv *vpe_priv)
949 {
950     uint16_t             stream_idx;
951     uint16_t             segment_idx;
952     struct stream_ctx   *stream_ctx;
953     struct vpe_cmd_info  cmd_info = {0};
954     bool                 tm_enabled;
955 
956     for (stream_idx = 0; stream_idx < vpe_priv->num_streams; stream_idx++) {
957         stream_ctx = &vpe_priv->stream_ctx[stream_idx];
958 
959         tm_enabled = stream_ctx->stream.tm_params.UID != 0 || stream_ctx->stream.tm_params.enable_3dlut;
960 
961         for (segment_idx = 0; segment_idx < stream_ctx->num_segments; segment_idx++) {
962 
963             cmd_info.inputs[0].stream_idx  = stream_idx;
964             cmd_info.cd                    = (uint8_t)(stream_ctx->num_segments - segment_idx - 1);
965             cmd_info.inputs[0].scaler_data = stream_ctx->segment_ctx[segment_idx].scaler_data;
966             cmd_info.num_outputs           = 1;
967 
968             cmd_info.outputs[0].dst_viewport =
969                 stream_ctx->segment_ctx[segment_idx].scaler_data.dst_viewport;
970             cmd_info.outputs[0].dst_viewport_c =
971                 stream_ctx->segment_ctx[segment_idx].scaler_data.dst_viewport_c;
972 
973             cmd_info.num_inputs         = 1;
974             cmd_info.ops                = VPE_CMD_OPS_COMPOSITING;
975             cmd_info.tm_enabled         = tm_enabled;
976             cmd_info.insert_start_csync = false;
977             cmd_info.insert_end_csync   = false;
978             vpe_vector_push(vpe_priv->vpe_cmd_vector, &cmd_info);
979 
980             // The following codes are only valid if blending is supported
981             /*
982             if (cmd_info->ops == VPE_CMD_OPS_BLENDING) {
983                 if (cmd_info->cd == (stream_ctx->num_segments - 1)) {
984                     cmd_info->insert_start_csync = true;
985                 }
986 
987                 if (cmd_info->cd == 0) {
988                     cmd_info->insert_end_csync = true;
989                 }
990             }
991             */
992         }
993     }
994 
995     return VPE_STATUS_OK;
996 }
997 
vpe10_create_stream_ops_config(struct vpe_priv * vpe_priv,uint32_t pipe_idx,struct stream_ctx * stream_ctx,struct vpe_cmd_input * cmd_input,enum vpe_cmd_ops ops)998 void vpe10_create_stream_ops_config(struct vpe_priv *vpe_priv, uint32_t pipe_idx,
999     struct stream_ctx *stream_ctx, struct vpe_cmd_input *cmd_input, enum vpe_cmd_ops ops)
1000 {
1001     /* put all hw programming that can be shared according to the cmd type within a stream here */
1002     struct mpcc_blnd_cfg blndcfg  = {0};
1003     struct dpp          *dpp      = vpe_priv->resource.dpp[pipe_idx];
1004     struct mpc          *mpc      = vpe_priv->resource.mpc[pipe_idx];
1005     enum vpe_cmd_type    cmd_type = VPE_CMD_TYPE_COUNT;
1006     struct vpe_vector   *config_vector;
1007 
1008     vpe_priv->fe_cb_ctx.stream_op_sharing = true;
1009     vpe_priv->fe_cb_ctx.stream_sharing    = false;
1010 
1011     if (ops == VPE_CMD_OPS_BG) {
1012         cmd_type = VPE_CMD_TYPE_BG;
1013     } else if (ops == VPE_CMD_OPS_COMPOSITING) {
1014         cmd_type = VPE_CMD_TYPE_COMPOSITING;
1015     } else if (ops == VPE_CMD_OPS_BG_VSCF_INPUT) {
1016         cmd_type = VPE_CMD_TYPE_BG_VSCF_INPUT;
1017     } else if (ops == VPE_CMD_OPS_BG_VSCF_OUTPUT) {
1018         cmd_type = VPE_CMD_TYPE_BG_VSCF_OUTPUT;
1019     } else
1020         return;
1021 
1022     // return if already generated
1023     config_vector = stream_ctx->stream_op_configs[pipe_idx][cmd_type];
1024     if (config_vector->num_elements)
1025         return;
1026 
1027     vpe_priv->fe_cb_ctx.cmd_type = cmd_type;
1028 
1029     dpp->funcs->set_frame_scaler(dpp, &cmd_input->scaler_data);
1030 
1031     if (ops == VPE_CMD_OPS_BG_VSCF_INPUT) {
1032         blndcfg.bg_color = vpe_get_visual_confirm_color(stream_ctx->stream.surface_info.format,
1033             stream_ctx->stream.surface_info.cs, vpe_priv->output_ctx.cs,
1034             vpe_priv->output_ctx.output_tf, vpe_priv->output_ctx.surface.format,
1035             (stream_ctx->stream.tm_params.UID != 0 || stream_ctx->stream.tm_params.enable_3dlut));
1036     } else if (ops == VPE_CMD_OPS_BG_VSCF_OUTPUT) {
1037         blndcfg.bg_color = vpe_get_visual_confirm_color(vpe_priv->output_ctx.surface.format,
1038             vpe_priv->output_ctx.surface.cs, vpe_priv->output_ctx.cs,
1039             vpe_priv->output_ctx.output_tf, vpe_priv->output_ctx.surface.format,
1040             false); // 3DLUT should only affect input visual confirm
1041     } else {
1042         blndcfg.bg_color = vpe_priv->output_ctx.mpc_bg_color;
1043     }
1044     blndcfg.global_gain          = 0xff;
1045     blndcfg.pre_multiplied_alpha = false;
1046 
1047     if (stream_ctx->stream.blend_info.blending) {
1048         if (stream_ctx->per_pixel_alpha) {
1049             blndcfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
1050 
1051             blndcfg.pre_multiplied_alpha = stream_ctx->stream.blend_info.pre_multiplied_alpha;
1052             if (stream_ctx->stream.blend_info.global_alpha)
1053                 blndcfg.global_gain =
1054                     (uint8_t)(stream_ctx->stream.blend_info.global_alpha_value * 0xff);
1055         } else {
1056             blndcfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
1057             if (stream_ctx->stream.blend_info.global_alpha == true) {
1058                 VPE_ASSERT(stream_ctx->stream.blend_info.global_alpha_value <= 1.0f);
1059                 blndcfg.global_alpha =
1060                     (uint8_t)(stream_ctx->stream.blend_info.global_alpha_value * 0xff);
1061             } else {
1062                 // Global alpha not enabled, make top layer opaque
1063                 blndcfg.global_alpha = 0xff;
1064             }
1065         }
1066     } else {
1067         blndcfg.alpha_mode   = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
1068         blndcfg.global_alpha = 0xff;
1069     }
1070 
1071     if (cmd_type == VPE_CMD_TYPE_BG || cmd_type == VPE_CMD_TYPE_BG_VSCF_INPUT ||
1072         cmd_type == VPE_CMD_TYPE_BG_VSCF_OUTPUT) {
1073         // for bg commands, make top layer transparent
1074         // as global alpha only works when global alpha mode, set global alpha mode as well
1075         blndcfg.global_alpha = 0;
1076         blndcfg.global_gain  = 0xff;
1077         blndcfg.alpha_mode   = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
1078     }
1079 
1080     blndcfg.overlap_only     = false;
1081     blndcfg.bottom_gain_mode = 0;
1082 
1083     switch (vpe_priv->init.debug.bg_bit_depth) {
1084     case 8:
1085         blndcfg.background_color_bpc = 0;
1086         break;
1087     case 9:
1088         blndcfg.background_color_bpc = 1;
1089         break;
1090     case 10:
1091         blndcfg.background_color_bpc = 2;
1092         break;
1093     case 11:
1094         blndcfg.background_color_bpc = 3;
1095         break;
1096     case 12:
1097     default:
1098         blndcfg.background_color_bpc = 4; // 12 bit. DAL's choice;
1099         break;
1100     }
1101 
1102     blndcfg.top_gain            = 0x1f000;
1103     blndcfg.bottom_inside_gain  = 0x1f000;
1104     blndcfg.bottom_outside_gain = 0x1f000;
1105 
1106     mpc->funcs->program_mpcc_blending(mpc, MPC_MPCCID_0, &blndcfg);
1107 
1108     config_writer_complete(&vpe_priv->config_writer);
1109 }
1110 
1111 #define VPE10_GENERAL_VPE_DESC_SIZE                144   // 4 * (4 + (2 * MAX_NUM_SAVED_CONFIG))
1112 #define VPE10_GENERAL_EMB_USAGE_FRAME_SHARED       6000  // currently max 4804 is recorded
1113 #define VPE10_GENERAL_EMB_USAGE_3DLUT_FRAME_SHARED 40960 // currently max 35192 is recorded
1114 #define VPE10_GENERAL_EMB_USAGE_BG_SHARED          3600 // currently max 52 + 128 + 1356 +1020 +92 + 60 + 116 = 2824 is recorded
1115 #define VPE10_GENERAL_EMB_USAGE_SEG_NON_SHARED                                                     \
1116     240 // segment specific config + plane descripor size. currently max 92 + 72 = 164 is recorded.
1117 
vpe10_get_bufs_req(struct vpe_priv * vpe_priv,struct vpe_bufs_req * req)1118 void vpe10_get_bufs_req(struct vpe_priv *vpe_priv, struct vpe_bufs_req *req)
1119 {
1120     uint32_t             i;
1121     struct vpe_cmd_info *cmd_info;
1122     uint32_t             stream_idx                 = 0xFFFFFFFF;
1123     uint64_t             emb_req                    = 0;
1124     bool                 have_visual_confirm_input  = false;
1125     bool                 have_visual_confirm_output = false;
1126 
1127     req->cmd_buf_size = 0;
1128     req->emb_buf_size = 0;
1129 
1130     for (i = 0; i < vpe_priv->vpe_cmd_vector->num_elements; i++) {
1131         cmd_info = vpe_vector_get(vpe_priv->vpe_cmd_vector, i);
1132         VPE_ASSERT(cmd_info);
1133 
1134         // each cmd consumes one VPE descriptor
1135         req->cmd_buf_size += VPE10_GENERAL_VPE_DESC_SIZE;
1136 
1137         // if a command represents the first segment of a stream,
1138         // total amount of config sizes is added, but for other segments
1139         // just the segment specific config size is added
1140         if (cmd_info->ops == VPE_CMD_OPS_COMPOSITING) {
1141             if (stream_idx != cmd_info->inputs[0].stream_idx) {
1142                 emb_req    = cmd_info->tm_enabled ? VPE10_GENERAL_EMB_USAGE_3DLUT_FRAME_SHARED
1143                                                   : VPE10_GENERAL_EMB_USAGE_FRAME_SHARED;
1144                 stream_idx = cmd_info->inputs[0].stream_idx;
1145             } else {
1146                 emb_req = VPE10_GENERAL_EMB_USAGE_SEG_NON_SHARED;
1147             }
1148         } else if (cmd_info->ops == VPE_CMD_OPS_BG) {
1149             emb_req =
1150                 i > 0 ? VPE10_GENERAL_EMB_USAGE_SEG_NON_SHARED : VPE10_GENERAL_EMB_USAGE_BG_SHARED;
1151         } else if (cmd_info->ops == VPE_CMD_OPS_BG_VSCF_INPUT) {
1152             emb_req = have_visual_confirm_input ? VPE10_GENERAL_EMB_USAGE_SEG_NON_SHARED
1153                                                 : VPE10_GENERAL_EMB_USAGE_BG_SHARED;
1154             have_visual_confirm_input = true;
1155         } else if (cmd_info->ops == VPE_CMD_OPS_BG_VSCF_OUTPUT) {
1156             emb_req = have_visual_confirm_output ? VPE10_GENERAL_EMB_USAGE_SEG_NON_SHARED
1157                                                  : VPE10_GENERAL_EMB_USAGE_BG_SHARED;
1158             have_visual_confirm_output = true;
1159         } else {
1160             VPE_ASSERT(0);
1161         }
1162 
1163         req->emb_buf_size += emb_req;
1164     }
1165 }
1166 
vpe10_check_mirror_rotation_support(const struct vpe_stream * stream)1167 enum vpe_status vpe10_check_mirror_rotation_support(const struct vpe_stream *stream)
1168 {
1169     VPE_ASSERT(stream != NULL);
1170 
1171     if (stream->rotation != VPE_ROTATION_ANGLE_0)
1172         return VPE_STATUS_ROTATION_NOT_SUPPORTED;
1173 
1174     if (stream->vertical_mirror)
1175         return VPE_STATUS_MIRROR_NOT_SUPPORTED;
1176 
1177     return VPE_STATUS_OK;
1178 }
1179 
1180 /* This function generates software points for the blnd gam programming block.
1181    The logic for the blndgam/ogam programming sequence is a function of:
1182    1. Output Range (Studio Full)
1183    2. 3DLUT usage
1184    3. Output format (HDR SDR)
1185 
1186    SDR Out or studio range out
1187       TM Case
1188          BLNDGAM : NL -> NL*S + B
1189          OGAM    : Bypass
1190       Non TM Case
1191          BLNDGAM : L -> NL*S + B
1192          OGAM    : Bypass
1193    Full range HDR Out
1194       TM Case
1195          BLNDGAM : NL -> L
1196          OGAM    : L -> NL
1197       Non TM Case
1198          BLNDGAM : Bypass
1199          OGAM    : L -> NL
1200 
1201 */
vpe10_update_blnd_gamma(struct vpe_priv * vpe_priv,const struct vpe_build_param * param,const struct vpe_stream * stream,struct transfer_func * blnd_tf)1202 enum vpe_status vpe10_update_blnd_gamma(struct vpe_priv *vpe_priv,
1203     const struct vpe_build_param *param, const struct vpe_stream *stream,
1204     struct transfer_func *blnd_tf)
1205 {
1206     struct output_ctx       *output_ctx;
1207     struct vpe_color_space   tm_out_cs;
1208     struct fixed31_32        x_scale       = vpe_fixpt_one;
1209     struct fixed31_32        y_scale       = vpe_fixpt_one;
1210     struct fixed31_32        y_bias        = vpe_fixpt_zero;
1211     bool                     is_studio     = false;
1212     bool                     can_bypass    = false;
1213     bool                     lut3d_enabled = false;
1214     enum color_space         cs            = COLOR_SPACE_2020_RGB_FULLRANGE;
1215     enum color_transfer_func tf            = TRANSFER_FUNC_LINEAR;
1216     enum vpe_status          status        = VPE_STATUS_OK;
1217     const struct vpe_tonemap_params *tm_params     = &stream->tm_params;
1218 
1219     is_studio = (param->dst_surface.cs.range == VPE_COLOR_RANGE_STUDIO);
1220     output_ctx = &vpe_priv->output_ctx;
1221     lut3d_enabled = tm_params->UID != 0 || tm_params->enable_3dlut;
1222 
1223     if (stream->flags.geometric_scaling) {
1224         vpe_color_update_degamma_tf(vpe_priv, tf, x_scale, y_scale, y_bias, true, blnd_tf);
1225     } else {
1226         if (is_studio) {
1227 
1228             if (vpe_is_rgb8(param->dst_surface.format)) {
1229                 y_scale = STUDIO_RANGE_SCALE_8_BIT;
1230                 y_bias  = STUDIO_RANGE_FOOT_ROOM_8_BIT;
1231             } else {
1232                 y_scale = STUDIO_RANGE_SCALE_10_BIT;
1233                 y_bias  = STUDIO_RANGE_FOOT_ROOM_10_BIT;
1234             }
1235         }
1236         // If SDR out -> Blend should be NL
1237         // If studio out -> No choice but to blend in NL
1238         if (!vpe_is_HDR(output_ctx->tf) || (is_studio)) {
1239             if (lut3d_enabled) {
1240                 tf = TRANSFER_FUNC_LINEAR;
1241             } else {
1242                 tf = output_ctx->tf;
1243             }
1244 
1245             if (vpe_is_fp16(param->dst_surface.format)) {
1246                 y_scale = vpe_fixpt_mul_int(y_scale, CCCS_NORM);
1247             }
1248             vpe_color_update_regamma_tf(
1249                 vpe_priv, tf, x_scale, y_scale, y_bias, can_bypass, blnd_tf);
1250         } else {
1251 
1252             if (lut3d_enabled) {
1253                 vpe_color_build_tm_cs(tm_params, &param->dst_surface, &tm_out_cs);
1254                 vpe_color_get_color_space_and_tf(&tm_out_cs, &cs, &tf);
1255             } else {
1256                 can_bypass = true;
1257             }
1258 
1259             vpe_color_update_degamma_tf(
1260                 vpe_priv, tf, x_scale, y_scale, y_bias, can_bypass, blnd_tf);
1261         }
1262     }
1263     return status;
1264 }
1265 
bg_color_outside_cs_gamut(const struct vpe_priv * vpe_priv,struct vpe_color * bg_color)1266 static enum vpe_status bg_color_outside_cs_gamut(
1267     const struct vpe_priv *vpe_priv, struct vpe_color *bg_color)
1268 {
1269     enum color_space              cs;
1270     enum color_transfer_func      tf;
1271     struct vpe_color              bg_color_copy = *bg_color;
1272     const struct vpe_color_space *vcs           = &vpe_priv->output_ctx.surface.cs;
1273 
1274     vpe_color_get_color_space_and_tf(vcs, &cs, &tf);
1275 
1276     if ((bg_color->is_ycbcr)) {
1277         // using the bg_color_copy instead as bg_csc will modify it
1278         // we should not do modification in checking stage
1279         // otherwise validate_cached_param() will fail
1280         if (vpe_bg_csc(&bg_color_copy, cs)) {
1281             return VPE_STATUS_BG_COLOR_OUT_OF_RANGE;
1282         }
1283     }
1284     return VPE_STATUS_OK;
1285 }
1286 
1287 /*
1288     In order to support background color fill correctly, we need to do studio -> full range
1289     conversion before the blend block. However, there is also a requirement for HDR output to be
1290     blended in linear space. Hence, if we have PQ out and studio range, we need to make sure no
1291     blending will occur. Otherwise the job is invalid.
1292 
1293 */
is_valid_blend(const struct vpe_priv * vpe_priv,struct vpe_color * bg_color)1294 static enum vpe_status is_valid_blend(const struct vpe_priv *vpe_priv, struct vpe_color *bg_color)
1295 {
1296 
1297     enum vpe_status               status = VPE_STATUS_OK;
1298     const struct vpe_color_space *vcs    = &vpe_priv->output_ctx.surface.cs;
1299     struct stream_ctx *stream_ctx = vpe_priv->stream_ctx; // Only need to check the first stream.
1300 
1301     if ((vcs->range == VPE_COLOR_RANGE_STUDIO) && (vcs->tf == VPE_TF_PQ) &&
1302         ((stream_ctx->stream.surface_info.cs.encoding == VPE_PIXEL_ENCODING_RGB) ||
1303             vpe_is_global_bg_blend_applied(stream_ctx)))
1304         status = VPE_STATUS_BG_COLOR_OUT_OF_RANGE;
1305 
1306     return status;
1307 }
1308 
vpe10_check_bg_color_support(struct vpe_priv * vpe_priv,struct vpe_color * bg_color)1309 enum vpe_status vpe10_check_bg_color_support(struct vpe_priv *vpe_priv, struct vpe_color *bg_color)
1310 {
1311 
1312     enum vpe_status status = VPE_STATUS_OK;
1313 
1314     /* no need for background filling as for target rect equal to dest rect */
1315     if (vpe_rec_is_equal(vpe_priv->output_ctx.target_rect,
1316             vpe_priv->stream_ctx[0].stream.scaling_info.dst_rect)) {
1317         return VPE_STATUS_OK;
1318     }
1319 
1320     status = is_valid_blend(vpe_priv, bg_color);
1321 
1322     if (status == VPE_STATUS_OK)
1323         status = bg_color_outside_cs_gamut(vpe_priv, bg_color);
1324 
1325     return status;
1326 }
1327