1428d7b3dSmrg/*
2428d7b3dSmrg * Copyright © 2009 Nokia Corporation
3428d7b3dSmrg * Copyright © 2010 Movial Creative Technologies Oy
4428d7b3dSmrg * Copyright © 2013 Intel Corporation
5428d7b3dSmrg *
6428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
7428d7b3dSmrg * copy of this software and associated documentation files (the "Software"),
8428d7b3dSmrg * to deal in the Software without restriction, including without limitation
9428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the
11428d7b3dSmrg * Software is furnished to do so, subject to the following conditions:
12428d7b3dSmrg *
13428d7b3dSmrg * The above copyright notice and this permission notice (including the next
14428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the
15428d7b3dSmrg * Software.
16428d7b3dSmrg *
17428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22428d7b3dSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23428d7b3dSmrg * DEALINGS IN THE SOFTWARE.
24428d7b3dSmrg */
25428d7b3dSmrg
26428d7b3dSmrg#ifdef HAVE_CONFIG_H
27428d7b3dSmrg#include "config.h"
28428d7b3dSmrg#endif
29428d7b3dSmrg
30428d7b3dSmrg#include <stdio.h>
31428d7b3dSmrg#include <stdlib.h>
32428d7b3dSmrg#include <string.h>
33428d7b3dSmrg#include <stdint.h>
34428d7b3dSmrg#include <stdbool.h>
35428d7b3dSmrg
36428d7b3dSmrg#include <X11/X.h>
37428d7b3dSmrg#include <X11/Xutil.h> /* for XDestroyImage */
38428d7b3dSmrg#include <X11/Xlibint.h>
39428d7b3dSmrg#include <X11/extensions/Xrender.h>
40428d7b3dSmrg#if HAVE_MIT_SHM
41428d7b3dSmrg#include <X11/extensions/XShm.h>
42428d7b3dSmrg#if HAVE_X11_EXTENSIONS_SHMPROTO_H
43428d7b3dSmrg#include <X11/extensions/shmproto.h>
44428d7b3dSmrg#elif HAVE_X11_EXTENSIONS_SHMSTR_H
45428d7b3dSmrg#include <X11/extensions/shmstr.h>
46428d7b3dSmrg#else
47428d7b3dSmrg#error Failed to find the right header for X11 MIT-SHM protocol definitions
48428d7b3dSmrg#endif
49428d7b3dSmrg#include <sys/ipc.h>
50428d7b3dSmrg#include <sys/shm.h>
51428d7b3dSmrg#endif
52428d7b3dSmrg#include <pixman.h> /* for pixman blt functions */
53428d7b3dSmrg
54428d7b3dSmrg#include "test.h"
55428d7b3dSmrg
56428d7b3dSmrgstatic const struct format {
57428d7b3dSmrg	const char *name;
58428d7b3dSmrg	pixman_format_code_t pixman_format;
59428d7b3dSmrg} formats[] = {
60428d7b3dSmrg	{ "a8r8g8b8", PIXMAN_a8r8g8b8 },
61428d7b3dSmrg	{ "x8r8g8b8", PIXMAN_x8r8g8b8 },
62428d7b3dSmrg	{ "a8", PIXMAN_a8 },
63428d7b3dSmrg	{ "a4", PIXMAN_a4 },
64428d7b3dSmrg	{ "a1", PIXMAN_a1 },
65428d7b3dSmrg};
66428d7b3dSmrg
67428d7b3dSmrgstatic const struct op {
68428d7b3dSmrg	int value;
69428d7b3dSmrg	const char *name;
70428d7b3dSmrg} ops[] = {
71428d7b3dSmrg	{ PictOpClear, "Clear" },
72428d7b3dSmrg	{ PictOpSrc, "Src" },
73428d7b3dSmrg	{ PictOpDst, "Dst" },
74428d7b3dSmrg	{ PictOpOver, "Over" },
75428d7b3dSmrg	{ PictOpOverReverse, "OverReverse" },
76428d7b3dSmrg	{ PictOpIn, "In" },
77428d7b3dSmrg	{ PictOpInReverse, "InReverse" },
78428d7b3dSmrg	{ PictOpOut, "Out" },
79428d7b3dSmrg	{ PictOpOutReverse, "OutReverse" },
80428d7b3dSmrg	{ PictOpAtop, "Atop" },
81428d7b3dSmrg	{ PictOpAtopReverse, "AtopReverse" },
82428d7b3dSmrg	{ PictOpXor, "Xor" },
83428d7b3dSmrg	{ PictOpAdd, "Add" },
84428d7b3dSmrg	{ PictOpSaturate, "Saturate" },
85428d7b3dSmrg	{ PictOpMultiply, "Multiply" },
86428d7b3dSmrg	{ PictOpScreen, "Screen" },
87428d7b3dSmrg	{ PictOpOverlay, "Overlay" },
88428d7b3dSmrg	{ PictOpDarken, "Darken" },
89428d7b3dSmrg	{ PictOpLighten, "Lighten" },
90428d7b3dSmrg	{ PictOpColorDodge, "Dodge" },
91428d7b3dSmrg	{ PictOpColorBurn, "Burn" },
92428d7b3dSmrg	{ PictOpHardLight, "HardLight" },
93428d7b3dSmrg	{ PictOpSoftLight, "SoftLight" },
94428d7b3dSmrg};
95428d7b3dSmrg
96428d7b3dSmrgstatic Picture source_pixmap(struct test_display *t, struct test_target *target, int format)
97428d7b3dSmrg{
98428d7b3dSmrg	XRenderColor render_color[2] = {
99428d7b3dSmrg		{ 0x8000, 0x8000, 0x8000, 0x8000 },
100428d7b3dSmrg		{ 0xffff, 0xffff, 0xffff, 0xffff },
101428d7b3dSmrg	};
102428d7b3dSmrg	Pixmap pixmap;
103428d7b3dSmrg	Picture picture;
104428d7b3dSmrg
105428d7b3dSmrg	pixmap = XCreatePixmap(t->dpy, t->root,
106428d7b3dSmrg			       target->width, target->height,
107428d7b3dSmrg			       PIXMAN_FORMAT_DEPTH(formats[format].pixman_format));
108428d7b3dSmrg
109428d7b3dSmrg	picture = XRenderCreatePicture(t->dpy, pixmap,
110428d7b3dSmrg				       XRenderFindStandardFormat(t->dpy, format),
111428d7b3dSmrg				       0, NULL);
112428d7b3dSmrg	XFreePixmap(t->dpy, pixmap);
113428d7b3dSmrg
114428d7b3dSmrg	XRenderFillRectangle(t->dpy, PictOpSrc, picture, &render_color[0],
115428d7b3dSmrg			     0, 0, target->width, target->height/2);
116428d7b3dSmrg	XRenderFillRectangle(t->dpy, PictOpSrc, picture, &render_color[1],
117428d7b3dSmrg			     0, target->height/2, target->width, target->height/2);
118428d7b3dSmrg
119428d7b3dSmrg	return picture;
120428d7b3dSmrg}
121428d7b3dSmrg
122428d7b3dSmrgstatic Picture source_a8r8g8b8(struct test_display *t, struct test_target *target)
123428d7b3dSmrg{
124428d7b3dSmrg	return source_pixmap(t, target, 0);
125428d7b3dSmrg}
126428d7b3dSmrg
127428d7b3dSmrgstatic Picture source_x8r8g8b8(struct test_display *t, struct test_target *target)
128428d7b3dSmrg{
129428d7b3dSmrg	return source_pixmap(t, target, 1);
130428d7b3dSmrg}
131428d7b3dSmrg
132428d7b3dSmrgstatic Picture source_a8(struct test_display *t, struct test_target *target)
133428d7b3dSmrg{
134428d7b3dSmrg	return source_pixmap(t, target, 2);
135428d7b3dSmrg}
136428d7b3dSmrg
137428d7b3dSmrgstatic Picture source_a4(struct test_display *t, struct test_target *target)
138428d7b3dSmrg{
139428d7b3dSmrg	return source_pixmap(t, target, 3);
140428d7b3dSmrg}
141428d7b3dSmrg
142428d7b3dSmrgstatic Picture source_a1(struct test_display *t, struct test_target *target)
143428d7b3dSmrg{
144428d7b3dSmrg	return source_pixmap(t, target, 3);
145428d7b3dSmrg}
146428d7b3dSmrg
147428d7b3dSmrgstatic Picture source_1x1r(struct test_display *t, struct test_target *target)
148428d7b3dSmrg{
149428d7b3dSmrg	XRenderColor render_color = { 0x8000, 0x8000, 0x8000, 0x8000 };
150428d7b3dSmrg	XRenderPictureAttributes pa;
151428d7b3dSmrg	Pixmap pixmap;
152428d7b3dSmrg	Picture picture;
153428d7b3dSmrg
154428d7b3dSmrg	pa.repeat = RepeatNormal;
155428d7b3dSmrg
156428d7b3dSmrg	pixmap = XCreatePixmap(t->dpy, t->root, 1, 1, 32);
157428d7b3dSmrg	picture = XRenderCreatePicture(t->dpy, pixmap,
158428d7b3dSmrg				       XRenderFindStandardFormat(t->dpy, 0),
159428d7b3dSmrg				       CPRepeat, &pa);
160428d7b3dSmrg	XFreePixmap(t->dpy, pixmap);
161428d7b3dSmrg
162428d7b3dSmrg	XRenderFillRectangle(t->dpy, PictOpSrc, picture, &render_color,
163428d7b3dSmrg			     0, 0, 1, 1);
164428d7b3dSmrg
165428d7b3dSmrg	return picture;
166428d7b3dSmrg}
167428d7b3dSmrg
168428d7b3dSmrgstatic Picture source_solid(struct test_display *t, struct test_target *target)
169428d7b3dSmrg{
170428d7b3dSmrg	XRenderColor render_color = { 0x8000, 0x8000, 0x8000, 0x8000 };
171428d7b3dSmrg	return XRenderCreateSolidFill(t->dpy, &render_color);
172428d7b3dSmrg}
173428d7b3dSmrg
174428d7b3dSmrgstatic Picture source_linear_horizontal(struct test_display *t, struct test_target *target)
175428d7b3dSmrg{
176428d7b3dSmrg	XRenderColor colors[2] = {{0}, {0xffff, 0xffff, 0xffff, 0xffff}};
177428d7b3dSmrg	XFixed stops[2] = {0, 0xffff};
178428d7b3dSmrg	XLinearGradient gradient = { {0, 0}, {target->width << 16, 0}};
179428d7b3dSmrg
180428d7b3dSmrg	return XRenderCreateLinearGradient(t->dpy, &gradient, stops, colors, 2);
181428d7b3dSmrg}
182428d7b3dSmrg
183428d7b3dSmrgstatic Picture source_linear_vertical(struct test_display *t, struct test_target *target)
184428d7b3dSmrg{
185428d7b3dSmrg	XRenderColor colors[2] = {{0}, {0xffff, 0xffff, 0xffff, 0xffff}};
186428d7b3dSmrg	XFixed stops[2] = {0, 0xffff};
187428d7b3dSmrg	XLinearGradient gradient = { {0, 0}, {0, target->height << 16}};
188428d7b3dSmrg
189428d7b3dSmrg	return XRenderCreateLinearGradient(t->dpy, &gradient, stops, colors, 2);
190428d7b3dSmrg}
191428d7b3dSmrg
192428d7b3dSmrgstatic Picture source_linear_diagonal(struct test_display *t, struct test_target *target)
193428d7b3dSmrg{
194428d7b3dSmrg	XRenderColor colors[2] = {{0}, {0xffff, 0xffff, 0xffff, 0xffff}};
195428d7b3dSmrg	XFixed stops[2] = {0, 0xffff};
196428d7b3dSmrg	XLinearGradient gradient = { {0, 0}, {target->width << 16, target->height << 16}};
197428d7b3dSmrg
198428d7b3dSmrg	return XRenderCreateLinearGradient(t->dpy, &gradient, stops, colors, 2);
199428d7b3dSmrg}
200428d7b3dSmrg
201428d7b3dSmrgstatic Picture source_radial_concentric(struct test_display *t, struct test_target *target)
202428d7b3dSmrg{
203428d7b3dSmrg	XRenderColor colors[2] = {{0}, {0xffff, 0xffff, 0xffff, 0xffff}};
204428d7b3dSmrg	XFixed stops[2] = {0, 0xffff};
205428d7b3dSmrg	XRadialGradient gradient = {
206428d7b3dSmrg		{
207428d7b3dSmrg			((target->width << 16) + 1) / 2,
208428d7b3dSmrg			((target->height << 16) + 1) / 2,
209428d7b3dSmrg			0,
210428d7b3dSmrg		},
211428d7b3dSmrg		{
212428d7b3dSmrg			((target->width << 16) + 1) / 2,
213428d7b3dSmrg			((target->height << 16) + 1) / 2,
214428d7b3dSmrg			target->width << 15,
215428d7b3dSmrg		}
216428d7b3dSmrg	};
217428d7b3dSmrg
218428d7b3dSmrg	return XRenderCreateRadialGradient(t->dpy, &gradient, stops, colors, 2);
219428d7b3dSmrg}
220428d7b3dSmrg
221428d7b3dSmrgstatic Picture source_radial_generic(struct test_display *t, struct test_target *target)
222428d7b3dSmrg{
223428d7b3dSmrg	XRenderColor colors[2] = {{0}, {0xffff, 0xffff, 0xffff, 0xffff}};
224428d7b3dSmrg	XFixed stops[2] = {0, 0xffff};
225428d7b3dSmrg	XRadialGradient gradient = {
226428d7b3dSmrg		{ 0, 0, target->width << 14, },
227428d7b3dSmrg		{ target->width << 16, target->height << 16, target->width << 14, }
228428d7b3dSmrg	};
229428d7b3dSmrg
230428d7b3dSmrg	return XRenderCreateRadialGradient(t->dpy, &gradient, stops, colors, 2);
231428d7b3dSmrg}
232428d7b3dSmrg
233428d7b3dSmrg#if HAVE_MIT_SHM
234428d7b3dSmrgstatic XShmSegmentInfo shmref, shmout;
235428d7b3dSmrg
236428d7b3dSmrgstatic void setup_shm(struct test *t)
237428d7b3dSmrg{
238428d7b3dSmrg	XShmSegmentInfo shm;
239428d7b3dSmrg	int size;
240428d7b3dSmrg
241428d7b3dSmrg	shm.shmid = -1;
242428d7b3dSmrg
243428d7b3dSmrg	if (!(t->ref.has_shm_pixmaps && t->out.has_shm_pixmaps))
244428d7b3dSmrg		return;
245428d7b3dSmrg
246428d7b3dSmrg	size = t->ref.width * t->ref.height * 4;
247428d7b3dSmrg	size = (size + 4095) & -4096;
248428d7b3dSmrg
249428d7b3dSmrg	shm.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0666);
250428d7b3dSmrg	if (shm.shmid == -1)
251428d7b3dSmrg		return;
252428d7b3dSmrg
253428d7b3dSmrg	shm.shmaddr = shmat(shm.shmid, 0, 0);
254428d7b3dSmrg	if (shm.shmaddr == (char *) -1) {
255428d7b3dSmrg		shmctl(shm.shmid, IPC_RMID, NULL);
256428d7b3dSmrg		shm.shmid = -1;
257428d7b3dSmrg		return;
258428d7b3dSmrg	}
259428d7b3dSmrg
260428d7b3dSmrg	shm.readOnly = False;
261428d7b3dSmrg
262428d7b3dSmrg	shmref = shm;
263428d7b3dSmrg	XShmAttach(t->ref.dpy, &shmref);
264428d7b3dSmrg	XSync(t->ref.dpy, True);
265428d7b3dSmrg
266428d7b3dSmrg	shmout = shm;
267428d7b3dSmrg	XShmAttach(t->out.dpy, &shmout);
268428d7b3dSmrg	XSync(t->out.dpy, True);
269428d7b3dSmrg}
270428d7b3dSmrg
271428d7b3dSmrgstatic Picture source_shm(struct test_display *t, struct test_target *target)
272428d7b3dSmrg{
273428d7b3dSmrg	XShmSegmentInfo *shm = t->target == REF ? &shmref : &shmout;
274428d7b3dSmrg	Pixmap pixmap;
275428d7b3dSmrg	Picture picture;
276428d7b3dSmrg	int size;
277428d7b3dSmrg
278428d7b3dSmrg	if (shm->shmid == -1)
279428d7b3dSmrg		return 0;
280428d7b3dSmrg
281428d7b3dSmrg	pixmap = XShmCreatePixmap(t->dpy, t->root,
282428d7b3dSmrg				  shm->shmaddr, shm,
283428d7b3dSmrg				  target->width, target->height, 32);
284428d7b3dSmrg
285428d7b3dSmrg	picture = XRenderCreatePicture(t->dpy, pixmap,
286428d7b3dSmrg				       XRenderFindStandardFormat(t->dpy, 0),
287428d7b3dSmrg				       0, NULL);
288428d7b3dSmrg	XFreePixmap(t->dpy, pixmap);
289428d7b3dSmrg
290428d7b3dSmrg	size = target->width * target->height * 4;
291428d7b3dSmrg	memset(shm->shmaddr, 0x80, size/2);
292428d7b3dSmrg	memset(shm->shmaddr+size/2, 0xff, size/2);
293428d7b3dSmrg
294428d7b3dSmrg	return picture;
295428d7b3dSmrg}
296428d7b3dSmrg#else
297428d7b3dSmrgstatic void setup_shm(struct test *t) { }
298428d7b3dSmrgstatic Picture source_shm(struct test_display *t, struct test_target *target) { return 0; }
299428d7b3dSmrg#endif
300428d7b3dSmrg
301428d7b3dSmrgstatic const struct {
302428d7b3dSmrg	Picture (*create)(struct test_display *, struct test_target *);
303428d7b3dSmrg	const char *name;
304428d7b3dSmrg} source[] = {
305428d7b3dSmrg	{ source_a8r8g8b8, "a8r8g8b8 pixmap" },
306428d7b3dSmrg	{ source_x8r8g8b8, "x8r8g8b8 pixmap" },
307428d7b3dSmrg	{ source_a8, "a8 pixmap" },
308428d7b3dSmrg	{ source_a4, "a4 pixmap" },
309428d7b3dSmrg	{ source_a1, "a1 pixmap" },
310428d7b3dSmrg	{ source_1x1r, "a8r8g8b8 1x1R pixmap" },
311428d7b3dSmrg	{ source_solid, "solid" },
312428d7b3dSmrg	{ source_shm, "a8r8g8b8 shm" },
313428d7b3dSmrg	{ source_linear_horizontal, "linear (horizontal gradient)" },
314428d7b3dSmrg	{ source_linear_vertical, "linear (vertical gradient)" },
315428d7b3dSmrg	{ source_linear_diagonal, "linear (diagonal gradient)" },
316428d7b3dSmrg	{ source_radial_concentric, "radial (concentric)" },
317428d7b3dSmrg	{ source_radial_generic, "radial (generic)" },
318428d7b3dSmrg};
319428d7b3dSmrg
320428d7b3dSmrgstatic double _bench_source(struct test_display *t, enum target target_type,
321428d7b3dSmrg			    int op, int src, int loops)
322428d7b3dSmrg{
323428d7b3dSmrg	XRenderColor render_color = { 0x8000, 0x8000, 0x8000, 0x8000 };
324428d7b3dSmrg	struct test_target target;
325428d7b3dSmrg	Picture picture;
326428d7b3dSmrg	struct timespec tv;
327428d7b3dSmrg	double elapsed;
328428d7b3dSmrg
329428d7b3dSmrg	test_target_create_render(t, target_type, &target);
330428d7b3dSmrg	XRenderFillRectangle(t->dpy, PictOpClear, target.picture, &render_color,
331428d7b3dSmrg			     0, 0, target.width, target.height);
332428d7b3dSmrg
333428d7b3dSmrg	picture = source[src].create(t, &target);
334428d7b3dSmrg	if (picture) {
335428d7b3dSmrg		test_timer_start(t, &tv);
336428d7b3dSmrg		while (loops--)
337428d7b3dSmrg			XRenderComposite(t->dpy, op,
338428d7b3dSmrg					 picture, 0, target.picture,
339428d7b3dSmrg					 0, 0,
340428d7b3dSmrg					 0, 0,
341428d7b3dSmrg					 0, 0,
342428d7b3dSmrg					 target.width, target.height);
343428d7b3dSmrg		elapsed = test_timer_stop(t, &tv);
344428d7b3dSmrg		XRenderFreePicture(t->dpy, picture);
345428d7b3dSmrg	} else
346428d7b3dSmrg		elapsed = -1;
347428d7b3dSmrg
348428d7b3dSmrg	test_target_destroy_render(t, &target);
349428d7b3dSmrg
350428d7b3dSmrg	return elapsed;
351428d7b3dSmrg}
352428d7b3dSmrg
353428d7b3dSmrgstatic void bench_source(struct test *t, enum target target, int op, int src)
354428d7b3dSmrg{
355428d7b3dSmrg	double out, ref;
356428d7b3dSmrg
357428d7b3dSmrg	fprintf(stdout, "%28s with %s: ", source[src].name, ops[op].name);
358428d7b3dSmrg	fflush(stdout);
359428d7b3dSmrg
360428d7b3dSmrg	op = ops[op].value;
361428d7b3dSmrg
362428d7b3dSmrg	ref = _bench_source(&t->ref, target, op, src, 1000);
363428d7b3dSmrg	if (ref < 0) {
364428d7b3dSmrg		fprintf(stdout, "SKIP\n");
365428d7b3dSmrg		return;
366428d7b3dSmrg	}
367428d7b3dSmrg	fprintf(stdout, "ref=%f, ", ref);
368428d7b3dSmrg	fflush(stdout);
369428d7b3dSmrg
370428d7b3dSmrg	out = _bench_source(&t->out, target, op, src, 1000);
371428d7b3dSmrg	if (out < 0) {
372428d7b3dSmrg		fprintf(stdout, "SKIP\n");
373428d7b3dSmrg		return;
374428d7b3dSmrg	}
375428d7b3dSmrg
376428d7b3dSmrg	fprintf(stdout, "out=%f\n", out);
377428d7b3dSmrg}
378428d7b3dSmrg
379428d7b3dSmrgstatic double _bench_mask(struct test_display *t, enum target target_type,
380428d7b3dSmrg			    int op, int src, int mask, int loops)
381428d7b3dSmrg{
382428d7b3dSmrg	XRenderColor render_color = { 0x8000, 0x8000, 0x8000, 0x8000 };
383428d7b3dSmrg	struct test_target target;
384428d7b3dSmrg	Picture ps, pm;
385428d7b3dSmrg	struct timespec tv;
386428d7b3dSmrg	double elapsed;
387428d7b3dSmrg
388428d7b3dSmrg	test_target_create_render(t, target_type, &target);
389428d7b3dSmrg	XRenderFillRectangle(t->dpy, PictOpClear, target.picture, &render_color,
390428d7b3dSmrg			     0, 0, target.width, target.height);
391428d7b3dSmrg
392428d7b3dSmrg	ps = source[src].create(t, &target);
393428d7b3dSmrg	pm = source[mask].create(t, &target);
394428d7b3dSmrg	if (ps && pm) {
395428d7b3dSmrg		test_timer_start(t, &tv);
396428d7b3dSmrg		while (loops--)
397428d7b3dSmrg			XRenderComposite(t->dpy, op,
398428d7b3dSmrg					 ps, pm, target.picture,
399428d7b3dSmrg					 0, 0,
400428d7b3dSmrg					 0, 0,
401428d7b3dSmrg					 0, 0,
402428d7b3dSmrg					 target.width, target.height);
403428d7b3dSmrg		elapsed = test_timer_stop(t, &tv);
404428d7b3dSmrg	} else
405428d7b3dSmrg		elapsed = -1;
406428d7b3dSmrg
407428d7b3dSmrg	if (ps)
408428d7b3dSmrg		XRenderFreePicture(t->dpy, ps);
409428d7b3dSmrg	if (pm)
410428d7b3dSmrg		XRenderFreePicture(t->dpy, pm);
411428d7b3dSmrg
412428d7b3dSmrg	test_target_destroy_render(t, &target);
413428d7b3dSmrg
414428d7b3dSmrg	return elapsed;
415428d7b3dSmrg}
416428d7b3dSmrg
417428d7b3dSmrgstatic void bench_mask(struct test *t, enum target target, int op, int src, int mask)
418428d7b3dSmrg{
419428d7b3dSmrg	double out, ref;
420428d7b3dSmrg
421428d7b3dSmrg	fprintf(stdout, "%28s In %28s with %s: ",
422428d7b3dSmrg		source[src].name, source[mask].name, ops[op].name);
423428d7b3dSmrg	fflush(stdout);
424428d7b3dSmrg
425428d7b3dSmrg	op = ops[op].value;
426428d7b3dSmrg
427428d7b3dSmrg	ref = _bench_mask(&t->ref, target, op, src, mask, 1000);
428428d7b3dSmrg	if (ref < 0) {
429428d7b3dSmrg		fprintf(stdout, "SKIP\n");
430428d7b3dSmrg		return;
431428d7b3dSmrg	}
432428d7b3dSmrg	fprintf(stdout, "ref=%f, ", ref);
433428d7b3dSmrg	fflush(stdout);
434428d7b3dSmrg
435428d7b3dSmrg	out = _bench_mask(&t->out, target, op, src, mask, 1000);
436428d7b3dSmrg	if (out < 0) {
437428d7b3dSmrg		fprintf(stdout, "SKIP\n");
438428d7b3dSmrg		return;
439428d7b3dSmrg	}
440428d7b3dSmrg
441428d7b3dSmrg	fprintf(stdout, "out=%f\n", out);
442428d7b3dSmrg}
443428d7b3dSmrg
444428d7b3dSmrgint main(int argc, char **argv)
445428d7b3dSmrg{
446428d7b3dSmrg	struct test test;
447428d7b3dSmrg	unsigned op, src, mask;
448428d7b3dSmrg
449428d7b3dSmrg	test_init(&test, argc, argv);
450428d7b3dSmrg
451428d7b3dSmrg	setup_shm(&test);
452428d7b3dSmrg
453428d7b3dSmrg	for (op = 0; op < sizeof(ops)/sizeof(ops[0]); op++) {
454428d7b3dSmrg		for (src = 0; src < sizeof(source)/sizeof(source[0]); src++)
455428d7b3dSmrg			bench_source(&test, ROOT, op, src);
456428d7b3dSmrg		fprintf (stdout, "\n");
457428d7b3dSmrg
458428d7b3dSmrg		for (src = 0; src < sizeof(source)/sizeof(source[0]); src++)
459428d7b3dSmrg			for (mask = 0; mask < sizeof(source)/sizeof(source[0]); mask++)
460428d7b3dSmrg				bench_mask(&test, ROOT, op, src, mask);
461428d7b3dSmrg		fprintf (stdout, "\n");
462428d7b3dSmrg	}
463428d7b3dSmrg
464428d7b3dSmrg	return 0;
465428d7b3dSmrg}
466