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
25 #include <string.h>
26 #include "vpelib.h"
27 #include "vpe_priv.h"
28 #include "common.h"
29 #include "color_bg.h"
30 #include "color_gamma.h"
31 #include "cmd_builder.h"
32 #include "resource.h"
33 #include "color.h"
34 #include "vpec.h"
35 #include "vpe_desc_writer.h"
36 #include "dpp.h"
37 #include "mpc.h"
38 #include "opp.h"
39 #include "geometric_scaling.h"
40
override_debug_option(struct vpe_debug_options * debug,const struct vpe_debug_options * user_debug)41 static void override_debug_option(
42 struct vpe_debug_options *debug, const struct vpe_debug_options *user_debug)
43 {
44 if (user_debug->flags.bg_bit_depth)
45 debug->bg_bit_depth = user_debug->bg_bit_depth;
46
47 if (user_debug->flags.cm_in_bypass)
48 debug->cm_in_bypass = user_debug->cm_in_bypass;
49
50 if (user_debug->flags.vpcnvc_bypass)
51 debug->vpcnvc_bypass = user_debug->vpcnvc_bypass;
52
53 if (user_debug->flags.mpc_bypass)
54 debug->mpc_bypass = user_debug->mpc_bypass;
55
56 if (user_debug->flags.disable_reuse_bit)
57 debug->disable_reuse_bit = user_debug->disable_reuse_bit;
58
59 if (user_debug->flags.identity_3dlut)
60 debug->identity_3dlut = user_debug->identity_3dlut;
61
62 if (user_debug->flags.sce_3dlut)
63 debug->sce_3dlut = user_debug->sce_3dlut;
64
65 if (user_debug->enable_mem_low_power.flags.cm)
66 debug->enable_mem_low_power.bits.cm = user_debug->enable_mem_low_power.bits.cm;
67
68 if (user_debug->enable_mem_low_power.flags.dscl)
69 debug->enable_mem_low_power.bits.dscl = user_debug->enable_mem_low_power.bits.dscl;
70
71 if (user_debug->enable_mem_low_power.flags.mpc)
72 debug->enable_mem_low_power.bits.mpc = user_debug->enable_mem_low_power.bits.mpc;
73
74 if (user_debug->flags.bg_color_fill_only)
75 debug->bg_color_fill_only = user_debug->bg_color_fill_only;
76
77 if (user_debug->flags.assert_when_not_support)
78 debug->assert_when_not_support = user_debug->assert_when_not_support;
79
80 if (user_debug->flags.bypass_ogam)
81 debug->bypass_ogam = user_debug->bypass_ogam;
82
83 if (user_debug->flags.bypass_gamcor)
84 debug->bypass_gamcor = user_debug->bypass_gamcor;
85
86 if (user_debug->flags.bypass_dpp_gamut_remap)
87 debug->bypass_dpp_gamut_remap = user_debug->bypass_dpp_gamut_remap;
88
89 if (user_debug->flags.bypass_post_csc)
90 debug->bypass_post_csc = user_debug->bypass_post_csc;
91
92 if (user_debug->flags.force_tf_calculation)
93 debug->force_tf_calculation = user_debug->force_tf_calculation;
94
95 if (user_debug->flags.clamping_setting) {
96 debug->clamping_setting = user_debug->clamping_setting;
97 debug->clamping_params = user_debug->clamping_params;
98 }
99
100 if (user_debug->flags.expansion_mode)
101 debug->expansion_mode = user_debug->expansion_mode;
102
103 if (user_debug->flags.bypass_per_pixel_alpha)
104 debug->bypass_per_pixel_alpha = user_debug->bypass_per_pixel_alpha;
105
106 if (user_debug->flags.opp_pipe_crc_ctrl)
107 debug->opp_pipe_crc_ctrl = user_debug->opp_pipe_crc_ctrl;
108
109 if (user_debug->flags.dpp_crc_ctrl)
110 debug->dpp_crc_ctrl = user_debug->dpp_crc_ctrl;
111
112 if (user_debug->flags.mpc_crc_ctrl)
113 debug->mpc_crc_ctrl = user_debug->mpc_crc_ctrl;
114
115 if (user_debug->flags.visual_confirm)
116 debug->visual_confirm_params = user_debug->visual_confirm_params;
117
118 if (user_debug->flags.skip_optimal_tap_check)
119 debug->skip_optimal_tap_check = user_debug->skip_optimal_tap_check;
120 }
121
vpe_create(const struct vpe_init_data * params)122 struct vpe *vpe_create(const struct vpe_init_data *params)
123 {
124 struct vpe_priv *vpe_priv;
125 enum vpe_status status;
126
127 if (!params || (params->funcs.zalloc == NULL) || (params->funcs.free == NULL) ||
128 (params->funcs.log == NULL))
129 return NULL;
130
131 vpe_priv =
132 (struct vpe_priv *)params->funcs.zalloc(params->funcs.mem_ctx, sizeof(struct vpe_priv));
133 if (!vpe_priv)
134 return NULL;
135
136 vpe_priv->init = *params;
137
138 vpe_priv->pub.level =
139 vpe_resource_parse_ip_version(params->ver_major, params->ver_minor, params->ver_rev);
140
141 vpe_priv->pub.version = (VPELIB_API_VERSION_MAJOR << VPELIB_API_VERSION_MAJOR_SHIFT) |
142 (VPELIB_API_VERSION_MINOR << VPELIB_API_VERSION_MINOR_SHIFT);
143
144 status = vpe_construct_resource(vpe_priv, vpe_priv->pub.level, &vpe_priv->resource);
145 if (status != VPE_STATUS_OK) {
146 vpe_free(vpe_priv);
147 return NULL;
148 }
149
150 override_debug_option(&vpe_priv->init.debug, ¶ms->debug);
151
152 vpe_color_setup_x_points_distribution();
153 vpe_color_setup_x_points_distribution_degamma();
154
155 vpe_priv->ops_support = false;
156 vpe_priv->scale_yuv_matrix = true;
157 return &vpe_priv->pub;
158 }
159
vpe_destroy(struct vpe ** vpe)160 void vpe_destroy(struct vpe **vpe)
161 {
162 struct vpe_priv *vpe_priv;
163
164 if (!vpe || ((*vpe) == NULL))
165 return;
166
167 vpe_priv = container_of(*vpe, struct vpe_priv, pub);
168
169 vpe_destroy_resource(vpe_priv, &vpe_priv->resource);
170
171 vpe_free_output_ctx(vpe_priv);
172
173 vpe_free_stream_ctx(vpe_priv);
174
175 if (vpe_priv->dummy_input_param)
176 vpe_free(vpe_priv->dummy_input_param);
177
178 if (vpe_priv->dummy_stream)
179 vpe_free(vpe_priv->dummy_stream);
180
181 vpe_free(vpe_priv);
182
183 *vpe = NULL;
184 }
185
186 /*
187 * Geometric scaling feature has two requirement when enabled:
188 * 1. only support single input stream, no blending support.
189 * 2. the target rect must equal to destination rect.
190 */
191
validate_geometric_scaling_support(const struct vpe_build_param * param)192 static enum vpe_status validate_geometric_scaling_support(const struct vpe_build_param *param)
193 {
194 if (param->streams[0].flags.geometric_scaling)
195 {
196 /* only support 1 stream */
197 if (param->num_streams > 1)
198 {
199 return VPE_STATUS_GEOMETRICSCALING_ERROR;
200 }
201
202 /* dest rect must equal to target rect */
203 if (param->target_rect.height != param->streams[0].scaling_info.dst_rect.height ||
204 param->target_rect.width != param->streams[0].scaling_info.dst_rect.width ||
205 param->target_rect.x != param->streams[0].scaling_info.dst_rect.x ||
206 param->target_rect.y != param->streams[0].scaling_info.dst_rect.y)
207 return VPE_STATUS_GEOMETRICSCALING_ERROR;
208 }
209 return VPE_STATUS_OK;
210 }
211
212 /*****************************************************************************************
213 * handle_zero_input
214 * handle any zero input stream but background output only
215 * struct vpe* vpe
216 * [input] vpe context
217 * const struct vpe_build_param* org_param
218 * [input] original parameter from caller
219 * struct vpe_build_param* dummy_input_param
220 * [output] caller provided param struct for filling with dummy input
221 * struct struct vpe_stream* dummy_stream
222 * [output] caller provided vpe_stream struct for use in dummy_input_param->streams
223 *****************************************************************************************/
handle_zero_input(struct vpe * vpe,const struct vpe_build_param * in_param,const struct vpe_build_param ** out_param)224 static enum vpe_status handle_zero_input(struct vpe *vpe, const struct vpe_build_param *in_param,
225 const struct vpe_build_param **out_param)
226 {
227 struct vpe_priv *vpe_priv;
228 struct vpe_surface_info *surface_info;
229 struct vpe_scaling_info *scaling_info;
230 struct vpe_scaling_filter_coeffs *polyphaseCoeffs;
231 struct vpe_stream *stream;
232
233 vpe_priv = container_of(vpe, struct vpe_priv, pub);
234
235 if (!in_param || !out_param)
236 return VPE_STATUS_ERROR;
237
238 *out_param = NULL;
239
240 if (in_param->num_streams == 0 || vpe_priv->init.debug.bg_color_fill_only) {
241
242 // if output surface is too small, don't use it as dummy input
243 // request 2x2 instead of 1x1 for bpc safety
244 // as we are to treat output as input for RGB 1x1, need 4bytes at least
245 // but if output is YUV, bpc will be smaller and need larger dimension
246
247 if (in_param->dst_surface.plane_size.surface_size.width < VPE_MIN_VIEWPORT_SIZE ||
248 in_param->dst_surface.plane_size.surface_size.height < VPE_MIN_VIEWPORT_SIZE ||
249 in_param->dst_surface.plane_size.surface_pitch < 256 / 4 || // 256bytes, 4bpp
250 in_param->target_rect.width < VPE_MIN_VIEWPORT_SIZE ||
251 in_param->target_rect.height < VPE_MIN_VIEWPORT_SIZE) {
252 return VPE_STATUS_ERROR;
253 }
254
255 if (!vpe_priv->dummy_input_param) {
256 vpe_priv->dummy_input_param = vpe_zalloc(sizeof(struct vpe_build_param));
257 if (!vpe_priv->dummy_input_param)
258 return VPE_STATUS_NO_MEMORY;
259 }
260
261 if (!vpe_priv->dummy_stream) {
262 vpe_priv->dummy_stream = vpe_zalloc(sizeof(struct vpe_stream));
263 if (!vpe_priv->dummy_stream)
264 return VPE_STATUS_NO_MEMORY;
265 }
266
267 *vpe_priv->dummy_input_param = *in_param;
268
269 vpe_priv->dummy_input_param->num_streams = 1;
270 vpe_priv->dummy_input_param->streams = vpe_priv->dummy_stream;
271
272 // set output surface as our dummy input
273 stream = vpe_priv->dummy_stream;
274 surface_info = &stream->surface_info;
275 scaling_info = &stream->scaling_info;
276 polyphaseCoeffs = &stream->polyphase_scaling_coeffs;
277 surface_info->address.type = VPE_PLN_ADDR_TYPE_GRAPHICS;
278 surface_info->address.tmz_surface = in_param->dst_surface.address.tmz_surface;
279 surface_info->address.grph.addr.quad_part =
280 in_param->dst_surface.address.grph.addr.quad_part;
281
282 surface_info->swizzle = VPE_SW_LINEAR; // treat it as linear for simple
283 surface_info->plane_size.surface_size.x = 0;
284 surface_info->plane_size.surface_size.y = 0;
285 surface_info->plane_size.surface_size.width = VPE_MIN_VIEWPORT_SIZE; // min width in pixels
286 surface_info->plane_size.surface_size.height =
287 VPE_MIN_VIEWPORT_SIZE; // min height in pixels
288 surface_info->plane_size.surface_pitch = 256 / 4; // pitch in pixels
289 surface_info->plane_size.surface_aligned_height = VPE_MIN_VIEWPORT_SIZE;
290 surface_info->dcc.enable = false;
291 surface_info->format = VPE_SURFACE_PIXEL_FORMAT_GRPH_RGBA8888;
292 surface_info->cs.encoding = VPE_PIXEL_ENCODING_RGB;
293 surface_info->cs.range = VPE_COLOR_RANGE_FULL;
294 surface_info->cs.tf = VPE_TF_G22;
295 surface_info->cs.cositing = VPE_CHROMA_COSITING_NONE;
296 surface_info->cs.primaries = VPE_PRIMARIES_BT709;
297 scaling_info->src_rect.x = 0;
298 scaling_info->src_rect.y = 0;
299 scaling_info->src_rect.width = VPE_MIN_VIEWPORT_SIZE;
300 scaling_info->src_rect.height = VPE_MIN_VIEWPORT_SIZE;
301 scaling_info->dst_rect.x = in_param->target_rect.x;
302 scaling_info->dst_rect.y = in_param->target_rect.y;
303 scaling_info->dst_rect.width = VPE_MIN_VIEWPORT_SIZE;
304 scaling_info->dst_rect.height = VPE_MIN_VIEWPORT_SIZE;
305 scaling_info->taps.v_taps = 4;
306 scaling_info->taps.h_taps = 4;
307 scaling_info->taps.v_taps_c = 2;
308 scaling_info->taps.h_taps_c = 2;
309
310 polyphaseCoeffs->taps = scaling_info->taps;
311 polyphaseCoeffs->nb_phases = 64;
312
313 stream->blend_info.blending = true;
314 stream->blend_info.pre_multiplied_alpha = false;
315 stream->blend_info.global_alpha = true; // hardcoded upon DAL request
316 stream->blend_info.global_alpha_value = 0; // transparent as we are dummy input
317
318 stream->color_adj.brightness = 0.0f;
319 stream->color_adj.contrast = 1.0f;
320 stream->color_adj.hue = 0.0f;
321 stream->color_adj.saturation = 1.0f;
322 stream->rotation = VPE_ROTATION_ANGLE_0;
323 stream->horizontal_mirror = false;
324 stream->vertical_mirror = false;
325 stream->enable_luma_key = false;
326 stream->lower_luma_bound = 0;
327 stream->upper_luma_bound = 0;
328 stream->flags.hdr_metadata = 0;
329 stream->flags.geometric_scaling = 0;
330 stream->use_external_scaling_coeffs = false;
331 *out_param = vpe_priv->dummy_input_param;
332 } else {
333 *out_param = in_param;
334 }
335
336 return VPE_STATUS_OK;
337 }
338
vpe_check_support(struct vpe * vpe,const struct vpe_build_param * param,struct vpe_bufs_req * req)339 enum vpe_status vpe_check_support(
340 struct vpe *vpe, const struct vpe_build_param *param, struct vpe_bufs_req *req)
341 {
342 struct vpe_priv *vpe_priv;
343 struct vpec *vpec;
344 struct dpp *dpp;
345 enum vpe_status status;
346 struct stream_ctx *stream_ctx;
347 struct output_ctx *output_ctx = NULL;
348 uint32_t i;
349 bool input_h_mirror, output_h_mirror;
350
351 vpe_priv = container_of(vpe, struct vpe_priv, pub);
352 vpec = &vpe_priv->resource.vpec;
353 dpp = vpe_priv->resource.dpp[0];
354
355 status = handle_zero_input(vpe, param, ¶m);
356 if (status != VPE_STATUS_OK)
357 status = VPE_STATUS_NUM_STREAM_NOT_SUPPORTED;
358
359 if (!vpe_priv->stream_ctx || vpe_priv->num_streams != param->num_streams) {
360 if (vpe_priv->stream_ctx)
361 vpe_free_stream_ctx(vpe_priv);
362
363 vpe_priv->stream_ctx = vpe_alloc_stream_ctx(vpe_priv, param->num_streams);
364 }
365
366 if (!vpe_priv->stream_ctx)
367 status = VPE_STATUS_NO_MEMORY;
368
369 // VPElib needs to cache whether or not the 3DLUT has been updated
370 // This is to deal with case when 3DLUT has been updated but VPE rejects the job.
371 // Need a sticky bit to tell vpe to program the 3dlut on next jobs submission even
372 // if 3dlut has not changed
373 for (i = 0; i < param->num_streams; i++) {
374 vpe_cache_tone_map_params(&vpe_priv->stream_ctx[i], ¶m->streams[i]);
375 }
376
377 if (status == VPE_STATUS_OK) {
378 // output checking - check per asic support
379 status = vpe_check_output_support(vpe, param);
380 if (status != VPE_STATUS_OK) {
381 vpe_log("fail output support check. status %d\n", (int)status);
382 }
383 }
384
385 if (status == VPE_STATUS_OK) {
386 // input checking - check per asic support
387 for (i = 0; i < param->num_streams; i++) {
388 status = vpe_check_input_support(vpe, ¶m->streams[i]);
389 if (status != VPE_STATUS_OK) {
390 vpe_log("fail input support check. status %d\n", (int)status);
391 break;
392 }
393 }
394 }
395
396 if (status == VPE_STATUS_OK) {
397 // input checking - check tone map support
398 for (i = 0; i < param->num_streams; i++) {
399 status = vpe_check_tone_map_support(vpe, ¶m->streams[i], param);
400 if (status != VPE_STATUS_OK) {
401 vpe_log("fail input support check. status %d\n", (int)status);
402 break;
403 }
404 }
405 }
406
407 if (status == VPE_STATUS_OK) {
408 // output resource preparation for further checking (cache the result)
409 output_ctx = &vpe_priv->output_ctx;
410 output_ctx->surface = param->dst_surface;
411 output_ctx->bg_color = param->bg_color;
412 output_ctx->target_rect = param->target_rect;
413 output_ctx->alpha_mode = param->alpha_mode;
414 output_ctx->flags.hdr_metadata = param->flags.hdr_metadata;
415 output_ctx->hdr_metadata = param->hdr_metadata;
416
417 vpe_priv->num_vpe_cmds = 0;
418 output_ctx->clamping_params = vpe_priv->init.debug.clamping_params;
419
420 vpe_priv->num_streams = param->num_streams;
421 }
422
423 if (status == VPE_STATUS_OK) {
424 // blending support check
425 vpe_priv->resource.check_h_mirror_support(&input_h_mirror, &output_h_mirror);
426
427 for (i = 0; i < param->num_streams; i++) {
428 stream_ctx = &vpe_priv->stream_ctx[i];
429 stream_ctx->stream_idx = (int32_t)i;
430 stream_ctx->per_pixel_alpha =
431 vpe_has_per_pixel_alpha(param->streams[i].surface_info.format);
432 if (vpe_priv->init.debug.bypass_per_pixel_alpha) {
433 stream_ctx->per_pixel_alpha = false;
434 }
435 if (param->streams[i].horizontal_mirror && !input_h_mirror && output_h_mirror)
436 stream_ctx->flip_horizonal_output = true;
437 else
438 stream_ctx->flip_horizonal_output = false;
439
440 memcpy(&stream_ctx->stream, ¶m->streams[i], sizeof(struct vpe_stream));
441
442 /* if top-bottom blending is not supported,
443 * the 1st stream still can support blending with background,
444 * however, the 2nd stream and onward can't enable blending.
445 */
446 if (i && param->streams[i].blend_info.blending &&
447 !vpe_priv->pub.caps->color_caps.mpc.top_bottom_blending) {
448 status = VPE_STATUS_ALPHA_BLENDING_NOT_SUPPORTED;
449 break;
450 }
451 }
452 }
453
454 if (status == VPE_STATUS_OK) {
455 status = vpe_priv->resource.calculate_segments(vpe_priv, param);
456 if (status != VPE_STATUS_OK)
457 vpe_log("failed in calculate segments %d\n", (int)status);
458 }
459
460 if (status == VPE_STATUS_OK) {
461 // if the bg_color support is false, there is a flag to verify if the bg_color falls in the
462 // output gamut
463 if (!vpe_priv->pub.caps->bg_color_check_support) {
464 status = vpe_is_valid_bg_color(vpe_priv, &output_ctx->bg_color);
465 if (status != VPE_STATUS_OK) {
466 vpe_log(
467 "failed in checking the background color versus the output color space %d\n",
468 (int)status);
469 }
470 }
471 }
472
473 if (status == VPE_STATUS_OK) {
474 // Calculate the buffer needed (worst case)
475 vpe_priv->resource.get_bufs_req(vpe_priv, &vpe_priv->bufs_required);
476 *req = vpe_priv->bufs_required;
477 vpe_priv->ops_support = true;
478 }
479
480 if (status == VPE_STATUS_OK) {
481 status = validate_geometric_scaling_support(param);
482 }
483
484 if (vpe_priv->init.debug.assert_when_not_support)
485 VPE_ASSERT(status == VPE_STATUS_OK);
486
487 return status;
488 }
489
vpe_build_noops(struct vpe * vpe,uint32_t num_dword,uint32_t ** ppcmd_space)490 enum vpe_status vpe_build_noops(struct vpe *vpe, uint32_t num_dword, uint32_t **ppcmd_space)
491 {
492 struct vpe_priv *vpe_priv;
493 struct cmd_builder *builder;
494 enum vpe_status status;
495
496 if (!vpe || !ppcmd_space || ((*ppcmd_space) == NULL))
497 return VPE_STATUS_ERROR;
498
499 vpe_priv = container_of(vpe, struct vpe_priv, pub);
500
501 builder = &vpe_priv->resource.cmd_builder;
502
503 status = builder->build_noops(vpe_priv, ppcmd_space, num_dword);
504
505 return status;
506 }
507
validate_cached_param(struct vpe_priv * vpe_priv,const struct vpe_build_param * param)508 static bool validate_cached_param(struct vpe_priv *vpe_priv, const struct vpe_build_param *param)
509 {
510 uint32_t i;
511 struct output_ctx *output_ctx;
512
513 if (vpe_priv->num_streams != param->num_streams)
514 return false;
515
516 for (i = 0; i < param->num_streams; i++) {
517 struct vpe_stream stream = param->streams[i];
518
519 vpe_clip_stream(
520 &stream.scaling_info.src_rect, &stream.scaling_info.dst_rect, ¶m->target_rect);
521
522 if (memcmp(&vpe_priv->stream_ctx[i].stream, &stream, sizeof(struct vpe_stream)))
523 return false;
524 }
525
526 output_ctx = &vpe_priv->output_ctx;
527 if (output_ctx->alpha_mode != param->alpha_mode)
528 return false;
529
530 if (memcmp(&output_ctx->bg_color, ¶m->bg_color, sizeof(struct vpe_color)))
531 return false;
532
533 if (memcmp(&output_ctx->target_rect, ¶m->target_rect, sizeof(struct vpe_rect)))
534 return false;
535
536 if (memcmp(&output_ctx->surface, ¶m->dst_surface, sizeof(struct vpe_surface_info)))
537 return false;
538
539 return true;
540 }
541
vpe_build_commands(struct vpe * vpe,const struct vpe_build_param * param,struct vpe_build_bufs * bufs)542 enum vpe_status vpe_build_commands(
543 struct vpe *vpe, const struct vpe_build_param *param, struct vpe_build_bufs *bufs)
544 {
545 struct vpe_priv *vpe_priv;
546 struct cmd_builder *builder;
547 enum vpe_status status = VPE_STATUS_OK;
548 uint32_t cmd_idx, i, j;
549 struct vpe_build_bufs curr_bufs;
550 int64_t cmd_buf_size;
551 int64_t emb_buf_size;
552 uint64_t cmd_buf_gpu_a, cmd_buf_cpu_a;
553 uint64_t emb_buf_gpu_a, emb_buf_cpu_a;
554
555 if (!vpe || !param || !bufs)
556 return VPE_STATUS_ERROR;
557
558 vpe_priv = container_of(vpe, struct vpe_priv, pub);
559
560 if (!vpe_priv->ops_support) {
561 VPE_ASSERT(vpe_priv->ops_support);
562 status = VPE_STATUS_NOT_SUPPORTED;
563 }
564
565 if (status == VPE_STATUS_OK) {
566 status = handle_zero_input(vpe, param, ¶m);
567 if (status != VPE_STATUS_OK)
568 status = VPE_STATUS_NUM_STREAM_NOT_SUPPORTED;
569 }
570
571 if (status == VPE_STATUS_OK) {
572 if (!validate_cached_param(vpe_priv, param)) {
573 status = VPE_STATUS_PARAM_CHECK_ERROR;
574 }
575 }
576
577 if (status == VPE_STATUS_OK) {
578 if (param->streams->flags.geometric_scaling) {
579 geometric_scaling_feature_skip(vpe_priv, param);
580 }
581
582 if (bufs->cmd_buf.size == 0 || bufs->emb_buf.size == 0) {
583 /* Here we directly return without setting ops_support to false
584 * becaues the supported check is already passed
585 * and the caller can come again with correct buffer size.
586 */
587 bufs->cmd_buf.size = vpe_priv->bufs_required.cmd_buf_size;
588 bufs->emb_buf.size = vpe_priv->bufs_required.emb_buf_size;
589 return VPE_STATUS_OK;
590 } else if ((bufs->cmd_buf.size < vpe_priv->bufs_required.cmd_buf_size) ||
591 (bufs->emb_buf.size < vpe_priv->bufs_required.emb_buf_size)) {
592 status = VPE_STATUS_INVALID_BUFFER_SIZE;
593 }
594 }
595
596 builder = &vpe_priv->resource.cmd_builder;
597
598 // store buffers original values
599 cmd_buf_cpu_a = bufs->cmd_buf.cpu_va;
600 cmd_buf_gpu_a = bufs->cmd_buf.gpu_va;
601 cmd_buf_size = bufs->cmd_buf.size;
602
603 emb_buf_cpu_a = bufs->emb_buf.cpu_va;
604 emb_buf_gpu_a = bufs->emb_buf.gpu_va;
605 emb_buf_size = bufs->emb_buf.size;
606
607 // curr_bufs is used for tracking the built size and next pointers
608 curr_bufs = *bufs;
609
610 // copy the param, reset saved configs
611 for (i = 0; i < param->num_streams; i++) {
612 vpe_priv->stream_ctx[i].num_configs = 0;
613 for (j = 0; j < VPE_CMD_TYPE_COUNT; j++)
614 vpe_priv->stream_ctx[i].num_stream_op_configs[j] = 0;
615 }
616 vpe_priv->output_ctx.num_configs = 0;
617
618 // Reset pipes
619 vpe_pipe_reset(vpe_priv);
620
621 if (status == VPE_STATUS_OK) {
622 status = vpe_color_update_color_space_and_tf(vpe_priv, param);
623 if (status != VPE_STATUS_OK) {
624 vpe_log("failed in updating color space and tf %d\n", (int)status);
625 }
626 }
627
628 if (status == VPE_STATUS_OK) {
629 status = vpe_color_update_movable_cm(vpe_priv, param);
630 if (status != VPE_STATUS_OK) {
631 vpe_log("failed in updating movable 3d lut unit %d\n", (int)status);
632 }
633 }
634
635 if (status == VPE_STATUS_OK) {
636 status = vpe_color_update_whitepoint(vpe_priv, param);
637 if (status != VPE_STATUS_OK) {
638 vpe_log("failed updating whitepoint gain %d\n", (int)status);
639 }
640 }
641
642 if (status == VPE_STATUS_OK) {
643 /* since the background is generated by the first stream,
644 * the 3dlut enablement for the background color conversion
645 * is used based on the information of the first stream.
646 */
647 vpe_bg_color_convert(vpe_priv->output_ctx.cs, vpe_priv->output_ctx.output_tf,
648 &vpe_priv->output_ctx.bg_color, vpe_priv->stream_ctx[0].enable_3dlut);
649
650 for (cmd_idx = 0; cmd_idx < vpe_priv->num_vpe_cmds; cmd_idx++) {
651
652 status = builder->build_vpe_cmd(vpe_priv, &curr_bufs, cmd_idx);
653 if (status != VPE_STATUS_OK) {
654 vpe_log("failed in building vpe cmd %d\n", (int)status);
655 }
656
657 }
658 }
659
660 if (status == VPE_STATUS_OK) {
661 bufs->cmd_buf.size = cmd_buf_size - curr_bufs.cmd_buf.size; // used cmd buffer size
662 bufs->cmd_buf.gpu_va = cmd_buf_gpu_a;
663 bufs->cmd_buf.cpu_va = cmd_buf_cpu_a;
664
665 bufs->emb_buf.size = emb_buf_size - curr_bufs.emb_buf.size; // used emb buffer size
666 bufs->emb_buf.gpu_va = emb_buf_gpu_a;
667 bufs->emb_buf.cpu_va = emb_buf_cpu_a;
668 }
669
670 vpe_priv->ops_support = false;
671
672 if (vpe_priv->init.debug.assert_when_not_support)
673 VPE_ASSERT(status == VPE_STATUS_OK);
674
675 return status;
676 }
677