drm/amd/display: Add more color KUnit tests

[Why & How]
Add KUnit tests for __set_tf_bypass(), __set_tf_distributed_points(),
the bypass paths of amdgpu_dm_set_atomic_regamma(),
amdgpu_dm_atomic_shaper_lut(), and amdgpu_dm_atomic_blend_lut(), and
all three input branches of __set_colorop_in_tf_1d_curve().

Export the three shaper/blend/regamma helpers and
__set_colorop_in_tf_1d_curve with STATIC_IFN_KUNIT and EXPORT_IF_KUNIT
to make their branches reachable from tests.
Add the following test cases in amdgpu_dm_color_test.c:
- dm_test_set_tf_bypass: verify bypass TF setup
- dm_test_set_tf_distributed_points_srgb: validate sRGB gamma
- dm_test_set_tf_distributed_points_pq: validate PQ gamma
- dm_test_set_atomic_regamma_bypass: verify regamma bypass path
- dm_test_atomic_shaper_lut_bypass: verify shaper LUT bypass path
- dm_test_atomic_blend_lut_bypass: verify blend LUT bypass path
- dm_test_set_colorop_in_tf_1d_curve_invalid_type: verify invalid
  colorop type returns -EINVAL
- dm_test_set_colorop_in_tf_1d_curve_unsupported_curve: verify
  unsupported curve type returns -EINVAL
- dm_test_set_colorop_in_tf_1d_curve_bypass: verify bypass path sets
  TF_TYPE_BYPASS and TRANSFER_FUNCTION_LINEAR

Assisted-by: Copilot:Claude-Sonnet-4.6
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Alex Hung 2026-05-14 14:29:52 -06:00 committed by Alex Deucher
parent d63cc4ca21
commit b640830f1a
3 changed files with 260 additions and 6 deletions

View File

@ -759,21 +759,23 @@ static int __set_output_tf_32(struct dc_transfer_func *func,
return res ? 0 : -ENOMEM;
}
static void __set_tf_bypass(struct dc_transfer_func *tf)
STATIC_IFN_KUNIT void __set_tf_bypass(struct dc_transfer_func *tf)
{
tf->type = TF_TYPE_BYPASS;
tf->tf = TRANSFER_FUNCTION_LINEAR;
}
EXPORT_IF_KUNIT(__set_tf_bypass);
static void __set_tf_distributed_points(struct dc_transfer_func *tf,
STATIC_IFN_KUNIT void __set_tf_distributed_points(struct dc_transfer_func *tf,
enum dc_transfer_func_predefined predefined_tf)
{
tf->type = TF_TYPE_DISTRIBUTED_POINTS;
tf->tf = predefined_tf;
tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
}
EXPORT_IF_KUNIT(__set_tf_distributed_points);
static int amdgpu_dm_set_atomic_regamma(struct dc_transfer_func *out_tf,
STATIC_IFN_KUNIT int amdgpu_dm_set_atomic_regamma(struct dc_transfer_func *out_tf,
const struct drm_color_lut *regamma_lut,
uint32_t regamma_size, bool has_rom,
enum dc_transfer_func_predefined tf)
@ -804,6 +806,7 @@ static int amdgpu_dm_set_atomic_regamma(struct dc_transfer_func *out_tf,
return ret;
}
EXPORT_IF_KUNIT(amdgpu_dm_set_atomic_regamma);
/**
* __set_input_tf - calculates the input transfer function based on expected
@ -1073,7 +1076,7 @@ STATIC_IFN_KUNIT void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut
}
EXPORT_IF_KUNIT(amdgpu_dm_atomic_lut3d);
static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut,
STATIC_IFN_KUNIT int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut,
bool has_rom,
enum dc_transfer_func_predefined tf,
uint32_t shaper_size,
@ -1094,8 +1097,9 @@ static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut,
return ret;
}
EXPORT_IF_KUNIT(amdgpu_dm_atomic_shaper_lut);
static int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut,
STATIC_IFN_KUNIT int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut,
bool has_rom,
enum dc_transfer_func_predefined tf,
uint32_t blend_size,
@ -1119,6 +1123,7 @@ static int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut,
return ret;
}
EXPORT_IF_KUNIT(amdgpu_dm_atomic_blend_lut);
/**
* amdgpu_dm_verify_lut3d_size - verifies if 3D LUT is supported and if user
@ -1496,7 +1501,7 @@ __set_dm_plane_degamma(struct drm_plane_state *plane_state,
return 0;
}
static int
STATIC_IFN_KUNIT int
__set_colorop_in_tf_1d_curve(struct dc_plane_state *dc_plane_state,
struct drm_colorop_state *colorop_state)
{
@ -1522,6 +1527,7 @@ __set_colorop_in_tf_1d_curve(struct dc_plane_state *dc_plane_state,
return 0;
}
EXPORT_IF_KUNIT(__set_colorop_in_tf_1d_curve);
static int
__set_dm_plane_colorop_degamma(struct drm_plane_state *plane_state,

View File

@ -36,11 +36,14 @@ struct drm_color_lut;
struct drm_color_lut32;
struct drm_color_ctm;
struct drm_color_ctm_3x4;
struct drm_colorop_state;
struct drm_property_blob;
struct dc_gamma;
struct dc_rgb;
struct dc_plane_state;
struct fixed31_32;
struct tetrahedral_params;
struct dc_transfer_func;
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
/*
@ -91,6 +94,25 @@ void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut3d,
int __set_colorop_3dlut(const struct drm_color_lut32 *drm_lut3d,
uint32_t drm_lut3d_size,
struct dc_3dlut *lut);
void __set_tf_bypass(struct dc_transfer_func *tf);
void __set_tf_distributed_points(struct dc_transfer_func *tf,
enum dc_transfer_func_predefined predefined_tf);
int amdgpu_dm_set_atomic_regamma(struct dc_transfer_func *out_tf,
const struct drm_color_lut *regamma_lut,
uint32_t regamma_size, bool has_rom,
enum dc_transfer_func_predefined tf);
int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut,
bool has_rom,
enum dc_transfer_func_predefined tf,
uint32_t shaper_size,
struct dc_transfer_func *func_shaper);
int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut,
bool has_rom,
enum dc_transfer_func_predefined tf,
uint32_t blend_size,
struct dc_transfer_func *func_blend);
int __set_colorop_in_tf_1d_curve(struct dc_plane_state *dc_plane_state,
struct drm_colorop_state *colorop_state);
#endif
#endif /* __AMDGPU_DM_COLOR_H__ */

View File

@ -1316,6 +1316,217 @@ static void dm_test_set_colorop_3dlut_data_forwarded(struct kunit *test)
drm_color_lut32_extract(0x40000000, 12));
}
/**
* dm_test_set_tf_bypass - __set_tf_bypass: sets TF_TYPE_BYPASS and TRANSFER_FUNCTION_LINEAR
* @test: KUnit test context
*/
static void dm_test_set_tf_bypass(struct kunit *test)
{
struct dc_transfer_func *tf;
tf = kunit_kzalloc(test, sizeof(*tf), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tf);
tf->type = TF_TYPE_DISTRIBUTED_POINTS;
tf->tf = TRANSFER_FUNCTION_SRGB;
__set_tf_bypass(tf);
KUNIT_EXPECT_EQ(test, (int)tf->type, (int)TF_TYPE_BYPASS);
KUNIT_EXPECT_EQ(test, (int)tf->tf, (int)TRANSFER_FUNCTION_LINEAR);
}
/**
* dm_test_set_tf_distributed_points_srgb - __set_tf_distributed_points: sRGB predefined TF
* @test: KUnit test context
*/
static void dm_test_set_tf_distributed_points_srgb(struct kunit *test)
{
struct dc_transfer_func *tf;
tf = kunit_kzalloc(test, sizeof(*tf), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tf);
__set_tf_distributed_points(tf, TRANSFER_FUNCTION_SRGB);
KUNIT_EXPECT_EQ(test, (int)tf->type, (int)TF_TYPE_DISTRIBUTED_POINTS);
KUNIT_EXPECT_EQ(test, (int)tf->tf, (int)TRANSFER_FUNCTION_SRGB);
KUNIT_EXPECT_EQ(test, tf->sdr_ref_white_level, 80U);
}
/**
* dm_test_set_tf_distributed_points_pq - __set_tf_distributed_points: PQ predefined TF
* @test: KUnit test context
*/
static void dm_test_set_tf_distributed_points_pq(struct kunit *test)
{
struct dc_transfer_func *tf;
tf = kunit_kzalloc(test, sizeof(*tf), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tf);
__set_tf_distributed_points(tf, TRANSFER_FUNCTION_PQ);
KUNIT_EXPECT_EQ(test, (int)tf->type, (int)TF_TYPE_DISTRIBUTED_POINTS);
KUNIT_EXPECT_EQ(test, (int)tf->tf, (int)TRANSFER_FUNCTION_PQ);
KUNIT_EXPECT_EQ(test, tf->sdr_ref_white_level, 80U);
}
/**
* dm_test_set_atomic_regamma_bypass - No LUT and linear TF: must take bypass path
* @test: KUnit test context
*/
static void dm_test_set_atomic_regamma_bypass(struct kunit *test)
{
struct dc_transfer_func *out_tf;
out_tf = kunit_kzalloc(test, sizeof(*out_tf), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, out_tf);
/* size=0 and tf=LINEAR: must take the bypass branch */
KUNIT_EXPECT_EQ(test,
amdgpu_dm_set_atomic_regamma(out_tf, NULL, 0, false,
TRANSFER_FUNCTION_LINEAR),
0);
KUNIT_EXPECT_EQ(test, (int)out_tf->type, (int)TF_TYPE_BYPASS);
KUNIT_EXPECT_EQ(test, (int)out_tf->tf, (int)TRANSFER_FUNCTION_LINEAR);
}
/**
* dm_test_atomic_shaper_lut_bypass - No LUT and linear TF: must take bypass path
* @test: KUnit test context
*/
static void dm_test_atomic_shaper_lut_bypass(struct kunit *test)
{
struct dc_transfer_func *func_shaper;
func_shaper = kunit_kzalloc(test, sizeof(*func_shaper), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, func_shaper);
/* size=0 and tf=LINEAR: must take the bypass branch */
KUNIT_EXPECT_EQ(test,
amdgpu_dm_atomic_shaper_lut(NULL, false,
TRANSFER_FUNCTION_LINEAR,
0, func_shaper),
0);
KUNIT_EXPECT_EQ(test, (int)func_shaper->type, (int)TF_TYPE_BYPASS);
KUNIT_EXPECT_EQ(test, (int)func_shaper->tf, (int)TRANSFER_FUNCTION_LINEAR);
}
/**
* dm_test_atomic_blend_lut_bypass - amdgpu_dm_atomic_blend_lut bypass: no LUT, linear TF -> bypass
* @test: KUnit test context
*/
static void dm_test_atomic_blend_lut_bypass(struct kunit *test)
{
struct dc_transfer_func *func_blend;
func_blend = kunit_kzalloc(test, sizeof(*func_blend), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, func_blend);
/* size=0 and tf=LINEAR: must take the bypass branch */
KUNIT_EXPECT_EQ(test,
amdgpu_dm_atomic_blend_lut(NULL, false,
TRANSFER_FUNCTION_LINEAR,
0, func_blend),
0);
KUNIT_EXPECT_EQ(test, (int)func_blend->type, (int)TF_TYPE_BYPASS);
KUNIT_EXPECT_EQ(test, (int)func_blend->tf, (int)TRANSFER_FUNCTION_LINEAR);
}
/* ---- Tests for __set_colorop_in_tf_1d_curve ---- */
/**
* dm_test_set_colorop_in_tf_1d_curve_invalid_type - Non-1D colorop type must be rejected
* @test: KUnit test context
*/
static void dm_test_set_colorop_in_tf_1d_curve_invalid_type(struct kunit *test)
{
struct dc_plane_state *dc_plane_state;
struct drm_colorop *colorop;
struct drm_colorop_state *colorop_state;
dc_plane_state = kunit_kzalloc(test, sizeof(*dc_plane_state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, dc_plane_state);
colorop = kunit_kzalloc(test, sizeof(*colorop), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, colorop);
colorop_state = kunit_kzalloc(test, sizeof(*colorop_state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, colorop_state);
colorop->type = DRM_COLOROP_3D_LUT;
colorop_state->colorop = colorop;
colorop_state->curve_1d_type = DRM_COLOROP_1D_CURVE_SRGB_EOTF;
KUNIT_EXPECT_EQ(test,
__set_colorop_in_tf_1d_curve(dc_plane_state, colorop_state),
-EINVAL);
}
/**
* dm_test_set_colorop_in_tf_1d_curve_unsupported_curve - Unsupported 1D curve type must be rejected
* @test: KUnit test context
*/
static void dm_test_set_colorop_in_tf_1d_curve_unsupported_curve(struct kunit *test)
{
struct dc_plane_state *dc_plane_state;
struct drm_colorop *colorop;
struct drm_colorop_state *colorop_state;
dc_plane_state = kunit_kzalloc(test, sizeof(*dc_plane_state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, dc_plane_state);
colorop = kunit_kzalloc(test, sizeof(*colorop), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, colorop);
colorop_state = kunit_kzalloc(test, sizeof(*colorop_state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, colorop_state);
colorop->type = DRM_COLOROP_1D_CURVE;
colorop_state->colorop = colorop;
colorop_state->curve_1d_type = DRM_COLOROP_1D_CURVE_COUNT;
KUNIT_EXPECT_EQ(test,
__set_colorop_in_tf_1d_curve(dc_plane_state, colorop_state),
-EINVAL);
}
/**
* dm_test_set_colorop_in_tf_1d_curve_bypass - Bypass mode forces linear bypass transfer function
* @test: KUnit test context
*/
static void dm_test_set_colorop_in_tf_1d_curve_bypass(struct kunit *test)
{
struct dc_plane_state *dc_plane_state;
struct drm_colorop *colorop;
struct drm_colorop_state *colorop_state;
dc_plane_state = kunit_kzalloc(test, sizeof(*dc_plane_state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, dc_plane_state);
colorop = kunit_kzalloc(test, sizeof(*colorop), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, colorop);
colorop_state = kunit_kzalloc(test, sizeof(*colorop_state), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, colorop_state);
colorop->type = DRM_COLOROP_1D_CURVE;
colorop_state->colorop = colorop;
colorop_state->curve_1d_type = DRM_COLOROP_1D_CURVE_SRGB_EOTF;
colorop_state->bypass = true;
KUNIT_EXPECT_EQ(test,
__set_colorop_in_tf_1d_curve(dc_plane_state, colorop_state),
0);
KUNIT_EXPECT_EQ(test,
(int)dc_plane_state->in_transfer_func.type,
(int)TF_TYPE_BYPASS);
KUNIT_EXPECT_EQ(test,
(int)dc_plane_state->in_transfer_func.tf,
(int)TRANSFER_FUNCTION_LINEAR);
}
static struct kunit_case dm_color_test_cases[] = {
/* amdgpu_dm_fixpt_from_s3132 */
KUNIT_CASE(dm_test_fixpt_from_s3132_zero),
@ -1398,6 +1609,21 @@ static struct kunit_case dm_color_test_cases[] = {
KUNIT_CASE(dm_test_set_colorop_3dlut_zero_size),
KUNIT_CASE(dm_test_set_colorop_3dlut_nonzero_state_bits),
KUNIT_CASE(dm_test_set_colorop_3dlut_data_forwarded),
/* __set_tf_bypass */
KUNIT_CASE(dm_test_set_tf_bypass),
/* __set_tf_distributed_points */
KUNIT_CASE(dm_test_set_tf_distributed_points_srgb),
KUNIT_CASE(dm_test_set_tf_distributed_points_pq),
/* amdgpu_dm_set_atomic_regamma */
KUNIT_CASE(dm_test_set_atomic_regamma_bypass),
/* amdgpu_dm_atomic_shaper_lut */
KUNIT_CASE(dm_test_atomic_shaper_lut_bypass),
/* amdgpu_dm_atomic_blend_lut */
KUNIT_CASE(dm_test_atomic_blend_lut_bypass),
/* __set_colorop_in_tf_1d_curve */
KUNIT_CASE(dm_test_set_colorop_in_tf_1d_curve_invalid_type),
KUNIT_CASE(dm_test_set_colorop_in_tf_1d_curve_unsupported_curve),
KUNIT_CASE(dm_test_set_colorop_in_tf_1d_curve_bypass),
{}
};