amd/vpelib: Studio Range Handling

The purpose of this change is to support bg color fill + studio range
output. Now, studio range conversion will be done in the gamma block
before bg color fill. That is for all studio range outputs adn SDR
outputs we will be in NL before blend block.  For full range HDR (full
range PQ of FP16 only), we will be linear before blend block.

- Added linear_0_1 gamma function
- Consolidated x_scale and y_scale
- Refactor Regam/Degam Funcs
- Add y bias to regam and degam
- Pull memory allocation for cm into a different function to make it
  more readable
- Added logic to degamma/regamma to re-calculate instead of using table
  if the scale factors are not one and the bias is not zero.
- Changing output gamma programming sequence in sw layer
- Fixes in hw layer for interpolation error assocaites with studio
  range transformation in gamma.
- Disabling ocsc
- PQ studio will still be 'blended' in NL. But A check was added
  to reject the job if it is not opaque

Reviewed-by: Roy Chan <Roy.Chan@amd.com>
Acked-by: Alan Liu <haoping.liu@amd.com>
Signed-off-by: Jesse Agate <Jesse.Agate@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26841>
This commit is contained in:
Agate, Jesse
2023-11-07 11:36:42 -05:00
committed by Marge Bot
parent e18761001e
commit 73713f837b
14 changed files with 597 additions and 358 deletions
@@ -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);
@@ -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,
+47 -21
View File
@@ -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,
+2 -11
View File
@@ -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);
@@ -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
+274 -163
View File
@@ -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, &params, 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, &params, 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, &param->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, &param->dst_surface.cs);
color_check_input_cm_update(vpe_priv, stream_ctx,
&param->streams[stream_idx].surface_info.cs, &param->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,
&param->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,
&param->streams[stream_idx].surface_info.cs, &param->streams[stream_idx].color_adj,
param->streams[stream_idx].tm_params.enable_3dlut);
build_scale_and_bias(stream_ctx->bias_scale,
&param->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,
&param->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);
+56 -13
View File
@@ -1,6 +1,7 @@
#include <string.h>
#include <math.h>
#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, &degam_r, true);
compute_degam(output_tf->tf, (double)bg_color->rgba.g, &degam_g, true);
compute_degam(output_tf->tf, (double)bg_color->rgba.b, &degam_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, &degam_r, true);
compute_depq((double)bg_color->rgba.g, &degam_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;
}
+138 -102
View File
@@ -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);
+23 -9
View File
@@ -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);
+4 -1
View File
@@ -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);
+4 -3
View File
@@ -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);
-5
View File
@@ -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;
+1 -1
View File
@@ -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);
+3 -27
View File
@@ -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);