[PATCH i-g-t 8/9] tests/kms_color: Add Intel plane pipeline tests with LUT1D (MULTSEG) and CTM
Swati Sharma
swati2.sharma at intel.com
Sun Jul 6 20:01:24 UTC 2025
From: Bhanuprakash Modem <bhanuprakash.modem at intel.com>
For now, Intel plane color pipeline contains 3 colorops:
Pre-csc gamma (1D LUT MULTSEG) --> CTM 3x4 --> Post-csc gamma (1D LUT MULTSEG)
Create subtests to cover different combinations of available
colorops:
igt at kms_color@plane-lut1d-multseg
igt at kms_color@plane-ctm3x4
igt at kms_color@plane-lut1d-multseg-ctm3x4
igt at kms_color@plane-ctm3x4-lut1d-multseg
igt at kms_color@plane-lut1d-multseg-lut1d-multseg
igt at kms_color@plane-lut1d-multseg-ctm3x4-lut1d-multseg
v2: -renamed subtests
-updated create_unity_lut() logic
-used CTM 3x4
Signed-off-by: Bhanuprakash Modem <bhanuprakash.modem at intel.com>
Signed-off-by: Swati Sharma <swati2.sharma at intel.com>
---
tests/kms_color.c | 279 ++++++++++++++++++++++++++++++++++++++-
tests/kms_color_helper.c | 20 ++-
2 files changed, 290 insertions(+), 9 deletions(-)
diff --git a/tests/kms_color.c b/tests/kms_color.c
index 447fcc7f9..1c61fac71 100644
--- a/tests/kms_color.c
+++ b/tests/kms_color.c
@@ -32,6 +32,8 @@
#include "kms_color_helper.h"
+#define MAX_COLOROPS 5
+
/**
* SUBTEST: degamma
* Description: Verify that degamma LUT transformation works correctly
@@ -76,6 +78,20 @@
* @gamma-lut: Gamma LUT
*/
+/**
+ * SUBTEST: plane-%s
+ * Description: Test plane color pipeline with colorops: %arg[1].
+ *
+ * arg[1]:
+ *
+ * @lut1d-multseg: 1D LUT MULTSEG
+ * @ctm3x4: 3X4 CTM
+ * @lut1d-multseg-ctm3x4: 1D LUT MULTSEG --> 3X4 CTM
+ * @ctm3x4-lut1d-multseg: 3X4 CTM --> 1D LUT MULTSEG
+ * @lut1d-multseg-lut1d-multseg: 1D LUT MULTSEG --> 1D LUT MULTSEG
+ * @lut1d-multseg-ctm3x4-lut1d-multseg: 1D LUT MULTSEG --> 3X4 CTM --> 1D LUT MULTSEG
+ */
+
IGT_TEST_DESCRIPTION("Test Color Features at Pipe level");
static bool test_pipe_degamma(data_t *data,
@@ -724,6 +740,137 @@ static void test_pipe_limited_range_ctm(data_t *data,
}
#endif
+static void clear_lut_data(kms_colorop_t *colorops[])
+{
+ int i;
+
+ for (i = 0; colorops[i]; i++) {
+ if (colorops[i]->type != KMS_COLOROP_MULTSEG_LUT1D)
+ continue;
+
+ if (colorops[i]->multseg_lut1d_info.lut)
+ free(colorops[i]->multseg_lut1d_info.lut);
+ }
+}
+
+static void prepare_lut_data(data_t *data, kms_colorop_t *colorops[])
+{
+ int i;
+
+ for (i = 0; colorops[i]; i++) {
+ uint64_t hwlut_caps = 0;
+ segment_data_t *segment_info;
+
+ if (colorops[i]->type != KMS_COLOROP_MULTSEG_LUT1D)
+ continue;
+
+ hwlut_caps = igt_colorop_get_prop(&data->display, colorops[i]->colorop, IGT_COLOROP_HW_CAPS);
+ segment_info = get_segment_data(data->drm_fd, hwlut_caps);
+
+ igt_info("Lut size (%s): %d\n", colorops[i]->name, segment_info->entries_count);
+
+ colorops[i]->multseg_lut1d_info.lut_size = segment_info->entries_count;
+ colorops[i]->multseg_lut1d_info.lut =
+ malloc(sizeof(struct drm_color_lut_32) * colorops[i]->multseg_lut1d_info.lut_size);
+ igt_assert(colorops[i]->multseg_lut1d_info.lut);
+
+ switch (colorops[i]->multseg_lut1d_info.lut_type) {
+ case KMS_COLOROP_MULTSEG_LUT1D_ZERO:
+ create_zero_lut(segment_info, colorops[i]->multseg_lut1d_info.lut);
+ break;
+ case KMS_COLOROP_MULTSEG_LUT1D_LINEAR:
+ create_unity_lut(segment_info, colorops[i]->multseg_lut1d_info.lut);
+ break;
+ case KMS_COLOROP_MULTSEG_LUT1D_MAX:
+ default:
+ create_max_lut(segment_info, colorops[i]->multseg_lut1d_info.lut);
+ }
+
+ clear_segment_data(segment_info);
+ }
+}
+
+static bool ctm_colorop_only(kms_colorop_t *colorops[])
+{
+ int i;
+
+ for (i = 0; colorops[i]; i++)
+ if (colorops[i]->type != KMS_COLOROP_CTM_3X4)
+ return false;
+ return true;
+}
+
+static bool test_plane_colorops(data_t *data,
+ const color_t *fb_colors,
+ const color_t *exp_colors,
+ kms_colorop_t *colorops[])
+{
+ igt_plane_t *plane = data->primary;
+ igt_output_t *output = data->output;
+ igt_display_t *display = &data->display;
+ drmModeModeInfo *mode = data->mode;
+ struct igt_fb fb;
+ bool ret;
+ igt_colorop_t *color_pipeline = get_color_pipeline(display, plane, colorops);
+ igt_crc_t crc_gamma, crc_fullcolors;
+
+ igt_output_set_pipe(output, plane->pipe->pipe);
+ mode = igt_output_get_mode(output);
+
+ /* Create a framebuffer at the size of the output. */
+ igt_assert(igt_create_fb(data->drm_fd,
+ mode->hdisplay,
+ mode->vdisplay,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_MOD_LINEAR,
+ &fb));
+ igt_plane_set_fb(plane, &fb);
+
+ /* Disable Pipe color props. */
+ disable_ctm(plane->pipe);
+ disable_degamma(plane->pipe);
+ disable_gamma(plane->pipe);
+ igt_display_commit2(display, COMMIT_ATOMIC);
+
+ set_color_pipeline_bypass(plane);
+ paint_rectangles(data, mode, exp_colors, &fb);
+ igt_plane_set_fb(plane, &fb);
+ igt_display_commit2(display, COMMIT_ATOMIC);
+ igt_wait_for_vblank(data->drm_fd,
+ display->pipes[plane->pipe->pipe].crtc_offset);
+ igt_pipe_crc_collect_crc(data->pipe_crc, &crc_fullcolors);
+
+ /*
+ * Draw gradient colors with LUT to remap all
+ * values to max red/green/blue.
+ */
+ prepare_lut_data(data, colorops);
+ set_color_pipeline(display, plane, colorops, color_pipeline);
+ if (ctm_colorop_only(colorops))
+ paint_rectangles(data, mode, fb_colors, &fb);
+ else
+ paint_gradient_rectangles(data, mode, fb_colors, &fb);
+ igt_plane_set_fb(plane, &fb);
+ igt_display_commit2(display, COMMIT_ATOMIC);
+ igt_wait_for_vblank(data->drm_fd,
+ display->pipes[plane->pipe->pipe].crtc_offset);
+ igt_pipe_crc_collect_crc(data->pipe_crc, &crc_gamma);
+
+ /*
+ * Verify that the CRC of the software computed output is
+ * equal to the CRC of the gamma LUT transformation output.
+ */
+ ret = igt_check_crc_equal(&crc_gamma, &crc_fullcolors);
+
+ clear_lut_data(colorops);
+ clear_color_pipeline(display, plane, colorops, color_pipeline);
+ igt_plane_set_fb(plane, NULL);
+ igt_output_set_pipe(output, PIPE_NONE);
+ igt_display_commit2(display, COMMIT_ATOMIC);
+
+ return ret;
+}
+
static void
prep_pipe(data_t *data, enum pipe p)
{
@@ -759,6 +906,10 @@ static void test_setup(data_t *data, enum pipe p)
data->primary->pipe->pipe,
IGT_PIPE_CRC_SOURCE_AUTO);
+ igt_display_require_output_on_pipe(&data->display, p);
+ data->output = igt_get_single_output_for_pipe(&data->display, p);
+ igt_require(data->output);
+
igt_display_reset(&data->display);
}
@@ -852,6 +1003,42 @@ run_ctm_tests_for_pipe(data_t *data, enum pipe p,
test_cleanup(data);
}
+static void run_plane_color_tests(data_t *data,
+ const color_t *fb_colors,
+ const color_t *exp_colors,
+ kms_colorop_t *colorops[])
+{
+ enum pipe pipe;
+
+ data->color_depth = 8;
+ data->drm_format = DRM_FORMAT_XRGB8888;
+
+ for_each_pipe(&data->display, pipe) {
+ test_setup(data, pipe);
+
+ data->mode = igt_output_get_mode(data->output);
+
+ if (!pipe_output_combo_valid(data, pipe)){
+ test_cleanup(data);
+ continue;
+ }
+
+ /*
+ * TODO: Extend the test to multiple planes?
+ * Since, Intel planes (HDR & SDR) have different capabilities.
+ */
+ if (!igt_plane_has_prop(data->primary, IGT_PLANE_COLOR_PIPELINE))
+ continue;
+
+ igt_dynamic_f("pipe-%s-%s",
+ kmstest_pipe_name(pipe),
+ igt_output_name(data->output))
+ igt_assert(test_plane_colorops(data, fb_colors, exp_colors, colorops));
+ }
+
+ test_cleanup(data);
+}
+
static void
run_deep_color_tests_for_pipe(data_t *data, enum pipe p)
{
@@ -1155,13 +1342,93 @@ run_tests_for_pipe(data_t *data)
}
}
- igt_fixture
- igt_require(data->display.is_atomic);
+ igt_subtest_group {
+ static const color_t colors_red_to_blue[] = {
+ { 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0 },
+ { 0.0, 0.0, 1.0 },
+ };
+ const igt_matrix_3x4_t ctm_red_to_blue = { {
+ 0.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 1.0, 0.0, 1.0, 0.0,
+ } };
+ kms_colorop_t lut1d_multseg_linear = {
+ .type = KMS_COLOROP_MULTSEG_LUT1D,
+ .name = "Pre/Post CSC GAMMA (linear LUT)",
+ .multseg_lut1d_info = {
+ .lut_type = KMS_COLOROP_MULTSEG_LUT1D_LINEAR,
+ },
+ };
+ kms_colorop_t lut1d_multseg_max = {
+ .type = KMS_COLOROP_MULTSEG_LUT1D,
+ .name = "Pre/Post CSC GAMMA (max LUT)",
+ .multseg_lut1d_info = {
+ .lut_type = KMS_COLOROP_MULTSEG_LUT1D_MAX,
+ },
+ };
+ kms_colorop_t ctm_3x4 = {
+ .type = KMS_COLOROP_CTM_3X4,
+ .name = "CTM 3X4 (red to blue)",
+ .matrix_3x4 = &ctm_red_to_blue,
+ };
+ struct {
+ const char *name;
+ const color_t *fb_colors;
+ const color_t *exp_colors;
+ kms_colorop_t *colorops[MAX_COLOROPS];
+ } plane_colorops_tests[] = {
+ { .name = "lut1d-multseg",
+ .fb_colors = colors_rgb,
+ .exp_colors = colors_rgb,
+ .colorops = { &lut1d_multseg_max, NULL },
+ },
+ { .name = "ctm3x4",
+ .fb_colors = colors_rgb,
+ .exp_colors = colors_red_to_blue,
+ .colorops = { &ctm_3x4, NULL },
+ },
+ { .name = "lut1d-multseg-ctm3x4",
+ .fb_colors = colors_rgb,
+ .exp_colors = colors_red_to_blue,
+ .colorops = { &lut1d_multseg_max, &ctm_3x4, NULL },
+ },
+ { .name = "ctm3x4-lut1d-multseg",
+ .fb_colors = colors_rgb,
+ .exp_colors = colors_red_to_blue,
+ .colorops = { &ctm_3x4, &lut1d_multseg_max, NULL },
+ },
+ { .name = "lut1d-multseg-lut1d-multseg",
+ .fb_colors = colors_rgb,
+ .exp_colors = colors_rgb,
+ .colorops = { &lut1d_multseg_linear, &lut1d_multseg_max, NULL },
+ },
+ { .name = "lut1d-multseg-ctm3x4-lut1d-multseg",
+ .fb_colors = colors_rgb,
+ .exp_colors = colors_red_to_blue,
+ .colorops = { &lut1d_multseg_linear, &ctm_3x4, &lut1d_multseg_max, NULL },
+ },
+ };
- igt_describe("Verify that deep color works correctly");
- igt_subtest_with_dynamic("deep-color") {
- for_each_pipe(&data->display, pipe) {
- run_deep_color_tests_for_pipe(data, pipe);
+ igt_fixture {
+ if (drmSetClientCap(data->display.drm_fd, DRM_CLIENT_CAP_ATOMIC, 1) == 0)
+ data->display.is_atomic = 1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(plane_colorops_tests); i++) {
+ igt_describe_f("Test plane color pipeline with colorops: %s", plane_colorops_tests[i].name);
+ igt_subtest_with_dynamic_f("plane-%s", plane_colorops_tests[i].name)
+ run_plane_color_tests(data,
+ plane_colorops_tests[i].fb_colors,
+ plane_colorops_tests[i].exp_colors,
+ plane_colorops_tests[i].colorops);
+ }
+
+ igt_describe("Verify that deep color works correctly");
+ igt_subtest_with_dynamic("deep-color") {
+ for_each_pipe(&data->display, pipe) {
+ run_deep_color_tests_for_pipe(data, pipe);
+ }
}
}
}
diff --git a/tests/kms_color_helper.c b/tests/kms_color_helper.c
index 9ca96919f..ba6890c86 100644
--- a/tests/kms_color_helper.c
+++ b/tests/kms_color_helper.c
@@ -642,18 +642,32 @@ void create_zero_lut(segment_data_t *info, struct drm_color_lut_32 *lut)
lut[i].red = lut[i].green = lut[i].blue = 0;
}
+static uint32_t get_max(int precision)
+{
+ if(precision > 32)
+ precision = 32;
+
+ return (uint64_t)(1 << precision) - 1;
+}
+
void create_unity_lut(segment_data_t *info, struct drm_color_lut_32 *lut)
{
uint32_t val, segment, entry, index = 0;
- uint32_t max_val = 0xffffffff;
+ float norm_val;
for (segment = 0; segment < info->segment_count; segment++) {
uint32_t entry_count = info->segment_data[segment].count;
uint32_t start = info->segment_data[segment].start;
uint32_t end = info->segment_data[segment].end;
+ uint32_t norm_factor = info->segment_data[segment].norm_factor;
+ int precision = info->segment_data[segment].precision.intp + info->segment_data[segment].precision.fracp;
+ uint32_t max_val = get_max(precision);
+
+ /* TODO: Add int precision logic */
+ for (entry = 0; entry < entry_count; entry++) {
+ norm_val = (start * 1.0) / norm_factor + entry * ((end - start) * 1.0 / (((entry_count - 1) ? entry_count - 1 : 1) * norm_factor));
+ val = (norm_val * (1 << info->segment_data[segment].precision.fracp));
- for (entry = 1; entry <= entry_count; entry++) {
- val = start + entry * ((end - start) * 1.0 / entry_count);
lut[index].red = lut[index].green = lut[index].blue =
(index == 0) ? 0 : MIN(val, max_val);
--
2.25.1
More information about the igt-dev
mailing list