1/*
2 * Copyright (c) 2014 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include <X11/Xlib.h>
30#include <X11/Xutil.h>
31#include <X11/Xlibint.h>
32#include <X11/extensions/Xrender.h>
33#include <X11/extensions/XShm.h>
34#if HAVE_X11_EXTENSIONS_SHMPROTO_H
35#include <X11/extensions/shmproto.h>
36#elif HAVE_X11_EXTENSIONS_SHMSTR_H
37#include <X11/extensions/shmstr.h>
38#else
39#error Failed to find the right header for X11 MIT-SHM protocol definitions
40#endif
41
42#include <stdio.h>
43#include <string.h>
44#include <fcntl.h>
45#include <unistd.h>
46#include <assert.h>
47#include <errno.h>
48
49#include <sys/mman.h>
50#include <sys/ipc.h>
51#include <sys/shm.h>
52#include <pciaccess.h>
53
54static int _x_error_occurred;
55
56static int
57can_use_shm(Display *dpy)
58{
59	int major, minor, has_pixmap;
60
61	if (!XShmQueryExtension(dpy))
62		return 0;
63
64	XShmQueryVersion(dpy, &major, &minor, &has_pixmap);
65	return has_pixmap;
66}
67
68static int test_subpage(Display *dpy)
69{
70	const int width = 10;
71	const int height = 10;
72	uint32_t pixel = 0xffffffff;
73	char *expected;
74	XShmSegmentInfo shm;
75	Pixmap pixmap, source;
76	XGCValues gcv;
77	GC gc;
78
79	printf("Creating %dx%d SHM pixmap\n", width, height);
80	_x_error_occurred = 0;
81
82	expected = malloc(4096);
83	if (expected == NULL)
84		return 0;
85
86	shm.shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666);
87	if (shm.shmid == -1)
88		return 0;
89
90	shm.shmaddr = shmat(shm.shmid, 0, 0);
91	if (shm.shmaddr == (char *) -1) {
92		shmctl(shm.shmid, IPC_RMID, NULL);
93		return 0;
94	}
95
96	shm.readOnly = False;
97	XShmAttach(dpy, &shm);
98
99	memset(shm.shmaddr, 0xcc, 4096);
100	memset(expected, 0xcc, 4096);
101	memset(expected + 64, 0xff, 4*width * height);
102
103	pixmap = XShmCreatePixmap(dpy, DefaultRootWindow(dpy),
104				  shm.shmaddr + 64, &shm, width, height, 24);
105	XSync(dpy, False);
106	shmctl(shm.shmid, IPC_RMID, NULL);
107
108	source = XCreatePixmap(dpy, DefaultRootWindow(dpy),
109			       width, height, 24);
110
111	gcv.graphics_exposures = False;
112	gcv.subwindow_mode = IncludeInferiors;
113	gcv.foreground = pixel;
114	gcv.function = GXcopy;
115	gcv.fill_style = FillSolid;
116	gc = XCreateGC(dpy, pixmap, GCGraphicsExposures | GCSubwindowMode | GCFillStyle | GCForeground | GCFunction, &gcv);
117
118	XCopyArea(dpy, pixmap, source, gc,
119		  0, 0, width, height, 0, 0);
120
121	XFillRectangle(dpy, source, gc, 0, 0, width, height);
122
123	XCopyArea(dpy, source, pixmap, gc,
124		  0, 0, width, height, 0, 0);
125	XSync(dpy, True);
126
127	if (_x_error_occurred == 0)
128		_x_error_occurred = memcmp(shm.shmaddr, expected, 4096);
129
130	printf("%s: %s\n", __func__, _x_error_occurred ? "failed" : "passed");
131
132	XShmDetach(dpy, &shm);
133	shmdt(shm.shmaddr);
134	free(expected);
135
136
137	return !_x_error_occurred;;
138}
139
140static int
141_check_error_handler(Display     *display,
142		     XErrorEvent *event)
143{
144	printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
145	       DisplayString(display),
146	       event->serial,
147	       event->error_code,
148	       event->request_code,
149	       event->minor_code);
150	_x_error_occurred++;
151	return False; /* ignored */
152}
153
154int main(void)
155{
156	Display *dpy;
157	int error = 0;
158
159	dpy = XOpenDisplay(NULL);
160	if (dpy == NULL)
161		return 77;
162
163	if (DefaultDepth(dpy, DefaultScreen(dpy)) != 24)
164		return 77;
165
166	if (!can_use_shm(dpy))
167		return 0;
168
169	XSetErrorHandler(_check_error_handler);
170
171	error += test_subpage(dpy);
172
173	return !!error;
174}
175