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