diff --git a/src/amd/vpelib/src/chip/vpe10/inc/vpe10_mpc.h b/src/amd/vpelib/src/chip/vpe10/inc/vpe10_mpc.h index 3a4416c6c5c..c523e50eac2 100644 --- a/src/amd/vpelib/src/chip/vpe10/inc/vpe10_mpc.h +++ b/src/amd/vpelib/src/chip/vpe10/inc/vpe10_mpc.h @@ -1433,7 +1433,7 @@ bool vpe10_mpc_program_3dlut_indirect(struct mpc *mpc, bool use_tetrahedral_9, bool use_12bits); // Blend-gamma control. -void vpe10_mpc_program_1dlut(struct mpc *mpc, const struct pwl_params *params); +void vpe10_mpc_program_1dlut(struct mpc *mpc, const struct pwl_params *params, enum cm_type gamma_type); void vpe10_mpc_program_cm_location(struct mpc *mpc, uint8_t location); diff --git a/src/amd/vpelib/src/chip/vpe10/vpe10_cm_common.c b/src/amd/vpelib/src/chip/vpe10/vpe10_cm_common.c index f892d2152de..109de042cc8 100644 --- a/src/amd/vpelib/src/chip/vpe10/vpe10_cm_common.c +++ b/src/amd/vpelib/src/chip/vpe10/vpe10_cm_common.c @@ -62,6 +62,22 @@ static bool cm_helper_convert_to_custom_float(struct pwl_result_data *rgb_result return false; } + if (!vpe_convert_to_custom_float_format( + corner_points[0].red.y, &fmt, &corner_points[0].red.custom_float_y)) { + VPE_ASSERT(0); + return false; + } + if (!vpe_convert_to_custom_float_format( + corner_points[0].green.y, &fmt, &corner_points[0].green.custom_float_y)) { + VPE_ASSERT(0); + return false; + } + if (!vpe_convert_to_custom_float_format( + corner_points[0].blue.y, &fmt, &corner_points[0].blue.custom_float_y)) { + VPE_ASSERT(0); + return false; + } + if (!vpe_convert_to_custom_float_format( corner_points[0].red.offset, &fmt, &corner_points[0].red.custom_float_offset)) { VPE_ASSERT(0); @@ -369,6 +385,17 @@ bool vpe10_cm_helper_translate_curve_to_hw_format( ++rgb; ++i; } + + corner_points[0].red.y = output_tf->start_base; + corner_points[0].green.y = output_tf->start_base; + corner_points[0].blue.y = output_tf->start_base; + + if (output_tf->start_base.value != vpe_fixpt_zero.value) { + corner_points[0].red.slope = vpe_fixpt_zero; + corner_points[0].green.slope = vpe_fixpt_zero; + corner_points[0].blue.slope = vpe_fixpt_zero; + } + cm_helper_convert_to_custom_float(rgb_resulted, lut_params->corner_points, hw_points, fixpoint); return true; @@ -480,6 +507,16 @@ bool vpe10_cm_helper_translate_curve_to_degamma_hw_format( ++i; } + corner_points[0].red.y = output_tf->start_base; + corner_points[0].green.y = output_tf->start_base; + corner_points[0].blue.y = output_tf->start_base; + + if (output_tf->start_base.value != vpe_fixpt_zero.value) { + corner_points[0].red.slope = vpe_fixpt_zero; + corner_points[0].green.slope = vpe_fixpt_zero; + corner_points[0].blue.slope = vpe_fixpt_zero; + } + cm_helper_convert_to_custom_float(rgb_resulted, lut_params->corner_points, hw_points, false); return true; @@ -561,6 +598,13 @@ void vpe10_cm_helper_program_gamcor_xfer_func(struct config_writer *config_write REG_SET_2_CM(reg->start_cntl_r, 0, exp_region_start, params->corner_points[0].red.custom_float_x, exp_region_start_segment, 0); + REG_SET_CM(reg->start_base_cntl_r, 0, field_region_start_base, + params->corner_points[0].red.custom_float_y); + REG_SET_CM(reg->start_base_cntl_g, 0, field_region_start_base, + params->corner_points[0].green.custom_float_y); + REG_SET_CM(reg->start_base_cntl_b, 0, field_region_start_base, + params->corner_points[0].blue.custom_float_y); + REG_SET_CM(reg->start_slope_cntl_b, 0, // linear slope at start of curve field_region_linear_slope, params->corner_points[0].blue.custom_float_slope); REG_SET_CM(reg->start_slope_cntl_g, 0, field_region_linear_slope, diff --git a/src/amd/vpelib/src/chip/vpe10/vpe10_mpc.c b/src/amd/vpelib/src/chip/vpe10/vpe10_mpc.c index a103027e06e..894a397ed2d 100644 --- a/src/amd/vpelib/src/chip/vpe10/vpe10_mpc.c +++ b/src/amd/vpelib/src/chip/vpe10/vpe10_mpc.c @@ -275,16 +275,17 @@ void vpe10_program_output_csc(struct mpc *mpc, enum vpe_surface_pixel_format pix enum mpc_output_csc_mode ocsc_mode = MPC_OUTPUT_CSC_COEF_A; - if (mpc->funcs->power_on_ogam_lut) - mpc->funcs->power_on_ogam_lut(mpc, true); + if (mpc->funcs->power_on_ogam_lut) + mpc->funcs->power_on_ogam_lut(mpc, true); - if (matrix != NULL) { - if (mpc->funcs->set_output_csc != NULL) - mpc->funcs->set_output_csc(mpc, matrix, ocsc_mode); - } else { - if (mpc->funcs->set_ocsc_default != NULL) - mpc->funcs->set_ocsc_default(mpc, pixel_format, colorspace, ocsc_mode); - } + if (matrix != NULL) { + if (mpc->funcs->set_output_csc != NULL) + mpc->funcs->set_output_csc(mpc, matrix, ocsc_mode); + } + else { + if (mpc->funcs->set_ocsc_default != NULL) + mpc->funcs->set_ocsc_default(mpc, pixel_format, colorspace, ocsc_mode); + } } enum vpmpcc_ogam_mode { @@ -1091,13 +1092,23 @@ static void vpe10_mpc_program_1dlut_luta_settings(struct mpc *mpc, const struct } static void vpe10_mpc_program_1dlut_pwl( - struct mpc *mpc, const struct pwl_result_data *rgb, uint32_t num) + struct mpc *mpc, const struct pwl_result_data *rgb, uint32_t num, enum cm_type gamma_type) { PROGRAM_ENTRY(); - uint32_t last_base_value_red = rgb[num].red_reg; - uint32_t last_base_value_green = rgb[num].blue_reg; - uint32_t last_base_value_blue = rgb[num].green_reg; + uint32_t last_base_value_red; + uint32_t last_base_value_green; + uint32_t last_base_value_blue; + + if (gamma_type == CM_DEGAM) { + last_base_value_red = rgb[num].red_reg; + last_base_value_green = rgb[num].blue_reg; + last_base_value_blue = rgb[num].green_reg; + } else { + last_base_value_red = rgb[num - 1].red_reg + rgb[num - 1].delta_red_reg; + last_base_value_green = rgb[num - 1].green_reg + rgb[num - 1].delta_green_reg; + last_base_value_blue = rgb[num - 1].blue_reg + rgb[num - 1].delta_blue_reg; + } if (vpe_is_rgb_equal(rgb, num)) { vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_red, num, @@ -1128,7 +1139,7 @@ static void vpe10_mpc_program_1dlut_pwl( } // Blend-gamma control. -void vpe10_mpc_program_1dlut(struct mpc *mpc, const struct pwl_params *params) +void vpe10_mpc_program_1dlut(struct mpc *mpc, const struct pwl_params *params, enum cm_type gamma_type) { PROGRAM_ENTRY(); @@ -1138,6 +1149,7 @@ void vpe10_mpc_program_1dlut(struct mpc *mpc, const struct pwl_params *params) if (vpe_priv->init.debug.enable_mem_low_power.bits.mpc) vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, false); + return; } @@ -1145,7 +1157,7 @@ void vpe10_mpc_program_1dlut(struct mpc *mpc, const struct pwl_params *params) vpe10_mpc_configure_1dlut(mpc, true); vpe10_mpc_program_1dlut_luta_settings(mpc, params); - vpe10_mpc_program_1dlut_pwl(mpc, params->rgb_resulted, params->hw_points_num); + vpe10_mpc_program_1dlut_pwl(mpc, params->rgb_resulted, params->hw_points_num, gamma_type); REG_SET( VPMPCC_MCM_1DLUT_CONTROL, REG_DEFAULT(VPMPCC_MCM_1DLUT_CONTROL), VPMPCC_MCM_1DLUT_MODE, 2); @@ -1286,17 +1298,31 @@ void vpe10_mpc_set_output_transfer_func(struct mpc *mpc, struct output_ctx *outp void vpe10_mpc_set_blend_lut(struct mpc *mpc, const struct transfer_func *blend_tf) { struct pwl_params *blend_lut = NULL; + enum cm_type gamma_type = CM_DEGAM; + + if (blend_tf && blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) { + + gamma_type = blend_tf->cm_gamma_type; + + if (blend_tf->use_pre_calculated_table) { + vpe10_cm_get_tf_pwl_params(blend_tf, &blend_lut, gamma_type); + + VPE_ASSERT(blend_lut != NULL); + if (blend_lut == NULL) + return; + } else { + if (gamma_type == CM_DEGAM) + vpe10_cm_helper_translate_curve_to_degamma_hw_format( + blend_tf, &mpc->blender_params); // TODO should init regamma_params first + else + vpe10_cm_helper_translate_curve_to_hw_format( + blend_tf, &mpc->blender_params, false); - if (blend_tf) { - if (blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) { - vpe10_cm_helper_translate_curve_to_degamma_hw_format( - blend_tf, &mpc->blender_params); // TODO should init regamma_params first blend_lut = &mpc->blender_params; } } - mpc->funcs->program_1dlut(mpc, blend_lut); - return; + mpc->funcs->program_1dlut(mpc, blend_lut, gamma_type); } bool vpe10_mpc_program_movable_cm(struct mpc *mpc, const struct transfer_func *func_shaper, diff --git a/src/amd/vpelib/src/chip/vpe10/vpe10_opp.c b/src/amd/vpelib/src/chip/vpe10/vpe10_opp.c index 71a68604f53..d8f92c0e5f2 100644 --- a/src/amd/vpelib/src/chip/vpe10/vpe10_opp.c +++ b/src/amd/vpelib/src/chip/vpe10/vpe10_opp.c @@ -56,22 +56,13 @@ void vpe10_opp_set_clamping( { PROGRAM_ENTRY(); + //OCSC operations are handled in output gamma sequence to allow + // full range bg color fill. Hence, no clamping should be done on the output. switch (params->clamping_level) { case CLAMPING_LIMITED_RANGE_8BPC: case CLAMPING_LIMITED_RANGE_10BPC: case CLAMPING_LIMITED_RANGE_12BPC: - REG_SET_2(VPFMT_CLAMP_CNTL, 0, VPFMT_CLAMP_DATA_EN, 1, VPFMT_CLAMP_COLOR_FORMAT, - params->clamping_level); - break; case CLAMPING_LIMITED_RANGE_PROGRAMMABLE: - REG_SET_2(VPFMT_CLAMP_CNTL, 0, VPFMT_CLAMP_DATA_EN, 1, VPFMT_CLAMP_COLOR_FORMAT, 7); - REG_SET_2(VPFMT_CLAMP_COMPONENT_R, 0, VPFMT_CLAMP_LOWER_R, params->r_clamp_component_lower, - VPFMT_CLAMP_UPPER_R, params->r_clamp_component_upper); - REG_SET_2(VPFMT_CLAMP_COMPONENT_G, 0, VPFMT_CLAMP_LOWER_G, params->g_clamp_component_lower, - VPFMT_CLAMP_UPPER_G, params->g_clamp_component_upper); - REG_SET_2(VPFMT_CLAMP_COMPONENT_B, 0, VPFMT_CLAMP_LOWER_B, params->b_clamp_component_lower, - VPFMT_CLAMP_UPPER_B, params->b_clamp_component_upper); - break; case CLAMPING_FULL_RANGE: default: REG_SET_2(VPFMT_CLAMP_CNTL, 0, VPFMT_CLAMP_DATA_EN, 0, VPFMT_CLAMP_COLOR_FORMAT, 0); diff --git a/src/amd/vpelib/src/chip/vpe10/vpe10_resource.c b/src/amd/vpelib/src/chip/vpe10/vpe10_resource.c index 368b41c454a..98a414f4e20 100644 --- a/src/amd/vpelib/src/chip/vpe10/vpe10_resource.c +++ b/src/amd/vpelib/src/chip/vpe10/vpe10_resource.c @@ -830,7 +830,6 @@ int32_t vpe10_program_backend( cdc->funcs->program_global_sync(cdc, VPE10_CDC_VUPDATE_OFFSET_DEFAULT, VPE10_CDC_VUPDATE_WIDTH_DEFAULT, VPE10_CDC_VREADY_OFFSET_DEFAULT); - mpc->funcs->program_output_csc(mpc, surface_info->format, output_ctx->cs, NULL); mpc->funcs->set_output_transfer_func(mpc, output_ctx); // program shaper, 3dlut and 1dlut in MPC for after blend // Note: cannot program both before and after blend CM diff --git a/src/amd/vpelib/src/core/color.c b/src/amd/vpelib/src/core/color.c index bd1ad3181b4..fdf95ccae10 100644 --- a/src/amd/vpelib/src/core/color.c +++ b/src/amd/vpelib/src/core/color.c @@ -43,15 +43,15 @@ static void color_check_input_cm_update(struct vpe_priv *vpe_priv, struct stream static void color_check_output_cm_update( struct vpe_priv *vpe_priv, const struct vpe_color_space *vcs); -static bool color_check_bypass_cm(struct vpe_priv *vpe_priv, const struct vpe_build_param *param); +static bool color_update_regamma_tf(struct vpe_priv *vpe_priv, + enum color_transfer_func output_transfer_function, struct fixed31_32 x_scale, + struct fixed31_32 y_scale, struct fixed31_32 y_bias, bool can_bypass, + struct transfer_func *output_tf); -static bool color_update_output_tf(struct vpe_priv *vpe_priv, - enum color_transfer_func output_transfer_function, struct transfer_func *output_tf, - bool can_bypass); - -static bool color_update_input_tf(struct vpe_priv *vpe_priv, - enum color_transfer_func input_transfer_function, struct transfer_func *input_tf, - bool can_bypass, bool force_tf_calculation); +static bool color_update_degamma_tf(struct vpe_priv *vpe_priv, + enum color_transfer_func color_input_tf, struct fixed31_32 x_scale, + struct fixed31_32 y_scale, struct fixed31_32 y_bias, bool can_bypass, + struct transfer_func *input_tf); static bool color_update_input_cs(struct vpe_priv *vpe_priv, enum color_space in_cs, const struct vpe_color_adjust *adjustments, struct vpe_csc_matrix *input_cs, @@ -136,19 +136,22 @@ static void color_check_input_cm_update(struct vpe_priv *vpe_priv, struct stream stream_ctx->enable_3dlut = enable_3dlut; } -static bool color_update_output_tf(struct vpe_priv *vpe_priv, - enum color_transfer_func output_transfer_function, struct transfer_func *output_tf, - bool can_bypass) +static bool color_update_regamma_tf(struct vpe_priv *vpe_priv, + enum color_transfer_func output_transfer_function, struct fixed31_32 x_scale, + struct fixed31_32 y_scale, struct fixed31_32 y_bias, bool can_bypass, + struct transfer_func* output_tf) { struct pwl_params *params = NULL; - output_tf->sdr_ref_white_level = 80; - + if (can_bypass) { output_tf->type = TF_TYPE_BYPASS; return true; } + output_tf->sdr_ref_white_level = 80; + output_tf->cm_gamma_type = CM_REGAM; output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; + output_tf->start_base = y_bias; switch (output_transfer_function) { case TRANSFER_FUNC_SRGB: @@ -156,6 +159,7 @@ static bool color_update_output_tf(struct vpe_priv *vpe_priv, case TRANSFER_FUNC_BT1886: case TRANSFER_FUNC_PQ2084: case TRANSFER_FUNC_LINEAR_0_125: + case TRANSFER_FUNC_LINEAR_0_1: output_tf->tf = output_transfer_function; break; default: @@ -163,7 +167,10 @@ static bool color_update_output_tf(struct vpe_priv *vpe_priv, break; } - if (!vpe_priv->init.debug.force_tf_calculation) + if (!vpe_priv->init.debug.force_tf_calculation && + x_scale.value == vpe_fixpt_one.value && + y_scale.value == vpe_fixpt_one.value && + y_bias.value == vpe_fixpt_zero.value) vpe_priv->resource.get_tf_pwl_params(output_tf, ¶ms, CM_REGAM); if (params) @@ -172,14 +179,20 @@ static bool color_update_output_tf(struct vpe_priv *vpe_priv, output_tf->use_pre_calculated_table = false; if (!output_tf->use_pre_calculated_table) - vpe_color_calculate_regamma_params(vpe_priv, output_tf, &vpe_priv->cal_buffer); + vpe_color_calculate_regamma_params(vpe_priv, + x_scale, + y_scale, + y_bias, + &vpe_priv->cal_buffer, + output_tf); return true; } -static bool color_update_input_tf(struct vpe_priv *vpe_priv, - const enum color_transfer_func color_input_tf, struct transfer_func *input_tf, bool can_bypass, - bool force_tf_calculation) +static bool color_update_degamma_tf(struct vpe_priv *vpe_priv, + enum color_transfer_func color_input_tf, struct fixed31_32 x_scale, + struct fixed31_32 y_scale, struct fixed31_32 y_bias, bool can_bypass, + struct transfer_func *input_tf) { bool ret = true; struct pwl_params *params = NULL; @@ -189,15 +202,18 @@ static bool color_update_input_tf(struct vpe_priv *vpe_priv, return true; } + input_tf->cm_gamma_type = CM_DEGAM; input_tf->type = TF_TYPE_DISTRIBUTED_POINTS; + input_tf->start_base = y_bias; switch (color_input_tf) { case TRANSFER_FUNC_SRGB: case TRANSFER_FUNC_BT709: case TRANSFER_FUNC_BT1886: case TRANSFER_FUNC_PQ2084: - case TRANSFER_FUNC_LINEAR_0_125: case TRANSFER_FUNC_NORMALIZED_PQ: + case TRANSFER_FUNC_LINEAR_0_1: + case TRANSFER_FUNC_LINEAR_0_125: input_tf->tf = color_input_tf; break; default: @@ -205,7 +221,10 @@ static bool color_update_input_tf(struct vpe_priv *vpe_priv, break; } - if (!vpe_priv->init.debug.force_tf_calculation) + if (!vpe_priv->init.debug.force_tf_calculation && + x_scale.value == vpe_fixpt_one.value && + y_scale.value == vpe_fixpt_one.value && + y_bias.value == vpe_fixpt_zero.value) vpe_priv->resource.get_tf_pwl_params(input_tf, ¶ms, CM_DEGAM); if (params) @@ -213,31 +232,80 @@ static bool color_update_input_tf(struct vpe_priv *vpe_priv, else input_tf->use_pre_calculated_table = false; - if ((!input_tf->use_pre_calculated_table) || (force_tf_calculation)) { - input_tf->use_pre_calculated_table = false; - vpe_color_calculate_degamma_params(vpe_priv, vpe_priv->stream_ctx->tf_scaling_factor, - vpe_fixpt_from_int(1), + if (!input_tf->use_pre_calculated_table) { + vpe_color_calculate_degamma_params(vpe_priv, + x_scale, + y_scale, + y_bias, input_tf); } return ret; } -// return true if bypass can be done -static bool color_check_bypass_cm(struct vpe_priv *vpe_priv, const struct vpe_build_param *param) -{ - uint32_t i; - struct stream_ctx *stream_ctx; +static enum vpe_status vpe_allocate_cm_memory(struct vpe_priv *vpe_priv, const struct vpe_build_param *param) { - // TODO: revisit the TM case - for (i = 0; i < param->num_streams; i++) { - stream_ctx = &vpe_priv->stream_ctx[i]; - if (stream_ctx->cs != vpe_priv->output_ctx.cs || - stream_ctx->tf != vpe_priv->output_ctx.tf) { - return false; + struct stream_ctx *stream_ctx; + struct output_ctx *output_ctx; + enum vpe_status status = VPE_STATUS_OK; + + for (uint32_t stream_idx = 0; stream_idx < param->num_streams; stream_idx++) { + stream_ctx = &vpe_priv->stream_ctx[stream_idx]; + + if (!stream_ctx->input_cs) { + stream_ctx->input_cs = + (struct vpe_csc_matrix *)vpe_zalloc(sizeof(struct vpe_csc_matrix)); + if (!stream_ctx->input_cs) { + vpe_log("err: out of memory for input cs!"); + return VPE_STATUS_NO_MEMORY; + } + } + + if (!stream_ctx->input_tf) { + stream_ctx->input_tf = + (struct transfer_func *)vpe_zalloc(sizeof(struct transfer_func)); + if (!stream_ctx->input_tf) { + vpe_log("err: out of memory for input tf!"); + return VPE_STATUS_NO_MEMORY; + } + } + + if (!stream_ctx->bias_scale) { + stream_ctx->bias_scale = + (struct bias_and_scale *)vpe_zalloc(sizeof(struct bias_and_scale)); + if (!stream_ctx->bias_scale) { + vpe_log("err: out of memory for bias and scale!"); + return VPE_STATUS_NO_MEMORY; + } + } + + if (!stream_ctx->gamut_remap) { + stream_ctx->gamut_remap = vpe_zalloc(sizeof(struct colorspace_transform)); + if (!stream_ctx->gamut_remap) { + vpe_log("err: out of memory for gamut_remap!"); + return VPE_STATUS_NO_MEMORY; + } + } + if (!stream_ctx->blend_tf) { + stream_ctx->blend_tf = vpe_zalloc(sizeof(struct transfer_func)); + if (!stream_ctx->blend_tf) { + vpe_log("err: out of memory for blend tf!"); + return VPE_STATUS_NO_MEMORY; + } } } - return true; + + output_ctx = &vpe_priv->output_ctx; + if (!output_ctx->output_tf) { + output_ctx->output_tf = + (struct transfer_func *)vpe_zalloc(sizeof(struct transfer_func)); + if (!output_ctx->output_tf) { + vpe_log("err: out of memory for output tf!"); + return VPE_STATUS_NO_MEMORY; + } + } + + return VPE_STATUS_OK; } static enum color_space color_get_icsc_cs(enum color_space ics) @@ -302,6 +370,126 @@ static bool color_update_input_cs(struct vpe_priv *vpe_priv, enum color_space in return true; } +/* This function generates software points for the blnd gam and ogam programming blocks. + The logic for the blndgam/ogam programming sequence is a function of: + 1. Output Range (Studio Full) + 2. 3DLUT usage + 3. Output format (HDR SDR) + + SDR Out or studio range out + TM Case + BLNDGAM : NL -> NL*S + B + OGAM : Bypass + Non TM Case + BLNDGAM : L -> NL*S + B + OGAM : Bypass + Full range HDR Out + TM Case + BLNDGAM : NL -> L + OGAM : L -> NL + Non TM Case + BLNDGAM : Bypass + OGAM : L -> NL + +*/ + +static bool vpe_update_output_gamma_sequence(struct vpe_priv *vpe_priv, + const struct vpe_build_param *param) +{ + + struct stream_ctx *stream_ctx; + struct output_ctx *output_ctx; + struct vpe_color_space tm_out_cs; + struct fixed31_32 x_scale; + struct fixed31_32 y_scale; + struct fixed31_32 y_bias; + enum vpe_status status; + bool is_studio; + bool can_bypass = false; + bool lut3d_enabled = false; + + + status = VPE_STATUS_OK; + x_scale = vpe_fixpt_one; + y_bias = vpe_fixpt_zero; + y_scale = vpe_fixpt_one; + is_studio = (param->dst_surface.cs.range == VPE_COLOR_RANGE_STUDIO); + + if (is_studio) { + + if (vpe_is_rgb8(param->dst_surface.format)) { + y_scale = STUDIO_RANGE_SCALE_8_BIT; + y_bias = STUDIO_RANGE_FOOT_ROOM_8_BIT; + } else { + y_scale = STUDIO_RANGE_SCALE_10_BIT; + y_bias = STUDIO_RANGE_FOOT_ROOM_10_BIT; + } + } + + output_ctx = &vpe_priv->output_ctx; + + for (uint32_t stream_idx = 0; stream_idx < param->num_streams; stream_idx++) { + + enum color_space cs; + enum color_transfer_func tf = TRANSFER_FUNC_LINEAR_0_1; + + stream_ctx = &vpe_priv->stream_ctx[stream_idx]; + lut3d_enabled = stream_ctx->enable_3dlut; + + //If SDR out -> Blend should be NL + //If studio out -> No choice but to blend in NL + if (!vpe_is_HDR(output_ctx->tf) || is_studio) { + if (lut3d_enabled) { + tf = TRANSFER_FUNC_LINEAR_0_1; + } + else { + tf = output_ctx->tf; + } + + color_update_regamma_tf(vpe_priv, + tf, + x_scale, + y_scale, + y_bias, + can_bypass, + stream_ctx->blend_tf); + } + else { + + if (lut3d_enabled) { + vpe_color_build_tm_cs(&stream_ctx->stream.tm_params, param->dst_surface, &tm_out_cs); + vpe_color_get_color_space_and_tf(&tm_out_cs, &cs, &tf); + } + else { + can_bypass = true; + } + + color_update_degamma_tf(vpe_priv, + tf, + x_scale, + y_scale, + y_bias, + can_bypass, + stream_ctx->blend_tf); + } + } + + if (vpe_is_HDR(output_ctx->tf) && !is_studio) + can_bypass = false; //Blending is done in linear light so ogam needs to handle the regam + else + can_bypass = true; + + color_update_regamma_tf(vpe_priv, + output_ctx->tf, + vpe_fixpt_one, + vpe_fixpt_one, + vpe_fixpt_zero, + can_bypass, + output_ctx->output_tf); + + return status; +} + bool vpe_use_csc_adjust(const struct vpe_color_adjust *adjustments) { float epsilon = 0.001f; // steps are 1.0f or 0.01f, so should be plenty @@ -444,110 +632,68 @@ enum vpe_status vpe_color_update_color_space_and_tf( { uint32_t stream_idx; struct stream_ctx *stream_ctx; - struct output_ctx *output_ctx; - enum vpe_status status = VPE_STATUS_OK; + struct fixed31_32 new_matrix_scaling_factor; + struct output_ctx *output_ctx = &vpe_priv->output_ctx; + enum vpe_status status = VPE_STATUS_OK; - color_check_output_cm_update(vpe_priv, ¶m->dst_surface.cs); + status = vpe_allocate_cm_memory(vpe_priv, param); + if (status == VPE_STATUS_OK) { - for (stream_idx = 0; stream_idx < param->num_streams; stream_idx++) { - stream_ctx = &vpe_priv->stream_ctx[stream_idx]; + color_check_output_cm_update(vpe_priv, ¶m->dst_surface.cs); - color_check_input_cm_update(vpe_priv, stream_ctx, - ¶m->streams[stream_idx].surface_info.cs, ¶m->streams[stream_idx].color_adj, - param->streams[stream_idx].tm_params.enable_3dlut); - } + for (stream_idx = 0; stream_idx < param->num_streams; stream_idx++) { - output_ctx = &vpe_priv->output_ctx; - if (output_ctx->dirty_bits.transfer_function) { - if (!output_ctx->output_tf) { - output_ctx->output_tf = - (struct transfer_func *)vpe_zalloc(sizeof(struct transfer_func)); - if (!output_ctx->output_tf) { - vpe_log("err: out of memory for output tf!"); - return VPE_STATUS_NO_MEMORY; - } - } + new_matrix_scaling_factor = vpe_fixpt_one; + stream_ctx = &vpe_priv->stream_ctx[stream_idx]; - color_update_output_tf(vpe_priv, output_ctx->tf, output_ctx->output_tf, - false); // No bypass, always do regam/degam - } - - for (stream_idx = 0; stream_idx < param->num_streams; stream_idx++) { - stream_ctx = &vpe_priv->stream_ctx[stream_idx]; - struct fixed31_32 new_matrix_scaling_factor = vpe_fixpt_one; - - if (stream_ctx->dirty_bits.color_space) { - if (!stream_ctx->input_cs) { - stream_ctx->input_cs = - (struct vpe_csc_matrix *)vpe_zalloc(sizeof(struct vpe_csc_matrix)); - if (!stream_ctx->input_cs) { - vpe_log("err: out of memory for input cs!"); - return VPE_STATUS_NO_MEMORY; - } - } - - if (!color_update_input_cs(vpe_priv, stream_ctx->cs, - ¶m->streams[stream_idx].color_adj, stream_ctx->input_cs, - &stream_ctx->color_adjustments, &new_matrix_scaling_factor)) { - vpe_log("err: input cs not being programmed!"); - } else { - if ((vpe_priv->scale_yuv_matrix) && // the option to scale the matrix yuv to rgb is - // on - (new_matrix_scaling_factor.value != - vpe_priv->stream_ctx->tf_scaling_factor.value)) { - vpe_priv->stream_ctx->tf_scaling_factor = new_matrix_scaling_factor; - stream_ctx->dirty_bits.transfer_function = 1; // force tf recalculation - } - } - } - - if (stream_ctx->dirty_bits.transfer_function) { - if (!stream_ctx->input_tf) { - stream_ctx->input_tf = - (struct transfer_func *)vpe_zalloc(sizeof(struct transfer_func)); - if (!stream_ctx->input_tf) { - vpe_log("err: out of memory for input tf!"); - return VPE_STATUS_NO_MEMORY; - } - } - - color_update_input_tf(vpe_priv, stream_ctx->tf, stream_ctx->input_tf, - stream_ctx->stream.tm_params.enable_3dlut, // By Pass regamma if 3DLUT is enabled - false); - } - - if (!stream_ctx->bias_scale) { - stream_ctx->bias_scale = - (struct bias_and_scale *)vpe_zalloc(sizeof(struct bias_and_scale)); - if (!stream_ctx->bias_scale) { - vpe_log("err: out of memory for bias and scale!"); - return VPE_STATUS_NO_MEMORY; - } + color_check_input_cm_update(vpe_priv, stream_ctx, + ¶m->streams[stream_idx].surface_info.cs, ¶m->streams[stream_idx].color_adj, + param->streams[stream_idx].tm_params.enable_3dlut); build_scale_and_bias(stream_ctx->bias_scale, ¶m->streams[stream_idx].surface_info.cs, param->streams[stream_idx].surface_info.format); - } - if (stream_ctx->dirty_bits.color_space || output_ctx->dirty_bits.color_space) { - if (!stream_ctx->gamut_remap) { - stream_ctx->gamut_remap = vpe_zalloc(sizeof(struct colorspace_transform)); - if (!stream_ctx->gamut_remap) { - vpe_log("err: out of memory for gamut_remap!"); - return VPE_STATUS_NO_MEMORY; + if (stream_ctx->dirty_bits.color_space) { + if (!color_update_input_cs(vpe_priv, stream_ctx->cs, + ¶m->streams[stream_idx].color_adj, stream_ctx->input_cs, + &stream_ctx->color_adjustments, &new_matrix_scaling_factor)) { + vpe_log("err: input cs not being programmed!"); + } + else { + if ((vpe_priv->scale_yuv_matrix) && // the option to scale the matrix yuv to rgb is + // on + (new_matrix_scaling_factor.value != + vpe_priv->stream_ctx->tf_scaling_factor.value)) { + vpe_priv->stream_ctx->tf_scaling_factor = new_matrix_scaling_factor; + stream_ctx->dirty_bits.transfer_function = 1; // force tf recalculation + } } } - status = vpe_color_update_gamut(vpe_priv, stream_ctx->cs, output_ctx->cs, - stream_ctx->gamut_remap, stream_ctx->stream.tm_params.enable_3dlut); + + if (stream_ctx->dirty_bits.transfer_function) { + color_update_degamma_tf(vpe_priv, stream_ctx->tf, + vpe_priv->stream_ctx->tf_scaling_factor, + vpe_fixpt_one, + vpe_fixpt_zero, + stream_ctx->stream.tm_params.enable_3dlut, // By Pass degamma if 3DLUT is enabled + stream_ctx->input_tf); + } + + if (stream_ctx->dirty_bits.color_space || output_ctx->dirty_bits.color_space) { + status = vpe_color_update_gamut(vpe_priv, stream_ctx->cs, output_ctx->cs, + stream_ctx->gamut_remap, stream_ctx->stream.tm_params.enable_3dlut); + } } - } - if (status != VPE_STATUS_OK) { - vpe_log("failed in updating gamut %d\n", (int)status); - return status; - } + if (status == VPE_STATUS_OK) { + if (output_ctx->dirty_bits.transfer_function || + output_ctx->dirty_bits.color_space) + vpe_update_output_gamma_sequence(vpe_priv, param); + } - return VPE_STATUS_OK; + } + return status; } enum vpe_status vpe_color_tm_update_hdr_mult(uint16_t shaper_in_exp_max, uint32_t peak_white, @@ -583,44 +729,10 @@ enum vpe_status vpe_color_update_shaper( shaper_in.use_const_hdr_mult = false; // can't be true. Fix is required. shaper_func->type = TF_TYPE_HWPWL; - shaper_func->tf = TRANSFER_FUNC_LINEAR_0_125; + shaper_func->tf = TRANSFER_FUNC_LINEAR_0_1; return vpe_build_shaper(&shaper_in, &shaper_func->pwl); } -enum vpe_status vpe_color_update_blnd_gam(struct vpe_priv *vpe_priv, - const struct vpe_build_param *param, const struct vpe_tonemap_params *tm_params, - struct transfer_func *blnd_tf_func, bool enable_3dlut) -{ - - if (!enable_3dlut) { - blnd_tf_func->type = TF_TYPE_BYPASS; - return VPE_STATUS_OK; - } - - enum vpe_status ret = VPE_STATUS_OK; - struct vpe_color_space tm_out_cs; - enum color_space cs; - enum color_transfer_func tf; - struct fixed31_32 tf_norm_gain; - - vpe_color_build_tm_cs(tm_params, param->dst_surface, &tm_out_cs); - vpe_color_get_color_space_and_tf(&tm_out_cs, &cs, &tf); - - if (tf == TRANSFER_FUNC_NORMALIZED_PQ) { - uint32_t outLuminance = vpe_priv->output_ctx.hdr_metadata.max_mastering; - vpe_compute_pq(vpe_fixpt_from_fraction((long long)outLuminance, 10000), &tf_norm_gain); - } else { - tf_norm_gain = vpe_fixpt_from_int(1); - } - - blnd_tf_func->type = TF_TYPE_DISTRIBUTED_POINTS; - blnd_tf_func->tf = tf; - blnd_tf_func->use_pre_calculated_table = false; - - vpe_color_calculate_degamma_params(vpe_priv, tf_norm_gain, vpe_fixpt_from_int(1), blnd_tf_func); - return VPE_STATUS_OK; -} - enum vpe_status vpe_color_update_movable_cm( struct vpe_priv *vpe_priv, const struct vpe_build_param *param) { @@ -679,6 +791,8 @@ enum vpe_status vpe_color_update_movable_cm( } } + //Blendgam is updated by output vpe_update_output_gamma_sequence + if (param->streams[stream_idx].tm_params.shaper_tf == VPE_TF_PQ_NORMALIZED) pqNormFactor = stream_ctx->stream.hdr_metadata.max_mastering; else @@ -689,9 +803,6 @@ enum vpe_status vpe_color_update_movable_cm( vpe_color_update_shaper(SHAPER_EXP_MAX_IN, stream_ctx->in_shaper_func, enable_3dlut); - vpe_color_update_blnd_gam( - vpe_priv, param, &stream_ctx->stream.tm_params, stream_ctx->blend_tf, enable_3dlut); - vpe_color_build_tm_cs(&stream_ctx->stream.tm_params, param->dst_surface, &tm_out_cs); vpe_color_get_color_space_and_tf(&tm_out_cs, &out_lut_cs, &tf); diff --git a/src/amd/vpelib/src/core/color_bg.c b/src/amd/vpelib/src/core/color_bg.c index ce919dd8b5c..7a2dafc664a 100644 --- a/src/amd/vpelib/src/core/color_bg.c +++ b/src/amd/vpelib/src/core/color_bg.c @@ -1,6 +1,7 @@ #include #include #include "color_bg.h" +#include "vpe_priv.h" struct csc_vector { float x; @@ -134,6 +135,35 @@ static bool bg_csc(struct vpe_color *bg_color, enum color_space cs) return output_is_clipped; } +static inline bool is_global_bg_blend_applied(struct stream_ctx *stream_ctx) { + + return (stream_ctx->stream.blend_info.blending) && + (stream_ctx->stream.blend_info.global_alpha) && + (stream_ctx->stream.blend_info.global_alpha_value != 1.0); +} + +/* + In order to support background color fill correctly, we need to do studio -> full range conversion + before the blend block. However, there is also a requirement for HDR output to be blended in linear space. + Hence, if we have PQ out and studio range, we need to make sure no blenidng will occur. Othewise the job + is invalid. + +*/ +static enum vpe_status is_valid_blend(const struct vpe_priv *vpe_priv, struct vpe_color *bg_color) { + + enum vpe_status status = VPE_STATUS_OK; + const struct vpe_color_space *vcs = &vpe_priv->output_ctx.surface.cs; + struct stream_ctx *stream_ctx = vpe_priv->stream_ctx; //Only need to check the first stream. + + if ((vcs->range == VPE_COLOR_RANGE_STUDIO) && + (vcs->tf == VPE_TF_PQ) && + ((stream_ctx->stream.surface_info.cs.encoding == VPE_PIXEL_ENCODING_RGB) || + is_global_bg_blend_applied(stream_ctx))) + status = VPE_STATUS_BG_COLOR_OUT_OF_RANGE; + + return status; +} + struct gamma_coefs { float a0; float a1; @@ -257,6 +287,8 @@ static bool is_rgb_limited(enum color_space cs) return (cs == COLOR_SPACE_SRGB_LIMITED || cs == COLOR_SPACE_2020_RGB_LIMITEDRANGE); } +// To understand the logic for background color conversion, +// please refer to vpe_update_output_gamma_sequence in color.c void vpe_bg_color_convert( enum color_space output_cs, struct transfer_func *output_tf, struct vpe_color *bg_color) { @@ -305,7 +337,7 @@ void vpe_bg_color_convert( // input is [0-0xffff] // convert bg color to RGB full range for use inside pipe - if (bg_color->is_ycbcr || is_rgb_limited(bgcolor_cs)) + if (bg_color->is_ycbcr) bg_csc(bg_color, bgcolor_cs); if (output_tf->type == TF_TYPE_DISTRIBUTED_POINTS) { @@ -315,16 +347,7 @@ void vpe_bg_color_convert( // de-gam switch (output_tf->tf) { - case TRANSFER_FUNC_SRGB: - case TRANSFER_FUNC_BT709: - case TRANSFER_FUNC_BT1886: - compute_degam(output_tf->tf, (double)bg_color->rgba.r, °am_r, true); - compute_degam(output_tf->tf, (double)bg_color->rgba.g, °am_g, true); - compute_degam(output_tf->tf, (double)bg_color->rgba.b, °am_b, true); - bg_color->rgba.r = (float)degam_r; - bg_color->rgba.g = (float)degam_g; - bg_color->rgba.b = (float)degam_b; - break; + case TRANSFER_FUNC_PQ2084: compute_depq((double)bg_color->rgba.r, °am_r, true); compute_depq((double)bg_color->rgba.g, °am_g, true); @@ -333,7 +356,11 @@ void vpe_bg_color_convert( bg_color->rgba.g = (float)degam_g; bg_color->rgba.b = (float)degam_b; break; + case TRANSFER_FUNC_SRGB: + case TRANSFER_FUNC_BT709: + case TRANSFER_FUNC_BT1886: case TRANSFER_FUNC_LINEAR_0_125: + case TRANSFER_FUNC_LINEAR_0_1: break; default: VPE_ASSERT(0); @@ -343,15 +370,18 @@ void vpe_bg_color_convert( // for TF_TYPE_BYPASS, bg color should be programmed to mpc as linear } + enum vpe_status vpe_bg_color_outside_cs_gamut( - const struct vpe_color_space *vcs, struct vpe_color *bg_color) + const struct vpe_priv *vpe_priv, struct vpe_color *bg_color) { enum color_space cs; enum color_transfer_func tf; struct vpe_color bg_color_copy = *bg_color; + const struct vpe_color_space *vcs = &vpe_priv->output_ctx.surface.cs; + vpe_color_get_color_space_and_tf(vcs, &cs, &tf); - if (is_rgb_limited(cs) || (bg_color->is_ycbcr)) { + if ((bg_color->is_ycbcr)) { // using the bg_color_copy instead as bg_csc will modify it // we should not do modification in checking stage // otherwise validate_cached_param() will fail @@ -361,3 +391,16 @@ enum vpe_status vpe_bg_color_outside_cs_gamut( } return VPE_STATUS_OK; } + +// These two checks are only neccessary for VPE1.0 and contain alot of quirks to work around VPE 1.0 limitations. +enum vpe_status vpe_is_valid_bg_color(const struct vpe_priv *vpe_priv, struct vpe_color *bg_color) { + + enum vpe_status status = VPE_STATUS_OK; + + status = is_valid_blend(vpe_priv, bg_color); + + if (status == VPE_STATUS_OK) + status = vpe_bg_color_outside_cs_gamut(vpe_priv, bg_color); + + return status; +} diff --git a/src/amd/vpelib/src/core/color_gamma.c b/src/amd/vpelib/src/core/color_gamma.c index 399f56cf96f..254631f3681 100644 --- a/src/amd/vpelib/src/core/color_gamma.c +++ b/src/amd/vpelib/src/core/color_gamma.c @@ -336,33 +336,30 @@ static struct fixed31_32 translate_from_linear_space_ex(struct fixed31_32 arg, return translate_from_linear_space(&scratch_gamma_args); } -static void build_pq(struct pwl_float_data_ex *rgb_regamma, uint32_t hw_points_num, - const struct hw_x_point *coordinate_x, uint32_t hdr_normalization) +static void build_pq(uint32_t hw_points_num, + const struct hw_x_point *coordinate_x, + struct fixed31_32 x_scale, struct fixed31_32 y_scale, struct fixed31_32 y_bias, + struct pwl_float_data_ex *rgb_regamma) { - uint32_t i, start_index; + uint32_t i, curve_start_index; struct pwl_float_data_ex *rgb = rgb_regamma; const struct hw_x_point *coord_x = coordinate_x; struct fixed31_32 output; - struct fixed31_32 scaling_factor = vpe_fixpt_from_fraction(1, hdr_normalization); + struct fixed31_32 slope; - /* TODO: start index is from segment 2^-24, skipping first segment - * due to x values too small for power calculations + /* Curve Start index is from segment 2^-24, the first segment must be + * treated as a linear interpolation due to numbers being to small for power + * operations */ - start_index = 32; - rgb += start_index; - coord_x += start_index; - - for (i = start_index; i <= hw_points_num; i++) { - - vpe_compute_pq(vpe_fixpt_mul(coord_x->x, scaling_factor), &output); - - /* should really not happen? */ - if (vpe_fixpt_lt(output, vpe_fixpt_zero)) - output = vpe_fixpt_zero; - else if (vpe_fixpt_lt(vpe_fixpt_one, output)) - output = vpe_fixpt_one; + curve_start_index = 32; + vpe_compute_pq(vpe_fixpt_mul(coord_x[curve_start_index].x, x_scale), &output); + output = vpe_fixpt_mul(output, y_scale); + slope = vpe_fixpt_div(output, coord_x[curve_start_index].x); + for (i = 0; i < curve_start_index; i++) { + output = vpe_fixpt_mul(coord_x->x, slope); + output = vpe_fixpt_add(output, y_bias); rgb->r = output; rgb->g = output; rgb->b = output; @@ -370,11 +367,12 @@ static void build_pq(struct pwl_float_data_ex *rgb_regamma, uint32_t hw_points_n ++coord_x; ++rgb; } - coord_x = coordinates_x; - rgb = rgb_regamma; - struct fixed31_32 slope = vpe_fixpt_div(rgb[start_index].r, coord_x[start_index].x); - for (i = 0; i < start_index; i++) { - output = vpe_fixpt_mul(coord_x->x, slope); + + for (i = curve_start_index; i <= hw_points_num; i++) { + + vpe_compute_pq(vpe_fixpt_mul(coord_x->x, x_scale), &output); + output = vpe_fixpt_mul(output, y_scale); + output = vpe_fixpt_add(output, y_bias); rgb->r = output; rgb->g = output; rgb->b = output; @@ -384,36 +382,30 @@ static void build_pq(struct pwl_float_data_ex *rgb_regamma, uint32_t hw_points_n } } -static void build_de_pq(struct transfer_func_distributed_points *de_pq, uint32_t hw_points_num, +static void build_de_pq(uint32_t hw_points_num, const struct hw_x_point *coordinate_x_degamma, struct fixed31_32 x_scale, - struct fixed31_32 y_scale) + struct fixed31_32 y_scale, struct fixed31_32 y_bias, struct transfer_func_distributed_points *de_pq) { - uint32_t i; struct fixed31_32 output; - struct fixed31_32 *de_pq_table = vpe_color_get_table(type_de_pq_table); - - precompute_de_pq(x_scale, y_scale); - - for (i = 0; i < hw_points_num; i++) { - output = de_pq_table[i]; - /* should really not happen? */ - if (vpe_fixpt_lt(output, vpe_fixpt_zero)) - output = vpe_fixpt_zero; + for (uint32_t i = 0; i < hw_points_num; i++) { + compute_de_pq(vpe_fixpt_mul(coordinates_x_degamma[i].x, x_scale), &output); + output = vpe_fixpt_mul(output, y_scale); + output = vpe_fixpt_add(output, y_bias); de_pq->red[i] = output; de_pq->green[i] = output; de_pq->blue[i] = output; } } -static bool build_degamma(struct transfer_func_distributed_points *curve, uint32_t hw_points_num, +static bool build_degamma(uint32_t hw_points_num, const struct hw_x_point *coordinate_x_degamma, enum color_transfer_func type, - struct fixed31_32 yuv2rgbScaling) + struct fixed31_32 x_scale, struct fixed31_32 y_scale, struct fixed31_32 y_bias, + struct transfer_func_distributed_points *curve) { uint32_t i; struct gamma_coefficients coeff; - struct fixed31_32 scaledX; - struct fixed31_32 scaledY; + struct fixed31_32 output; bool ret = false; if (!build_coefficients(&coeff, type)) @@ -424,11 +416,15 @@ static bool build_degamma(struct transfer_func_distributed_points *curve, uint32 i = 0; while (i != MAX_HW_POINTS_DEGAMMA) { - scaledX = vpe_fixpt_mul(coordinate_x_degamma[i].x, yuv2rgbScaling); - scaledY = translate_to_linear_space_ex(scaledX, &coeff, 0); - curve->red[i] = scaledY; - curve->green[i] = scaledY; - curve->blue[i] = scaledY; + output = vpe_fixpt_mul(coordinate_x_degamma[i].x, x_scale); + + output = translate_to_linear_space_ex(output, &coeff, 0); + output = vpe_fixpt_mul(output, y_scale); + output = vpe_fixpt_add(output, y_bias); + + curve->red[i] = output; + curve->green[i] = output; + curve->blue[i] = output; i++; } ret = true; @@ -436,9 +432,10 @@ release: return ret; } -static bool build_regamma(struct vpe_priv *vpe_priv, struct pwl_float_data_ex *rgb_regamma, - uint32_t hw_points_num, const struct hw_x_point *coordinate_x, enum color_transfer_func type, - struct calculate_buffer *cal_buffer) +static bool build_regamma(struct vpe_priv *vpe_priv, uint32_t hw_points_num, + const struct hw_x_point *coordinate_x, enum color_transfer_func type, + struct fixed31_32 x_scale, struct fixed31_32 y_scale, struct fixed31_32 y_bias, + struct calculate_buffer *cal_buffer, struct pwl_float_data_ex *rgb_regamma) { uint32_t i; bool ret = false; @@ -460,7 +457,9 @@ static bool build_regamma(struct vpe_priv *vpe_priv, struct pwl_float_data_ex *r i = 0; while (i <= hw_points_num) { /* TODO use y vs r,g,b */ - rgb->r = translate_from_linear_space_ex(coord_x->x, coeff, 0, cal_buffer); + rgb->r = vpe_fixpt_mul(coord_x->x, x_scale); + rgb->r = translate_from_linear_space_ex(rgb->r, coeff, 0, cal_buffer); + rgb->r = vpe_fixpt_add(vpe_fixpt_mul(rgb->r, y_scale), y_bias); rgb->g = rgb->r; rgb->b = rgb->r; ++coord_x; @@ -488,8 +487,7 @@ static void build_new_custom_resulted_curve( } } -static bool map_regamma_hw_to_x_user(struct pixel_gamma_point *coeff128, - struct hw_x_point *coords_x, const struct pwl_float_data_ex *rgb_regamma, +static bool map_regamma_hw_to_x_user(struct hw_x_point *coords_x, const struct pwl_float_data_ex *rgb_regamma, uint32_t hw_points_num, struct transfer_func_distributed_points *tf_pts, bool doClamping) { /* setup to spare calculated ideal regamma values */ @@ -517,78 +515,114 @@ static bool map_regamma_hw_to_x_user(struct pixel_gamma_point *coeff128, } static bool calculate_curve(struct vpe_priv *vpe_priv, enum color_transfer_func trans, + struct fixed31_32 x_scale, struct fixed31_32 y_scale, struct fixed31_32 y_bias, struct transfer_func_distributed_points *points, struct pwl_float_data_ex *rgb_regamma, - uint32_t hdr_normalization, struct calculate_buffer *cal_buffer) + struct calculate_buffer *cal_buffer) { + int hdr_norm = vpe_priv->resource.internal_hdr_normalization; + int y_norm; + struct fixed31_32 combined_scale; + bool ret = false; - - if (trans == TRANSFER_FUNC_PQ2084) { - points->end_exponent = 0; - points->x_point_at_y1_red = 1; - points->x_point_at_y1_green = 1; - points->x_point_at_y1_blue = 1; - - build_pq(rgb_regamma, MAX_HW_POINTS, coordinates_x, hdr_normalization); + switch (trans) + { + case TRANSFER_FUNC_SRGB: + case TRANSFER_FUNC_BT709: + case TRANSFER_FUNC_BT1886: + build_regamma(vpe_priv, MAX_HW_POINTS, coordinates_x, trans, x_scale, y_scale, y_bias, cal_buffer, rgb_regamma); ret = true; - } else if (trans == TRANSFER_FUNC_LINEAR_0_125) { + break; + case TRANSFER_FUNC_PQ2084: + build_pq(MAX_HW_POINTS, coordinates_x, x_scale, y_scale, y_bias, rgb_regamma); + ret = true; + break; + case TRANSFER_FUNC_LINEAR_0_125: + case TRANSFER_FUNC_LINEAR_0_1: + if (trans == TRANSFER_FUNC_LINEAR_0_1) + y_norm = 1; + else + y_norm = CCCS_NORM; + + combined_scale = vpe_fixpt_div_int(vpe_fixpt_from_int(y_norm), hdr_norm); + combined_scale = vpe_fixpt_mul(combined_scale, y_scale); + combined_scale = vpe_fixpt_mul(combined_scale, x_scale); for (int i = 0; i < MAX_HW_POINTS; i++) { - rgb_regamma[i].r = - vpe_fixpt_mul(coordinates_x[i].x, vpe_fixpt_from_fraction(125, hdr_normalization)); + rgb_regamma[i].r = vpe_fixpt_mul(coordinates_x[i].x, combined_scale); + rgb_regamma[i].r = vpe_fixpt_add(rgb_regamma[i].r, y_bias); rgb_regamma[i].g = rgb_regamma[i].r; rgb_regamma[i].b = rgb_regamma[i].r; } + ret = true; - } else { - // trans == TRANSFER_FUNC_SRGB - // trans == TRANSFER_FUNC_BT709 - // trans == TRANSFER_FUNCTION_GAMMA22 - // trans == TRANSFER_FUNCTION_GAMMA24 - // trans == TRANSFER_FUNCTION_GAMMA26 - points->end_exponent = 0; - points->x_point_at_y1_red = 1; - points->x_point_at_y1_green = 1; - points->x_point_at_y1_blue = 1; - - build_regamma(vpe_priv, rgb_regamma, MAX_HW_POINTS, coordinates_x, trans, cal_buffer); - - ret = true; + break; + case TRANSFER_FUNC_NORMALIZED_PQ: + case TRANSFER_FUNC_UNKNOWN: + break; + default: + break; } + return ret; } #define _EXTRA_POINTS 3 bool vpe_color_calculate_degamma_params(struct vpe_priv *vpe_priv, struct fixed31_32 x_scale, - struct fixed31_32 y_scale, struct transfer_func *input_tf) + struct fixed31_32 y_scale, struct fixed31_32 y_bias, struct transfer_func *input_tf) { - struct transfer_func_distributed_points *tf_pts = &input_tf->tf_pts; - enum color_transfer_func tf; - uint32_t i; - bool ret = true; + struct transfer_func_distributed_points *tf_pts = &input_tf->tf_pts; + enum color_transfer_func tf = input_tf->tf; + int hdr_norm = vpe_priv->resource.internal_hdr_normalization; + bool ret = false; + int x_norm; + struct fixed31_32 scale_combined; + struct fixed31_32 output; - tf = input_tf->tf; - if (tf == TRANSFER_FUNC_PQ2084 || tf == TRANSFER_FUNC_NORMALIZED_PQ) - build_de_pq(tf_pts, MAX_HW_POINTS_DEGAMMA, coordinates_x_degamma, x_scale, y_scale); - else if (tf == TRANSFER_FUNC_SRGB || tf == TRANSFER_FUNC_BT709 || tf == TRANSFER_FUNC_BT1886) - build_degamma(tf_pts, MAX_HW_POINTS_DEGAMMA, coordinates_x_degamma, tf, x_scale); - else if (tf == TRANSFER_FUNC_LINEAR_0_125) { - // just copy coordinates_x_degamma into curve - i = 0; - while (i != MAX_HW_POINTS_DEGAMMA) { - tf_pts->red[i] = vpe_fixpt_mul(coordinates_x[i].x, y_scale); - tf_pts->red[i] = tf_pts->red[i]; - tf_pts->red[i] = tf_pts->red[i]; - i++; + + switch (tf) + { + case TRANSFER_FUNC_PQ2084: + case TRANSFER_FUNC_NORMALIZED_PQ: + build_de_pq(MAX_HW_POINTS_DEGAMMA, coordinates_x_degamma, x_scale, y_scale, y_bias, tf_pts); + ret = true; + break; + case TRANSFER_FUNC_SRGB: + case TRANSFER_FUNC_BT709: + case TRANSFER_FUNC_BT1886: + build_degamma(MAX_HW_POINTS_DEGAMMA, coordinates_x_degamma, tf, x_scale, y_scale, y_bias, tf_pts); + ret = true; + break; + case TRANSFER_FUNC_LINEAR_0_1: + case TRANSFER_FUNC_LINEAR_0_125: + if (tf == TRANSFER_FUNC_LINEAR_0_1) + x_norm = 1; + else + x_norm = CCCS_NORM; + + scale_combined = vpe_fixpt_div_int(vpe_fixpt_from_int(hdr_norm), x_norm); + scale_combined = vpe_fixpt_mul(scale_combined, x_scale); + scale_combined = vpe_fixpt_mul(scale_combined, y_scale); + + for (int i = 0; i < MAX_HW_POINTS_DEGAMMA; i ++) { + output = vpe_fixpt_mul(coordinates_x_degamma[i].x, scale_combined); + output = vpe_fixpt_add(output, y_bias); + tf_pts->red[i] = output; + tf_pts->green[i] = output; + tf_pts->blue[i] = output; } - } else - ret = false; - + ret = true; + break; + default: + break; + } return ret; } bool vpe_color_calculate_regamma_params( - struct vpe_priv *vpe_priv, struct transfer_func *output_tf, struct calculate_buffer *cal_buffer) + struct vpe_priv* vpe_priv, struct fixed31_32 x_scale, + struct fixed31_32 y_scale, struct fixed31_32 y_bias, + struct calculate_buffer *cal_buffer, struct transfer_func *output_tf) { struct transfer_func_distributed_points *tf_pts = &output_tf->tf_pts; struct pwl_float_data_ex *rgb_regamma = NULL; @@ -608,11 +642,13 @@ bool vpe_color_calculate_regamma_params( tf = output_tf->tf; - ret = calculate_curve(vpe_priv, tf, tf_pts, rgb_regamma, - vpe_priv->resource.internal_hdr_normalization, cal_buffer); + ret = calculate_curve(vpe_priv, tf, + x_scale, y_scale, y_bias, + tf_pts, rgb_regamma, + cal_buffer); if (ret) { - map_regamma_hw_to_x_user(coeff, coordinates_x, rgb_regamma, MAX_HW_POINTS, tf_pts, false); + map_regamma_hw_to_x_user(coordinates_x, rgb_regamma, MAX_HW_POINTS, tf_pts, false); } vpe_free(coeff); diff --git a/src/amd/vpelib/src/core/inc/color.h b/src/amd/vpelib/src/core/inc/color.h index 231ef6a737c..4e6db7cb894 100644 --- a/src/amd/vpelib/src/core/inc/color.h +++ b/src/amd/vpelib/src/core/inc/color.h @@ -32,9 +32,14 @@ extern "C" { #endif -#define SDR_VIDEO_WHITE_POINT 100 // nits -#define SDR_WHITE_POINT 80 // nits -#define HDR_PEAK_WHITE 10000 +#define SDR_VIDEO_WHITE_POINT 100 // nits +#define SDR_WHITE_POINT 80 // nits +#define HDR_PEAK_WHITE 10000 +#define CCCS_NORM HDR_PEAK_WHITE/SDR_WHITE_POINT +#define STUDIO_RANGE_FOOT_ROOM_10_BIT vpe_fixpt_from_fraction(64, 1023) +#define STUDIO_RANGE_SCALE_10_BIT vpe_fixpt_from_fraction(940 - 64, 1023) +#define STUDIO_RANGE_FOOT_ROOM_8_BIT vpe_fixpt_from_fraction(16, 255) +#define STUDIO_RANGE_SCALE_8_BIT vpe_fixpt_from_fraction(235 - 16, 255) struct vpe_priv; struct stream_ctx; @@ -52,13 +57,19 @@ enum color_depth { COLOR_DEPTH_COUNT }; -enum color_transfer_func { +/* +* Special comment for TRANSFER_FUNC_LINEAR_0_125, + Inside of the pipeline, vpe operates in 0 - 1 nominal range. + For degamma operations, 0_125 refers to input normalization and for regam, 0_125 refers to output normalization. + */ + enum color_transfer_func { TRANSFER_FUNC_UNKNOWN, TRANSFER_FUNC_SRGB, TRANSFER_FUNC_BT709, TRANSFER_FUNC_BT1886, TRANSFER_FUNC_PQ2084, - TRANSFER_FUNC_LINEAR_0_125, + TRANSFER_FUNC_LINEAR_0_1, + TRANSFER_FUNC_LINEAR_0_125, TRANSFER_FUNC_NORMALIZED_PQ }; @@ -115,6 +126,11 @@ enum transfer_func_type { TF_TYPE_HWPWL }; +enum cm_type { + CM_DEGAM, + CM_REGAM, +}; + enum { TRANSFER_FUNC_POINTS = 1025 }; @@ -135,6 +151,8 @@ struct transfer_func_distributed_points { struct transfer_func { enum transfer_func_type type; enum color_transfer_func tf; + enum cm_type cm_gamma_type; + struct fixed31_32 start_base; //Used to clamp curve start /* FP16 1.0 reference level in nits, default is 80 nits, only for PQ*/ uint32_t sdr_ref_white_level; @@ -235,10 +253,6 @@ enum vpe_status vpe_color_tm_update_hdr_mult(uint16_t shaper_in_exp_max, uint32_ enum vpe_status vpe_color_update_shaper( uint16_t shaper_in_exp_max, struct transfer_func *shaper_func, bool enable_3dlut); -enum vpe_status vpe_color_update_blnd_gam(struct vpe_priv *vpe_priv, - const struct vpe_build_param *param, const struct vpe_tonemap_params *tm_params, - struct transfer_func *blnd_tf_func, bool enable_3dlut); - enum vpe_status vpe_color_build_tm_cs(const struct vpe_tonemap_params *tm_params, struct vpe_surface_info surface_info, struct vpe_color_space *vcs); diff --git a/src/amd/vpelib/src/core/inc/color_bg.h b/src/amd/vpelib/src/core/inc/color_bg.h index 8821e9e6948..fbc47695a35 100644 --- a/src/amd/vpelib/src/core/inc/color_bg.h +++ b/src/amd/vpelib/src/core/inc/color_bg.h @@ -30,4 +30,7 @@ void vpe_bg_color_convert( enum color_space cs, struct transfer_func *output_tf, struct vpe_color *bg_color); enum vpe_status vpe_bg_color_outside_cs_gamut( - const struct vpe_color_space *vcs, struct vpe_color *bg_color); + const struct vpe_priv *vpe_priv, struct vpe_color *bg_color); + +enum vpe_status vpe_is_valid_bg_color(const struct vpe_priv *vpe_priv, struct vpe_color *bg_color); + diff --git a/src/amd/vpelib/src/core/inc/color_gamma.h b/src/amd/vpelib/src/core/inc/color_gamma.h index a870697947f..02c42e36eaa 100644 --- a/src/amd/vpelib/src/core/inc/color_gamma.h +++ b/src/amd/vpelib/src/core/inc/color_gamma.h @@ -51,11 +51,12 @@ void vpe_color_setup_x_points_distribution(void); void vpe_color_setup_x_points_distribution_degamma(void); -bool vpe_color_calculate_regamma_params(struct vpe_priv *vpe_priv, struct transfer_func *output_tf, - struct calculate_buffer *cal_buffer); +bool vpe_color_calculate_regamma_params(struct vpe_priv *vpe_priv, struct fixed31_32 x_scale, + struct fixed31_32 y_scale, struct fixed31_32 y_bias, + struct calculate_buffer *cal_buffer, struct transfer_func* output_tf); bool vpe_color_calculate_degamma_params(struct vpe_priv *vpe_priv, struct fixed31_32 x_scale, - struct fixed31_32 y_scale, struct transfer_func *input_tf); + struct fixed31_32 y_scale, struct fixed31_32 y_bias, struct transfer_func *input_tf); void vpe_compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y); diff --git a/src/amd/vpelib/src/core/inc/hw_shared.h b/src/amd/vpelib/src/core/inc/hw_shared.h index 43e477fb367..464358dd7ec 100644 --- a/src/amd/vpelib/src/core/inc/hw_shared.h +++ b/src/amd/vpelib/src/core/inc/hw_shared.h @@ -30,11 +30,6 @@ extern "C" { #endif -enum cm_type { - CM_DEGAM, - CM_REGAM, -}; - struct bias_and_scale { uint32_t scale_red; uint32_t bias_red; diff --git a/src/amd/vpelib/src/core/inc/mpc.h b/src/amd/vpelib/src/core/inc/mpc.h index 7ac9fac4e56..3a4162cbbf1 100644 --- a/src/amd/vpelib/src/core/inc/mpc.h +++ b/src/amd/vpelib/src/core/inc/mpc.h @@ -143,7 +143,7 @@ struct mpc_funcs { bool use_tetrahedral_9, bool use_12bits); // Blend-gamma control. - void (*program_1dlut)(struct mpc *mpc, const struct pwl_params *params); + void (*program_1dlut)(struct mpc *mpc, const struct pwl_params *params, enum cm_type gamma_type); void (*program_cm_location)(struct mpc *mpc, uint8_t location); diff --git a/src/amd/vpelib/src/core/vpelib.c b/src/amd/vpelib/src/core/vpelib.c index 06cd5af9aab..224d4c1abd2 100644 --- a/src/amd/vpelib/src/core/vpelib.c +++ b/src/amd/vpelib/src/core/vpelib.c @@ -343,7 +343,7 @@ enum vpe_status vpe_check_support( vpe_cache_tone_map_params(&vpe_priv->stream_ctx[i], param); } - if (status == VPE_STATUS_OK) { + if (status == VPE_STATUS_OK) { // output checking - check per asic support status = vpe_check_output_support(vpe, param); if (status != VPE_STATUS_OK) { @@ -430,7 +430,7 @@ enum vpe_status vpe_check_support( // if the bg_color support is false, there is a flag to verify if the bg_color falls in the // output gamut if (!vpe_priv->pub.caps->bg_color_check_support) { - status = vpe_bg_color_outside_cs_gamut(&output_ctx->surface.cs, &output_ctx->bg_color); + status = vpe_is_valid_bg_color(vpe_priv, &output_ctx->bg_color); if (status != VPE_STATUS_OK) { vpe_log( "failed in checking the background color versus the output color space %d\n", @@ -504,28 +504,6 @@ static bool validate_cached_param(struct vpe_priv *vpe_priv, const struct vpe_bu return true; } -static bool validate_color_pipeline(struct vpe_priv *vpe_priv, const struct vpe_build_param *param) -{ - uint32_t stream_idx; - struct stream_ctx *stream_ctx; - struct output_ctx *output_ctx; - - output_ctx = &vpe_priv->output_ctx; - - /* For BG color, we need to make sure degamm / regamm is not bypass, - * as we want to have input in the range of 0-1 in mpc, - * since mpc only allows 0-1 range for BG color - */ - for (stream_idx = 0; stream_idx < param->num_streams; stream_idx++) { - stream_ctx = &vpe_priv->stream_ctx[stream_idx]; - if (output_ctx->output_tf->type == TF_TYPE_BYPASS && - stream_ctx->input_tf->type == TF_TYPE_BYPASS) - return false; - } - - return true; -} - enum vpe_status vpe_build_commands( struct vpe *vpe, const struct vpe_build_param *param, struct vpe_build_bufs *bufs) { @@ -622,9 +600,7 @@ enum vpe_status vpe_build_commands( vpe_log("failed updating whitepoint gain %d\n", (int)status); } } - if (status == VPE_STATUS_OK) { - VPE_ASSERT(validate_color_pipeline(vpe_priv, param)); - } + if (status == VPE_STATUS_OK) { vpe_bg_color_convert(vpe_priv->output_ctx.cs, vpe_priv->output_ctx.output_tf, &vpe_priv->output_ctx.bg_color);