[igt-dev] [PATCH i-g-t v2 2/2] tests/kms_color_chamelium: add subtests to validate color.

Shankar, Uma uma.shankar at intel.com
Mon Jan 20 07:38:56 UTC 2020



> -----Original Message-----
> From: Joshi, Kunal1 <kunal1.joshi at intel.com>
> Sent: Thursday, January 16, 2020 11:50 AM
> To: igt-dev at lists.freedesktop.org
> Cc: Latvala, Petri <petri.latvala at intel.com>; Hiler, Arkadiusz
> <arkadiusz.hiler at intel.com>; Vetter, Daniel <daniel.vetter at intel.com>; Shankar,
> Uma <uma.shankar at intel.com>; Sharma, Swati2 <swati2.sharma at intel.com>;
> Syrjala, Ville <ville.syrjala at intel.com>; Joshi, Kunal1 <kunal1.joshi at intel.com>
> Subject: [PATCH i-g-t v2 2/2] tests/kms_color_chamelium: add subtests to validate
> color.
> 
> 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.
> 
> (v2)
>         Comparing framedump with framebuffer reference instead of
>         comparing two framedump.
> 
> Signed-off-by: Kunal Joshi <kunal1.joshi at intel.com>
> Signed-off-by: Swati Sharma <swati2.sharma at intel.com>
> Suggested-by: Uma Shankar <uma.shankar at intel.com>
> ---
>  tests/Makefile.am           |    1 +
>  tests/kms_color_chamelium.c | 1130
> +++++++++++++++++++++++++++++++++++++++++++
>  tests/meson.build           |    1 +
>  3 files changed, 1132 insertions(+)
>  create mode 100644 tests/kms_color_chamelium.c
> 
> diff --git a/tests/Makefile.am b/tests/Makefile.am index fc30524..50fc989 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..ee0c6c5
> --- /dev/null
> +++ b/tests/kms_color_chamelium.c
> @@ -0,0 +1,1130 @@
> +/*
> + * 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");
> +

This new file duplicates many functions from kms_color, can you create a header file
and export those so that we can avoid the duplicacy.

> +/* 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)
> +{
> +	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, fbref;
> +		struct chamelium_frame_dump *frame_fullcolors;
> +		int fb_id, fb_modeset_id, fbref_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);
> +
> +		fbref_id = igt_create_fb(data->drm_fd,
> +					      mode->hdisplay,
> +					      mode->vdisplay,
> +					      DRM_FORMAT_XRGB8888,
> +					      LOCAL_DRM_FORMAT_MOD_NONE,
> +					      &fbref);
> +		igt_assert(fbref_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, &fbref);
> +
> +		/* 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 framebuffer reference of the software
> +		 * computed output is equal to the frame dump of the degamma
> +		 * LUT transformation output.
> +		 */
> +		igt_assert(chamelium_frame_match_or_dump(data->chamelium,
> port,
> +							 frame_fullcolors,
> +							 &fbref,
> +
> CHAMELIUM_CHECK_ANALOG));
> +
> +		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, fbref;
> +		struct chamelium_frame_dump *frame_fullcolors;
> +		int fb_id, fb_modeset_id, fbref_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);
> +
> +		fbref_id = igt_create_fb(data->drm_fd,
> +				      mode->hdisplay,
> +				      mode->vdisplay,
> +				      DRM_FORMAT_XRGB8888,
> +				      LOCAL_DRM_FORMAT_MOD_NONE,
> +				      &fbref);
> +		igt_assert(fbref_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, &fbref);
> +
> +		/* 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 framebuffer reference of the software
> +		 * computed output is equal to the frame dump of the
> +		 * degamma LUT transformation output.
> +		 */
> +		igt_assert(chamelium_frame_match_or_dump(data->chamelium,
> port,
> +							 frame_fullcolors,
> +							 &fbref,
> +
> CHAMELIUM_CHECK_ANALOG));
> +
> +		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)
> +{
> +	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, fbref;
> +		struct chamelium_frame_dump *frame_hardware;
> +		int fb_id, fb_modeset_id, fbref_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);
> +
> +		fbref_id = igt_create_fb(data->drm_fd,
> +				      mode->hdisplay,
> +				      mode->vdisplay,
> +				      DRM_FORMAT_XRGB8888,
> +				      LOCAL_DRM_FORMAT_MOD_NONE,
> +				      &fbref);
> +		igt_assert(fbref_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, &fbref);
> +
> +		/* 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 framebuffer reference of the software
> +		 * computed output is equal to the frame dump of the CTM
> +		 * matrix transformation output.
> +		 */
> +		ret &= chamelium_frame_match_or_dump(data->chamelium, port,
> +						     frame_hardware,
> +						     &fbref,
> +						     CHAMELIUM_CHECK_ANALOG);
> +
> +		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, fbref;
> +		struct chamelium_frame_dump *frame_limited;
> +		int fb_id, fb_modeset_id, fbref_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);
> +
> +		fbref_id = igt_create_fb(data->drm_fd,
> +				      mode->hdisplay,
> +				      mode->vdisplay,
> +				      DRM_FORMAT_XRGB8888,
> +				      LOCAL_DRM_FORMAT_MOD_NONE,
> +				      &fbref);
> +		igt_assert(fbref_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);
> +
> +		/* 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 framebuffer reference of the software
> +		 * computed output is equal to the frame dump of the CTM
> +		 * matrix transformation output.
> +		 */
> +		igt_assert(chamelium_frame_match_or_dump(data->chamelium,
> port,
> +							 frame_limited,
> +							 &fbref,
> +
> CHAMELIUM_CHECK_ANALOG));
> +
> +	}
> +
> +	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 a79d22b..a10854f 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -255,6 +255,7 @@ endif
>  if chamelium.found()
>  	test_progs += [
>  		'kms_chamelium',
> +		'kms_color_chamelium',
>  	]
>  	test_deps += chamelium
>  endif
> --
> 2.7.4



More information about the igt-dev mailing list