From e64b5b24dfef1741ee168ef7ed2a7a2c4158e82b Mon Sep 17 00:00:00 2001 From: "Assadian, Navid" Date: Tue, 12 May 2026 16:56:32 -0400 Subject: [PATCH] amd/vpelib: FP16 non linear handling [WHY] FP16 with non-linear gamma is not a regular format. But to support multi-pass with FP16 intermediate format, the support needs to be added. Acked-by: Peyton Lee Signed-off-by: Navid Assadian Part-of: --- .../vpelib/src/chip/vpe20/vpe20_resource.c | 19 ++++--- src/amd/vpelib/src/core/color.c | 53 +++++++++++-------- 2 files changed, 42 insertions(+), 30 deletions(-) diff --git a/src/amd/vpelib/src/chip/vpe20/vpe20_resource.c b/src/amd/vpelib/src/chip/vpe20/vpe20_resource.c index 55a98ebbec4..87491b1b83a 100644 --- a/src/amd/vpelib/src/chip/vpe20/vpe20_resource.c +++ b/src/amd/vpelib/src/chip/vpe20/vpe20_resource.c @@ -2296,9 +2296,6 @@ bool vpe20_check_output_color_space( if (cs == COLOR_SPACE_UNKNOWN || tf == TRANSFER_FUNC_UNKNOWN) return false; - if (vpe_is_fp16(format) && tf != TRANSFER_FUNC_LINEAR) - return false; - if ((cs == COLOR_SPACE_CUSTOM) || (tf == TRANSFER_FUNC_CUSTOM)) return false; @@ -2765,6 +2762,12 @@ enum vpe_status vpe20_update_blnd_gamma(struct vpe_priv *vpe_priv, if (lut3d_enabled) { vpe_color_build_tm_cs(tm_params, ¶m->dst_surface, &tm_out_cs); vpe_color_get_color_space_and_tf(&tm_out_cs, &cs, &tf); + + // For HLG final output, use Linear TF to apply scaling without additional curve + if (output_ctx->tf == TRANSFER_FUNC_HLG) { + tf = TRANSFER_FUNC_LINEAR; + } + } else { can_bypass = true; } @@ -2802,14 +2805,14 @@ enum vpe_status vpe20_update_output_gamma(struct vpe_priv *vpe_priv, enum vpe_status status = VPE_STATUS_OK; struct fixed31_32 y_scale = vpe_fixpt_one; - if (vpe_is_fp16(param->dst_surface.format)) { - y_scale = vpe_fixpt_mul_int(y_scale, CCCS_NORM); + if ((vpe_is_fp16(param->dst_surface.format) == true) && + (param->dst_surface.cs.tf == VPE_TF_G10)) { + y_scale = vpe_fixpt_mul_int(vpe_fixpt_one, CCCS_NORM); } - if (!geometric_scaling && vpe_is_HDR(output_ctx->tf)) - can_bypass = false; - else + if ((geometric_scaling == true) || (vpe_is_HDR(output_ctx->tf) == false)) { can_bypass = true; + } vpe_color_update_regamma_tf( vpe_priv, output_ctx->tf, vpe_fixpt_one, y_scale, vpe_fixpt_zero, can_bypass, output_tf); diff --git a/src/amd/vpelib/src/core/color.c b/src/amd/vpelib/src/core/color.c index b37579bcbf3..fcba4099ff0 100644 --- a/src/amd/vpelib/src/core/color.c +++ b/src/amd/vpelib/src/core/color.c @@ -279,17 +279,25 @@ static bool color_update_input_cs(struct vpe_priv *vpe_priv, enum color_space in static bool can_bypass_degamma(const struct stream_ctx *stream_ctx) { - if (vpe_is_fp16(stream_ctx->stream.surface_info.format)) - return true; - if ((stream_ctx->stream.tm_params.UID != 0) || (stream_ctx->stream.tm_params.enable_3dlut)) - return true; - if (stream_ctx->geometric_scaling) - return true; + bool can_bypass = false; + // Linear FP16 + if ((vpe_is_fp16(stream_ctx->stream.surface_info.format) == true) && + (stream_ctx->stream.surface_info.cs.tf == VPE_TF_G10)) { + can_bypass = true; + } + // 3D LUT + if ((stream_ctx->stream.tm_params.UID != 0) || (stream_ctx->stream.tm_params.enable_3dlut)) { + can_bypass = true; + } + // First and intermediate passes of multi-pass VPE + if (stream_ctx->geometric_scaling) { + can_bypass = true; + } if (stream_ctx->stream.surface_info.format == VPE_SURFACE_PIXEL_FORMAT_GRPH_RGBE) { - return true; + can_bypass = true; } - return false; + return can_bypass; } bool vpe_use_csc_adjust(const struct vpe_color_adjust *adjustments) @@ -1249,25 +1257,28 @@ enum vpe_status vpe_color_update_whitepoint( const struct vpe_priv *vpe_priv, const struct vpe_build_param *param) { - struct stream_ctx *stream = vpe_priv->stream_ctx; - const struct output_ctx *output_ctx = &vpe_priv->output_ctx; - const struct vpe_color_space *vpe_cs = &stream->stream.surface_info.cs; - bool output_isHDR = vpe_is_HDR(vpe_priv->output_ctx.tf); - bool input_isHDR = false; - bool is_yCbCr = false; - bool is_g24 = false; - bool is_fp16 = false; + struct stream_ctx *stream = vpe_priv->stream_ctx; + const struct output_ctx *output_ctx = &vpe_priv->output_ctx; + bool output_isHDR = vpe_is_HDR(vpe_priv->output_ctx.tf); + bool input_isHDR = false; + bool is_yCbCr = false; + bool is_g24 = false; + bool is_fp16_linear = false; bool is_compound = stream->stream.lut_compound.enabled; for (unsigned int stream_index = 0; stream_index < vpe_priv->num_streams; stream_index++) { input_isHDR = vpe_is_HDR(stream->tf); is_yCbCr = stream->is_yuv_input; - is_g24 = (vpe_cs->tf == VPE_TF_G24); - is_fp16 = vpe_is_fp16(stream->stream.surface_info.format); + is_g24 = (stream->stream.surface_info.cs.tf == VPE_TF_G24); + // Only FP16 G10 input has data in [0, CCCS_NORM] range + is_fp16_linear = (vpe_is_fp16(stream->stream.surface_info.format) && + (stream->stream.surface_info.cs.tf == VPE_TF_G10)); + if (is_compound) { stream->white_point_gain = vpe_fixpt_one; } else if (!input_isHDR && output_isHDR) { + int sdrWhiteLevel = (is_yCbCr || is_g24) ? SDR_VIDEO_WHITE_POINT : SDR_WHITE_POINT; stream->white_point_gain = vpe_fixpt_from_fraction(sdrWhiteLevel, 10000); } else if (input_isHDR && !output_isHDR) { @@ -1280,10 +1291,8 @@ enum vpe_status vpe_color_update_whitepoint( stream->white_point_gain = vpe_fixpt_one; } - if (is_fp16) { - stream->white_point_gain = vpe_fixpt_div_int(stream->white_point_gain, CCCS_NORM); - } - if (stream->stream.surface_info.format == VPE_SURFACE_PIXEL_FORMAT_GRPH_RGBE) { + if ((is_fp16_linear == true) || + (stream->stream.surface_info.format == VPE_SURFACE_PIXEL_FORMAT_GRPH_RGBE)) { stream->white_point_gain = vpe_fixpt_div_int(stream->white_point_gain, CCCS_NORM); }