[igt-dev] [PATCH i-g-t 5/9] tests/kms_color: Add test setting and changing a plane color pipeline
Chaitanya Kumar Borah
chaitanya.kumar.borah at intel.com
Tue Aug 29 14:38:17 UTC 2023
Identify a plane color pipeline with support for pre-csc, CTM and
post-csc hardware blocks.
Enable all these hardware blocks with unity lut values and co-effs,
by creating blobs and sending the same with SET_COLOR_PIPELINE property.
Later change pre-csc hardware unit from unity to max lut co-effs keeping
the rest of the hardware blocks intact.
ToDo: Break the change down to smaller parts with the helpers going to
separate patch.
Co-developed-by: Uma Shankar <uma.shankar at intel.com>
Signed-off-by: Uma Shankar <uma.shankar at intel.com>
Signed-off-by: Chaitanya Kumar Borah <chaitanya.kumar.borah at intel.com>
---
tests/kms_color.c | 322 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 321 insertions(+), 1 deletion(-)
diff --git a/tests/kms_color.c b/tests/kms_color.c
index 22f957534..a0159a0de 100644
--- a/tests/kms_color.c
+++ b/tests/kms_color.c
@@ -1072,11 +1072,38 @@ static void run_plane_color_test(data_t *data, enum pipe pipe,
#define HAS_COLOR_CONVERSION_CAP (HAS_PRE_CSC |\
HAS_CSC | HAS_POST_CSC)
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+/* Structure to store information regarding lut ranges */
+typedef struct {
+ uint32_t segment_count;
+ struct drm_color_lut_range *segment_data;
+ uint32_t entries_count;
+} segment_data_t;
+
+struct color_conversion_pipeline_info {
+ u32 pre_csc_blob_id;
+ u32 csc_blob_id;
+ u32 post_csc_blob_id;
+ segment_data_t *pre_csc_seg_data;
+ segment_data_t *post_csc_seg_data;
+};
+
uint32_t get_color_op_cap(enum color_op_block name);
drmModePropertyPtr get_plane_property(igt_plane_t *plane,
enum igt_atomic_plane_properties prop);
uint64_t get_color_pipeline(data_t *data,
igt_plane_t *plane, uint8_t capabilities);
+segment_data_t *get_segment_data(data_t *data,
+ uint64_t blob_id);
+void parse_color_conv_pipeline(data_t *data, uint64_t color_pipeline,
+ struct color_conversion_pipeline_info *cp_info);
+void clear_pipeline_seg_info(struct color_conversion_pipeline_info cp_info);
+void destroy_csc_pipeline_blobs(data_t *data,
+ struct color_conversion_pipeline_info cp_info);
+struct drm_color_lut_ext *create_linear_lut(segment_data_t *info);
+struct drm_color_lut_ext *create_max_lut(segment_data_t *info);
+struct drm_color_ctm *create_ctm(const double *ctm_coefficients);
uint32_t get_color_op_cap(enum color_op_block name)
{
@@ -1163,6 +1190,294 @@ uint64_t get_color_pipeline(data_t *data,
return color_pipeline;
}
+/* helper to extract segment data from a blob */
+segment_data_t *get_segment_data(data_t *data,
+ uint64_t blob_id)
+{
+ drmModePropertyBlobPtr blob;
+ struct drm_color_lut_range *lut_range = NULL;
+ segment_data_t *info = NULL;
+ uint32_t i;
+
+ blob = drmModeGetPropertyBlob(data->drm_fd, blob_id);
+ igt_assert(blob);
+ igt_assert(blob->length);
+
+ info = malloc(sizeof(segment_data_t));
+ igt_assert(info);
+
+ lut_range = (struct drm_color_lut_range *)blob->data;
+ info->segment_count = blob->length / sizeof(lut_range[0]);
+ igt_assert(info->segment_count);
+
+ info->segment_data = malloc(sizeof(struct drm_color_lut_range) * info->segment_count);
+ igt_assert(info->segment_data);
+
+ info->entries_count = 0;
+ for (i = 0; i < info->segment_count; i++) {
+ info->entries_count += lut_range[i].count;
+ info->segment_data[i] = lut_range[i];
+ }
+
+ drmModeFreePropertyBlob(blob);
+
+ return info;
+}
+
+/* helper to parse segment data for pre-csc and post-csc blocks */
+void parse_color_conv_pipeline(data_t *data, uint64_t color_pipeline,
+ struct color_conversion_pipeline_info *cp_info)
+{
+ drmModePropertyBlobPtr blob = NULL;
+ struct drm_color_op *color_op;
+
+ blob = drmModeGetPropertyBlob(data->drm_fd, color_pipeline);
+ igt_assert(blob);
+ igt_assert(blob->length);
+ color_op = blob->data;
+
+ for (int j = 0; j < blob->length / sizeof(struct drm_color_op); j++) {
+ if (color_op[j].blob_id) {
+ if (color_op[j].name == DRM_CB_PRE_CSC) {
+ cp_info->pre_csc_seg_data =
+ get_segment_data(data, color_op[j].blob_id);
+ } else if (color_op[j].name == DRM_CB_POST_CSC) {
+ cp_info->post_csc_seg_data =
+ get_segment_data(data, color_op[j].blob_id);
+ }
+ }
+ }
+
+ drmModeFreePropertyBlob(blob);
+}
+
+void clear_pipeline_seg_info(struct color_conversion_pipeline_info cp_info)
+{
+ free(cp_info.pre_csc_seg_data);
+ free(cp_info.post_csc_seg_data);
+}
+
+void destroy_csc_pipeline_blobs(data_t *data,
+ struct color_conversion_pipeline_info cp_info)
+{
+ if (cp_info.pre_csc_blob_id)
+ igt_assert(drmModeDestroyPropertyBlob(data->drm_fd,
+ cp_info.pre_csc_blob_id) == 0);
+ if (cp_info.csc_blob_id)
+ igt_assert(drmModeDestroyPropertyBlob(data->drm_fd,
+ cp_info.csc_blob_id) == 0);
+ if (cp_info.post_csc_blob_id)
+ igt_assert(drmModeDestroyPropertyBlob(data->drm_fd,
+ cp_info.post_csc_blob_id) == 0);
+}
+
+struct drm_color_lut_ext *create_linear_lut(segment_data_t *info)
+{
+ uint32_t val, segment, entry, index = 0;
+ uint32_t max_val = 0xffffffff;
+ struct drm_color_lut_ext *lut = malloc(sizeof(struct drm_color_lut_ext) *
+ info->entries_count);
+
+ igt_assert(lut);
+
+ 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;
+
+ for (entry = 1; entry <= entry_count; entry++) {
+ val = (index == 0) ? /* First entry is Zero. */
+ 0 : start + entry * ((end - start) * 1.0 / entry_count);
+
+ lut[index].red = lut[index].green = lut[index].blue = MIN(val, max_val);
+
+ index++;
+ }
+ }
+
+ return lut;
+}
+
+struct drm_color_lut_ext *create_max_lut(segment_data_t *info)
+{
+ int i;
+ struct drm_color_lut_ext *lut;
+ /* ToDo: Determine max value for Lut taking h/w precision into account */
+ uint32_t max_val = 0xffffffff;
+
+ lut = malloc(sizeof(struct drm_color_lut_ext) * info->entries_count);
+ igt_assert(lut);
+
+ lut[0].red = lut[0].green = lut[0].blue = 0; /* First entry is Zero. */
+
+ for (i = 1; i < info->entries_count; i++)
+ lut[i].red = lut[i].green = lut[i].blue = max_val;
+
+ return lut;
+}
+
+struct drm_color_ctm *create_ctm(const double *ctm_coefficients)
+{
+ struct drm_color_ctm *ctm;
+ int i;
+
+ ctm = malloc(sizeof(struct drm_color_ctm));
+ igt_assert(ctm);
+
+ for (i = 0; i < ARRAY_SIZE(ctm->matrix); i++) {
+ if (ctm_coefficients[i] < 0) {
+ ctm->matrix[i] =
+ (int64_t)(-ctm_coefficients[i] *
+ ((int64_t)1L << 32));
+ ctm->matrix[i] |= 1ULL << 63;
+ } else {
+ ctm->matrix[i] =
+ (int64_t)(ctm_coefficients[i] *
+ ((int64_t)1L << 32));
+ }
+ }
+
+ return ctm;
+}
+
+/*
+ * Find a color pipeline with pre-csc,csc and post-csc pipeline.
+ * Set up all blocks and then set only pre-csc
+ */
+static bool plane_cp_test_1(data_t *data, igt_plane_t *plane)
+{
+ igt_display_t *display = &data->display;
+ drmModeModeInfo *mode = data->mode;
+ igt_output_t *output = data->output;
+ struct igt_fb fb;
+ uint64_t color_pipeline = 0;
+ struct color_conversion_pipeline_info cp_info;
+ struct drm_color_pipeline cp;
+ struct drm_color_op_data *color_op_data;
+ struct drm_color_ctm *ctm;
+ struct drm_color_lut_ext *pre_csc_lut, *post_csc_lut;
+ uint32_t blob_id;
+ const double ctm_coefficients[] = {
+ 1.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 0.0, 1.0
+ };
+ int lut_size = 0;
+
+ igt_info("Plane Color Pipeline test is running on pipe-%s plane-%d(%s)\n",
+ kmstest_pipe_name(plane->pipe->pipe), plane->index,
+ kmstest_plane_type_name(plane->type));
+
+ igt_require(igt_plane_has_prop(plane, IGT_PLANE_GET_COLOR_PIPELINE));
+ igt_require(igt_plane_has_prop(plane, IGT_PLANE_SET_COLOR_PIPELINE));
+
+ igt_output_set_pipe(output, plane->pipe->pipe);
+
+ igt_assert(igt_create_fb(data->drm_fd,
+ mode->hdisplay,
+ mode->vdisplay,
+ data->drm_format,
+ DRM_FORMAT_MOD_LINEAR,
+ &fb));
+
+ igt_plane_set_fb(plane, &fb);
+
+ igt_display_commit2(display, COMMIT_ATOMIC);
+
+ /* Find the pipeline with pre-csc, ctm and post-csc hardware unit */
+ color_pipeline = get_color_pipeline(data, plane, HAS_COLOR_CONVERSION_CAP);
+
+ if (!color_pipeline) {
+ igt_info("No pipeline with caps 0x%lx\n", HAS_COLOR_CONVERSION_CAP);
+ return true;
+ }
+
+ igt_info("color pipeline %ld\n", color_pipeline);
+
+ /* Parse the pipeline data and get capabilities for the respective hardware blocks */
+ parse_color_conv_pipeline(data, color_pipeline, &cp_info);
+ igt_assert(cp_info.pre_csc_seg_data);
+ igt_assert(cp_info.post_csc_seg_data);
+
+ /*
+ * Allocate color_op_data with 3 entries representing the hardware units
+ * which needs to be updated. This will be updated with the actual lut
+ * and CTM co-effs and passed to driver using SET_COLOR_PIPELINE property.
+ */
+ color_op_data = calloc(1, sizeof(struct drm_color_op_data) * 3);
+ cp.num = color_pipeline;
+ cp.size = sizeof(struct drm_color_op_data) * 3;
+ cp.data = color_op_data;
+
+ /* Set Pre-CSC */
+ color_op_data[0].name = DRM_CB_PRE_CSC;
+ lut_size = sizeof(struct drm_color_lut_ext) *
+ cp_info.pre_csc_seg_data->entries_count;
+ pre_csc_lut = create_linear_lut(cp_info.pre_csc_seg_data);
+ igt_assert(drmModeCreatePropertyBlob(display->drm_fd,
+ pre_csc_lut, lut_size, &blob_id) == 0);
+ color_op_data[0].blob_id = blob_id;
+ cp_info.pre_csc_blob_id = blob_id;
+
+ /* Set CTM */
+ color_op_data[1].name = DRM_CB_CSC;
+ ctm = create_ctm(ctm_coefficients);
+ igt_assert(drmModeCreatePropertyBlob(display->drm_fd,
+ ctm, sizeof(struct drm_color_ctm), &blob_id) == 0);
+ color_op_data[1].blob_id = blob_id;
+ cp_info.csc_blob_id = blob_id;
+
+ /* Set Post-CSC */
+ color_op_data[2].name = DRM_CB_POST_CSC;
+ lut_size = sizeof(struct drm_color_lut_ext) *
+ cp_info.post_csc_seg_data->entries_count;
+ post_csc_lut = create_linear_lut(cp_info.post_csc_seg_data);
+ igt_assert(drmModeCreatePropertyBlob(display->drm_fd,
+ post_csc_lut, lut_size, &blob_id) == 0);
+ color_op_data[2].blob_id = blob_id;
+ cp_info.post_csc_blob_id = blob_id;
+
+ /* Data structure with values for all blocks is ready. Send the same to driver */
+ igt_plane_replace_prop_blob(plane, IGT_PLANE_SET_COLOR_PIPELINE, &cp,
+ sizeof(struct drm_color_pipeline));
+ igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+ /*
+ * Now the Color pipeline with pre-csc, ctm and post-csc is enabled
+ * Lets change just the pre-csc unit in hardware
+ */
+ if (color_op_data[0].blob_id) {
+ drmModeDestroyPropertyBlob(display->drm_fd,
+ color_op_data[0].blob_id);
+ free(pre_csc_lut);
+
+ lut_size = sizeof(struct drm_color_lut_ext) *
+ cp_info.pre_csc_seg_data->entries_count;
+
+ pre_csc_lut = create_max_lut(cp_info.pre_csc_seg_data);
+ igt_assert(drmModeCreatePropertyBlob(display->drm_fd,
+ pre_csc_lut, lut_size, &blob_id) == 0);
+
+ color_op_data[0].blob_id = blob_id;
+ cp_info.pre_csc_blob_id = blob_id;
+ igt_plane_replace_prop_blob(plane, IGT_PLANE_SET_COLOR_PIPELINE, &cp,
+ sizeof(struct drm_color_pipeline));
+ igt_display_commit2(&data->display, COMMIT_ATOMIC);
+ }
+
+ /* Reset Pipeline */
+ igt_plane_replace_prop_blob(plane, IGT_PLANE_SET_COLOR_PIPELINE, NULL, 0);
+ igt_display_commit2(&data->display, COMMIT_ATOMIC);
+ destroy_csc_pipeline_blobs(data, cp_info);
+ free(ctm);
+ free(pre_csc_lut);
+ free(post_csc_lut);
+ free(color_op_data);
+ clear_pipeline_seg_info(cp_info);
+
+ return true;
+}
+
#undef HAS_PRE_CSC
#undef HAS_CSC
#undef HAS_POST_CSC
@@ -1315,7 +1630,12 @@ run_tests_for_pipe(data_t *data)
const char *name;
bool (*test_t)(data_t*, igt_plane_t*);
const char *desc;
- } plane_colorpipeline_tests[] = {};
+ } plane_colorpipeline_tests[] = {
+ { "plane-cp-test-1", plane_cp_test_1,
+ "Find a color pipeline with pre-csc,csc and post-csc pipeline."
+ "Set up all blocks and then set only pre-csc"
+ },
+ };
enum pipe active_pipes[IGT_MAX_PIPES];
uint32_t last_pipe = 0;
int i;
--
2.25.1
More information about the igt-dev
mailing list