From 007ab1e5a47fdd31e8425b746f07dd4ac3c3e0cc Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 25 Nov 2019 14:54:06 +0200 Subject: [PATCH] tests: add range argument for fuzzy image matching The fuzzy range will be used with GL-renderer testing, as it may produce slightly different images than Pixman-renderer yet still correct results. Such allowed differences are due to different rounding. Signed-off-by: Pekka Paalanen --- tests/internal-screenshot-test.c | 6 +-- tests/subsurface-shot-test.c | 4 +- tests/weston-test-client-helper.c | 62 ++++++++++++++++++++++++++++--- tests/weston-test-client-helper.h | 11 +++++- 4 files changed, 71 insertions(+), 12 deletions(-) diff --git a/tests/internal-screenshot-test.c b/tests/internal-screenshot-test.c index e1a7c43b..6c1b774e 100644 --- a/tests/internal-screenshot-test.c +++ b/tests/internal-screenshot-test.c @@ -141,7 +141,7 @@ TEST(internal_screenshot) /* Test check_images_match() without a clip. * We expect this to fail since we use a bad reference image */ - match = check_images_match(screenshot->image, reference_bad, NULL); + match = check_images_match(screenshot->image, reference_bad, NULL, NULL); testlog("Screenshot %s reference image\n", match? "equal to" : "different from"); assert(!match); pixman_image_unref(reference_bad); @@ -155,10 +155,10 @@ TEST(internal_screenshot) clip.width = 100; clip.height = 100; testlog("Clip: %d,%d %d x %d\n", clip.x, clip.y, clip.width, clip.height); - match = check_images_match(screenshot->image, reference_good, &clip); + match = check_images_match(screenshot->image, reference_good, &clip, NULL); testlog("Screenshot %s reference image in clipped area\n", match? "matches" : "doesn't match"); if (!match) { - diffimg = visualize_image_difference(screenshot->image, reference_good, &clip); + diffimg = visualize_image_difference(screenshot->image, reference_good, &clip, NULL); fname = screenshot_output_filename("internal-screenshot-error", 0); write_image_as_png(diffimg, fname); pixman_image_unref(diffimg); diff --git a/tests/subsurface-shot-test.c b/tests/subsurface-shot-test.c index dcbce0c3..dc11bec0 100644 --- a/tests/subsurface-shot-test.c +++ b/tests/subsurface-shot-test.c @@ -135,7 +135,7 @@ write_visual_diff(pixman_image_t *ref_image, assert(ret >= 0); fname = screenshot_output_filename(ext_test_name, seq_no); - diff = visualize_image_difference(shot->image, ref_image, clip); + diff = visualize_image_difference(shot->image, ref_image, clip, NULL); write_image_as_png(diff, fname); pixman_image_unref(diff); @@ -166,7 +166,7 @@ check_screen(struct client *client, shot = capture_screenshot_of_output(client); assert(shot); - match = check_images_match(shot->image, ref, clip); + match = check_images_match(shot->image, ref, clip, NULL); testlog("ref %s vs. shot %s: %s\n", ref_fname, shot_fname, match ? "PASS" : "FAIL"); diff --git a/tests/weston-test-client-helper.c b/tests/weston-test-client-helper.c index 3fb6b72f..927523cb 100644 --- a/tests/weston-test-client-helper.c +++ b/tests/weston-test-client-helper.c @@ -1077,6 +1077,24 @@ format_pixman2cairo(pixman_format_code_t fmt) assert(0 && "unknown Pixman pixel format"); } +/** + * Validate range + * + * \param r Range to validate or NULL. + * \return The given range, or {0, 0} for NULL. + * + * Will abort if range is invalid, that is a > b. + */ +static struct range +range_get(const struct range *r) +{ + if (!r) + return (struct range){ 0, 0 }; + + assert(r->a <= r->b); + return *r; +} + /** * Compute the ROI for image comparisons * @@ -1157,8 +1175,25 @@ image_iter_get_row(struct image_iterator *it, int y) return (uint32_t *)(it->data + y * it->stride); } +static bool +fuzzy_match_pixels(uint32_t pix_a, uint32_t pix_b, const struct range *fuzz) +{ + int shift; + + for (shift = 0; shift < 32; shift += 8) { + int val_a = (pix_a >> shift) & 0xffu; + int val_b = (pix_b >> shift) & 0xffu; + int d = val_b - val_a; + + if (d < fuzz->a || d > fuzz->b) + return false; + } + + return true; +} + /** - * Test if a given region within two images are pixel-identical. + * Test if a given region within two images are pixel-identical * * Returns true if the two images pixel-wise identical, and false otherwise. * @@ -1166,15 +1201,23 @@ image_iter_get_row(struct image_iterator *it, int y) * \param img_b Second image. * \param clip_rect The region of interest, or NULL for comparing the whole * images. + * \param prec Per-channel allowed difference, or NULL for identical match + * required. * * This function hard-fails if clip_rect is not inside both images. If clip_rect * is given, the images do not have to match in size, otherwise size mismatch * will be a hard failure. + * + * The per-pixel, per-channel difference is computed as img_b - img_a which is + * required to be in the range [prec->a, prec->b] inclusive. The difference is + * signed. All four channels are compared the same way, without any special + * meaning on alpha channel. */ bool check_images_match(pixman_image_t *img_a, pixman_image_t *img_b, - const struct rectangle *clip_rect) + const struct rectangle *clip_rect, const struct range *prec) { + struct range fuzz = range_get(prec); struct image_iterator it_a; struct image_iterator it_b; pixman_box32_t box; @@ -1192,7 +1235,7 @@ check_images_match(pixman_image_t *img_a, pixman_image_t *img_b, pix_b = image_iter_get_row(&it_b, y) + box.x1; for (x = box.x1; x < box.x2; x++) { - if (*pix_a != *pix_b) + if (!fuzzy_match_pixels(*pix_a, *pix_b, &fuzz)) return false; pix_a++; @@ -1232,6 +1275,8 @@ tint(uint32_t src, uint32_t add) * \param img_b Second image. * \param clip_rect The region of interest, or NULL for comparing the whole * images. + * \param prec Per-channel allowed difference, or NULL for identical match + * required. * \return A new image with the differences highlighted. * * Regions outside of the region of interest are shaded with black, matching @@ -1241,11 +1286,18 @@ tint(uint32_t src, uint32_t add) * This function hard-fails if clip_rect is not inside both images. If clip_rect * is given, the images do not have to match in size, otherwise size mismatch * will be a hard failure. + * + * The per-pixel, per-channel difference is computed as img_b - img_a which is + * required to be in the range [prec->a, prec->b] inclusive. The difference is + * signed. All four channels are compared the same way, without any special + * meaning on alpha channel. */ pixman_image_t * visualize_image_difference(pixman_image_t *img_a, pixman_image_t *img_b, - const struct rectangle *clip_rect) + const struct rectangle *clip_rect, + const struct range *prec) { + struct range fuzz = range_get(prec); pixman_image_t *diffimg; pixman_image_t *shade; struct image_iterator it_a; @@ -1288,7 +1340,7 @@ visualize_image_difference(pixman_image_t *img_a, pixman_image_t *img_b, pix_d = image_iter_get_row(&it_d, y) + box.x1; for (x = box.x1; x < box.x2; x++) { - if (*pix_a == *pix_b) + if (fuzzy_match_pixels(*pix_a, *pix_b, &fuzz)) *pix_d = tint(*pix_d, 0x00008000); /* green */ else *pix_d = tint(*pix_d, 0x00c00000); /* red */ diff --git a/tests/weston-test-client-helper.h b/tests/weston-test-client-helper.h index 52e8a560..45e6db93 100644 --- a/tests/weston-test-client-helper.h +++ b/tests/weston-test-client-helper.h @@ -176,6 +176,11 @@ struct rectangle { int height; }; +struct range { + int a; + int b; +}; + struct client * create_client(void); @@ -224,11 +229,13 @@ screenshot_reference_filename(const char *basename, uint32_t seq); bool check_images_match(pixman_image_t *img_a, pixman_image_t *img_b, - const struct rectangle *clip); + const struct rectangle *clip, + const struct range *prec); pixman_image_t * visualize_image_difference(pixman_image_t *img_a, pixman_image_t *img_b, - const struct rectangle *clip_rect); + const struct rectangle *clip_rect, + const struct range *prec); bool write_image_as_png(pixman_image_t *image, const char *fname);