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@xxxxxxxxxxxxxxx> --- 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]++; } } } 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_XRGB8888, + 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 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx