[PATCH weston 08/11] tests: convert reference image loader to pixman

Pekka Paalanen ppaalanen at gmail.com
Thu Jun 16 14:13:27 UTC 2016


From: Pekka Paalanen <pekka.paalanen at collabora.co.uk>

This rewrites load_surface_from_png() to load_image_from_png(), to
return a pixman_image_t instead of a struct surface.

A loaded image has no need for wl_buffer or wl_surface or any of the
associated attributes. This is part of unifying to make everything use
pixman_image_t.

cairo_surface_flush() is added, because Cairo documentation for
cairo_image_surface_get_data() says you have to flush after drawing,
before using the data. It is unclear if loading a PNG counts as drawing,
so stay on the safe side.

load_image_from_png() now pays attention to the pixel format returned by
Cairo, which seems to come out as CAIRO_FORMAT_RGB24 in
internal-screenshot-test, not as CAIRO_FORMAT_ARGB32 as expected. I do
not know if Cairo actually guarantees the x8/a8 channel to be 0xff for
RGB24, but better to not trust it. Therefore the image is explicitly
converted to a8r8g8b8 as needed. This also adds support for loading A8
and RGB16_565 images, provided that Cairo delivers them.

The cairo surface is now wrapped directly into a pixman_image_t. If the
pixel format conversion is not needed, this eliminates a copy of the
image data. The Cairo surface will get automatically destroyed with the
Pixman image.

Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
 tests/internal-screenshot-test.c  |  19 +++---
 tests/weston-test-client-helper.c | 127 ++++++++++++++++++++++++++------------
 tests/weston-test-client-helper.h |   4 +-
 3 files changed, 96 insertions(+), 54 deletions(-)

diff --git a/tests/internal-screenshot-test.c b/tests/internal-screenshot-test.c
index c584d26..51072a6 100644
--- a/tests/internal-screenshot-test.c
+++ b/tests/internal-screenshot-test.c
@@ -66,8 +66,8 @@ TEST(internal_screenshot)
 	struct client *client;
 	struct wl_surface *surface;
 	struct surface *screenshot = NULL;
-	struct surface *reference_good = NULL;
-	struct surface *reference_bad = NULL;
+	pixman_image_t *reference_good = NULL;
+	pixman_image_t *reference_bad = NULL;
 	struct rectangle clip;
 	const char *fname;
 	bool match = false;
@@ -93,24 +93,23 @@ TEST(internal_screenshot)
 	/* Load good reference image */
 	fname = screenshot_reference_filename("internal-screenshot-good", 0);
 	printf("Loading good reference image %s\n", fname);
-	reference_good = load_surface_from_png(fname);
+	reference_good = load_image_from_png(fname);
 	assert(reference_good);
 
 	/* Load bad reference image */
 	fname = screenshot_reference_filename("internal-screenshot-bad", 0);
 	printf("Loading bad reference image %s\n", fname);
-	reference_bad = load_surface_from_png(fname);
+	reference_bad = load_image_from_png(fname);
 	assert(reference_bad);
 
 	/* Test check_images_match() without a clip.
 	 * We expect this to fail since we use a bad reference image
 	 */
 	match = check_images_match(screenshot->buffer->image,
-				   reference_bad->buffer->image, NULL);
+				   reference_bad, NULL);
 	printf("Screenshot %s reference image\n", match? "equal to" : "different from");
 	assert(!match);
-	buffer_destroy(reference_bad->buffer);
-	free(reference_bad);
+	pixman_image_unref(reference_bad);
 
 	/* Test check_images_match() with clip.
 	 * Alpha-blending and other effects can cause irrelevant discrepancies, so look only
@@ -122,11 +121,9 @@ TEST(internal_screenshot)
 	clip.height = 100;
 	printf("Clip: %d,%d %d x %d\n", clip.x, clip.y, clip.width, clip.height);
 	match = check_images_match(screenshot->buffer->image,
-				   reference_good->buffer->image,
-				   &clip);
+				   reference_good, &clip);
 	printf("Screenshot %s reference image in clipped area\n", match? "matches" : "doesn't match");
-	buffer_destroy(reference_good->buffer);
-	free(reference_good);
+	pixman_image_unref(reference_good);
 
 	/* Test dumping of non-matching images */
 	if (!match || dump_all_images) {
diff --git a/tests/weston-test-client-helper.c b/tests/weston-test-client-helper.c
index 53b8d80..67ef4b4 100644
--- a/tests/weston-test-client-helper.c
+++ b/tests/weston-test-client-helper.c
@@ -967,6 +967,30 @@ screenshot_reference_filename(const char *basename, uint32_t seq)
 	return filename;
 }
 
+struct format_map_entry {
+	cairo_format_t cairo;
+	pixman_format_code_t pixman;
+};
+
+static const struct format_map_entry format_map[] = {
+	{ CAIRO_FORMAT_ARGB32,    PIXMAN_a8r8g8b8 },
+	{ CAIRO_FORMAT_RGB24,     PIXMAN_x8r8g8b8 },
+	{ CAIRO_FORMAT_A8,        PIXMAN_a8 },
+	{ CAIRO_FORMAT_RGB16_565, PIXMAN_r5g6b5 },
+};
+
+static pixman_format_code_t
+format_cairo2pixman(cairo_format_t fmt)
+{
+	unsigned i;
+
+	for (i = 0; i < ARRAY_LENGTH(format_map); i++)
+		if (format_map[i].cairo == fmt)
+			return format_map[i].pixman;
+
+	assert(0 && "unknown Cairo pixel format");
+}
+
 /**
  * Compute the ROI for image comparisons
  *
@@ -1126,25 +1150,63 @@ write_surface_as_png(const struct surface *weston_surface, const char *fname)
 	return true;
 }
 
-/** load_surface_from_png()
+static pixman_image_t *
+image_convert_to_a8r8g8b8(pixman_image_t *image)
+{
+	pixman_image_t *ret;
+	int width;
+	int height;
+
+	if (pixman_image_get_format(image) == PIXMAN_a8r8g8b8)
+		return pixman_image_ref(image);
+
+	width = pixman_image_get_width(image);
+	height = pixman_image_get_height(image);
+
+	ret = pixman_image_create_bits_no_clear(PIXMAN_a8r8g8b8, width, height,
+						NULL, 0);
+	assert(ret);
+
+	pixman_image_composite32(PIXMAN_OP_SRC, image, NULL, ret,
+				 0, 0, 0, 0, 0, 0, width, height);
+
+	return ret;
+}
+
+static void
+destroy_cairo_surface(pixman_image_t *image, void *data)
+{
+	cairo_surface_t *surface = data;
+
+	cairo_surface_destroy(surface);
+}
+
+/**
+ * Load an image from a PNG file
  *
  * Reads a PNG image from disk using the given filename (and path)
- * and returns as a freshly allocated weston test surface.
+ * and returns as a Pixman image. Use pixman_image_unref() to free it.
+ *
+ * The returned image is always in PIXMAN_a8r8g8b8 format.
  *
- * @returns weston test surface with image, which should be free'd
- * when no longer used; or, NULL in case of error.
+ * @returns Pixman image, or NULL in case of error.
  */
-struct surface *
-load_surface_from_png(const char *fname)
+pixman_image_t *
+load_image_from_png(const char *fname)
 {
-	struct surface *reference;
+	pixman_image_t *image;
+	pixman_image_t *converted;
+	cairo_format_t cairo_fmt;
+	pixman_format_code_t pixman_fmt;
 	cairo_surface_t *reference_cairo_surface;
 	cairo_status_t status;
-	size_t source_data_size;
-	int bpp;
+	int width;
+	int height;
 	int stride;
+	void *data;
 
 	reference_cairo_surface = cairo_image_surface_create_from_png(fname);
+	cairo_surface_flush(reference_cairo_surface);
 	status = cairo_surface_status(reference_cairo_surface);
 	if (status != CAIRO_STATUS_SUCCESS) {
 		printf("Could not open %s: %s\n", fname, cairo_status_to_string(status));
@@ -1152,43 +1214,26 @@ load_surface_from_png(const char *fname)
 		return NULL;
 	}
 
-	/* Disguise the cairo surface in a weston test surface */
-	reference = zalloc(sizeof *reference);
-	if (reference == NULL) {
-		perror("zalloc reference");
-		cairo_surface_destroy(reference_cairo_surface);
-		return NULL;
-	}
-	reference->width = cairo_image_surface_get_width(reference_cairo_surface);
-	reference->height = cairo_image_surface_get_height(reference_cairo_surface);
-	stride = cairo_image_surface_get_stride(reference_cairo_surface);
-	source_data_size = stride * reference->height;
+	cairo_fmt = cairo_image_surface_get_format(reference_cairo_surface);
+	pixman_fmt = format_cairo2pixman(cairo_fmt);
 
-	/* Check that the file's stride matches our assumption */
-	bpp = 4;
-	if (stride != bpp * reference->width) {
-		printf("Mismatched stride for screenshot reference image %s\n", fname);
-		cairo_surface_destroy(reference_cairo_surface);
-		free(reference);
-		return NULL;
-	}
+	width = cairo_image_surface_get_width(reference_cairo_surface);
+	height = cairo_image_surface_get_height(reference_cairo_surface);
+	stride = cairo_image_surface_get_stride(reference_cairo_surface);
+	data = cairo_image_surface_get_data(reference_cairo_surface);
 
-	/* Allocate new buffer for our weston reference, and copy the data from
-	   the cairo surface so we can destroy it */
+	/* The Cairo surface will own the data, so we keep it around. */
+	image = pixman_image_create_bits_no_clear(pixman_fmt,
+						  width, height, data, stride);
+	assert(image);
 
-	reference->buffer = xzalloc(sizeof *reference->buffer);
-	reference->buffer->image = pixman_image_create_bits(PIXMAN_a8r8g8b8,
-							    reference->width,
-							    reference->height,
-							    NULL, 0);
-	assert(reference->buffer->image);
+	pixman_image_set_destroy_function(image, destroy_cairo_surface,
+					  reference_cairo_surface);
 
-	memcpy(pixman_image_get_data(reference->buffer->image),
-	       cairo_image_surface_get_data(reference_cairo_surface),
-	       source_data_size);
+	converted = image_convert_to_a8r8g8b8(image);
+	pixman_image_unref(image);
 
-	cairo_surface_destroy(reference_cairo_surface);
-	return reference;
+	return converted;
 }
 
 /** create_screenshot_surface()
diff --git a/tests/weston-test-client-helper.h b/tests/weston-test-client-helper.h
index 4910136..e74e835 100644
--- a/tests/weston-test-client-helper.h
+++ b/tests/weston-test-client-helper.h
@@ -204,8 +204,8 @@ check_images_match(pixman_image_t *img_a, pixman_image_t *img_b,
 bool
 write_surface_as_png(const struct surface *weston_surface, const char *fname);
 
-struct surface *
-load_surface_from_png(const char *fname);
+pixman_image_t *
+load_image_from_png(const char *fname);
 
 struct surface *
 create_screenshot_surface(struct client *client);
-- 
2.7.3



More information about the wayland-devel mailing list