From patchwork Wed Jul 19 13:48:09 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowki X-Patchwork-Id: 9852053 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 48AE9602BD for ; Wed, 19 Jul 2017 13:48:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3787F285BE for ; Wed, 19 Jul 2017 13:48:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2C68828675; Wed, 19 Jul 2017 13:48:46 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 66A85285BE for ; Wed, 19 Jul 2017 13:48:45 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 0AF056E521; Wed, 19 Jul 2017 13:48:45 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by gabe.freedesktop.org (Postfix) with ESMTPS id AD1DF6E51D for ; Wed, 19 Jul 2017 13:48:43 +0000 (UTC) Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 19 Jul 2017 06:48:43 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos; i="5.40,381,1496127600"; d="scan'208"; a="1174390144" Received: from linux.intel.com ([10.54.29.200]) by fmsmga001.fm.intel.com with ESMTP; 19 Jul 2017 06:48:26 -0700 Received: from workstation.fi.intel.com (workstation.fi.intel.com [10.237.68.144]) by linux.intel.com (Postfix) with ESMTP id 9A93C58037A; Wed, 19 Jul 2017 06:48:21 -0700 (PDT) From: Paul Kocialkowski To: intel-gfx@lists.freedesktop.org Date: Wed, 19 Jul 2017 16:48:09 +0300 Message-Id: <20170719134809.8446-3-paul.kocialkowski@linux.intel.com> X-Mailer: git-send-email 2.13.2 In-Reply-To: <20170719134809.8446-1-paul.kocialkowski@linux.intel.com> References: <20170706132614.4163-1-paul.kocialkowski@linux.intel.com> <20170719134809.8446-1-paul.kocialkowski@linux.intel.com> Subject: [Intel-gfx] [PATCH i-g-t v3 2/2] chamelium: Add support for VGA frame comparison testing X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP 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 analog frame matches or dump it to png if not. Signed-off-by: Paul Kocialkowski --- lib/igt_chamelium.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++-- lib/igt_chamelium.h | 7 ++- tests/chamelium.c | 57 ++++++++++++++++++ 3 files changed, 222 insertions(+), 6 deletions(-) diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c index 348d2176..dcd8855f 100644 --- a/lib/igt_chamelium.c +++ b/lib/igt_chamelium.c @@ -937,6 +937,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, @@ -946,9 +948,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); @@ -1054,6 +1060,154 @@ void chamelium_assert_crc_eq_or_dump(struct chamelium *chamelium, } /** + * chamelium_assert_analog_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_analog_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_analog_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_analog_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_analog_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 analog 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 analog 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..2a0fa234 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_analog_frame_match_or_dump(struct chamelium *chamelium, + struct chamelium_port *port, + const struct chamelium_frame_dump *frame, + struct igt_fb *fb); +void chamelium_crop_analog_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/tests/chamelium.c b/tests/chamelium.c index 34448152..33ecc2e7 100644 --- a/tests/chamelium.c +++ b/tests/chamelium.c @@ -399,6 +399,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); @@ -533,6 +537,56 @@ test_display_frame_dump(data_t *data, struct chamelium_port *port) } static void +test_analog_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_analog_frame(frame, mode->hdisplay, + mode->vdisplay); + + chamelium_assert_analog_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(); @@ -775,6 +829,9 @@ igt_main connector_subtest("vga-hpd-without-ddc", VGA) test_hpd_without_ddc(&data, port); + + connector_subtest("vga-frame-dump", VGA) + test_analog_frame_dump(&data, port); } igt_subtest_group {