142542f5fSchristos/*
242542f5fSchristos * Copyright (c) 2014 Intel Corporation
342542f5fSchristos *
442542f5fSchristos * Permission is hereby granted, free of charge, to any person obtaining a
542542f5fSchristos * copy of this software and associated documentation files (the "Software"),
642542f5fSchristos * to deal in the Software without restriction, including without limitation
742542f5fSchristos * the rights to use, copy, modify, merge, publish, distribute, sublicense,
842542f5fSchristos * and/or sell copies of the Software, and to permit persons to whom the
942542f5fSchristos * Software is furnished to do so, subject to the following conditions:
1042542f5fSchristos *
1142542f5fSchristos * The above copyright notice and this permission notice (including the next
1242542f5fSchristos * paragraph) shall be included in all copies or substantial portions of the
1342542f5fSchristos * Software.
1442542f5fSchristos *
1542542f5fSchristos * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1642542f5fSchristos * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1742542f5fSchristos * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1842542f5fSchristos * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1942542f5fSchristos * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2042542f5fSchristos * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2142542f5fSchristos * SOFTWARE.
2242542f5fSchristos *
2342542f5fSchristos */
2442542f5fSchristos
2542542f5fSchristos#ifdef HAVE_CONFIG_H
2642542f5fSchristos#include "config.h"
2742542f5fSchristos#endif
2842542f5fSchristos
2942542f5fSchristos#include <X11/Xlib.h>
3042542f5fSchristos#include <X11/Xutil.h>
3142542f5fSchristos#include <X11/Xlibint.h>
3242542f5fSchristos#include <X11/extensions/Xrender.h>
3342542f5fSchristos#include <X11/extensions/XShm.h>
3442542f5fSchristos#if HAVE_X11_EXTENSIONS_SHMPROTO_H
3542542f5fSchristos#include <X11/extensions/shmproto.h>
3642542f5fSchristos#elif HAVE_X11_EXTENSIONS_SHMSTR_H
3742542f5fSchristos#include <X11/extensions/shmstr.h>
3842542f5fSchristos#else
3942542f5fSchristos#error Failed to find the right header for X11 MIT-SHM protocol definitions
4042542f5fSchristos#endif
4142542f5fSchristos
4242542f5fSchristos#include <stdio.h>
4342542f5fSchristos#include <string.h>
4442542f5fSchristos#include <fcntl.h>
4542542f5fSchristos#include <unistd.h>
4642542f5fSchristos#include <assert.h>
4742542f5fSchristos#include <errno.h>
4842542f5fSchristos
4942542f5fSchristos#include <sys/mman.h>
5042542f5fSchristos#include <sys/ipc.h>
5142542f5fSchristos#include <sys/shm.h>
5242542f5fSchristos#include <pciaccess.h>
5342542f5fSchristos
5442542f5fSchristosstatic int _x_error_occurred;
5542542f5fSchristos
5642542f5fSchristosstatic int
5742542f5fSchristoscan_use_shm(Display *dpy)
5842542f5fSchristos{
5942542f5fSchristos	int major, minor, has_pixmap;
6042542f5fSchristos
6142542f5fSchristos	if (!XShmQueryExtension(dpy))
6242542f5fSchristos		return 0;
6342542f5fSchristos
6442542f5fSchristos	XShmQueryVersion(dpy, &major, &minor, &has_pixmap);
6542542f5fSchristos	return has_pixmap;
6642542f5fSchristos}
6742542f5fSchristos
6842542f5fSchristosstatic int test_subpage(Display *dpy)
6942542f5fSchristos{
7042542f5fSchristos	const int width = 10;
7142542f5fSchristos	const int height = 10;
7242542f5fSchristos	uint32_t pixel = 0xffffffff;
7342542f5fSchristos	char *expected;
7442542f5fSchristos	XShmSegmentInfo shm;
7542542f5fSchristos	Pixmap pixmap, source;
7642542f5fSchristos	XGCValues gcv;
7742542f5fSchristos	GC gc;
7842542f5fSchristos
7942542f5fSchristos	printf("Creating %dx%d SHM pixmap\n", width, height);
8042542f5fSchristos	_x_error_occurred = 0;
8142542f5fSchristos
8242542f5fSchristos	expected = malloc(4096);
8342542f5fSchristos	if (expected == NULL)
8442542f5fSchristos		return 0;
8542542f5fSchristos
8642542f5fSchristos	shm.shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666);
8742542f5fSchristos	if (shm.shmid == -1)
8842542f5fSchristos		return 0;
8942542f5fSchristos
9042542f5fSchristos	shm.shmaddr = shmat(shm.shmid, 0, 0);
9142542f5fSchristos	if (shm.shmaddr == (char *) -1) {
9242542f5fSchristos		shmctl(shm.shmid, IPC_RMID, NULL);
9342542f5fSchristos		return 0;
9442542f5fSchristos	}
9542542f5fSchristos
9642542f5fSchristos	shm.readOnly = False;
9742542f5fSchristos	XShmAttach(dpy, &shm);
9842542f5fSchristos
9942542f5fSchristos	memset(shm.shmaddr, 0xcc, 4096);
10042542f5fSchristos	memset(expected, 0xcc, 4096);
10142542f5fSchristos	memset(expected + 64, 0xff, 4*width * height);
10242542f5fSchristos
10342542f5fSchristos	pixmap = XShmCreatePixmap(dpy, DefaultRootWindow(dpy),
10442542f5fSchristos				  shm.shmaddr + 64, &shm, width, height, 24);
10542542f5fSchristos	XSync(dpy, False);
10642542f5fSchristos	shmctl(shm.shmid, IPC_RMID, NULL);
10742542f5fSchristos
10842542f5fSchristos	source = XCreatePixmap(dpy, DefaultRootWindow(dpy),
10942542f5fSchristos			       width, height, 24);
11042542f5fSchristos
11142542f5fSchristos	gcv.graphics_exposures = False;
11242542f5fSchristos	gcv.subwindow_mode = IncludeInferiors;
11342542f5fSchristos	gcv.foreground = pixel;
11442542f5fSchristos	gcv.function = GXcopy;
11542542f5fSchristos	gcv.fill_style = FillSolid;
11642542f5fSchristos	gc = XCreateGC(dpy, pixmap, GCGraphicsExposures | GCSubwindowMode | GCFillStyle | GCForeground | GCFunction, &gcv);
11742542f5fSchristos
11842542f5fSchristos	XCopyArea(dpy, pixmap, source, gc,
11942542f5fSchristos		  0, 0, width, height, 0, 0);
12042542f5fSchristos
12142542f5fSchristos	XFillRectangle(dpy, source, gc, 0, 0, width, height);
12242542f5fSchristos
12342542f5fSchristos	XCopyArea(dpy, source, pixmap, gc,
12442542f5fSchristos		  0, 0, width, height, 0, 0);
12542542f5fSchristos	XSync(dpy, True);
12642542f5fSchristos
12742542f5fSchristos	if (_x_error_occurred == 0)
12842542f5fSchristos		_x_error_occurred = memcmp(shm.shmaddr, expected, 4096);
12942542f5fSchristos
13042542f5fSchristos	printf("%s: %s\n", __func__, _x_error_occurred ? "failed" : "passed");
13142542f5fSchristos
13242542f5fSchristos	XShmDetach(dpy, &shm);
13342542f5fSchristos	shmdt(shm.shmaddr);
13442542f5fSchristos	free(expected);
13542542f5fSchristos
13642542f5fSchristos
13742542f5fSchristos	return !_x_error_occurred;;
13842542f5fSchristos}
13942542f5fSchristos
14042542f5fSchristosstatic int
14142542f5fSchristos_check_error_handler(Display     *display,
14242542f5fSchristos		     XErrorEvent *event)
14342542f5fSchristos{
14442542f5fSchristos	printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
14542542f5fSchristos	       DisplayString(display),
14642542f5fSchristos	       event->serial,
14742542f5fSchristos	       event->error_code,
14842542f5fSchristos	       event->request_code,
14942542f5fSchristos	       event->minor_code);
15042542f5fSchristos	_x_error_occurred++;
15142542f5fSchristos	return False; /* ignored */
15242542f5fSchristos}
15342542f5fSchristos
15442542f5fSchristosint main(void)
15542542f5fSchristos{
15642542f5fSchristos	Display *dpy;
15742542f5fSchristos	int error = 0;
15842542f5fSchristos
15942542f5fSchristos	dpy = XOpenDisplay(NULL);
16042542f5fSchristos	if (dpy == NULL)
16142542f5fSchristos		return 77;
16242542f5fSchristos
16342542f5fSchristos	if (DefaultDepth(dpy, DefaultScreen(dpy)) != 24)
16442542f5fSchristos		return 77;
16542542f5fSchristos
16642542f5fSchristos	if (!can_use_shm(dpy))
16742542f5fSchristos		return 0;
16842542f5fSchristos
16942542f5fSchristos	XSetErrorHandler(_check_error_handler);
17042542f5fSchristos
17142542f5fSchristos	error += test_subpage(dpy);
17242542f5fSchristos
17342542f5fSchristos	return !!error;
17442542f5fSchristos}
175