1 // SPDX-License-Identifier: MIT 2 // 3 // Copyright 2024 Advanced Micro Devices, Inc. 4 5 #include "dc_spl_translate.h" 6 #include "dcn20/dcn20_dpp.h" 7 #include "dcn32/dcn32_dpp.h" 8 #include "dcn401/dcn401_dpp.h" 9 10 static struct spl_callbacks dcn2_spl_callbacks = { 11 .spl_calc_lb_num_partitions = dscl2_spl_calc_lb_num_partitions, 12 }; 13 static struct spl_callbacks dcn32_spl_callbacks = { 14 .spl_calc_lb_num_partitions = dscl32_spl_calc_lb_num_partitions, 15 }; 16 static struct spl_callbacks dcn401_spl_callbacks = { 17 .spl_calc_lb_num_partitions = dscl401_spl_calc_lb_num_partitions, 18 }; 19 static struct spl_callbacks dcn50_spl_callbacks = { 20 .spl_calc_lb_num_partitions = dscl401_spl_calc_lb_num_partitions, 21 }; 22 static void populate_splrect_from_rect(struct spl_rect *spl_rect, const struct rect *rect) 23 { 24 spl_rect->x = rect->x; 25 spl_rect->y = rect->y; 26 spl_rect->width = rect->width; 27 spl_rect->height = rect->height; 28 } 29 static void populate_rect_from_splrect(struct rect *rect, const struct spl_rect *spl_rect) 30 { 31 rect->x = spl_rect->x; 32 rect->y = spl_rect->y; 33 rect->width = spl_rect->width; 34 rect->height = spl_rect->height; 35 } 36 static void populate_spltaps_from_taps(struct spl_taps *spl_scaling_quality, 37 const struct scaling_taps *scaling_quality) 38 { 39 spl_scaling_quality->h_taps_c = scaling_quality->h_taps_c; 40 spl_scaling_quality->h_taps = scaling_quality->h_taps; 41 spl_scaling_quality->v_taps_c = scaling_quality->v_taps_c; 42 spl_scaling_quality->v_taps = scaling_quality->v_taps; 43 spl_scaling_quality->integer_scaling = scaling_quality->integer_scaling; 44 } 45 static void populate_taps_from_spltaps(struct scaling_taps *scaling_quality, 46 const struct spl_taps *spl_scaling_quality) 47 { 48 scaling_quality->h_taps_c = spl_scaling_quality->h_taps_c + 1; 49 scaling_quality->h_taps = spl_scaling_quality->h_taps + 1; 50 scaling_quality->v_taps_c = spl_scaling_quality->v_taps_c + 1; 51 scaling_quality->v_taps = spl_scaling_quality->v_taps + 1; 52 } 53 static void populate_ratios_from_splratios(struct scaling_ratios *ratios, 54 const struct ratio *spl_ratios) 55 { 56 ratios->horz = dc_fixpt_from_ux_dy(spl_ratios->h_scale_ratio >> 5, 3, 19); 57 ratios->vert = dc_fixpt_from_ux_dy(spl_ratios->v_scale_ratio >> 5, 3, 19); 58 ratios->horz_c = dc_fixpt_from_ux_dy(spl_ratios->h_scale_ratio_c >> 5, 3, 19); 59 ratios->vert_c = dc_fixpt_from_ux_dy(spl_ratios->v_scale_ratio_c >> 5, 3, 19); 60 } 61 static void populate_inits_from_splinits(struct scl_inits *inits, 62 const struct init *spl_inits) 63 { 64 inits->h = dc_fixpt_from_int_dy(spl_inits->h_filter_init_int, spl_inits->h_filter_init_frac >> 5, 0, 19); 65 inits->v = dc_fixpt_from_int_dy(spl_inits->v_filter_init_int, spl_inits->v_filter_init_frac >> 5, 0, 19); 66 inits->h_c = dc_fixpt_from_int_dy(spl_inits->h_filter_init_int_c, spl_inits->h_filter_init_frac_c >> 5, 0, 19); 67 inits->v_c = dc_fixpt_from_int_dy(spl_inits->v_filter_init_int_c, spl_inits->v_filter_init_frac_c >> 5, 0, 19); 68 } 69 static void populate_splformat_from_format(enum spl_pixel_format *spl_pixel_format, 70 const enum dc_pixel_format pixel_format) 71 { 72 if (pixel_format < PIXEL_FORMAT_INVALID) 73 *spl_pixel_format = (enum spl_pixel_format)pixel_format; 74 else 75 *spl_pixel_format = SPL_PIXEL_FORMAT_INVALID; 76 } 77 static void set_linear_light_scaling_preference(const struct dc_plane_state *plane_state, struct spl_in *spl_in) 78 { 79 if (plane_state != NULL) { 80 switch (plane_state->scaling_linearity) { 81 case DC_SCALING_LINEARITY_LINEAR: 82 spl_in->lls_pref = LLS_PREF_YES; 83 break; 84 case DC_SCALING_LINEARITY_SOURCE: 85 spl_in->lls_pref = LLS_PREF_NO; 86 break; 87 default: 88 spl_in->lls_pref = LLS_PREF_DONT_CARE; 89 break; 90 } 91 } else 92 spl_in->lls_pref = LLS_PREF_DONT_CARE; 93 } 94 /// @brief Translate SPL input parameters from pipe context 95 /// @param pipe_ctx 96 /// @param spl_in 97 void translate_SPL_in_params_from_pipe_ctx(struct pipe_ctx *pipe_ctx, struct spl_in *spl_in) 98 { 99 const struct dc_plane_state *plane_state = pipe_ctx->plane_state; 100 const struct dc_stream_state *stream = pipe_ctx->stream; 101 struct rect odm_slice_src = resource_get_odm_slice_src_rect(pipe_ctx); 102 103 // Assign the function to calculate the number of partitions in the line buffer 104 // This is used to determine the vtap support 105 switch (plane_state->ctx->dce_version) { 106 case DCN_VERSION_2_0: 107 spl_in->callbacks = dcn2_spl_callbacks; 108 break; 109 case DCN_VERSION_3_2: 110 spl_in->callbacks = dcn32_spl_callbacks; 111 break; 112 case DCN_VERSION_4_01: 113 case DCN_VERSION_4_2: 114 case DCN_VERSION_4_2B: 115 spl_in->callbacks = dcn401_spl_callbacks; 116 break; 117 case DCN_VERSION_6_0: 118 spl_in->callbacks = dcn50_spl_callbacks; 119 break; 120 default: 121 spl_in->callbacks = dcn2_spl_callbacks; 122 } 123 // Make format field from spl_in point to plane_res scl_data format 124 populate_splformat_from_format(&spl_in->basic_in.format, pipe_ctx->plane_res.scl_data.format); 125 // Make view_format from basic_out point to view_format from stream 126 spl_in->basic_out.view_format = (enum spl_view_3d)stream->view_format; 127 // Populate spl input basic input clip rect from plane state clip rect 128 populate_splrect_from_rect(&spl_in->basic_in.clip_rect, &plane_state->clip_rect); 129 // Populate spl input basic out src rect from stream src rect 130 populate_splrect_from_rect(&spl_in->basic_out.src_rect, &stream->src); 131 // Populate spl input basic out dst rect from stream dst rect 132 populate_splrect_from_rect(&spl_in->basic_out.dst_rect, &stream->dst); 133 // Make spl input basic input info rotation field point to plane state rotation 134 spl_in->basic_in.rotation = (enum spl_rotation_angle)plane_state->rotation; 135 // Populate spl input basic input src rect from plane state src rect 136 populate_splrect_from_rect(&spl_in->basic_in.src_rect, &plane_state->src_rect); 137 // Populate spl input basic input dst rect from plane state dst rect 138 populate_splrect_from_rect(&spl_in->basic_in.dst_rect, &plane_state->dst_rect); 139 // Make spl input basic input info horiz mirror field point to plane state horz mirror 140 spl_in->basic_in.horizontal_mirror = plane_state->horizontal_mirror; 141 142 // Calculate horizontal splits and split index 143 spl_in->basic_in.num_h_slices_recout_width_align.use_recout_width_aligned = false; 144 spl_in->basic_in.num_h_slices_recout_width_align.num_slices_recout_width.mpc_num_h_slices = 145 resource_get_mpc_slice_count(pipe_ctx); 146 147 if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE) 148 spl_in->basic_in.mpc_h_slice_index = 0; 149 else 150 spl_in->basic_in.mpc_h_slice_index = resource_get_mpc_slice_index(pipe_ctx); 151 152 populate_splrect_from_rect(&spl_in->basic_out.odm_slice_rect, &odm_slice_src); 153 spl_in->basic_out.odm_combine_factor = 0; 154 spl_in->odm_slice_index = resource_get_odm_slice_index(pipe_ctx); 155 // Make spl input basic out info output_size width point to stream h active 156 spl_in->basic_out.output_size.width = 157 stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right + pipe_ctx->dsc_padding_params.dsc_hactive_padding; 158 // Make spl input basic out info output_size height point to v active 159 spl_in->basic_out.output_size.height = 160 stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top; 161 spl_in->basic_out.max_downscale_src_width = 162 pipe_ctx->stream->ctx->dc->debug.max_downscale_src_width; 163 spl_in->basic_out.always_scale = pipe_ctx->stream->ctx->dc->debug.always_scale; 164 // Make spl input basic output info alpha_en field point to plane res scl_data lb_params alpha_en 165 spl_in->basic_out.alpha_en = pipe_ctx->plane_res.scl_data.lb_params.alpha_en; 166 spl_in->basic_out.use_two_pixels_per_container = pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing); 167 // Make spl input basic input info scaling quality field point to plane state scaling_quality 168 populate_spltaps_from_taps(&spl_in->scaling_quality, &plane_state->scaling_quality); 169 // Translate edge adaptive scaler preference 170 spl_in->prefer_easf = pipe_ctx->stream->ctx->dc->config.prefer_easf; 171 spl_in->disable_easf = false; 172 if (pipe_ctx->stream->ctx->dc->debug.force_easf == 1) 173 spl_in->prefer_easf = false; 174 else if (pipe_ctx->stream->ctx->dc->debug.force_easf == 2) 175 spl_in->disable_easf = true; 176 else if (pipe_ctx->stream->ctx->dc->debug.force_easf == 3) 177 spl_in->override_easf = true; 178 /* Translate adaptive sharpening preference */ 179 unsigned int sharpness_setting = pipe_ctx->stream->ctx->dc->debug.force_sharpness; 180 unsigned int force_sharpness_level = pipe_ctx->stream->ctx->dc->debug.force_sharpness_level; 181 if (sharpness_setting == SHARPNESS_HW_OFF) 182 spl_in->adaptive_sharpness.enable = false; 183 else if (sharpness_setting == SHARPNESS_ZERO) { 184 spl_in->adaptive_sharpness.enable = true; 185 spl_in->adaptive_sharpness.sharpness_level = 0; 186 } else if (sharpness_setting == SHARPNESS_CUSTOM) { 187 /* SAT: read harpness_range from dc_plane_state */ 188 spl_in->adaptive_sharpness.sharpness_range.sdr_rgb_min = plane_state->sharpness_range.sdr_rgb_min; 189 spl_in->adaptive_sharpness.sharpness_range.sdr_rgb_max = plane_state->sharpness_range.sdr_rgb_max; 190 spl_in->adaptive_sharpness.sharpness_range.sdr_rgb_mid = plane_state->sharpness_range.sdr_rgb_mid; 191 spl_in->adaptive_sharpness.sharpness_range.sdr_yuv_min = plane_state->sharpness_range.sdr_yuv_min; 192 spl_in->adaptive_sharpness.sharpness_range.sdr_yuv_max = plane_state->sharpness_range.sdr_yuv_max; 193 spl_in->adaptive_sharpness.sharpness_range.sdr_yuv_mid = plane_state->sharpness_range.sdr_yuv_mid; 194 spl_in->adaptive_sharpness.sharpness_range.hdr_rgb_min = plane_state->sharpness_range.hdr_rgb_min; 195 spl_in->adaptive_sharpness.sharpness_range.hdr_rgb_max = plane_state->sharpness_range.hdr_rgb_max; 196 spl_in->adaptive_sharpness.sharpness_range.hdr_rgb_mid = plane_state->sharpness_range.hdr_rgb_mid; 197 198 if (force_sharpness_level > 0) { 199 if (force_sharpness_level > 10) 200 force_sharpness_level = 10; 201 spl_in->adaptive_sharpness.enable = true; 202 spl_in->adaptive_sharpness.sharpness_level = force_sharpness_level; 203 } else if (!plane_state->adaptive_sharpness_en) { 204 spl_in->adaptive_sharpness.enable = false; 205 spl_in->adaptive_sharpness.sharpness_level = 0; 206 } else { 207 spl_in->adaptive_sharpness.enable = true; 208 spl_in->adaptive_sharpness.sharpness_level = plane_state->sharpness_level; 209 } 210 } 211 // Translate linear light scaling preference 212 if (pipe_ctx->stream->ctx->dc->debug.force_lls > 0) 213 spl_in->lls_pref = pipe_ctx->stream->ctx->dc->debug.force_lls; 214 else 215 if ((plane_state->ctx->dce_version == DCN_VERSION_4_01) || 216 (plane_state->ctx->dce_version == DCN_VERSION_4_2) || 217 (plane_state->ctx->dce_version == DCN_VERSION_4_2B)) 218 spl_in->lls_pref = LLS_PREF_DONT_CARE; 219 else 220 set_linear_light_scaling_preference(plane_state, spl_in); 221 /* Translate upsampling mode*/ 222 spl_in->upsp_mode = pipe_ctx->plane_res.scl_data.upsp; 223 /* Translate chroma subsampling offset ( cositing ) */ 224 if (pipe_ctx->stream->ctx->dc->debug.force_cositing) 225 spl_in->basic_in.cositing = pipe_ctx->stream->ctx->dc->debug.force_cositing - 1; 226 else 227 spl_in->basic_in.cositing = plane_state->cositing; 228 /* Translate transfer function */ 229 spl_in->basic_in.tf_type = (enum spl_transfer_func_type) plane_state->in_transfer_func.type; 230 spl_in->basic_in.tf_predefined_type = (enum spl_transfer_func_predefined) plane_state->in_transfer_func.tf; 231 232 spl_in->h_active = pipe_ctx->plane_res.scl_data.h_active; 233 spl_in->v_active = pipe_ctx->plane_res.scl_data.v_active; 234 235 spl_in->sharpen_policy = (enum sharpen_policy)plane_state->adaptive_sharpness_policy; 236 spl_in->debug.scale_to_sharpness_policy = 237 (enum scale_to_sharpness_policy)pipe_ctx->stream->ctx->dc->debug.scale_to_sharpness_policy; 238 239 /* Check if it is stream is in fullscreen and if its HDR. 240 * Use this to determine sharpness levels 241 */ 242 spl_in->is_fullscreen = pipe_ctx->stream->sharpening_required; 243 spl_in->is_hdr_on = dm_helpers_is_hdr_on(pipe_ctx->stream->ctx, pipe_ctx->stream); 244 spl_in->sdr_white_level_nits = plane_state->sdr_white_level_nits; 245 } 246 247 /// @brief Translate SPL output parameters to pipe context 248 /// @param pipe_ctx 249 /// @param spl_out 250 void translate_SPL_out_params_to_pipe_ctx(struct pipe_ctx *pipe_ctx, struct spl_out *spl_out) 251 { 252 // Make scaler data recout point to spl output field recout 253 populate_rect_from_splrect(&pipe_ctx->plane_res.scl_data.recout, &spl_out->dscl_prog_data->recout); 254 // Make scaler data ratios point to spl output field ratios 255 populate_ratios_from_splratios(&pipe_ctx->plane_res.scl_data.ratios, &spl_out->dscl_prog_data->ratios); 256 // Make scaler data viewport point to spl output field viewport 257 populate_rect_from_splrect(&pipe_ctx->plane_res.scl_data.viewport, &spl_out->dscl_prog_data->viewport); 258 // Make scaler data viewport_c point to spl output field viewport_c 259 populate_rect_from_splrect(&pipe_ctx->plane_res.scl_data.viewport_c, &spl_out->dscl_prog_data->viewport_c); 260 // Make scaler data taps point to spl output field scaling taps 261 populate_taps_from_spltaps(&pipe_ctx->plane_res.scl_data.taps, &spl_out->dscl_prog_data->taps); 262 // Make scaler data init point to spl output field init 263 populate_inits_from_splinits(&pipe_ctx->plane_res.scl_data.inits, &spl_out->dscl_prog_data->init); 264 } 265