This test enables testing of :

* degamma LUTs
* csc matrix
* gamma LUTs

Signed-off-by: Lionel Landwerlin <lionel.g.landwer...@intel.com>
---
 tests/.gitignore       |   1 +
 tests/Makefile.sources |   1 +
 tests/kms_color.c      | 611 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 613 insertions(+)
 create mode 100644 tests/kms_color.c

diff --git a/tests/.gitignore b/tests/.gitignore
index 7f20f2b..6fc4782 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -130,6 +130,7 @@ gen7_forcewake_mt
 kms_3d
 kms_addfb_basic
 kms_atomic
+kms_color
 kms_crtc_background_color
 kms_cursor_crc
 kms_draw_crc
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index d594038..f2af648 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -68,6 +68,7 @@ TESTS_progs_M = \
        gem_write_read_ring_switch \
        kms_addfb_basic \
        kms_atomic \
+       kms_color \
        kms_cursor_crc \
        kms_draw_crc \
        kms_fbc_crc \
diff --git a/tests/kms_color.c b/tests/kms_color.c
new file mode 100644
index 0000000..f1492a2
--- /dev/null
+++ b/tests/kms_color.c
@@ -0,0 +1,611 @@
+/*
+ * Copyright © 2015 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 "drmtest.h"
+#include "drm.h"
+#include "igt_debugfs.h"
+#include "igt_kms.h"
+#include "igt_core.h"
+#include "intel_io.h"
+#include "intel_chipset.h"
+#include "igt_aux.h"
+#include<unistd.h>
+#include<stdlib.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+
+
+IGT_TEST_DESCRIPTION("Test Color Features at Pipe level");
+
+/* Data structures for gamma/degamma ramps & ctm matrix. */
+struct _drm_r32g32b32 {
+       __u32 r32;
+       __u32 g32;
+       __u32 b32;
+       __u32 reserved;
+};
+
+struct _drm_palette {
+       struct _drm_r32g32b32 lut[0];
+};
+
+struct _drm_ctm {
+       __s64 ctm_coeff[9];
+};
+
+/* Internal */
+typedef struct {
+       float r, g, b;
+} color_t;
+
+typedef struct {
+       int drm_fd;
+       igt_display_t display;
+
+       uint32_t color_depth;
+       uint64_t coeffs_after_ctm;
+       uint64_t coeffs_before_ctm;
+} data_t;
+
+
+static float ctm_identity[] = {
+       1.0, 0.0, 0.0,
+       0.0, 1.0, 0.0,
+       0.0, 0.0, 1.0
+};
+
+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;
+
+       /* 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.5 : 0,
+                                              colors[i].g != 0 ? 0.5 : 0,
+                                              colors[i].b != 0 ? 0.5 : 0,
+                                              colors[i].r,
+                                              colors[i].g,
+                                              colors[i].b);
+       }
+
+       cairo_destroy(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;
+
+       /* 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);
+
+       cairo_destroy(cr);
+}
+
+static float *generate_table(uint32_t lut_size, float exp)
+{
+       float *coeffs = malloc(sizeof(float) * lut_size);
+       uint32_t i;
+
+       for (i = 0; i < lut_size; i++)
+               coeffs[i] = powf((float) i * 1.0 / (float) lut_size, exp);
+
+       return coeffs;
+}
+
+static float *generate_table_max(uint32_t lut_size)
+{
+       float *coeffs = malloc(sizeof(float) * lut_size);
+       uint32_t i;
+
+       coeffs[0] = 0.0;
+       for (i = 1; i < lut_size; i++)
+               coeffs[i] = 1.0;
+
+       return coeffs;
+}
+
+static struct _drm_palette *coeffs_to_palette(const float *coefficients,
+                                             uint32_t lut_size,
+                                             uint32_t color_depth,
+                                             size_t *size)
+{
+       struct _drm_palette *palette;
+       uint32_t i;
+       uint32_t max_value_mask = ((1 << (color_depth + 1)) - 1) << 16;
+
+       *size = sizeof(struct _drm_r32g32b32) * lut_size;
+       palette = malloc(*size);
+
+       for (i = 0; i < lut_size; i++) {
+               /*
+                * Hardware might encode colors at a different number
+                * of bits that what is in our framebuffer (10 or
+                * 12bits for example). Map the max value to the max
+                * value of the framebuffer so we can do CRC
+                * comparisons.
+                */
+               uint32_t v = coefficients[i] * max_value_mask;
+
+               palette->lut[i].r32 = v;
+               palette->lut[i].g32 = v;
+               palette->lut[i].b32 = v;
+       }
+
+       return palette;
+}
+
+static void set_degamma(igt_pipe_t *pipe,
+                       const float *coefficients,
+                       uint32_t lut_size,
+                       uint32_t color_depth)
+{
+       size_t size;
+       struct _drm_palette *palette = coeffs_to_palette(coefficients, lut_size,
+                                                        color_depth, &size);
+
+       igt_assert_eq(igt_pipe_set_blob_property(pipe, "PALETTE_BEFORE_CTM",
+                                                palette, size), 0);
+
+       free(palette);
+}
+
+static void set_gamma(igt_pipe_t *pipe,
+                     const float *coefficients,
+                     uint32_t lut_size,
+                     uint32_t color_depth)
+{
+       size_t size;
+       struct _drm_palette *palette = coeffs_to_palette(coefficients, lut_size,
+                                                        color_depth, &size);
+
+       igt_assert_eq(igt_pipe_set_blob_property(pipe, "PALETTE_AFTER_CTM",
+                                                palette, size), 0);
+
+       free(palette);
+}
+
+static void set_ctm(igt_pipe_t *pipe, const float *coefficients)
+{
+       struct _drm_ctm ctm;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ctm.ctm_coeff); i++) {
+               ctm.ctm_coeff[i] =
+                       (int64_t) (coefficients[i] * ((int64_t) 1L << 32));
+       }
+
+       igt_assert_eq(igt_pipe_set_blob_property(pipe, "CTM",
+                                                &ctm, sizeof(ctm)), 0);
+}
+
+/*
+ * Draw 3 gradient rectangles in red, green and blue, with a maxed out
+ * degamma LUT and verify we have the same CRC 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;
+       igt_pipe_crc_t *pipe_crc;
+       float *degamma_linear, *degamma_full;
+       float *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 }
+       };
+
+       pipe_crc = igt_pipe_crc_new(primary->pipe->pipe,
+                                   INTEL_PIPE_CRC_SOURCE_AUTO);
+
+       degamma_linear = generate_table(data->coeffs_before_ctm, 1.0);
+       degamma_full = generate_table_max(data->coeffs_before_ctm);
+
+       gamma_linear = generate_table(data->coeffs_after_ctm, 1.0);
+
+       for_each_connected_output(&data->display, output) {
+               drmModeModeInfo *mode;
+               struct igt_fb fb_modeset, fb;
+               igt_crc_t crc_fullgamma, crc_fullcolors;
+               int fb_id, fb_modeset_id;
+
+               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->hdisplay,
+                                     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->hdisplay,
+                                             DRM_FORMAT_XRGB8888,
+                                             LOCAL_DRM_FORMAT_MOD_NONE,
+                                             &fb_modeset);
+               igt_assert(fb_modeset_id);
+
+               igt_plane_set_fb(primary, &fb_modeset);
+               set_ctm(primary->pipe, ctm_identity);
+               set_gamma(primary->pipe, gamma_linear,
+                         data->coeffs_after_ctm, data->color_depth);
+               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);
+               set_degamma(primary->pipe, degamma_linear,
+                           data->coeffs_before_ctm, data->color_depth);
+               igt_display_commit(&data->display);
+               igt_wait_for_vblank(data->drm_fd, primary->pipe->pipe);
+               igt_pipe_crc_collect_crc(pipe_crc, &crc_fullcolors);
+
+               /* 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(primary->pipe, degamma_full,
+                           data->coeffs_before_ctm, data->color_depth);
+               igt_display_commit(&data->display);
+               igt_wait_for_vblank(data->drm_fd, primary->pipe->pipe);
+               igt_pipe_crc_collect_crc(pipe_crc, &crc_fullgamma);
+
+               /* Verify that the CRC of the software computed output
+                * is equal to the CRC of the degamma LUT
+                * transformation output.
+                */
+               igt_assert_crc_equal(&crc_fullgamma, &crc_fullcolors);
+
+               /* Reset output. */
+               igt_output_set_pipe(output, PIPE_ANY);
+               igt_display_commit(&data->display);
+       }
+
+       /* Reset the degamma ramp. */
+       set_degamma(primary->pipe, degamma_linear,
+                   data->coeffs_before_ctm, data->color_depth);
+       igt_display_commit(&data->display);
+
+       igt_pipe_crc_free(pipe_crc);
+
+       free(degamma_linear);
+       free(degamma_full);
+       free(gamma_linear);
+}
+
+/*
+ * Draw 3 gradient rectangles in red, green and blue, with a maxed out
+ * gamma LUT and verify we have the same CRC as drawing solid color
+ * rectangles with linear gamma LUT.
+ */
+static void test_pipe_gamma(data_t *data,
+                           igt_plane_t *primary)
+{
+       igt_output_t *output;
+       igt_pipe_crc_t *pipe_crc;
+       float *degamma_linear;
+       float *gamma_linear, *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 }
+       };
+
+       pipe_crc = igt_pipe_crc_new(primary->pipe->pipe,
+                                   INTEL_PIPE_CRC_SOURCE_AUTO);
+
+       degamma_linear = generate_table(data->coeffs_before_ctm, 1.0);
+
+       gamma_linear = generate_table(data->coeffs_after_ctm, 1.0);
+       gamma_full = generate_table_max(data->coeffs_after_ctm);
+
+       for_each_connected_output(&data->display, output) {
+               drmModeModeInfo *mode;
+               struct igt_fb fb_modeset, fb;
+               igt_crc_t crc_fullgamma, crc_fullcolors;
+               int fb_id, fb_modeset_id;
+
+               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->hdisplay,
+                                     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->hdisplay,
+                                             DRM_FORMAT_XRGB8888,
+                                             LOCAL_DRM_FORMAT_MOD_NONE,
+                                             &fb_modeset);
+               igt_assert(fb_modeset_id);
+
+               igt_plane_set_fb(primary, &fb_modeset);
+               set_ctm(primary->pipe, ctm_identity);
+               set_degamma(primary->pipe, degamma_linear,
+                           data->coeffs_before_ctm, data->color_depth);
+               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);
+               set_gamma(primary->pipe, gamma_linear,
+                         data->coeffs_after_ctm, data->color_depth);
+               igt_display_commit(&data->display);
+               igt_wait_for_vblank(data->drm_fd, primary->pipe->pipe);
+               igt_pipe_crc_collect_crc(pipe_crc, &crc_fullcolors);
+
+               /* 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);
+               set_gamma(primary->pipe, gamma_full,
+                         data->coeffs_after_ctm, data->color_depth);
+               igt_display_commit(&data->display);
+               igt_wait_for_vblank(data->drm_fd, primary->pipe->pipe);
+               igt_pipe_crc_collect_crc(pipe_crc, &crc_fullgamma);
+
+               /* Verify that the CRC of the software computed output
+                * is equal to the CRC of the gamma LUT
+                * transformation output.
+                */
+               igt_assert_crc_equal(&crc_fullgamma, &crc_fullcolors);
+
+               /* Reset output. */
+               igt_output_set_pipe(output, PIPE_ANY);
+               igt_display_commit(&data->display);
+       }
+
+       /* Reset the gamma ramp. */
+       set_gamma(primary->pipe, gamma_linear,
+                 data->coeffs_before_ctm, data->color_depth);
+       igt_display_commit(&data->display);
+
+       igt_pipe_crc_free(pipe_crc);
+
+       free(degamma_linear);
+       free(gamma_full);
+       free(gamma_linear);
+}
+
+/*
+ * Draw 3 rectangles using before colors, apply the ctm matrix and
+ * verify the CRC is equal to using after colors with an identify ctm
+ * matrix.
+ */
+static void test_pipe_ctm(data_t *data,
+                         igt_plane_t *primary,
+                         color_t *before,
+                         color_t *after,
+                         float *ctm_matrix)
+{
+       igt_output_t *output;
+       igt_pipe_crc_t *pipe_crc;
+       float *degamma_linear, *gamma_linear;
+
+       pipe_crc = igt_pipe_crc_new(primary->pipe->pipe,
+                                   INTEL_PIPE_CRC_SOURCE_AUTO);
+
+       degamma_linear = generate_table(data->coeffs_before_ctm, 1.0);
+       gamma_linear = generate_table(data->coeffs_after_ctm, 1.0);
+
+       for_each_connected_output(&data->display, output) {
+               drmModeModeInfo *mode;
+               struct igt_fb fb_modeset, fb;
+               igt_crc_t crc_software, crc_hardware;
+               int fb_id, fb_modeset_id;
+
+               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->hdisplay,
+                                     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->hdisplay,
+                                             DRM_FORMAT_XRGB8888,
+                                             LOCAL_DRM_FORMAT_MOD_NONE,
+                                             &fb_modeset);
+               igt_assert(fb_modeset_id);
+
+               igt_plane_set_fb(primary, &fb_modeset);
+               set_degamma(primary->pipe, degamma_linear,
+                           data->coeffs_before_ctm, data->color_depth);
+               set_gamma(primary->pipe, gamma_linear,
+                         data->coeffs_after_ctm, data->color_depth);
+               igt_display_commit(&data->display);
+
+               /* No CTM transformation. */
+               paint_rectangles(data, mode, after, &fb);
+               igt_plane_set_fb(primary, &fb);
+               set_ctm(primary->pipe, ctm_identity);
+               igt_display_commit(&data->display);
+               igt_wait_for_vblank(data->drm_fd, primary->pipe->pipe);
+               igt_pipe_crc_collect_crc(pipe_crc, &crc_software);
+
+               /* 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);
+               igt_wait_for_vblank(data->drm_fd, primary->pipe->pipe);
+               igt_pipe_crc_collect_crc(pipe_crc, &crc_hardware);
+
+               /* Verify that the CRC of the software computed output
+                * is equal to the CRC of the CTM matrix
+                * transformation output.
+                */
+               igt_assert_crc_equal(&crc_software, &crc_hardware);
+
+               /* Reset output. */
+               igt_output_set_pipe(output, PIPE_ANY);
+               igt_display_commit(&data->display);
+       }
+
+       /* Reset the CTM matrix. */
+       set_ctm(primary->pipe, ctm_identity);
+       igt_display_commit(&data->display);
+
+       igt_pipe_crc_free(pipe_crc);
+
+       free(degamma_linear);
+       free(gamma_linear);
+}
+
+static void
+run_tests_for_pipe(data_t *data, enum pipe p)
+{
+       igt_pipe_t *pipe;
+       igt_plane_t *primary;
+       color_t red_green_blue[] = {
+               { 1.0, 0.0, 0.0 },
+               { 0.0, 1.0, 0.0 },
+               { 0.0, 0.0, 1.0 }
+       };
+
+       if (p >= data->display.n_pipes)
+               return;
+
+       pipe = &data->display.pipes[p];
+       if (pipe->n_planes < IGT_PLANE_PRIMARY)
+               return;
+
+       primary = &pipe->planes[IGT_PLANE_PRIMARY];
+
+       igt_subtest_f("csc-red-to-blue-pipe%d", p) {
+               color_t blue_green_blue[] = {
+                       { 0.0, 0.0, 1.0 },
+                       { 0.0, 1.0, 0.0 },
+                       { 0.0, 0.0, 1.0 }
+               };
+               float ctm[] = { 0.0, 0.0, 0.0,
+                               0.0, 1.0, 0.0,
+                               1.0, 0.0, 1.0 };
+               test_pipe_ctm(data, primary, red_green_blue,
+                             blue_green_blue, ctm);
+       }
+
+       igt_subtest_f("csc-green-to-red-pipe%d", p) {
+               color_t red_red_blue[] = {
+                       { 1.0, 0.0, 0.0 },
+                       { 1.0, 0.0, 0.0 },
+                       { 0.0, 0.0, 1.0 }
+               };
+               float ctm[] = { 1.0, 1.0, 0.0,
+                               0.0, 0.0, 0.0,
+                               0.0, 0.0, 1.0 };
+               test_pipe_ctm(data, primary, red_green_blue,
+                             red_red_blue, ctm);
+       }
+
+       igt_subtest_f("csc-blue-to-red-pipe%d", p) {
+               color_t red_green_red[] = {
+                       { 1.0, 0.0, 0.0 },
+                       { 0.0, 1.0, 0.0 },
+                       { 1.0, 0.0, 0.0 }
+               };
+               float ctm[] = { 1.0, 0.0, 1.0,
+                               0.0, 1.0, 0.0,
+                               0.0, 0.0, 0.0 };
+               test_pipe_ctm(data, primary, red_green_blue,
+                             red_green_red, ctm);
+       }
+
+       igt_subtest_f("degamma%d", p)
+               test_pipe_degamma(data, primary);
+
+       igt_subtest_f("gamma%d", p)
+               test_pipe_gamma(data, primary);
+}
+
+igt_main
+{
+       data_t data = {};
+
+       igt_skip_on_simulation();
+       igt_fixture {
+               igt_require_pipe_crc();
+
+               data.drm_fd = drm_open_driver_master(DRIVER_INTEL);
+               kmstest_set_vt_graphics_mode();
+
+               igt_display_init(&data.display, data.drm_fd);
+
+               igt_require(igt_pipe_get_property(&data.display.pipes[0],
+                                                 "COEFFICIENTS_AFTER_CTM",
+                                                 NULL,
+                                                 &data.coeffs_after_ctm,
+                                                 NULL));
+               igt_require(igt_pipe_get_property(&data.display.pipes[0],
+                                                 "COEFFICIENTS_BEFORE_CTM",
+                                                 NULL,
+                                                 &data.coeffs_before_ctm,
+                                                 NULL));
+
+               /* We assume an 8bits depth per color framebuffer. */
+               data.color_depth = 8;
+       }
+
+       for (int pipe = 0; pipe < I915_MAX_PIPES; pipe++)
+               run_tests_for_pipe(&data, pipe);
+
+       igt_fixture {
+               igt_display_fini(&data.display);
+       }
+}
-- 
2.6.3

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to