[igt-dev] [PATCH i-g-t 2/2] tests/kms_color_chamelium: add subtests to validate color.
Arkadiusz Hiler
arkadiusz.hiler at intel.com
Wed Jan 15 09:59:52 UTC 2020
On Tue, Jan 14, 2020 at 07:05:04PM +0530, Kunal Joshi wrote:
> 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 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 | 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));
Is there any practical reason that you are capturing two frames and then
compareing them in this way?
There's chamelium_assert_frame_match_or_dump() which you can use to
compare against a reference fb without the need to display it first.
The added bonus is that it handles a lot of edge cases for you and dumps
the frame in case of a mismatch.
--
Cheers,
Arek
More information about the igt-dev
mailing list