[Intel-gfx] [PATCH 4/4] tests/kms_color: New test for color management
Lionel Landwerlin
lionel.g.landwerlin at intel.com
Thu Dec 17 08:31:50 PST 2015
This test enables testing of :
* degamma LUTs
* csc matrix
* gamma LUTs
Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin at 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
More information about the Intel-gfx
mailing list