amd/vpelib: Fix CS translation for geometric downscaling

Geometric downscaling uses RGB10 as the intermediate format. The support for P601 and JFIF with RGB formats is added.

Co-authored-by: Roy Chan <roy.chan@amd.com>
Reviewed-by: Roy Chan <Roy.Chan@amd.com>
Acked-by: Jack Chih <chiachih@amd.com>
Signed-off-by: Navid Assadian <navid.assadian@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30531>
This commit is contained in:
Assadian, Navid 2024-04-16 17:56:18 -04:00 committed by Marge Bot
parent 699f88f844
commit e1ef91ac2a
8 changed files with 139 additions and 115 deletions

View file

@ -34,13 +34,14 @@
#include "color_test_values.h"
#include "3dlut_builder.h"
#include "shaper_builder.h"
#include "geometric_scaling.h"
static void color_check_input_cm_update(struct vpe_priv *vpe_priv, struct stream_ctx *stream_ctx,
const struct vpe_color_space *vcs, const struct vpe_color_adjust *adjustments,
bool enable_3dlut);
bool enable_3dlut, bool geometric_update);
static void color_check_output_cm_update(
struct vpe_priv *vpe_priv, const struct vpe_color_space *vcs);
struct vpe_priv *vpe_priv, const struct vpe_color_space *vcs, bool geometric_update);
static bool color_update_regamma_tf(struct vpe_priv *vpe_priv,
enum color_transfer_func output_transfer_function, struct fixed31_32 x_scale,
@ -83,7 +84,7 @@ static bool is_ycbcr(enum color_space in_cs)
}
static void color_check_output_cm_update(
struct vpe_priv *vpe_priv, const struct vpe_color_space *vcs)
struct vpe_priv *vpe_priv, const struct vpe_color_space *vcs, bool geometric_update)
{
enum color_space cs;
enum color_transfer_func tf;
@ -93,14 +94,14 @@ static void color_check_output_cm_update(
if (cs == COLOR_SPACE_UNKNOWN || tf == TRANSFER_FUNC_UNKNOWN)
VPE_ASSERT(0);
if (cs != vpe_priv->output_ctx.cs) {
if (cs != vpe_priv->output_ctx.cs || geometric_update) {
vpe_priv->output_ctx.dirty_bits.color_space = 1;
vpe_priv->output_ctx.cs = cs;
} else {
vpe_priv->output_ctx.dirty_bits.color_space = 0;
}
if (tf != vpe_priv->output_ctx.tf) {
if (tf != vpe_priv->output_ctx.tf || geometric_update) {
vpe_priv->output_ctx.dirty_bits.transfer_function = 1;
vpe_priv->output_ctx.tf = tf;
} else {
@ -110,7 +111,7 @@ static void color_check_output_cm_update(
static void color_check_input_cm_update(struct vpe_priv *vpe_priv, struct stream_ctx *stream_ctx,
const struct vpe_color_space *vcs, const struct vpe_color_adjust *adjustments,
bool enable_3dlut)
bool enable_3dlut, bool geometric_update)
{
enum color_space cs;
enum color_transfer_func tf;
@ -125,7 +126,7 @@ static void color_check_input_cm_update(struct vpe_priv *vpe_priv, struct stream
if (cs == COLOR_SPACE_UNKNOWN && tf == TRANSFER_FUNC_UNKNOWN)
VPE_ASSERT(0);
if (cs != stream_ctx->cs || enable_3dlut != stream_ctx->enable_3dlut) {
if (cs != stream_ctx->cs || enable_3dlut != stream_ctx->enable_3dlut || geometric_update) {
stream_ctx->dirty_bits.color_space = 1;
stream_ctx->cs = cs;
} else {
@ -139,7 +140,7 @@ static void color_check_input_cm_update(struct vpe_priv *vpe_priv, struct stream
}
// if the new transfer function is different than the old one or the scaling factor is not one
// any new stream will start with a transfer function which is not scaled
if (tf != stream_ctx->tf || enable_3dlut != stream_ctx->enable_3dlut) {
if (tf != stream_ctx->tf || enable_3dlut != stream_ctx->enable_3dlut || geometric_update) {
stream_ctx->dirty_bits.transfer_function = 1;
stream_ctx->tf = tf;
} else {
@ -295,8 +296,11 @@ static enum color_space color_get_icsc_cs(enum color_space ics)
case COLOR_SPACE_MSREF_SCRGB:
case COLOR_SPACE_2020_RGB_FULLRANGE:
case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
case COLOR_SPACE_RGB601:
case COLOR_SPACE_RGB601_LIMITED:
case COLOR_SPACE_RGB_JFIF:
return COLOR_SPACE_SRGB;
case COLOR_SPACE_JFIF:
case COLOR_SPACE_YCBCR_JFIF:
case COLOR_SPACE_YCBCR601:
case COLOR_SPACE_YCBCR601_LIMITED:
return COLOR_SPACE_YCBCR601;
@ -371,15 +375,12 @@ static bool color_update_input_cs(struct vpe_priv *vpe_priv, enum color_space in
OGAM : L -> NL
*/
static enum vpe_status vpe_update_blnd_gamma(
struct vpe_priv *vpe_priv,
const struct vpe_build_param *param,
const struct vpe_tonemap_params *tm_params,
struct transfer_func *blnd_tf)
static enum vpe_status vpe_update_blnd_gamma(struct vpe_priv *vpe_priv,
const struct vpe_build_param *param, const struct vpe_stream *stream,
struct transfer_func *blnd_tf)
{
struct output_ctx *output_ctx;
struct output_ctx *output_ctx;
struct vpe_color_space tm_out_cs;
struct fixed31_32 x_scale = vpe_fixpt_one;
struct fixed31_32 y_scale = vpe_fixpt_one;
@ -390,62 +391,50 @@ static enum vpe_status vpe_update_blnd_gamma(
enum color_space cs = COLOR_SPACE_2020_RGB_FULLRANGE;
enum color_transfer_func tf = TRANSFER_FUNC_LINEAR;
enum vpe_status status = VPE_STATUS_OK;
const struct vpe_tonemap_params *tm_params = &stream->tm_params;
is_studio = (param->dst_surface.cs.range == VPE_COLOR_RANGE_STUDIO);
output_ctx = &vpe_priv->output_ctx;
lut3d_enabled = tm_params->UID != 0 || tm_params->enable_3dlut;
if (is_studio) {
if (stream->flags.geometric_scaling) {
color_update_degamma_tf(vpe_priv, tf, x_scale, y_scale, y_bias, true, blnd_tf);
} else {
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;
}
}
//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;
}
else {
tf = output_ctx->tf;
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;
}
}
if (vpe_is_fp16(param->dst_surface.format)) {
y_scale = vpe_fixpt_mul_int(y_scale, CCCS_NORM);
}
color_update_regamma_tf(vpe_priv,
tf,
x_scale,
y_scale,
y_bias,
can_bypass,
blnd_tf);
}
else {
// 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;
} else {
tf = output_ctx->tf;
}
if (lut3d_enabled) {
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);
}
else {
can_bypass = true;
}
if (vpe_is_fp16(param->dst_surface.format)) {
y_scale = vpe_fixpt_mul_int(y_scale, CCCS_NORM);
}
color_update_regamma_tf(vpe_priv, tf, x_scale, y_scale, y_bias, can_bypass, blnd_tf);
} else {
color_update_degamma_tf(vpe_priv,
tf,
x_scale,
y_scale,
y_bias,
can_bypass,
blnd_tf);
if (lut3d_enabled) {
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);
} else {
can_bypass = true;
}
color_update_degamma_tf(vpe_priv, tf, x_scale, y_scale, y_bias, can_bypass, blnd_tf);
}
}
return status;
}
@ -472,10 +461,8 @@ static enum vpe_status vpe_update_blnd_gamma(
OGAM : L -> NL
*/
static enum vpe_status vpe_update_output_gamma(
struct vpe_priv *vpe_priv,
const struct vpe_build_param *param,
struct transfer_func *output_tf)
static enum vpe_status vpe_update_output_gamma(struct vpe_priv *vpe_priv,
const struct vpe_build_param *param, struct transfer_func *output_tf, bool geometric_scaling)
{
bool can_bypass = false;
struct output_ctx *output_ctx = &vpe_priv->output_ctx;
@ -487,7 +474,7 @@ static enum vpe_status vpe_update_output_gamma(
y_scale = vpe_fixpt_mul_int(y_scale, CCCS_NORM);
}
if (vpe_is_HDR(output_ctx->tf) && !is_studio)
if (!geometric_scaling && 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;
@ -643,24 +630,28 @@ enum vpe_status vpe_color_update_color_space_and_tf(
struct fixed31_32 new_matrix_scaling_factor;
struct output_ctx *output_ctx = &vpe_priv->output_ctx;
enum vpe_status status = VPE_STATUS_OK;
struct fixed31_32 y_scale = vpe_fixpt_one;
struct fixed31_32 y_scale = vpe_fixpt_one;
bool geometric_update = false;
bool geometric_scaling = false;
status = vpe_allocate_cm_memory(vpe_priv, param);
if (status == VPE_STATUS_OK) {
color_check_output_cm_update(vpe_priv, &vpe_priv->output_ctx.surface.cs);
vpe_update_geometric_scaling(vpe_priv, param, &geometric_update, &geometric_scaling);
color_check_output_cm_update(vpe_priv, &vpe_priv->output_ctx.surface.cs, geometric_update);
for (stream_idx = 0; stream_idx < param->num_streams; stream_idx++) {
new_matrix_scaling_factor = vpe_fixpt_one;
stream_ctx = &vpe_priv->stream_ctx[stream_idx];
stream_ctx->geometric_scaling = geometric_scaling;
bool is_3dlut_enable =
stream_ctx->stream.tm_params.UID != 0 || stream_ctx->stream.tm_params.enable_3dlut;
bool require_update = stream_ctx->UID_3DLUT != param->streams[stream_idx].tm_params.UID;
color_check_input_cm_update(vpe_priv, stream_ctx,
&param->streams[stream_idx].surface_info.cs, &param->streams[stream_idx].color_adj,
is_3dlut_enable);
is_3dlut_enable, geometric_update);
build_scale_and_bias(stream_ctx->bias_scale,
&param->streams[stream_idx].surface_info.cs,
@ -690,28 +681,27 @@ enum vpe_status vpe_color_update_color_space_and_tf(
color_update_degamma_tf(vpe_priv, stream_ctx->tf,
vpe_priv->stream_ctx->tf_scaling_factor, y_scale, vpe_fixpt_zero,
is_3dlut_enable, // By Pass degamma if 3DLUT is enabled
is_3dlut_enable || geometric_scaling, // 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, is_3dlut_enable);
stream_ctx->gamut_remap, is_3dlut_enable || geometric_scaling);
}
if (output_ctx->dirty_bits.transfer_function || output_ctx->dirty_bits.color_space ||
require_update) {
vpe_update_blnd_gamma(vpe_priv, param, &stream_ctx->stream.tm_params, stream_ctx->blend_tf);
vpe_update_blnd_gamma(vpe_priv, param, &stream_ctx->stream, stream_ctx->blend_tf);
}
}
if (status == VPE_STATUS_OK) {
if (output_ctx->dirty_bits.transfer_function ||
output_ctx->dirty_bits.color_space) {
vpe_update_output_gamma(vpe_priv, param, output_ctx->output_tf);
vpe_update_output_gamma(vpe_priv, param, output_ctx->output_tf, geometric_scaling);
}
}
}
return status;
}
@ -897,7 +887,7 @@ void vpe_color_get_color_space_and_tf(
: COLOR_SPACE_2020_YCBCR_LIMITED;
break;
case VPE_PRIMARIES_JFIF:
*cs = colorRange == VPE_COLOR_RANGE_FULL ? COLOR_SPACE_JFIF : COLOR_SPACE_UNKNOWN;
*cs = colorRange == VPE_COLOR_RANGE_FULL ? COLOR_SPACE_YCBCR_JFIF : COLOR_SPACE_UNKNOWN;
break;
default:
break;
@ -905,8 +895,8 @@ void vpe_color_get_color_space_and_tf(
} else {
switch (vcs->primaries) {
case VPE_PRIMARIES_BT601:
*cs = colorRange == VPE_COLOR_RANGE_FULL ? COLOR_SPACE_YCBCR601
: COLOR_SPACE_YCBCR601_LIMITED;
*cs = colorRange == VPE_COLOR_RANGE_FULL ? COLOR_SPACE_RGB601
: COLOR_SPACE_RGB601_LIMITED;
break;
case VPE_PRIMARIES_BT709:
if (vcs->tf == VPE_TF_G10) {
@ -925,7 +915,7 @@ void vpe_color_get_color_space_and_tf(
* color check fail.
*/
case VPE_PRIMARIES_JFIF:
*cs = colorRange == VPE_COLOR_RANGE_FULL ? COLOR_SPACE_JFIF : COLOR_SPACE_UNKNOWN;
*cs = colorRange == VPE_COLOR_RANGE_FULL ? COLOR_SPACE_RGB_JFIF : COLOR_SPACE_UNKNOWN;
break;
default:
break;
@ -954,6 +944,9 @@ void vpe_convert_full_range_color_enum(enum color_space *cs)
case COLOR_SPACE_YCBCR601_LIMITED:
*cs = COLOR_SPACE_YCBCR601;
break;
case COLOR_SPACE_RGB601_LIMITED:
*cs = COLOR_SPACE_RGB601;
break;
case COLOR_SPACE_YCBCR709_LIMITED:
*cs = COLOR_SPACE_YCBCR709;
break;

View file

@ -158,7 +158,8 @@ static void set_gamut_remap_matrix(double* res, enum color_space src_cs, enum co
case COLOR_SPACE_MSREF_SCRGB:
case COLOR_SPACE_YCBCR709_LIMITED:
case COLOR_SPACE_YCBCR709:
case COLOR_SPACE_JFIF:
case COLOR_SPACE_YCBCR_JFIF:
case COLOR_SPACE_RGB_JFIF:
memcpy(rgb_to_xyz, bt_709_rgb_xyz_matrix, 9 * sizeof(double));
break;
case COLOR_SPACE_YCBCR601:
@ -183,7 +184,8 @@ static void set_gamut_remap_matrix(double* res, enum color_space src_cs, enum co
case COLOR_SPACE_MSREF_SCRGB:
case COLOR_SPACE_YCBCR709_LIMITED:
case COLOR_SPACE_YCBCR709:
case COLOR_SPACE_JFIF:
case COLOR_SPACE_YCBCR_JFIF:
case COLOR_SPACE_RGB_JFIF:
memcpy(xyz_to_rgb, bt_709_xyz_rgb_matrix, 9 * sizeof(double));
break;
case COLOR_SPACE_YCBCR601:
@ -405,7 +407,8 @@ static bool is_limited_cs(enum color_space cs)
case COLOR_SPACE_MSREF_SCRGB:
case COLOR_SPACE_YCBCR601:
case COLOR_SPACE_YCBCR709:
case COLOR_SPACE_JFIF:
case COLOR_SPACE_YCBCR_JFIF:
case COLOR_SPACE_RGB_JFIF:
case COLOR_SPACE_2020_YCBCR:
is_limited = false;
break;
@ -513,6 +516,7 @@ static void inverse_output_csc(enum color_space output_cs, struct vpe_color* bg_
// output is RGB cs, follow output's range
// but need yuv to rgb csc
case COLOR_SPACE_SRGB_LIMITED:
case COLOR_SPACE_RGB601_LIMITED:
bgcolor_cs = COLOR_SPACE_YCBCR709_LIMITED;
break;
case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
@ -520,6 +524,7 @@ static void inverse_output_csc(enum color_space output_cs, struct vpe_color* bg_
break;
case COLOR_SPACE_SRGB:
case COLOR_SPACE_MSREF_SCRGB:
case COLOR_SPACE_RGB601:
bgcolor_cs = COLOR_SPACE_YCBCR709;
break;
case COLOR_SPACE_2020_RGB_FULLRANGE:

View file

@ -133,12 +133,15 @@ static enum predefined_gamut_type color_space_to_predefined_gamut_types(
enum color_space color_space)
{
switch (color_space) {
case COLOR_SPACE_JFIF:
case COLOR_SPACE_YCBCR_JFIF:
case COLOR_SPACE_RGB_JFIF:
case COLOR_SPACE_YCBCR709:
case COLOR_SPACE_YCBCR709_LIMITED:
return gamut_type_bt709;
case COLOR_SPACE_YCBCR601:
case COLOR_SPACE_YCBCR601_LIMITED:
case COLOR_SPACE_RGB601:
case COLOR_SPACE_RGB601_LIMITED:
return gamut_type_bt601;
case COLOR_SPACE_SRGB:
case COLOR_SPACE_SRGB_LIMITED:

View file

@ -35,12 +35,14 @@
*
*/
void geometric_scaling_feature_skip(struct vpe_priv *vpe_priv, const struct vpe_build_param *param)
void vpe_geometric_scaling_feature_skip(
struct vpe_priv *vpe_priv, const struct vpe_build_param *param)
{
/* copy input cs to output for skiping gamut and gamma conversion */
vpe_priv->output_ctx.surface.cs.primaries = param->streams[0].surface_info.cs.primaries;
vpe_priv->output_ctx.surface.cs.range = param->streams[0].surface_info.cs.range;
vpe_priv->output_ctx.surface.cs.tf = param->streams[0].surface_info.cs.tf;
vpe_priv->output_ctx.surface.cs.cositing = VPE_CHROMA_COSITING_NONE;
vpe_priv->output_ctx.surface.cs.range = VPE_COLOR_RANGE_FULL;
/* skip tone mapping */
vpe_priv->stream_ctx[0].stream.tm_params.UID = 0;
@ -50,3 +52,40 @@ void geometric_scaling_feature_skip(struct vpe_priv *vpe_priv, const struct vpe_
vpe_priv->stream_ctx[0].stream.blend_info.blending = false;
}
/*
* Geometric scaling feature has two requirement when enabled:
* 1. only support single input stream, no blending support.
* 2. the target rect must equal to destination rect.
*/
enum vpe_status vpe_validate_geometric_scaling_support(const struct vpe_build_param *param)
{
if (param->streams[0].flags.geometric_scaling) {
/* only support 1 stream */
if (param->num_streams > 1) {
return VPE_STATUS_GEOMETRICSCALING_ERROR;
}
/* dest rect must equal to target rect */
if (param->target_rect.height != param->streams[0].scaling_info.dst_rect.height ||
param->target_rect.width != param->streams[0].scaling_info.dst_rect.width ||
param->target_rect.x != param->streams[0].scaling_info.dst_rect.x ||
param->target_rect.y != param->streams[0].scaling_info.dst_rect.y)
return VPE_STATUS_GEOMETRICSCALING_ERROR;
}
return VPE_STATUS_OK;
}
void vpe_update_geometric_scaling(struct vpe_priv *vpe_priv, const struct vpe_build_param *param,
bool *geometric_update, bool *geometric_scaling)
{
if (param->num_streams == 1) {
if ((bool)vpe_priv->stream_ctx[0].stream.flags.geometric_scaling !=
vpe_priv->stream_ctx[0].geometric_scaling) {
*geometric_update = true;
}
*geometric_scaling = (bool)vpe_priv->stream_ctx[0].stream.flags.geometric_scaling;
}
}

View file

@ -103,8 +103,11 @@ enum color_space {
COLOR_SPACE_SRGB_LIMITED,
COLOR_SPACE_MSREF_SCRGB,
COLOR_SPACE_YCBCR601,
COLOR_SPACE_RGB601,
COLOR_SPACE_RGB601_LIMITED,
COLOR_SPACE_YCBCR709,
COLOR_SPACE_JFIF,
COLOR_SPACE_YCBCR_JFIF,
COLOR_SPACE_RGB_JFIF,
COLOR_SPACE_YCBCR601_LIMITED,
COLOR_SPACE_YCBCR709_LIMITED,
COLOR_SPACE_2020_RGB_FULLRANGE,

View file

@ -30,7 +30,12 @@
#include "vpe_types.h"
#include "common.h"
// In order to support geometric down scaling, we will skip gamut and gamma conversion in this
// function.
void geometric_scaling_feature_skip(struct vpe_priv *vpe_priv, const struct vpe_build_param *param);
void vpe_geometric_scaling_feature_skip(
struct vpe_priv *vpe_priv, const struct vpe_build_param *param);
enum vpe_status vpe_validate_geometric_scaling_support(const struct vpe_build_param *param);
void vpe_update_geometric_scaling(struct vpe_priv *vpe_priv, const struct vpe_build_param *param,
bool *geometric_update, bool *geometric_scaling);

View file

@ -129,6 +129,7 @@ struct stream_ctx {
enum color_space cs;
bool enable_3dlut;
uint64_t UID_3DLUT; // UID for current 3D LUT params
bool geometric_scaling;
union {
struct {

View file

@ -203,31 +203,6 @@ void vpe_destroy(struct vpe **vpe)
*vpe = NULL;
}
/*
* Geometric scaling feature has two requirement when enabled:
* 1. only support single input stream, no blending support.
* 2. the target rect must equal to destination rect.
*/
static enum vpe_status validate_geometric_scaling_support(const struct vpe_build_param *param)
{
if (param->streams[0].flags.geometric_scaling)
{
/* only support 1 stream */
if (param->num_streams > 1)
{
return VPE_STATUS_GEOMETRICSCALING_ERROR;
}
/* dest rect must equal to target rect */
if (param->target_rect.height != param->streams[0].scaling_info.dst_rect.height ||
param->target_rect.width != param->streams[0].scaling_info.dst_rect.width ||
param->target_rect.x != param->streams[0].scaling_info.dst_rect.x ||
param->target_rect.y != param->streams[0].scaling_info.dst_rect.y)
return VPE_STATUS_GEOMETRICSCALING_ERROR;
}
return VPE_STATUS_OK;
}
/*****************************************************************************************
* handle_zero_input
@ -496,7 +471,7 @@ enum vpe_status vpe_check_support(
}
if (status == VPE_STATUS_OK) {
status = validate_geometric_scaling_support(param);
status = vpe_validate_geometric_scaling_support(param);
}
if (vpe_priv->init.debug.assert_when_not_support)
@ -605,7 +580,7 @@ enum vpe_status vpe_build_commands(
if (status == VPE_STATUS_OK) {
if (param->streams->flags.geometric_scaling) {
geometric_scaling_feature_skip(vpe_priv, param);
vpe_geometric_scaling_feature_skip(vpe_priv, param);
}
if (bufs->cmd_buf.size == 0 || bufs->emb_buf.size == 0) {