From: Kunal Joshi <kunal1.joshi@intel.com>
To: igt-dev@lists.freedesktop.org
Cc: Kunal Joshi <kunal1.joshi@intel.com>,
ville.syrjala@intel.com, petri.latvala@intel.com,
daniel.vetter@intel.com
Subject: [igt-dev] [PATCH i-g-t 2/2] tests/kms_color_chamelium: add subtests to validate color.
Date: Tue, 14 Jan 2020 19:05:04 +0530 [thread overview]
Message-ID: <1579008904-22441-3-git-send-email-kunal1.joshi@intel.com> (raw)
In-Reply-To: <1579008904-22441-1-git-send-email-kunal1.joshi@intel.com>
To validate color subtests using chamelium, subtests modified
to do frame dump comparison instead of crc comparison.
Tests require chamelium and will validate color features
at pipe level.
Signed-off-by: Kunal Joshi <kunal1.joshi@intel.com>
Signed-off-by: Swati Sharma <swati2.sharma@intel.com>
Suggested-by: Uma Shankar <uma.shankar@intel.com>
---
tests/Makefile.am | 1 +
tests/kms_color_chamelium.c | 1119 +++++++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
3 files changed, 1121 insertions(+)
create mode 100644 tests/kms_color_chamelium.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9a320bc..1794569 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -13,6 +13,7 @@ endif
if HAVE_CHAMELIUM
TESTS_progs += \
kms_chamelium \
+ kms_color_chamelium \
$(NULL)
endif
diff --git a/tests/kms_color_chamelium.c b/tests/kms_color_chamelium.c
new file mode 100644
index 0000000..0c87bf5
--- /dev/null
+++ b/tests/kms_color_chamelium.c
@@ -0,0 +1,1119 @@
+/*
+ * Copyright © 2020 Intel Corporation
+ *
+ * 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 (including the next
+ * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ */
+
+#include <math.h>
+#include <unistd.h>
+
+#include "drm.h"
+#include "drmtest.h"
+#include "igt.h"
+
+IGT_TEST_DESCRIPTION("Test Color Features at Pipe level");
+
+/* Internal */
+typedef struct {
+ double r, g, b;
+} color_t;
+
+typedef struct {
+ int drm_fd;
+ uint32_t devid;
+ igt_display_t display;
+
+ uint32_t color_depth;
+ uint64_t degamma_lut_size;
+ uint64_t gamma_lut_size;
+
+ struct chamelium *chamelium;
+ struct chamelium_port **ports;
+ int port_count;
+} data_t;
+
+typedef struct {
+ int size;
+ double coeffs[];
+} gamma_lut_t;
+
+static void paint_gradient_rectangles(data_t *data,
+ drmModeModeInfo *mode,
+ color_t *colors,
+ struct igt_fb *fb)
+{
+ cairo_t *cr = igt_get_cairo_ctx(data->drm_fd, fb);
+ int i, l = mode->hdisplay / 3;
+ int rows_remaining = mode->hdisplay % 3;
+
+ /* Paint 3 gradient rectangles with red/green/blue between 1.0 and
+ * 0.5. We want to avoid 0 so each max LUTs only affect their own
+ * rectangle.
+ */
+ for (i = 0 ; i < 3; i++) {
+ igt_paint_color_gradient_range(cr, i * l, 0, l, mode->vdisplay,
+ colors[i].r != 0 ? 0.2 : 0,
+ colors[i].g != 0 ? 0.2 : 0,
+ colors[i].b != 0 ? 0.2 : 0,
+ colors[i].r,
+ colors[i].g,
+ colors[i].b);
+ }
+
+ if (rows_remaining > 0)
+ igt_paint_color_gradient_range(cr, i * l, 0, rows_remaining,
+ mode->vdisplay,
+ colors[i-1].r != 0 ? 0.2 : 0,
+ colors[i-1].g != 0 ? 0.2 : 0,
+ colors[i-1].b != 0 ? 0.2 : 0,
+ colors[i-1].r,
+ colors[i-1].g,
+ colors[i-1].b);
+
+ igt_put_cairo_ctx(data->drm_fd, fb, cr);
+}
+
+static void paint_rectangles(data_t *data,
+ drmModeModeInfo *mode,
+ color_t *colors,
+ struct igt_fb *fb)
+{
+ cairo_t *cr = igt_get_cairo_ctx(data->drm_fd, fb);
+ int i, l = mode->hdisplay / 3;
+ int rows_remaining = mode->hdisplay % 3;
+
+ /* Paint 3 solid rectangles. */
+ for (i = 0 ; i < 3; i++) {
+ igt_paint_color(cr, i * l, 0, l, mode->vdisplay,
+ colors[i].r, colors[i].g, colors[i].b);
+ }
+
+ if (rows_remaining > 0)
+ igt_paint_color(cr, i * l, 0, rows_remaining, mode->vdisplay,
+ colors[i-1].r, colors[i-1].g, colors[i-1].b);
+
+ igt_put_cairo_ctx(data->drm_fd, fb, cr);
+}
+
+static gamma_lut_t *alloc_lut(int lut_size)
+{
+ gamma_lut_t *gamma;
+
+ igt_assert_lt(0, lut_size);
+
+ gamma = malloc(sizeof(*gamma) + lut_size * sizeof(gamma->coeffs[0]));
+ igt_assert(gamma);
+ gamma->size = lut_size;
+
+ return gamma;
+}
+
+static void free_lut(gamma_lut_t *gamma)
+{
+ if (!gamma)
+ return;
+
+ free(gamma);
+}
+
+static gamma_lut_t *generate_table(int lut_size, double exp)
+{
+ gamma_lut_t *gamma = alloc_lut(lut_size);
+ int i;
+
+ gamma->coeffs[0] = 0.0;
+ for (i = 1; i < lut_size; i++)
+ gamma->coeffs[i] = pow(i * 1.0 / (lut_size - 1), exp);
+
+ return gamma;
+}
+
+static gamma_lut_t *generate_table_max(int lut_size)
+{
+ gamma_lut_t *gamma = alloc_lut(lut_size);
+ int i;
+
+ gamma->coeffs[0] = 0.0;
+ for (i = 1; i < lut_size; i++)
+ gamma->coeffs[i] = 1.0;
+
+ return gamma;
+}
+
+static struct drm_color_lut *coeffs_to_lut(data_t *data,
+ const gamma_lut_t *gamma,
+ uint32_t color_depth,
+ int off)
+{
+ struct drm_color_lut *lut;
+ int i, lut_size = gamma->size;
+ uint32_t max_value = (1 << 16) - 1;
+ uint32_t mask;
+
+ if (is_i915_device(data->drm_fd))
+ mask = ((1 << color_depth) - 1) << 8;
+ else
+ mask = max_value;
+
+ lut = malloc(sizeof(struct drm_color_lut) * lut_size);
+
+ if (IS_CHERRYVIEW(data->devid))
+ lut_size -= 1;
+ for (i = 0; i < lut_size; i++) {
+ uint32_t v = (gamma->coeffs[i] * max_value);
+
+ v &= mask;
+
+ lut[i].red = v;
+ lut[i].green = v;
+ lut[i].blue = v;
+ }
+
+ if (IS_CHERRYVIEW(data->devid))
+ lut[lut_size].red =
+ lut[lut_size].green =
+ lut[lut_size].blue = lut[lut_size - 1].red;
+
+ return lut;
+}
+
+static void set_degamma(data_t *data,
+ igt_pipe_t *pipe,
+ const gamma_lut_t *gamma)
+{
+ size_t size = sizeof(struct drm_color_lut) * gamma->size;
+ struct drm_color_lut *lut = coeffs_to_lut(data, gamma,
+ data->color_depth, 0);
+
+ free(lut);
+}
+
+static void set_gamma(data_t *data,
+ igt_pipe_t *pipe,
+ const gamma_lut_t *gamma)
+{
+ size_t size = sizeof(struct drm_color_lut) * gamma->size;
+ struct drm_color_lut *lut = coeffs_to_lut(data, gamma,
+ data->color_depth, 0);
+
+ igt_pipe_obj_replace_prop_blob(pipe, IGT_CRTC_GAMMA_LUT, lut, size);
+
+ free(lut);
+}
+
+static void set_ctm(igt_pipe_t *pipe, const double *coefficients)
+{
+ struct drm_color_ctm ctm;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ctm.matrix); i++) {
+ if (coefficients[i] < 0) {
+ ctm.matrix[i] =
+ (int64_t) (-coefficients[i] *
+ ((int64_t) 1L << 32));
+ ctm.matrix[i] |= 1ULL << 63;
+ } else
+ ctm.matrix[i] =
+ (int64_t) (coefficients[i] *
+ ((int64_t) 1L << 32));
+ }
+
+ igt_pipe_obj_replace_prop_blob(pipe, IGT_CRTC_CTM, &ctm, sizeof(ctm));
+}
+
+static void disable_prop(igt_pipe_t *pipe, enum igt_atomic_crtc_properties prop)
+{
+ if (igt_pipe_obj_has_prop(pipe, prop))
+ igt_pipe_obj_replace_prop_blob(pipe, prop, NULL, 0);
+}
+
+#define disable_degamma(pipe) disable_prop(pipe, IGT_CRTC_DEGAMMA_LUT)
+#define disable_gamma(pipe) disable_prop(pipe, IGT_CRTC_GAMMA_LUT)
+#define disable_ctm(pipe) disable_prop(pipe, IGT_CRTC_CTM)
+
+/*
+ * Draw 3 gradient rectangles in red, green and blue, with a maxed out
+ * degamma LUT and verify we have the same frame dump as drawing solid color
+ * rectangles with linear degamma LUT.
+ */
+static void test_pipe_degamma(data_t *data,
+ igt_plane_t *primary)
+{
+ igt_output_t *output;
+ gamma_lut_t *degamma_linear, *degamma_full;
+ gamma_lut_t *gamma_linear;
+ color_t red_green_blue[] = {
+ { 1.0, 0.0, 0.0 },
+ { 0.0, 1.0, 0.0 },
+ { 0.0, 0.0, 1.0 }
+ };
+
+ int i;
+ struct chamelium_port *port;
+ char *connected_ports[4];
+ bool valid_output = false;
+
+ for (i = 0; i < data->port_count; i++)
+ connected_ports[i] =
+ (char *) chamelium_port_get_name(data->ports[i]);
+
+ igt_require(igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT));
+ igt_require(igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT));
+
+ degamma_linear = generate_table(data->degamma_lut_size, 1.0);
+ degamma_full = generate_table_max(data->degamma_lut_size);
+
+ gamma_linear = generate_table(data->gamma_lut_size, 1.0);
+
+ for_each_valid_output_on_pipe(&data->display,
+ primary->pipe->pipe,
+ output) {
+ drmModeModeInfo *mode;
+ struct igt_fb fb_modeset, fb;
+ struct chamelium_frame_dump *frame_fullgamma, *frame_fullcolors;
+ int fb_id, fb_modeset_id;
+
+ for (i = 0; i < data->port_count; i++)
+ valid_output |=
+ (strcmp(output->name, connected_ports[i]) == 0);
+ if (!valid_output)
+ continue;
+ else
+ for (i = 0; i < data->port_count; i++)
+ if (strcmp(output->name,
+ connected_ports[i]) == 0)
+ port = data->ports[i];
+
+ igt_output_set_pipe(output, primary->pipe->pipe);
+ mode = igt_output_get_mode(output);
+
+ /* Create a framebuffer at the size of the output. */
+ fb_id = igt_create_fb(data->drm_fd,
+ mode->hdisplay,
+ mode->vdisplay,
+ DRM_FORMAT_XRGB8888,
+ LOCAL_DRM_FORMAT_MOD_NONE,
+ &fb);
+ igt_assert(fb_id);
+
+ fb_modeset_id = igt_create_fb(data->drm_fd,
+ mode->hdisplay,
+ mode->vdisplay,
+ DRM_FORMAT_XRGB8888,
+ LOCAL_DRM_FORMAT_MOD_NONE,
+ &fb_modeset);
+ igt_assert(fb_modeset_id);
+
+ igt_plane_set_fb(primary, &fb_modeset);
+ disable_ctm(primary->pipe);
+ disable_degamma(primary->pipe);
+ set_gamma(data, primary->pipe, gamma_linear);
+ igt_display_commit(&data->display);
+
+ /* Draw solid colors with no degamma transformation. */
+ paint_rectangles(data, mode, red_green_blue, &fb);
+ igt_plane_set_fb(primary, &fb);
+ igt_display_commit(&data->display);
+ chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
+ frame_fullgamma =
+ chamelium_read_captured_frame(data->chamelium, 0);
+
+ /* Draw a gradient with degamma LUT to remap all
+ * values to max red/green/blue.
+ */
+ paint_gradient_rectangles(data, mode, red_green_blue, &fb);
+ igt_plane_set_fb(primary, &fb);
+ set_degamma(data, primary->pipe, degamma_full);
+ igt_display_commit(&data->display);
+ chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
+ frame_fullcolors =
+ chamelium_read_captured_frame(data->chamelium, 0);
+
+ /* Verify that the frame dump of the software computed output
+ * is equal to the frame dump of the degamma LUT transformation
+ * output.
+ */
+ igt_assert(chamelium_assert_frame_dump_eq(data->chamelium,
+ frame_fullgamma,
+ frame_fullcolors));
+
+ igt_plane_set_fb(primary, NULL);
+ igt_output_set_pipe(output, PIPE_NONE);
+ }
+
+ free_lut(degamma_linear);
+ free_lut(degamma_full);
+ free_lut(gamma_linear);
+}
+
+/*
+ * Draw 3 gradient rectangles in red, green and blue, with a maxed out
+ * gamma LUT and verify we have the same frame dump as drawing solid
+ * color rectangles.
+ */
+static void test_pipe_gamma(data_t *data,
+ igt_plane_t *primary)
+{
+ igt_output_t *output;
+ gamma_lut_t *gamma_full;
+ color_t red_green_blue[] = {
+ { 1.0, 0.0, 0.0 },
+ { 0.0, 1.0, 0.0 },
+ { 0.0, 0.0, 1.0 }
+ };
+
+ int i;
+ struct chamelium_port *port;
+ char *connected_ports[4];
+ bool valid_output = false;
+
+ for (i = 0; i < data->port_count; i++)
+ connected_ports[i] =
+ (char *) chamelium_port_get_name(data->ports[i]);
+
+ igt_require(igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT));
+
+ gamma_full = generate_table_max(data->gamma_lut_size);
+
+ for_each_valid_output_on_pipe(&data->display,
+ primary->pipe->pipe,
+ output) {
+ drmModeModeInfo *mode;
+ struct igt_fb fb_modeset, fb;
+ struct chamelium_frame_dump *frame_fullgamma, *frame_fullcolors;
+ int fb_id, fb_modeset_id;
+
+ for (i = 0; i < data->port_count; i++)
+ valid_output |=
+ (strcmp(output->name, connected_ports[i]) == 0);
+ if (!valid_output)
+ continue;
+ else
+ for (i = 0; i < data->port_count; i++)
+ if (strcmp(output->name,
+ connected_ports[i]) == 0)
+ port = data->ports[i];
+
+ igt_output_set_pipe(output, primary->pipe->pipe);
+ mode = igt_output_get_mode(output);
+
+ /* Create a framebuffer at the size of the output. */
+ fb_id = igt_create_fb(data->drm_fd,
+ mode->hdisplay,
+ mode->vdisplay,
+ DRM_FORMAT_XRGB8888,
+ LOCAL_DRM_FORMAT_MOD_NONE,
+ &fb);
+ igt_assert(fb_id);
+
+ fb_modeset_id = igt_create_fb(data->drm_fd,
+ mode->hdisplay,
+ mode->vdisplay,
+ DRM_FORMAT_XRGB8888,
+ LOCAL_DRM_FORMAT_MOD_NONE,
+ &fb_modeset);
+ igt_assert(fb_modeset_id);
+
+ igt_plane_set_fb(primary, &fb_modeset);
+ disable_ctm(primary->pipe);
+ disable_degamma(primary->pipe);
+ set_gamma(data, primary->pipe, gamma_full);
+ igt_display_commit(&data->display);
+
+ /* Draw solid colors with no gamma transformation. */
+ paint_rectangles(data, mode, red_green_blue, &fb);
+ igt_plane_set_fb(primary, &fb);
+ igt_display_commit(&data->display);
+ chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
+ frame_fullgamma =
+ chamelium_read_captured_frame(data->chamelium, 0);
+
+ /* Draw a gradient with gamma LUT to remap all values
+ * to max red/green/blue.
+ */
+ paint_gradient_rectangles(data, mode, red_green_blue, &fb);
+ igt_plane_set_fb(primary, &fb);
+ igt_display_commit(&data->display);
+ chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
+ frame_fullcolors =
+ chamelium_read_captured_frame(data->chamelium, 0);
+
+ /* Verify that the frame dump of the software computed output is
+ * equal to the frame dump of the degamma LUT transformation
+ * output.
+ */
+ igt_assert(chamelium_assert_frame_dump_eq(data->chamelium,
+ frame_fullgamma,
+ frame_fullcolors));
+
+ igt_plane_set_fb(primary, NULL);
+ igt_output_set_pipe(output, PIPE_NONE);
+ }
+
+ free_lut(gamma_full);
+}
+
+/*
+ * Draw 3 rectangles using before colors with the ctm matrix apply and verify
+ * the frame dump is equal to using after colors with an identify ctm matrix.
+ */
+static bool test_pipe_ctm(data_t *data,
+ igt_plane_t *primary,
+ color_t *before,
+ color_t *after,
+ double *ctm_matrix)
+{
+ const double ctm_identity[] = {
+ 1.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 0.0, 1.0
+ };
+ gamma_lut_t *degamma_linear, *gamma_linear;
+ igt_output_t *output;
+
+ int i;
+ bool ret = true;
+ struct chamelium_port *port;
+ char *connected_ports[4];
+ bool valid_output = false;
+
+ igt_require(igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM));
+
+ for (i = 0; i < data->port_count; i++)
+ connected_ports[i] =
+ (char *) chamelium_port_get_name(data->ports[i]);
+
+ degamma_linear = generate_table(data->degamma_lut_size, 1.0);
+ gamma_linear = generate_table(data->gamma_lut_size, 1.0);
+
+ for_each_valid_output_on_pipe(&data->display,
+ primary->pipe->pipe,
+ output) {
+ drmModeModeInfo *mode;
+ struct igt_fb fb_modeset, fb;
+ struct chamelium_frame_dump *frame_software, *frame_hardware;
+ int fb_id, fb_modeset_id;
+
+ for (i = 0; i < data->port_count; i++)
+ valid_output |=
+ (strcmp(output->name, connected_ports[i]) == 0);
+ if (!valid_output)
+ continue;
+ else
+ for (i = 0; i < data->port_count; i++)
+ if (strcmp(output->name,
+ connected_ports[i]) == 0)
+ port = data->ports[i];
+
+ igt_output_set_pipe(output, primary->pipe->pipe);
+ mode = igt_output_get_mode(output);
+
+ /* Create a framebuffer at the size of the output. */
+ fb_id = igt_create_fb(data->drm_fd,
+ mode->hdisplay,
+ mode->vdisplay,
+ DRM_FORMAT_XRGB8888,
+ LOCAL_DRM_FORMAT_MOD_NONE,
+ &fb);
+ igt_assert(fb_id);
+
+ fb_modeset_id = igt_create_fb(data->drm_fd,
+ mode->hdisplay,
+ mode->vdisplay,
+ DRM_FORMAT_XRGB8888,
+ LOCAL_DRM_FORMAT_MOD_NONE,
+ &fb_modeset);
+ igt_assert(fb_modeset_id);
+ igt_plane_set_fb(primary, &fb_modeset);
+
+ if (memcmp(before, after, sizeof(color_t))) {
+ set_degamma(data, primary->pipe, degamma_linear);
+ set_gamma(data, primary->pipe, gamma_linear);
+ } else {
+ /* Disable Degamma and Gamma for ctm max test */
+ disable_degamma(primary->pipe);
+ disable_gamma(primary->pipe);
+ }
+
+ disable_ctm(primary->pipe);
+ igt_display_commit(&data->display);
+
+ paint_rectangles(data, mode, after, &fb);
+ igt_plane_set_fb(primary, &fb);
+ set_ctm(primary->pipe, ctm_identity);
+ igt_display_commit(&data->display);
+ chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
+ frame_software =
+ chamelium_read_captured_frame(data->chamelium, 0);
+
+ /* With CTM transformation. */
+ paint_rectangles(data, mode, before, &fb);
+ igt_plane_set_fb(primary, &fb);
+ set_ctm(primary->pipe, ctm_matrix);
+ igt_display_commit(&data->display);
+ chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
+ frame_hardware =
+ chamelium_read_captured_frame(data->chamelium, 0);
+
+ /* Verify that the frame dump of the software computed output is
+ * equal to the frame dump of the CTM matrix transformation
+ * output.
+ */
+ ret &= chamelium_assert_frame_dump_eq(data->chamelium,
+ frame_software,
+ frame_hardware);
+
+ igt_plane_set_fb(primary, NULL);
+ igt_output_set_pipe(output, PIPE_NONE);
+ }
+
+ free_lut(degamma_linear);
+ free_lut(gamma_linear);
+
+ return ret;
+}
+
+static void test_pipe_limited_range_ctm(data_t *data,
+ igt_plane_t *primary)
+{
+ double limited_result = 235.0 / 255.0;
+ color_t red_green_blue_limited[] = {
+ { limited_result, 0.0, 0.0 },
+ { 0.0, limited_result, 0.0 },
+ { 0.0, 0.0, limited_result }
+ };
+ color_t red_green_blue_full[] = {
+ { 0.5, 0.0, 0.0 },
+ { 0.0, 0.5, 0.0 },
+ { 0.0, 0.0, 0.5 }
+ };
+ double ctm[] = { 1.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 0.0, 1.0 };
+ gamma_lut_t *degamma_linear, *gamma_linear;
+ igt_output_t *output;
+ bool has_broadcast_rgb_output = false;
+
+ int i;
+ struct chamelium_port *port;
+ char *connected_ports[4];
+ bool valid_output = false;
+
+ degamma_linear = generate_table(data->degamma_lut_size, 1.0);
+ gamma_linear = generate_table(data->gamma_lut_size, 1.0);
+
+ for (i = 0; i < data->port_count; i++)
+ connected_ports[i] =
+ (char *) chamelium_port_get_name(data->ports[i]);
+
+ for_each_valid_output_on_pipe(&data->display,
+ primary->pipe->pipe,
+ output) {
+ drmModeModeInfo *mode;
+ struct igt_fb fb_modeset, fb;
+ struct chamelium_frame_dump *frame_full, *frame_limited;
+ int fb_id, fb_modeset_id;
+
+ for (i = 0; i < data->port_count; i++)
+ valid_output |=
+ (strcmp(output->name, connected_ports[i]) == 0);
+ if (!valid_output)
+ continue;
+ else
+ for (i = 0; i < data->port_count; i++)
+ if (strcmp(output->name,
+ connected_ports[i]) == 0)
+ port = data->ports[i];
+
+ if (!igt_output_has_prop(output, IGT_CONNECTOR_BROADCAST_RGB))
+ continue;
+
+ has_broadcast_rgb_output = true;
+
+ igt_output_set_pipe(output, primary->pipe->pipe);
+ mode = igt_output_get_mode(output);
+
+ /* Create a framebuffer at the size of the output. */
+ fb_id = igt_create_fb(data->drm_fd,
+ mode->hdisplay,
+ mode->vdisplay,
+ DRM_FORMAT_XRGB8888,
+ LOCAL_DRM_FORMAT_MOD_NONE,
+ &fb);
+ igt_assert(fb_id);
+
+ fb_modeset_id = igt_create_fb(data->drm_fd,
+ mode->hdisplay,
+ mode->vdisplay,
+ DRM_FORMAT_XRGB8888,
+ LOCAL_DRM_FORMAT_MOD_NONE,
+ &fb_modeset);
+ igt_assert(fb_modeset_id);
+ igt_plane_set_fb(primary, &fb_modeset);
+
+ set_degamma(data, primary->pipe, degamma_linear);
+ set_gamma(data, primary->pipe, gamma_linear);
+ set_ctm(primary->pipe, ctm);
+
+ igt_output_set_prop_value(output,
+ IGT_CONNECTOR_BROADCAST_RGB,
+ BROADCAST_RGB_FULL);
+ paint_rectangles(data, mode, red_green_blue_limited, &fb);
+ igt_plane_set_fb(primary, &fb);
+ igt_display_commit(&data->display);
+
+ /* Set the output into limited range. */
+ igt_output_set_prop_value(output,
+ IGT_CONNECTOR_BROADCAST_RGB,
+ BROADCAST_RGB_16_235);
+ paint_rectangles(data, mode, red_green_blue_full, &fb);
+ igt_plane_set_fb(primary, &fb);
+ igt_display_commit(&data->display);
+ chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
+ frame_full =
+ chamelium_read_captured_frame(data->chamelium, 0);
+
+
+ /* And reset.. */
+ igt_output_set_prop_value(output,
+ IGT_CONNECTOR_BROADCAST_RGB,
+ BROADCAST_RGB_FULL);
+ igt_plane_set_fb(primary, NULL);
+ igt_output_set_pipe(output, PIPE_NONE);
+ chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
+ frame_limited =
+ chamelium_read_captured_frame(data->chamelium, 0);
+
+
+ /* Verify that the frame dump of the software computed output is
+ * equal to the frame dump of the CTM matrix transformation
+ * output.
+ */
+ igt_assert(chamelium_assert_frame_dump_eq(data->chamelium,
+ frame_full,
+ frame_limited));
+ }
+
+ free_lut(gamma_linear);
+ free_lut(degamma_linear);
+
+ igt_require(has_broadcast_rgb_output);
+}
+
+static void
+run_tests_for_pipe(data_t *data, enum pipe p)
+{
+ igt_pipe_t *pipe;
+ igt_plane_t *primary;
+ double delta;
+ int i;
+ color_t red_green_blue[] = {
+ { 1.0, 0.0, 0.0 },
+ { 0.0, 1.0, 0.0 },
+ { 0.0, 0.0, 1.0 }
+ };
+
+ igt_fixture {
+
+ igt_require(p < data->display.n_pipes);
+
+ pipe = &data->display.pipes[p];
+ igt_require(pipe->n_planes >= 0);
+
+ primary = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
+
+ if (igt_pipe_obj_has_prop(&data->display.pipes[p],
+ IGT_CRTC_DEGAMMA_LUT_SIZE)) {
+ data->degamma_lut_size =
+ igt_pipe_obj_get_prop(&data->display.pipes[p],
+ IGT_CRTC_DEGAMMA_LUT_SIZE);
+ igt_assert_lt(0, data->degamma_lut_size);
+ }
+
+ if (igt_pipe_obj_has_prop(&data->display.pipes[p],
+ IGT_CRTC_GAMMA_LUT_SIZE)) {
+ data->gamma_lut_size =
+ igt_pipe_obj_get_prop(&data->display.pipes[p],
+ IGT_CRTC_GAMMA_LUT_SIZE);
+ igt_assert_lt(0, data->gamma_lut_size);
+ }
+
+ igt_display_require_output_on_pipe(&data->display, p);
+ }
+
+ data->color_depth = 8;
+ delta = 1.0 / (1 << data->color_depth);
+
+ igt_describe("Compare after applying ctm matrix & identity matrix");
+ igt_subtest_f("pipe-%s-ctm-red-to-blue", kmstest_pipe_name(p)) {
+ color_t blue_green_blue[] = {
+ { 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0 },
+ { 0.0, 0.0, 1.0 }
+ };
+ double ctm[] = { 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 1.0, 0.0, 1.0 };
+ igt_assert(test_pipe_ctm(data, primary, red_green_blue,
+ blue_green_blue, ctm));
+ }
+
+ igt_describe("Compare after applying ctm matrix & identity matrix");
+ igt_subtest_f("pipe-%s-ctm-green-to-red", kmstest_pipe_name(p)) {
+ color_t red_red_blue[] = {
+ { 1.0, 0.0, 0.0 },
+ { 1.0, 0.0, 0.0 },
+ { 0.0, 0.0, 1.0 }
+ };
+ double ctm[] = { 1.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0 };
+ igt_assert(test_pipe_ctm(data, primary, red_green_blue,
+ red_red_blue, ctm));
+ }
+
+ igt_describe("Compare after applying ctm matrix & identity matrix");
+ igt_subtest_f("pipe-%s-ctm-blue-to-red", kmstest_pipe_name(p)) {
+ color_t red_green_red[] = {
+ { 1.0, 0.0, 0.0 },
+ { 0.0, 1.0, 0.0 },
+ { 1.0, 0.0, 0.0 }
+ };
+ double ctm[] = { 1.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0 };
+ igt_assert(test_pipe_ctm(data, primary, red_green_blue,
+ red_green_red, ctm));
+ }
+
+ /* We tests a few values around the expected result because
+ * the it depends on the hardware we're dealing with, we can
+ * either get clamped or rounded values and we also need to
+ * account for odd number of items in the LUTs.
+ */
+ igt_describe("Compare after applying ctm matrix & identity matrix");
+ igt_subtest_f("pipe-%s-ctm-0-25", kmstest_pipe_name(p)) {
+ color_t expected_colors[] = {
+ { 0.0, }, { 0.0, }, { 0.0, }
+ };
+ double ctm[] = { 0.25, 0.0, 0.0,
+ 0.0, 0.25, 0.0,
+ 0.0, 0.0, 0.25 };
+ bool success = false;
+
+ for (i = 0; i < 5; i++) {
+ expected_colors[0].r =
+ expected_colors[1].g =
+ expected_colors[2].b =
+ 0.25 + delta * (i - 2);
+ success |= test_pipe_ctm(data, primary,
+ red_green_blue,
+ expected_colors, ctm);
+ }
+ igt_assert(success);
+ }
+
+ igt_describe("Compare after applying ctm matrix & identity matrix");
+ igt_subtest_f("pipe-%s-ctm-0-5", kmstest_pipe_name(p)) {
+ color_t expected_colors[] = {
+ { 0.0, }, { 0.0, }, { 0.0, }
+ };
+ double ctm[] = { 0.5, 0.0, 0.0,
+ 0.0, 0.5, 0.0,
+ 0.0, 0.0, 0.5 };
+ bool success = false;
+
+ for (i = 0; i < 5; i++) {
+ expected_colors[0].r =
+ expected_colors[1].g =
+ expected_colors[2].b =
+ 0.5 + delta * (i - 2);
+ success |= test_pipe_ctm(data, primary,
+ red_green_blue,
+ expected_colors, ctm);
+ }
+ igt_assert(success);
+ }
+
+ igt_describe("Compare after applying ctm matrix & identity matrix");
+ igt_subtest_f("pipe-%s-ctm-0-75", kmstest_pipe_name(p)) {
+ color_t expected_colors[] = {
+ { 0.0, }, { 0.0, }, { 0.0, }
+ };
+ double ctm[] = { 0.75, 0.0, 0.0,
+ 0.0, 0.75, 0.0,
+ 0.0, 0.0, 0.75 };
+ bool success = false;
+
+ for (i = 0; i < 7; i++) {
+ expected_colors[0].r =
+ expected_colors[1].g =
+ expected_colors[2].b =
+ 0.75 + delta * (i - 3);
+ success |= test_pipe_ctm(data, primary,
+ red_green_blue,
+ expected_colors, ctm);
+ }
+ igt_assert(success);
+ }
+
+ igt_describe("Compare after applying ctm matrix & identity matrix");
+ igt_subtest_f("pipe-%s-ctm-max", kmstest_pipe_name(p)) {
+ color_t full_rgb[] = {
+ { 1.0, 0.0, 0.0 },
+ { 0.0, 1.0, 0.0 },
+ { 0.0, 0.0, 1.0 }
+ };
+ double ctm[] = { 100.0, 0.0, 0.0,
+ 0.0, 100.0, 0.0,
+ 0.0, 0.0, 100.0 };
+
+ /* CherryView generates values on 10bits that we
+ * produce with an 8 bits per color framebuffer.
+ */
+ igt_require(!IS_CHERRYVIEW(data->devid));
+
+ igt_assert(test_pipe_ctm(data, primary, red_green_blue,
+ full_rgb, ctm));
+ }
+
+ igt_describe("Compare after applying ctm matrix & identity matrix");
+ igt_subtest_f("pipe-%s-ctm-negative", kmstest_pipe_name(p)) {
+ color_t all_black[] = {
+ { 0.0, 0.0, 0.0 },
+ { 0.0, 0.0, 0.0 },
+ { 0.0, 0.0, 0.0 }
+ };
+ double ctm[] = { -1.0, 0.0, 0.0,
+ 0.0, -1.0, 0.0,
+ 0.0, 0.0, -1.0 };
+ igt_assert(test_pipe_ctm(data, primary, red_green_blue,
+ all_black, ctm));
+ }
+
+ igt_describe("Compare after applying ctm matrix & identity matrix");
+ igt_subtest_f("pipe-%s-ctm-limited-range", kmstest_pipe_name(p))
+ test_pipe_limited_range_ctm(data, primary);
+
+ igt_describe("Compare maxed out gamma LUT and solid color linear LUT");
+ igt_subtest_f("pipe-%s-degamma", kmstest_pipe_name(p))
+ test_pipe_degamma(data, primary);
+
+ igt_describe("Compare maxed out gamma LUT and solid color linear LUT");
+ igt_subtest_f("pipe-%s-gamma", kmstest_pipe_name(p))
+ test_pipe_gamma(data, primary);
+
+ igt_fixture {
+ disable_degamma(primary->pipe);
+ disable_gamma(primary->pipe);
+ disable_ctm(primary->pipe);
+ igt_display_commit(&data->display);
+ }
+}
+
+static int
+pipe_set_property_blob_id(igt_pipe_t *pipe,
+ enum igt_atomic_crtc_properties prop,
+ uint32_t blob_id)
+{
+ int ret;
+
+ igt_pipe_obj_replace_prop_blob(pipe, prop, NULL, 0);
+
+ igt_pipe_obj_set_prop_value(pipe, prop, blob_id);
+
+ ret = igt_display_try_commit2(pipe->display,
+ pipe->display->is_atomic ?
+ COMMIT_ATOMIC : COMMIT_LEGACY);
+
+ igt_pipe_obj_set_prop_value(pipe, prop, 0);
+
+ return ret;
+}
+
+static int
+pipe_set_property_blob(igt_pipe_t *pipe,
+ enum igt_atomic_crtc_properties prop,
+ void *ptr, size_t length)
+{
+ igt_pipe_obj_replace_prop_blob(pipe, prop, ptr, length);
+
+ return igt_display_try_commit2(pipe->display,
+ pipe->display->is_atomic ?
+ COMMIT_ATOMIC : COMMIT_LEGACY);
+}
+
+static void
+invalid_gamma_lut_sizes(data_t *data)
+{
+ igt_display_t *display = &data->display;
+ igt_pipe_t *pipe = &display->pipes[0];
+ size_t gamma_lut_size = data->gamma_lut_size *
+ sizeof(struct drm_color_lut);
+ struct drm_color_lut *gamma_lut;
+
+ igt_require(igt_pipe_obj_has_prop(pipe, IGT_CRTC_GAMMA_LUT));
+
+ gamma_lut = malloc(gamma_lut_size * 2);
+
+ igt_display_commit2(display,
+ display->is_atomic ?
+ COMMIT_ATOMIC : COMMIT_LEGACY);
+
+ igt_assert_eq(pipe_set_property_blob(pipe,
+ IGT_CRTC_GAMMA_LUT,
+ gamma_lut, 1),
+ -EINVAL);
+ igt_assert_eq(pipe_set_property_blob(pipe,
+ IGT_CRTC_GAMMA_LUT,
+ gamma_lut, gamma_lut_size + 1),
+ -EINVAL);
+ igt_assert_eq(pipe_set_property_blob(pipe,
+ IGT_CRTC_GAMMA_LUT,
+ gamma_lut,
+ gamma_lut_size - 1),
+ -EINVAL);
+ igt_assert_eq(pipe_set_property_blob(pipe,
+ IGT_CRTC_GAMMA_LUT,
+ gamma_lut,
+ gamma_lut_size +
+ sizeof(struct drm_color_lut)),
+ -EINVAL);
+ igt_assert_eq(pipe_set_property_blob_id(pipe,
+ IGT_CRTC_GAMMA_LUT,
+ pipe->crtc_id),
+ -EINVAL);
+ igt_assert_eq(pipe_set_property_blob_id(pipe,
+ IGT_CRTC_GAMMA_LUT,
+ 4096 * 4096),
+ -EINVAL);
+
+ free(gamma_lut);
+}
+
+static void
+invalid_degamma_lut_sizes(data_t *data)
+{
+ igt_display_t *display = &data->display;
+ igt_pipe_t *pipe = &display->pipes[0];
+ size_t degamma_lut_size = data->degamma_lut_size *
+ sizeof(struct drm_color_lut);
+ struct drm_color_lut *degamma_lut;
+
+ igt_require(igt_pipe_obj_has_prop(pipe, IGT_CRTC_DEGAMMA_LUT));
+
+ degamma_lut = malloc(degamma_lut_size * 2);
+
+ igt_display_commit2(display,
+ display->is_atomic ?
+ COMMIT_ATOMIC : COMMIT_LEGACY);
+
+ igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_DEGAMMA_LUT,
+ degamma_lut, 1), -EINVAL);
+ igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_DEGAMMA_LUT,
+ degamma_lut, degamma_lut_size + 1),
+ -EINVAL);
+ igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_DEGAMMA_LUT,
+ degamma_lut,
+ degamma_lut_size - 1),
+ -EINVAL);
+ igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_DEGAMMA_LUT,
+ degamma_lut,
+ degamma_lut_size +
+ sizeof(struct drm_color_lut)),
+ -EINVAL);
+ igt_assert_eq(pipe_set_property_blob_id(pipe, IGT_CRTC_DEGAMMA_LUT,
+ pipe->crtc_id), -EINVAL);
+ igt_assert_eq(pipe_set_property_blob_id(pipe, IGT_CRTC_DEGAMMA_LUT,
+ 4096 * 4096), -EINVAL);
+
+ free(degamma_lut);
+}
+
+static void
+invalid_ctm_matrix_sizes(data_t *data)
+{
+ igt_display_t *display = &data->display;
+ igt_pipe_t *pipe = &display->pipes[0];
+ void *ptr;
+
+ igt_require(igt_pipe_obj_has_prop(pipe, IGT_CRTC_CTM));
+
+ ptr = malloc(sizeof(struct drm_color_ctm) * 4);
+
+ igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_CTM, ptr, 1),
+ -EINVAL);
+ igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_CTM, ptr,
+ sizeof(struct drm_color_ctm) + 1),
+ -EINVAL);
+ igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_CTM, ptr,
+ sizeof(struct drm_color_ctm) - 1),
+ -EINVAL);
+ igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_CTM, ptr,
+ sizeof(struct drm_color_ctm) * 2),
+ -EINVAL);
+ igt_assert_eq(pipe_set_property_blob_id(pipe, IGT_CRTC_CTM,
+ pipe->crtc_id), -EINVAL);
+ igt_assert_eq(pipe_set_property_blob_id(pipe, IGT_CRTC_CTM,
+ 4096 * 4096), -EINVAL);
+
+ free(ptr);
+}
+
+igt_main
+{
+ data_t data = {};
+ enum pipe pipe;
+
+ igt_fixture {
+ data.drm_fd = drm_open_driver_master(DRIVER_ANY);
+ if (is_i915_device(data.drm_fd))
+ data.devid = intel_get_drm_devid(data.drm_fd);
+ data.chamelium = chamelium_init(data.drm_fd);
+ igt_require(data.chamelium);
+
+ data.ports = chamelium_get_ports(data.chamelium,
+ &data.port_count);
+
+ kmstest_set_vt_graphics_mode();
+ igt_display_require(&data.display, data.drm_fd);
+ igt_require(data.display.is_atomic);
+ }
+
+ for_each_pipe_static(pipe)
+ igt_subtest_group
+ run_tests_for_pipe(&data, pipe);
+ igt_describe("Negative test case gamma lut size");
+ igt_subtest_f("pipe-invalid-gamma-lut-sizes")
+ invalid_gamma_lut_sizes(&data);
+
+ igt_describe("Negative test case degamma lut size");
+ igt_subtest_f("pipe-invalid-degamma-lut-sizes")
+ invalid_degamma_lut_sizes(&data);
+
+ igt_describe("Negative test case ctm matrix size");
+ igt_subtest_f("pipe-invalid-ctm-matrix-sizes")
+ invalid_ctm_matrix_sizes(&data);
+
+ igt_fixture {
+ igt_display_fini(&data.display);
+ }
+}
diff --git a/tests/meson.build b/tests/meson.build
index 570de54..74a5541 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -256,6 +256,7 @@ endif
if chamelium.found()
test_progs += [
'kms_chamelium',
+ 'kms_color_chamelium',
]
test_deps += chamelium
endif
--
2.7.4
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev
next prev parent reply other threads:[~2020-01-14 13:35 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-01-14 13:35 [igt-dev] [PATCH i-g-t 0/2] validate color tests using chamelium Kunal Joshi
2020-01-14 13:35 ` [igt-dev] [PATCH i-g-t 1/2] lib/igt_chamelium: add function to compare two frame dumps Kunal Joshi
2020-01-14 13:35 ` Kunal Joshi [this message]
2020-01-15 9:59 ` [igt-dev] [PATCH i-g-t 2/2] tests/kms_color_chamelium: add subtests to validate color Arkadiusz Hiler
2020-01-14 14:22 ` [igt-dev] ✓ Fi.CI.BAT: success for validate color tests using chamelium Patchwork
2020-01-16 16:26 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1579008904-22441-3-git-send-email-kunal1.joshi@intel.com \
--to=kunal1.joshi@intel.com \
--cc=daniel.vetter@intel.com \
--cc=igt-dev@lists.freedesktop.org \
--cc=petri.latvala@intel.com \
--cc=ville.syrjala@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox