[Intel-gfx] [PATCH i-g-t v2 2/2] chamelium: Add support for VGA frame comparison testing

Paul Kocialkowski paul.kocialkowski at linux.intel.com
Wed Jul 19 12:31:40 UTC 2017


On Mon, 2017-07-17 at 13:35 -0400, Lyude Paul wrote:
> Just one change for this patch below
> 
> On Wed, 2017-07-12 at 17:57 +0300, Paul Kocialkowski wrote:
> > This adds support for VGA frame comparison testing with the
> > reference
> > generated from cairo. The retrieved frame from the chamelium is
> > first
> > cropped, as it contains the blanking intervals, through a dedicated
> > helper. Another helper function asserts that the analogue frame
> > matches or dump it to png if not.
> > 
> > Signed-off-by: Paul Kocialkowski <paul.kocialkowski at linux.intel.com>
> > ---
> >  lib/igt_chamelium.c | 164
> > ++++++++++++++++++++++++++++++++++++++++++++++++++--
> >  lib/igt_chamelium.h |   7 ++-
> >  lib/igt_frame.c     |   6 +-
> >  tests/chamelium.c   |  57 ++++++++++++++++++
> >  4 files changed, 225 insertions(+), 9 deletions(-)
> > 
> > diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> > index df49936b..8701192e 100644
> > --- a/lib/igt_chamelium.c
> > +++ b/lib/igt_chamelium.c
> > @@ -938,6 +938,8 @@ static cairo_surface_t
> > *convert_frame_dump_argb32(const struct chamelium_frame_d
> >         int w = dump->width, h = dump->height;
> >         uint32_t *bits_bgr = (uint32_t *) dump->bgr;
> >         unsigned char *bits_argb;
> > +       unsigned char *bits_target;
> > +       int size;
> >  
> >         image_bgr = pixman_image_create_bits(
> >             PIXMAN_b8g8r8, w, h, bits_bgr,
> > @@ -947,9 +949,13 @@ static cairo_surface_t
> > *convert_frame_dump_argb32(const struct chamelium_frame_d
> >  
> >         bits_argb = (unsigned char *)
> > pixman_image_get_data(image_argb);
> >  
> > -       dump_surface = cairo_image_surface_create_for_data(
> > -           bits_argb, CAIRO_FORMAT_ARGB32, w, h,
> > -           PIXMAN_FORMAT_BPP(PIXMAN_x8r8g8b8) / 8 * w);
> > +       dump_surface = cairo_image_surface_create(
> > +           CAIRO_FORMAT_ARGB32, w, h);
> > +
> > +       bits_target = cairo_image_surface_get_data(dump_surface);
> > +       size = cairo_image_surface_get_stride(dump_surface) * h;
> > +       memcpy(bits_target, bits_argb, size);
> > +       cairo_surface_mark_dirty(dump_surface);
> >  
> >         pixman_image_unref(image_argb);
> >  
> > @@ -1055,6 +1061,154 @@ void chamelium_assert_crc_eq_or_dump(struct
> > chamelium *chamelium,
> >  }
> >  
> >  /**
> > + * chamelium_assert_analogue_frame_match_or_dump:
> > + * @chamelium: The chamelium instance the frame dump belongs to
> > + * @frame: The chamelium frame dump to match
> > + * @fb: pointer to an #igt_fb structure
> > + *
> > + * Asserts that the provided captured frame matches the reference
> > frame from
> > + * the framebuffer. If they do not, this saves the reference and
> > captured frames
> > + * to a png file.
> > + */
> > +void chamelium_assert_analogue_frame_match_or_dump(struct chamelium
> > *chamelium,
> > +                                                  struct
> > chamelium_port *port,
> > +                                                  const struct
> > chamelium_frame_dump *frame,
> > +                                                  struct igt_fb
> > *fb)
> > +{
> > +       cairo_surface_t *reference;
> > +       cairo_surface_t *capture;
> > +       igt_crc_t *reference_crc;
> > +       igt_crc_t *capture_crc;
> > +       char *reference_suffix;
> > +       char *capture_suffix;
> > +       bool match;
> > +
> > +       /* Grab the reference frame from framebuffer */
> > +       reference = igt_get_cairo_surface(chamelium->drm_fd, fb);
> > +
> > +       /* Grab the captured frame from chamelium */
> > +       capture = convert_frame_dump_argb32(frame);
> > +
> > +       match = igt_check_analogue_frame_match(reference, capture);
> > +       if (!match && igt_frame_dump_is_enabled()) {
> > +               reference_crc =
> > chamelium_calculate_fb_crc(chamelium-
> > > drm_fd,
> > 
> > +                                                          fb);
> > +               capture_crc = chamelium_get_crc_for_area(chamelium,
> > port, 0, 0,
> > +                                                        0, 0);
> > +
> > +               reference_suffix =
> > igt_crc_to_string_extended(reference_crc,
> > +                                                             '-',
> > 2);
> > +               capture_suffix =
> > igt_crc_to_string_extended(capture_crc, '-',
> > +                                                           2);
> > +
> > +               /* Write reference and capture frames to png */
> > +               igt_write_compared_frames_to_png(reference, capture,
> > +                                                reference_suffix,
> > +                                                capture_suffix);
> > +
> > +               free(reference_suffix);
> > +               free(capture_suffix);
> > +       }
> > +
> > +       cairo_surface_destroy(capture);
> > +
> > +       igt_assert(match);
> > +}
> > +
> > +
> > +/**
> > + * chamelium_analogue_frame_crop:
> > + * @chamelium: The Chamelium instance to use
> > + * @dump: The chamelium frame dump to crop
> > + * @width: The cropped frame width
> > + * @height: The cropped frame height
> > + *
> > + * Detects the corners of a chamelium frame and crops it to the
> > requested
> > + * width/height. This is useful for VGA frame dumps that also
> > contain the
> > + * pixels dumped during the blanking intervals.
> > + *
> > + * The detection is done on a brightness-threshold-basis, that is
> > adapted
> > + * to the reference frame used by i-g-t. It may not be as relevant
> > for other
> > + * frames.
> > + */
> > +void chamelium_crop_analogue_frame(struct chamelium_frame_dump
> > *dump, int width,
> > +                                  int height)
> > +{
> > +       unsigned char *bgr;
> > +       unsigned char *p;
> > +       unsigned char *q;
> > +       int top, left;
> > +       int x, y, xx, yy;
> > +       int score;
> > +
> > +       if (dump->width == width && dump->height == height)
> > +               return;
> > +
> > +       /* Start with the most bottom-right position. */
> > +       top = dump->height - height;
> > +       left = dump->width - width;
> > +
> > +       igt_assert(top >= 0 && left >= 0);
> > +
> > +       igt_debug("Cropping analogue frame from %dx%d to %dx%d\n",
> > dump->width,
> > +                 dump->height, width, height);
> > +
> > +       /* Detect the top-left corner of the frame. */
> > +       for (x = 0; x < dump->width; x++) {
> > +               for (y = 0; y < dump->height; y++) {
> > +                       p = &dump->bgr[(x + y * dump->width) * 3];
> > +
> > +                       /* Detect significantly bright pixels. */
> > +                       if (p[0] < 50 && p[1] < 50 && p[2] < 50)
> > +                               continue;
> > +
> > +                       /*
> > +                        * Make sure close-by pixels are also
> > significantly
> > +                        * bright.
> > +                        */
> > +                       score = 0;
> > +                       for (xx = x; xx < x + 10; xx++) {
> > +                               for (yy = y; yy < y + 10; yy++) {
> > +                                       p = &dump->bgr[(xx + yy *
> > dump->width) * 3];
> > +
> > +                                       if (p[0] > 50 && p[1] > 50
> > &&
> > p[2] > 50)
> > +                                               score++;
> > +                               }
> > +                       }
> > +
> > +                       /* Not enough pixels are significantly
> > bright. */
> > +                       if (score < 25)
> > +                               continue;
> > +
> > +                       if (x < left)
> > +                               left = x;
> > +
> > +                       if (y < top)
> > +                               top = y;
> > +
> > +                       if (left == x || top == y)
> > +                               continue;
> > +               }
> > +       }
> > +
> > +       igt_debug("Detected analogue frame edges at %dx%d\n", left,
> > top);
> > +
> > +       /* Crop the frame given the detected top-left corner. */
> > +       bgr = malloc(width * height * 3);
> > +
> > +       for (y = 0; y < height; y++) {
> > +               p = &dump->bgr[(left + (top + y) * dump->width) *
> > 3];
> > +               q = &bgr[(y * width) * 3];
> > +               memcpy(q, p, width * 3);
> > +       }
> > +
> > +       free(dump->bgr);
> > +       dump->width = width;
> > +       dump->height = height;
> > +       dump->bgr = bgr;
> > +}
> > +
> > +/**
> >   * chamelium_get_frame_limit:
> >   * @chamelium: The Chamelium instance to use
> >   * @port: The port to check the frame limit on
> > @@ -1480,7 +1634,7 @@ igt_constructor {
> >         /* Frame dumps can be large, so we need to be able to handle
> > very large
> >          * responses
> >          *
> > -        * Limit here is 10MB
> > +        * Limit here is 15MB
> >          */
> > -       xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, 10485760);
> > +       xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, 15728640);
> >  }
> > diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> > index 80afcafa..101e64b6 100644
> > --- a/lib/igt_chamelium.h
> > +++ b/lib/igt_chamelium.h
> > @@ -101,7 +101,6 @@ int chamelium_get_captured_frame_count(struct
> > chamelium *chamelium);
> >  int chamelium_get_frame_limit(struct chamelium *chamelium,
> >                               struct chamelium_port *port,
> >                               int w, int h);
> > -
> >  void chamelium_assert_frame_eq(const struct chamelium *chamelium,
> >                                const struct chamelium_frame_dump
> > *dump,
> >                                struct igt_fb *fb);
> > @@ -109,6 +108,12 @@ void chamelium_assert_crc_eq_or_dump(struct
> > chamelium *chamelium,
> >                                      igt_crc_t *reference_crc,
> >                                      igt_crc_t *capture_crc, struct
> > igt_fb *fb,
> >                                      int index);
> > +void chamelium_assert_analogue_frame_match_or_dump(struct chamelium
> > *chamelium,
> > +                                                  struct
> > chamelium_port *port,
> > +                                                  const struct
> > chamelium_frame_dump *frame,
> > +                                                  struct igt_fb
> > *fb);
> > +void chamelium_crop_analogue_frame(struct chamelium_frame_dump
> > *dump, int width,
> > +                                  int height);
> >  void chamelium_destroy_frame_dump(struct chamelium_frame_dump
> > *dump);
> >  
> >  #endif /* IGT_CHAMELIUM_H */
> > diff --git a/lib/igt_frame.c b/lib/igt_frame.c
> > index dc84fe01..8ca110c9 100644
> > --- a/lib/igt_frame.c
> > +++ b/lib/igt_frame.c
> > @@ -204,13 +204,13 @@ bool
> > igt_check_analogue_frame_match(cairo_surface_t *reference,
> >                         p = &capture_pixels[(x + y * w) * 4];
> >                         q = &reference_pixels[(x + y * w) * 4];
> >  
> > -                       for (i = 1; i < 4; i++) {
> > +                       for (i = 0; i < 3; i++) {
> >                                 diff = (int) p[i] - q[i];
> >                                 if (diff < 0)
> >                                         diff = -diff;
> >  
> > -                               error_count[i-1][q[i-1]][0] += diff;
> > -                               error_count[i-1][q[i-1]][1]++;
> > +                               error_count[i][q[i]][0] += diff;
> > +                               error_count[i][q[i]][1]++;
> 
> Am I missing something? This change seems like it should just be part
> of patch #1 instead of being done afterwards in patch #2.

Woops, looks like I messed this one up when crafting the new version.

Thanks for catching it!

> >                         }
> >                 }
> >         }
> > diff --git a/tests/chamelium.c b/tests/chamelium.c
> > index 89a3bde0..baaa424b 100644
> > --- a/tests/chamelium.c
> > +++ b/tests/chamelium.c
> > @@ -358,6 +358,10 @@ enable_output(data_t *data,
> >                                             BROADCAST_RGB_FULL);
> >  
> >         igt_display_commit(display);
> > +
> > +       if (chamelium_port_get_type(port) == DRM_MODE_CONNECTOR_VGA)
> > +               usleep(250000);
> > +
> >         chamelium_port_wait_video_input_stable(data->chamelium,
> > port,
> >                                                HOTPLUG_TIMEOUT);
> >  
> > @@ -492,6 +496,56 @@ test_display_frame_dump(data_t *data, struct
> > chamelium_port *port)
> >  }
> >  
> >  static void
> > +test_analogue_frame_dump(data_t *data, struct chamelium_port *port)
> > +{
> > +       igt_display_t display;
> > +       igt_output_t *output;
> > +       igt_plane_t *primary;
> > +       struct igt_fb fb;
> > +       struct chamelium_frame_dump *frame;
> > +       drmModeModeInfo *mode;
> > +       drmModeConnector *connector;
> > +       int fb_id, i;
> > +
> > +       output = prepare_output(data, &display, port);
> > +       connector = chamelium_port_get_connector(data->chamelium,
> > port, false);
> > +       primary = igt_output_get_plane_type(output,
> > DRM_PLANE_TYPE_PRIMARY);
> > +       igt_assert(primary);
> > +
> > +       for (i = 0; i < connector->count_modes; i++) {
> > +               mode = &connector->modes[i];
> > +
> > +               fb_id = igt_create_color_pattern_fb(data->drm_fd,
> > +                                                   mode->hdisplay,
> > mode->vdisplay,
> > +                                                   DRM_FORMAT_XRGB8
> > 8
> > 88,
> > +                                                   LOCAL_DRM_FORMAT
> > _
> > MOD_NONE,
> > +                                                   0, 0, 0, &fb);
> > +               igt_assert(fb_id > 0);
> > +
> > +               enable_output(data, port, output, mode, &fb);
> > +
> > +               igt_debug("Reading frame dumps from
> > Chamelium...\n");
> > +
> > +               frame = chamelium_port_dump_pixels(data->chamelium,
> > port, 0, 0,
> > +                                                  0, 0);
> > +
> > +               chamelium_crop_analogue_frame(frame, mode->hdisplay,
> > +                                             mode->vdisplay);
> > +
> > +               chamelium_assert_analogue_frame_match_or_dump(data-
> > > chamelium,
> > 
> > +                                                             port,
> > frame, &fb);
> > +
> > +               chamelium_destroy_frame_dump(frame);
> > +
> > +               disable_output(data, port, output);
> > +               igt_remove_fb(data->drm_fd, &fb);
> > +       }
> > +
> > +       drmModeFreeConnector(connector);
> > +       igt_display_fini(&display);
> > +}
> > +
> > +static void
> >  test_hpd_without_ddc(data_t *data, struct chamelium_port *port)
> >  {
> >         struct udev_monitor *mon = igt_watch_hotplug();
> > @@ -734,6 +788,9 @@ igt_main
> >  
> >                 connector_subtest("vga-hpd-without-ddc", VGA)
> >                         test_hpd_without_ddc(&data, port);
> > +
> > +               connector_subtest("vga-frame-dump", VGA)
> > +                       test_analogue_frame_dump(&data, port);
> >         }
> >  
> >         igt_subtest_group {
> > -- 
> > 2.13.2
> > 
-- 
Paul Kocialkowski <paul.kocialkowski at linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland


More information about the Intel-gfx mailing list