• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2022 Advanced Micro Devices, Inc.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a
4  * copy of this software and associated documentation files (the "Software"),
5  * to deal in the Software without restriction, including without limitation
6  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7  * and/or sell copies of the Software, and to permit persons to whom the
8  * Software is furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
16  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
17  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19  * OTHER DEALINGS IN THE SOFTWARE.
20  *
21  * Authors: AMD
22  *
23  */
24 
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, &params->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, &param);
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], &param->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, &param->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, &param->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, &param->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, &param->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, &param->bg_color, sizeof(struct vpe_color)))
531         return false;
532 
533     if (memcmp(&output_ctx->target_rect, &param->target_rect, sizeof(struct vpe_rect)))
534         return false;
535 
536     if (memcmp(&output_ctx->surface, &param->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, &param);
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