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 = ∩︀
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, ¶ms->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, ¶m->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