blob: 6038e1d044b4729fa4444e3a6f0a9d18c909bd0c [file] [log] [blame]
Bryce Harringtonfb9089d2014-11-04 16:39:38 -08001/*
2 * Copyright © 2015 Samsung Electronics Co., Ltd
3 *
Bryce Harrington2cc92972015-06-11 15:39:40 -07004 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
Bryce Harringtonfb9089d2014-11-04 16:39:38 -080011 *
Bryce Harrington2cc92972015-06-11 15:39:40 -070012 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
Bryce Harringtonfb9089d2014-11-04 16:39:38 -080024 */
25
26#include "config.h"
27
28#include <unistd.h>
29#include <stdio.h>
30#include <string.h> /* memcpy */
31#include <cairo.h>
32
33#include "weston-test-client-helper.h"
34
35char *server_parameters="--use-pixman --width=320 --height=240";
36
Bryce Harrington85e65f52015-05-14 12:21:13 -070037/** write_surface_as_png()
38 *
39 * Writes out a given weston test surface to disk as a PNG image
40 * using the provided filename (with path).
41 *
42 * @returns true if successfully saved file; false otherwise.
43 */
44static bool
45write_surface_as_png(const struct surface* weston_surface, const char *fname) {
46 cairo_surface_t *cairo_surface;
47 cairo_status_t status;
48 int bpp = 4; /* Assume ARGB */
49 int stride = bpp * weston_surface->width;
50
51 cairo_surface = cairo_image_surface_create_for_data(weston_surface->data,
52 CAIRO_FORMAT_ARGB32,
53 weston_surface->width,
54 weston_surface->height,
55 stride);
56 printf("Writing PNG to disk\n");
57 status = cairo_surface_write_to_png(cairo_surface, fname);
58 if (status != CAIRO_STATUS_SUCCESS) {
59 printf("Failed to save screenshot: %s\n",
60 cairo_status_to_string(status));
61 return false;
62 }
63 cairo_surface_destroy(cairo_surface);
64 return true;
65}
66
Bryce Harrington198f9412015-05-14 14:18:56 -070067/** load_surface_from_png()
68 *
69 * Reads a PNG image from disk using the given filename (and path)
70 * and returns as a freshly allocated weston test surface.
71 *
72 * @returns weston test surface with image, which should be free'd
73 * when no longer used; or, NULL in case of error.
74 */
75static struct surface*
76load_surface_from_png(const char *fname) {
77 struct surface *reference;
78 cairo_surface_t *reference_cairo_surface;
79 cairo_status_t status;
80 size_t source_data_size;
Bryce Harringtonc9198832015-05-21 11:53:54 -070081 int bpp;
Bryce Harrington198f9412015-05-14 14:18:56 -070082 int stride;
83
Bryce Harrington198f9412015-05-14 14:18:56 -070084 reference_cairo_surface = cairo_image_surface_create_from_png(fname);
85 status = cairo_surface_status(reference_cairo_surface);
86 if (status != CAIRO_STATUS_SUCCESS) {
87 printf("Could not open %s: %s\n", fname, cairo_status_to_string(status));
88 cairo_surface_destroy(reference_cairo_surface);
89 return NULL;
90 }
91
92 /* Disguise the cairo surface in a weston test surface */
93 reference = xzalloc(sizeof *reference);
94 if (reference == NULL) {
95 perror("xzalloc reference");
96 cairo_surface_destroy(reference_cairo_surface);
97 return NULL;
98 }
99 reference->width = cairo_image_surface_get_width(reference_cairo_surface);
100 reference->height = cairo_image_surface_get_height(reference_cairo_surface);
101 stride = cairo_image_surface_get_stride(reference_cairo_surface);
102 source_data_size = stride * reference->height;
103
Bryce Harringtonc9198832015-05-21 11:53:54 -0700104 /* Check that the file's stride matches our assumption */
105 bpp = 4;
106 if (stride != bpp * reference->width) {
107 printf("Mismatched stride for screenshot reference image %s\n", fname);
108 cairo_surface_destroy(reference_cairo_surface);
109 free(reference);
110 return NULL;
111 }
112
Bryce Harrington198f9412015-05-14 14:18:56 -0700113 /* Allocate new buffer for our weston reference, and copy the data from
114 the cairo surface so we can destroy it */
115 reference->data = xzalloc(source_data_size);
116 if (reference->data == NULL) {
117 perror("xzalloc reference data");
118 cairo_surface_destroy(reference_cairo_surface);
119 free(reference);
120 return NULL;
121 }
122 memcpy(reference->data,
123 cairo_image_surface_get_data(reference_cairo_surface),
124 source_data_size);
125
126 cairo_surface_destroy(reference_cairo_surface);
127 return reference;
128}
129
Bryce Harrington2eaf7d72015-05-14 12:50:00 -0700130/** create_screenshot_surface()
131 *
132 * Allocates and initializes a weston test surface for use in
133 * storing a screenshot of the client's output. Establishes a
134 * shm backed wl_buffer for retrieving screenshot image data
135 * from the server, sized to match the client's output display.
136 *
137 * @returns stack allocated surface image, which should be
138 * free'd when done using it.
139 */
140static struct surface*
141create_screenshot_surface(struct client *client) {
142 struct surface* screenshot;
143 screenshot = xzalloc(sizeof *screenshot);
144 if (screenshot == NULL)
145 return NULL;
Bryce Harrington0ccf8e22015-05-21 15:03:50 -0700146 screenshot->wl_buffer = create_shm_buffer(client,
147 client->output->width,
148 client->output->height,
149 &screenshot->data);
150 screenshot->height = client->output->height;
151 screenshot->width = client->output->width;
Bryce Harrington2eaf7d72015-05-14 12:50:00 -0700152
153 return screenshot;
154}
155
Bryce Harrington111e0222015-05-14 15:07:55 -0700156/** capture_screenshot_of_output()
157 *
158 * Requests a screenshot from the server of the output that the
159 * client appears on. The image data returned from the server
160 * can be accessed from the screenshot surface's data member.
161 *
162 * @returns a new surface object, which should be free'd when no
163 * longer needed.
164 */
165static struct surface *
166capture_screenshot_of_output(struct client *client) {
167 struct surface *screenshot;
168
169 /* Create a surface to hold the screenshot */
170 screenshot = create_screenshot_surface(client);
171
172 client->test->buffer_copy_done = 0;
173 weston_test_capture_screenshot(client->test->weston_test,
174 client->output->wl_output,
175 screenshot->wl_buffer);
176 while (client->test->buffer_copy_done == 0)
177 if (wl_display_dispatch(client->wl_display) < 0)
178 break;
179
180 /* FIXME: Document somewhere the orientation the screenshot is taken
181 * and how the clip coords are interpreted, in case of scaling/transform.
182 * If we're using read_pixels() just make sure it is documented somewhere.
183 * Protocol docs in the XML, comparison function docs in Doxygen style.
184 */
185
186 return screenshot;
187}
188
Derek Foreman35b7f252015-05-25 15:19:38 -0500189static void
Derek Foreman97b9b172015-05-26 12:00:49 -0500190draw_stuff(void *pixels, int w, int h)
Derek Foreman35b7f252015-05-25 15:19:38 -0500191{
192 int x, y;
Derek Foreman97b9b172015-05-26 12:00:49 -0500193 uint8_t r, g, b;
194 uint32_t *pixel;
Derek Foreman35b7f252015-05-25 15:19:38 -0500195
196 for (x = 0; x < w; x++)
197 for (y = 0; y < h; y++) {
Derek Foreman97b9b172015-05-26 12:00:49 -0500198 b = x;
199 g = x + y;
200 r = y;
201 pixel = (uint32_t *)pixels + y * w + x;
202 *pixel = (255 << 24) | (r << 16) | (g << 8) | b;
Derek Foreman35b7f252015-05-25 15:19:38 -0500203 }
204}
205
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800206TEST(internal_screenshot)
207{
Derek Foreman35b7f252015-05-25 15:19:38 -0500208 struct wl_buffer *buf;
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800209 struct client *client;
Derek Foreman35b7f252015-05-25 15:19:38 -0500210 struct wl_surface *surface;
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800211 struct surface *screenshot = NULL;
Derek Foreman35b7f252015-05-25 15:19:38 -0500212 struct surface *reference_good = NULL;
213 struct surface *reference_bad = NULL;
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800214 struct rectangle clip;
215 const char *fname;
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800216 bool match = false;
217 bool dump_all_images = true;
Derek Foreman35b7f252015-05-25 15:19:38 -0500218 void *pixels;
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800219
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800220 /* Create the client */
Bryce Harrington111e0222015-05-14 15:07:55 -0700221 printf("Creating client for test\n");
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800222 client = create_client_and_test_surface(100, 100, 100, 100);
223 assert(client);
Derek Foreman35b7f252015-05-25 15:19:38 -0500224 surface = client->surface->wl_surface;
225
226 buf = create_shm_buffer(client, 100, 100, &pixels);
227 draw_stuff(pixels, 100, 100);
228 wl_surface_attach(surface, buf, 0, 0);
229 wl_surface_damage(surface, 0, 0, 100, 100);
230 wl_surface_commit(surface);
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800231
232 /* Take a snapshot. Result will be in screenshot->wl_buffer. */
Bryce Harrington111e0222015-05-14 15:07:55 -0700233 printf("Taking a screenshot\n");
234 screenshot = capture_screenshot_of_output(client);
235 assert(screenshot);
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800236
Derek Foreman35b7f252015-05-25 15:19:38 -0500237 /* Load good reference image */
238 fname = screenshot_reference_filename("internal-screenshot-good", 0);
239 printf("Loading good reference image %s\n", fname);
240 reference_good = load_surface_from_png(fname);
241 assert(reference_good);
242
243 /* Load bad reference image */
244 fname = screenshot_reference_filename("internal-screenshot-bad", 0);
245 printf("Loading bad reference image %s\n", fname);
246 reference_bad = load_surface_from_png(fname);
247 assert(reference_bad);
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800248
249 /* Test check_surfaces_equal()
Derek Foreman35b7f252015-05-25 15:19:38 -0500250 * We expect this to fail since we use a bad reference image
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800251 */
Derek Foreman35b7f252015-05-25 15:19:38 -0500252 match = check_surfaces_equal(screenshot, reference_bad);
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800253 printf("Screenshot %s reference image\n", match? "equal to" : "different from");
254 assert(!match);
Derek Foreman35b7f252015-05-25 15:19:38 -0500255 free(reference_bad->data);
256 free(reference_bad);
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800257
258 /* Test check_surfaces_match_in_clip()
259 * Alpha-blending and other effects can cause irrelevant discrepancies, so look only
260 * at a small portion of the solid-colored background
261 */
Derek Foreman35b7f252015-05-25 15:19:38 -0500262 clip.x = 100;
263 clip.y = 100;
264 clip.width = 100;
265 clip.height = 100;
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800266 printf("Clip: %d,%d %d x %d\n", clip.x, clip.y, clip.width, clip.height);
Derek Foreman35b7f252015-05-25 15:19:38 -0500267 match = check_surfaces_match_in_clip(screenshot, reference_good,
268 &clip);
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800269 printf("Screenshot %s reference image in clipped area\n", match? "matches" : "doesn't match");
Derek Foreman35b7f252015-05-25 15:19:38 -0500270 free(reference_good->data);
271 free(reference_good);
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800272
273 /* Test dumping of non-matching images */
274 if (!match || dump_all_images) {
Bryce Harrington85e65f52015-05-14 12:21:13 -0700275 fname = screenshot_output_filename("internal-screenshot", 0);
276 write_surface_as_png(screenshot, fname);
Bryce Harringtonfb9089d2014-11-04 16:39:38 -0800277 }
278
279 free(screenshot);
280
281 printf("Test complete\n");
282 assert(match);
283}