drm/amd/display: Add KUnit test for color helpers

Add KUnit tests for six pure-logic functions in
amdgpu_dm_color.c: amdgpu_dm_fixpt_from_s3132,
__is_lut_linear, __drm_ctm_to_dc_matrix,
__drm_ctm_3x4_to_dc_matrix, amdgpu_tf_to_dc_tf,
and amdgpu_colorop_tf_to_dc_tf.

Expose these static functions under CONFIG_DRM_AMD_DC_KUNIT_TEST
and add a new amdgpu_dm_color.h header with the KUnit-only
prototypes. The test file re-declares the dc and amdgpu
transfer function enums locally to avoid pulling in the full
DC/amdgpu include chain that fails under UML.

26 test cases cover signed-magnitude to two's complement
conversion, LUT linearity detection, CTM-to-DC matrix
conversion, and transfer function enum mapping.

Assisted-by: Copilot:Claude-Opus-4.6
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ivan Lipski <ivan.lipski@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Alex Hung
2026-04-22 11:54:33 -06:00
committed by Alex Deucher
parent 77f3ed873c
commit 647d1fd046
4 changed files with 1209 additions and 18 deletions

View File

@@ -29,9 +29,12 @@
#include "amdgpu.h"
#include "amdgpu_mode.h"
#include "amdgpu_dm.h"
#include "amdgpu_dm_color.h"
#include "amdgpu_dm_colorop.h"
#include "dc.h"
#include "modules/color/color_gamma.h"
#include "amdgpu_dm_kunit_helpers.h"
/**
* DOC: overview
@@ -157,8 +160,6 @@
*
*/
#define MAX_DRM_LUT_VALUE 0xFFFF
#define MAX_DRM_LUT32_VALUE 0xFFFFFFFF
#define SDR_WHITE_LEVEL_INIT_VALUE 80
/**
@@ -172,7 +173,8 @@ void amdgpu_dm_init_color_mod(void)
setup_x_points_distribution();
}
static inline struct fixed31_32 amdgpu_dm_fixpt_from_s3132(__u64 x)
STATIC_IFN_KUNIT INLINE_IFN_KUNIT
struct fixed31_32 amdgpu_dm_fixpt_from_s3132(__u64 x)
{
struct fixed31_32 val;
@@ -183,6 +185,7 @@ static inline struct fixed31_32 amdgpu_dm_fixpt_from_s3132(__u64 x)
val.value = x;
return val;
}
EXPORT_IF_KUNIT(amdgpu_dm_fixpt_from_s3132);
#ifdef AMD_PRIVATE_COLOR
/* Pre-defined Transfer Functions (TF)
@@ -421,12 +424,14 @@ amdgpu_dm_create_color_properties(struct amdgpu_device *adev)
* Returns:
* DRM LUT or NULL
*/
static const struct drm_color_lut *
STATIC_IFN_KUNIT
const struct drm_color_lut *
__extract_blob_lut(const struct drm_property_blob *blob, uint32_t *size)
{
*size = blob ? drm_color_lut_size(blob) : 0;
return blob ? (struct drm_color_lut *)blob->data : NULL;
}
EXPORT_IF_KUNIT(__extract_blob_lut);
/**
* __extract_blob_lut32 - Extracts the DRM lut and lut size from a blob.
@@ -436,12 +441,14 @@ __extract_blob_lut(const struct drm_property_blob *blob, uint32_t *size)
* Returns:
* DRM LUT or NULL
*/
static const struct drm_color_lut32 *
STATIC_IFN_KUNIT
const struct drm_color_lut32 *
__extract_blob_lut32(const struct drm_property_blob *blob, uint32_t *size)
{
*size = blob ? drm_color_lut32_size(blob) : 0;
return blob ? (struct drm_color_lut32 *)blob->data : NULL;
}
EXPORT_IF_KUNIT(__extract_blob_lut32);
/**
* __is_lut_linear - check if the given lut is a linear mapping of values
@@ -456,7 +463,8 @@ __extract_blob_lut32(const struct drm_property_blob *blob, uint32_t *size)
* True if the given lut is a linear mapping of values, i.e. it acts like a
* bypass LUT. Otherwise, false.
*/
static bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size)
STATIC_IFN_KUNIT
bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size)
{
int i;
uint32_t expected;
@@ -476,6 +484,7 @@ static bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size)
}
return true;
}
EXPORT_IF_KUNIT(__is_lut_linear);
/**
* __drm_lut_to_dc_gamma - convert the drm_color_lut to dc_gamma.
@@ -485,7 +494,8 @@ static bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size)
*
* The conversion depends on the size of the lut - whether or not it's legacy.
*/
static void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut,
STATIC_IFN_KUNIT
void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut,
struct dc_gamma *gamma, bool is_legacy)
{
uint32_t r, g, b;
@@ -515,6 +525,7 @@ static void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut,
gamma->entries.blue[i] = dc_fixpt_from_fraction(b, MAX_DRM_LUT_VALUE);
}
}
EXPORT_IF_KUNIT(__drm_lut_to_dc_gamma);
/**
* __drm_lut32_to_dc_gamma - convert the drm_color_lut to dc_gamma.
@@ -523,7 +534,8 @@ static void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut,
*
* The conversion depends on the size of the lut - whether or not it's legacy.
*/
static void __drm_lut32_to_dc_gamma(const struct drm_color_lut32 *lut, struct dc_gamma *gamma)
STATIC_IFN_KUNIT
void __drm_lut32_to_dc_gamma(const struct drm_color_lut32 *lut, struct dc_gamma *gamma)
{
int i;
@@ -533,6 +545,7 @@ static void __drm_lut32_to_dc_gamma(const struct drm_color_lut32 *lut, struct dc
gamma->entries.blue[i] = dc_fixpt_from_fraction(lut[i].blue, MAX_DRM_LUT32_VALUE);
}
}
EXPORT_IF_KUNIT(__drm_lut32_to_dc_gamma);
/**
* __drm_ctm_to_dc_matrix - converts a DRM CTM to a DC CSC float matrix
@@ -541,8 +554,9 @@ static void __drm_lut32_to_dc_gamma(const struct drm_color_lut32 *lut, struct dc
*
* The matrix needs to be a 3x4 (12 entry) matrix.
*/
static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm,
struct fixed31_32 *matrix)
STATIC_IFN_KUNIT
void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm,
struct fixed31_32 *matrix)
{
int i;
@@ -565,6 +579,7 @@ static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm,
matrix[i] = amdgpu_dm_fixpt_from_s3132(ctm->matrix[i - (i / 4)]);
}
}
EXPORT_IF_KUNIT(__drm_ctm_to_dc_matrix);
/**
* __drm_ctm_3x4_to_dc_matrix - converts a DRM CTM 3x4 to a DC CSC float matrix
@@ -573,8 +588,9 @@ static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm,
*
* The matrix needs to be a 3x4 (12 entry) matrix.
*/
static void __drm_ctm_3x4_to_dc_matrix(const struct drm_color_ctm_3x4 *ctm,
struct fixed31_32 *matrix)
STATIC_IFN_KUNIT
void __drm_ctm_3x4_to_dc_matrix(const struct drm_color_ctm_3x4 *ctm,
struct fixed31_32 *matrix)
{
int i;
@@ -587,6 +603,7 @@ static void __drm_ctm_3x4_to_dc_matrix(const struct drm_color_ctm_3x4 *ctm,
matrix[i] = amdgpu_dm_fixpt_from_s3132(ctm->matrix[i]);
}
}
EXPORT_IF_KUNIT(__drm_ctm_3x4_to_dc_matrix);
/**
* __set_legacy_tf - Calculates the legacy transfer function
@@ -851,7 +868,8 @@ static int __set_input_tf_32(struct dc_color_caps *caps, struct dc_transfer_func
return res ? 0 : -ENOMEM;
}
static enum dc_transfer_func_predefined
STATIC_IFN_KUNIT
enum dc_transfer_func_predefined
amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf)
{
switch (tf) {
@@ -879,8 +897,10 @@ amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf)
return TRANSFER_FUNCTION_GAMMA26;
}
}
EXPORT_IF_KUNIT(amdgpu_tf_to_dc_tf);
static enum dc_transfer_func_predefined
STATIC_IFN_KUNIT
enum dc_transfer_func_predefined
amdgpu_colorop_tf_to_dc_tf(enum drm_colorop_curve_1d_type tf)
{
switch (tf) {
@@ -900,8 +920,10 @@ amdgpu_colorop_tf_to_dc_tf(enum drm_colorop_curve_1d_type tf)
return TRANSFER_FUNCTION_LINEAR;
}
}
EXPORT_IF_KUNIT(amdgpu_colorop_tf_to_dc_tf);
static void __to_dc_lut3d_color(struct dc_rgb *rgb,
STATIC_IFN_KUNIT
void __to_dc_lut3d_color(struct dc_rgb *rgb,
const struct drm_color_lut lut,
int bit_precision)
{
@@ -909,8 +931,10 @@ static void __to_dc_lut3d_color(struct dc_rgb *rgb,
rgb->green = drm_color_lut_extract(lut.green, bit_precision);
rgb->blue = drm_color_lut_extract(lut.blue, bit_precision);
}
EXPORT_IF_KUNIT(__to_dc_lut3d_color);
static void __drm_3dlut_to_dc_3dlut(const struct drm_color_lut *lut,
STATIC_IFN_KUNIT
void __drm_3dlut_to_dc_3dlut(const struct drm_color_lut *lut,
uint32_t lut3d_size,
struct tetrahedral_params *params,
bool use_tetrahedral_9,
@@ -953,8 +977,10 @@ static void __drm_3dlut_to_dc_3dlut(const struct drm_color_lut *lut,
/* lut0 has 1229 points (lut_size/4 + 1) */
__to_dc_lut3d_color(&lut0[lut_i], lut[i], bit_depth);
}
EXPORT_IF_KUNIT(__drm_3dlut_to_dc_3dlut);
static void __to_dc_lut3d_32_color(struct dc_rgb *rgb,
STATIC_IFN_KUNIT
void __to_dc_lut3d_32_color(struct dc_rgb *rgb,
const struct drm_color_lut32 lut,
int bit_precision)
{
@@ -962,8 +988,10 @@ static void __to_dc_lut3d_32_color(struct dc_rgb *rgb,
rgb->green = drm_color_lut32_extract(lut.green, bit_precision);
rgb->blue = drm_color_lut32_extract(lut.blue, bit_precision);
}
EXPORT_IF_KUNIT(__to_dc_lut3d_32_color);
static void __drm_3dlut32_to_dc_3dlut(const struct drm_color_lut32 *lut,
STATIC_IFN_KUNIT
void __drm_3dlut32_to_dc_3dlut(const struct drm_color_lut32 *lut,
uint32_t lut3d_size,
struct tetrahedral_params *params,
bool use_tetrahedral_9,
@@ -1006,6 +1034,7 @@ static void __drm_3dlut32_to_dc_3dlut(const struct drm_color_lut32 *lut,
/* lut0 has 1229 points (lut_size/4 + 1) */
__to_dc_lut3d_32_color(&lut0[lut_i], lut[i], bit_depth);
}
EXPORT_IF_KUNIT(__drm_3dlut32_to_dc_3dlut);
/* amdgpu_dm_atomic_lut3d - set DRM 3D LUT to DC stream
* @drm_lut3d: user 3D LUT

View File

@@ -0,0 +1,89 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright 2026 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#ifndef __AMDGPU_DM_COLOR_H__
#define __AMDGPU_DM_COLOR_H__
#define MAX_DRM_LUT_VALUE 0xFFFF
#define MAX_DRM_LUT32_VALUE 0xFFFFFFFF
#include <linux/types.h>
struct drm_color_lut;
struct drm_color_lut32;
struct drm_color_ctm;
struct drm_color_ctm_3x4;
struct drm_property_blob;
struct dc_gamma;
struct dc_rgb;
struct fixed31_32;
struct tetrahedral_params;
#ifdef CONFIG_DRM_AMD_DC_KUNIT_TEST
/*
* Prototypes for functions exposed to KUnit tests. The enum types
* used below (dc_transfer_func_predefined, amdgpu_transfer_function,
* drm_colorop_curve_1d_type) must be defined before this header is
* included the source file (amdgpu_dm_color.c) ensures this via
* its own includes of dc.h, amdgpu_dm.h, and drm/drm_colorop.h.
*/
struct fixed31_32 amdgpu_dm_fixpt_from_s3132(__u64 x);
bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size);
void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut,
struct dc_gamma *gamma, bool is_legacy);
void __drm_lut32_to_dc_gamma(const struct drm_color_lut32 *lut,
struct dc_gamma *gamma);
void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm,
struct fixed31_32 *matrix);
void __drm_ctm_3x4_to_dc_matrix(const struct drm_color_ctm_3x4 *ctm,
struct fixed31_32 *matrix);
enum dc_transfer_func_predefined
amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf);
enum dc_transfer_func_predefined
amdgpu_colorop_tf_to_dc_tf(enum drm_colorop_curve_1d_type tf);
const struct drm_color_lut *
__extract_blob_lut(const struct drm_property_blob *blob, uint32_t *size);
const struct drm_color_lut32 *
__extract_blob_lut32(const struct drm_property_blob *blob, uint32_t *size);
void __to_dc_lut3d_color(struct dc_rgb *rgb,
const struct drm_color_lut lut,
int bit_precision);
void __drm_3dlut_to_dc_3dlut(const struct drm_color_lut *lut,
uint32_t lut3d_size,
struct tetrahedral_params *params,
bool use_tetrahedral_9,
int bit_depth);
void __to_dc_lut3d_32_color(struct dc_rgb *rgb,
const struct drm_color_lut32 lut,
int bit_precision);
void __drm_3dlut32_to_dc_3dlut(const struct drm_color_lut32 *lut,
uint32_t lut3d_size,
struct tetrahedral_params *params,
bool use_tetrahedral_9,
int bit_depth);
#endif
#endif /* __AMDGPU_DM_COLOR_H__ */

View File

@@ -7,7 +7,9 @@ ccflags-y += -I$(src)/../..
ccflags-y += -I$(src)/../../include
ccflags-y += -I$(src)/../../modules/inc
ccflags-y += -I$(src)/../../dc
ccflags-y += -I$(src)/../../../amdgpu
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_crc_test.o
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_hdcp_test.o
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_color_test.o
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_colorop_test.o

File diff suppressed because it is too large Load Diff