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#include <xf86drm.h>
4242542f5fSchristos#include <i915_drm.h>
4342542f5fSchristos
4442542f5fSchristos#include <stdio.h>
4542542f5fSchristos#include <string.h>
4642542f5fSchristos#include <fcntl.h>
4742542f5fSchristos#include <unistd.h>
4842542f5fSchristos#include <assert.h>
4942542f5fSchristos#include <errno.h>
5042542f5fSchristos
5142542f5fSchristos#include <sys/mman.h>
5242542f5fSchristos#include <sys/ipc.h>
5342542f5fSchristos#include <sys/shm.h>
5442542f5fSchristos#include <pciaccess.h>
5542542f5fSchristos
5642542f5fSchristos#include "dri3.h"
5742542f5fSchristos#include "../src/i915_pciids.h"
5842542f5fSchristos
5942542f5fSchristos#define ALIGN(x, y) (((x) + (y) - 1) & -(y))
6042542f5fSchristos#define PAGE_ALIGN(x) ALIGN(x, 4096)
6142542f5fSchristos
6242542f5fSchristos#define GTT I915_GEM_DOMAIN_GTT
6342542f5fSchristos#define CPU I915_GEM_DOMAIN_CPU
6442542f5fSchristos
6542542f5fSchristosstatic int _x_error_occurred;
6642542f5fSchristos
6742542f5fSchristosstatic const struct pci_id_match ids[] = {
6842542f5fSchristos	INTEL_I830_IDS(020),
6942542f5fSchristos	INTEL_I845G_IDS(021),
7042542f5fSchristos	INTEL_I85X_IDS(022),
7142542f5fSchristos	INTEL_I865G_IDS(023),
7242542f5fSchristos
7342542f5fSchristos	INTEL_I915G_IDS(030),
7442542f5fSchristos	INTEL_I915GM_IDS(030),
7542542f5fSchristos	INTEL_I945G_IDS(031),
7642542f5fSchristos	INTEL_I945GM_IDS(031),
7742542f5fSchristos
7842542f5fSchristos	INTEL_G33_IDS(033),
7942542f5fSchristos	INTEL_PINEVIEW_IDS(033),
8042542f5fSchristos
8142542f5fSchristos	INTEL_I965G_IDS(040),
8242542f5fSchristos	INTEL_I965GM_IDS(040),
8342542f5fSchristos
8442542f5fSchristos	INTEL_G45_IDS(045),
8542542f5fSchristos	INTEL_GM45_IDS(045),
8642542f5fSchristos
8742542f5fSchristos	INTEL_IRONLAKE_D_IDS(050),
8842542f5fSchristos	INTEL_IRONLAKE_M_IDS(050),
8942542f5fSchristos
9042542f5fSchristos	INTEL_SNB_D_IDS(060),
9142542f5fSchristos	INTEL_SNB_M_IDS(060),
9242542f5fSchristos
9342542f5fSchristos	INTEL_IVB_D_IDS(070),
9442542f5fSchristos	INTEL_IVB_M_IDS(070),
9542542f5fSchristos
96fe8aea9eSmrg	INTEL_HSW_IDS(075),
97fe8aea9eSmrg	INTEL_VLV_IDS(071),
98fe8aea9eSmrg	INTEL_BDW_IDS(0100),
9942542f5fSchristos};
10042542f5fSchristos
10142542f5fSchristosstatic int i915_gen(int device)
10242542f5fSchristos{
10342542f5fSchristos	struct drm_i915_getparam gp;
10442542f5fSchristos	int devid = 0;
10542542f5fSchristos	int n;
10642542f5fSchristos
10742542f5fSchristos	gp.param = I915_PARAM_CHIPSET_ID;
10842542f5fSchristos	gp.value = &devid;
10942542f5fSchristos
11042542f5fSchristos	if (drmIoctl(device, DRM_IOCTL_I915_GETPARAM, &gp))
11142542f5fSchristos		return 0;
11242542f5fSchristos
11342542f5fSchristos	for (n = 0; n < sizeof(ids)/sizeof(ids[0]); n++) {
11442542f5fSchristos		if (devid == ids[n].device_id)
11542542f5fSchristos			return ids[n].match_data;
11642542f5fSchristos	}
11742542f5fSchristos
11842542f5fSchristos	return 0;
11942542f5fSchristos}
12042542f5fSchristos
12142542f5fSchristosstatic int is_i915_device(int fd)
12242542f5fSchristos{
12342542f5fSchristos	drm_version_t version;
12442542f5fSchristos	char name[5] = "";
12542542f5fSchristos
12642542f5fSchristos	memset(&version, 0, sizeof(version));
12742542f5fSchristos	version.name_len = 4;
12842542f5fSchristos	version.name = name;
12942542f5fSchristos
13042542f5fSchristos	if (drmIoctl(fd, DRM_IOCTL_VERSION, &version))
13142542f5fSchristos		return 0;
13242542f5fSchristos
13342542f5fSchristos	return strcmp("i915", name) == 0;
13442542f5fSchristos}
13542542f5fSchristos
13642542f5fSchristosstatic int is_intel(int fd)
13742542f5fSchristos{
13842542f5fSchristos	struct drm_i915_getparam gp;
13942542f5fSchristos	int ret;
14042542f5fSchristos
14142542f5fSchristos	/* Confirm that this is a i915.ko device with GEM/KMS enabled */
14242542f5fSchristos	ret = is_i915_device(fd);
14342542f5fSchristos	if (ret) {
14442542f5fSchristos		gp.param = I915_PARAM_HAS_GEM;
14542542f5fSchristos		gp.value = &ret;
14642542f5fSchristos		if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp))
14742542f5fSchristos			ret = 0;
14842542f5fSchristos	}
14942542f5fSchristos	return ret;
15042542f5fSchristos}
15142542f5fSchristos
15242542f5fSchristosstatic uint32_t gem_create(int fd, int size)
15342542f5fSchristos{
15442542f5fSchristos	struct drm_i915_gem_create create;
15542542f5fSchristos
15642542f5fSchristos	create.handle = 0;
15742542f5fSchristos	create.size = size;
15842542f5fSchristos	(void)drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
15942542f5fSchristos
16042542f5fSchristos	return create.handle;
16142542f5fSchristos}
16242542f5fSchristos
16342542f5fSchristosstruct local_i915_gem_caching {
16442542f5fSchristos	uint32_t handle;
16542542f5fSchristos	uint32_t caching;
16642542f5fSchristos};
16742542f5fSchristos
16842542f5fSchristos#define LOCAL_I915_GEM_SET_CACHING	0x2f
16942542f5fSchristos#define LOCAL_IOCTL_I915_GEM_SET_CACHING DRM_IOW(DRM_COMMAND_BASE + LOCAL_I915_GEM_SET_CACHING, struct local_i915_gem_caching)
17042542f5fSchristos
17142542f5fSchristosstatic int gem_set_caching(int fd, uint32_t handle, int caching)
17242542f5fSchristos{
17342542f5fSchristos	struct local_i915_gem_caching arg;
17442542f5fSchristos
17542542f5fSchristos	arg.handle = handle;
17642542f5fSchristos	arg.caching = caching;
17742542f5fSchristos
17842542f5fSchristos	return drmIoctl(fd, LOCAL_IOCTL_I915_GEM_SET_CACHING, &arg) == 0;
17942542f5fSchristos}
18042542f5fSchristos
18142542f5fSchristosstatic int gem_export(int fd, uint32_t handle)
18242542f5fSchristos{
18342542f5fSchristos	struct drm_prime_handle args;
18442542f5fSchristos
18542542f5fSchristos	args.handle = handle;
18642542f5fSchristos	args.flags = O_CLOEXEC;
18742542f5fSchristos
18842542f5fSchristos	if (drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args))
18942542f5fSchristos		return -1;
19042542f5fSchristos
19142542f5fSchristos	return args.fd;
19242542f5fSchristos}
19342542f5fSchristos
19442542f5fSchristosstatic uint32_t gem_import(int fd, int name)
19542542f5fSchristos{
19642542f5fSchristos	struct drm_prime_handle args;
19742542f5fSchristos
19842542f5fSchristos	args.fd = name;
19942542f5fSchristos	args.flags = 0;
20042542f5fSchristos	if (drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args))
20142542f5fSchristos		return 0;
20242542f5fSchristos
20342542f5fSchristos	return args.handle;
20442542f5fSchristos}
20542542f5fSchristos
20642542f5fSchristosstatic int gem_write(int fd, uint32_t handle, int offset, void *data, int len)
20742542f5fSchristos{
20842542f5fSchristos	struct drm_i915_gem_pwrite gem_pwrite;
20942542f5fSchristos
21042542f5fSchristos	gem_pwrite.handle = handle;
21142542f5fSchristos	gem_pwrite.offset = offset;
21242542f5fSchristos	gem_pwrite.size = len;
21342542f5fSchristos	gem_pwrite.data_ptr = (uintptr_t)data;
21442542f5fSchristos	return drmIoctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &gem_pwrite);
21542542f5fSchristos}
21642542f5fSchristos
21742542f5fSchristosstatic void *gem_mmap(int fd, uint32_t handle, int size, unsigned prot, int domain)
21842542f5fSchristos{
21942542f5fSchristos	struct drm_i915_gem_set_domain set_domain;
22042542f5fSchristos	void *ptr;
22142542f5fSchristos
22242542f5fSchristos	if (domain == CPU) {
22342542f5fSchristos		struct drm_i915_gem_mmap mmap_arg;
22442542f5fSchristos
22542542f5fSchristos		mmap_arg.handle = handle;
22642542f5fSchristos		mmap_arg.offset = 0;
22742542f5fSchristos		mmap_arg.size = size;
22842542f5fSchristos		if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg))
22942542f5fSchristos			return NULL;
23042542f5fSchristos
23142542f5fSchristos		ptr = (void *)(uintptr_t)mmap_arg.addr_ptr;
23242542f5fSchristos	} else {
23342542f5fSchristos		struct drm_i915_gem_mmap_gtt mmap_arg;
23442542f5fSchristos
23542542f5fSchristos		mmap_arg.handle = handle;
23642542f5fSchristos		if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg))
23742542f5fSchristos			return NULL;
23842542f5fSchristos
23942542f5fSchristos		ptr = mmap(0, size, prot, MAP_SHARED, fd, mmap_arg.offset);
24042542f5fSchristos		if (ptr == MAP_FAILED)
24142542f5fSchristos			return NULL;
24242542f5fSchristos	}
24342542f5fSchristos
24442542f5fSchristos	set_domain.handle = handle;
24542542f5fSchristos	set_domain.read_domains = domain;
24642542f5fSchristos	set_domain.write_domain = prot & PROT_WRITE ? set_domain.read_domains : 0;
24742542f5fSchristos	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) {
24842542f5fSchristos		munmap(ptr, size);
24942542f5fSchristos		return NULL;
25042542f5fSchristos	}
25142542f5fSchristos
25242542f5fSchristos	return ptr;
25342542f5fSchristos}
25442542f5fSchristos
25542542f5fSchristosstatic void gem_sync(int fd, uint32_t handle, int read)
25642542f5fSchristos{
25742542f5fSchristos	struct drm_i915_gem_set_domain set_domain;
25842542f5fSchristos
25942542f5fSchristos	set_domain.handle = handle;
26042542f5fSchristos	set_domain.read_domains = read;
26142542f5fSchristos	set_domain.write_domain = 0;
26242542f5fSchristos	drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
26342542f5fSchristos}
26442542f5fSchristos
26542542f5fSchristosstatic int gem_get_tiling(int fd, uint32_t handle)
26642542f5fSchristos{
26742542f5fSchristos	struct drm_i915_gem_get_tiling tiling;
26842542f5fSchristos
26942542f5fSchristos	tiling.handle = handle;
27042542f5fSchristos	tiling.tiling_mode = -1;
27142542f5fSchristos	(void)drmIoctl(fd, DRM_IOCTL_I915_GEM_GET_TILING, &tiling);
27242542f5fSchristos	return tiling.tiling_mode;
27342542f5fSchristos}
27442542f5fSchristos
27542542f5fSchristosstatic void gem_close(int fd, uint32_t handle)
27642542f5fSchristos{
27742542f5fSchristos	struct drm_gem_close close;
27842542f5fSchristos
27942542f5fSchristos	close.handle = handle;
28042542f5fSchristos	(void)drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close);
28142542f5fSchristos}
28242542f5fSchristos
28342542f5fSchristosstatic void gem_fill(int fd, uint32_t handle, uint32_t pixel, uint32_t size, int domain)
28442542f5fSchristos{
28542542f5fSchristos	uint32_t *ptr, s;
28642542f5fSchristos
28742542f5fSchristos	ptr = gem_mmap(fd, handle, size, PROT_READ | PROT_WRITE, domain);
28842542f5fSchristos	if (ptr == NULL)
28942542f5fSchristos		return;
29042542f5fSchristos
29142542f5fSchristos	for (s = 0; s < size; s += 4)
29242542f5fSchristos		ptr[s/4] = pixel;
29342542f5fSchristos	munmap(ptr, size);
29442542f5fSchristos}
29542542f5fSchristos
29642542f5fSchristosstatic int check_pixmap(Display *dpy, Pixmap pix,
29742542f5fSchristos			int x, int y, uint32_t expected, int bpp)
29842542f5fSchristos{
29942542f5fSchristos	XImage *image;
30042542f5fSchristos	int w = 32 / bpp;
30142542f5fSchristos
30242542f5fSchristos	image = XGetImage(dpy, pix, x - (x % w), y, w, 1, AllPlanes, ZPixmap);
30342542f5fSchristos	if (image == NULL)
30442542f5fSchristos		return 0;
30542542f5fSchristos
30642542f5fSchristos	if (*(uint32_t *)image->data != expected) {
30742542f5fSchristos		printf("pixmap[%d, %d]:%d = %08x\n", x, y, bpp, *(uint32_t *)image->data);
30842542f5fSchristos		return 0;
30942542f5fSchristos	}
31042542f5fSchristos	XDestroyImage(image);
31142542f5fSchristos
31242542f5fSchristos	return 1;
31342542f5fSchristos}
31442542f5fSchristos
31542542f5fSchristosstatic int check_pixel(int fd, uint32_t handle, uint32_t stride, uint32_t size,
31642542f5fSchristos		       int x, int y, uint32_t expected, int bpp, int domain)
31742542f5fSchristos{
31842542f5fSchristos	uint32_t *ptr;
31942542f5fSchristos	int w = 32 / bpp;
32042542f5fSchristos
32142542f5fSchristos	assert((stride & 3) == 0);
32242542f5fSchristos
32342542f5fSchristos	ptr = gem_mmap(fd, handle, size, PROT_READ, domain);
32442542f5fSchristos	if (ptr == NULL)
32542542f5fSchristos		return 0;
32642542f5fSchristos
32742542f5fSchristos	if (ptr[(y*stride + x - (x % w))/4] != expected) {
32842542f5fSchristos		printf("pixel[%d, %d]:%d = %08x\n", x, y, bpp, ptr[(y * stride + x)/4]);
32942542f5fSchristos		return 0;
33042542f5fSchristos	}
33142542f5fSchristos	munmap(ptr, size);
33242542f5fSchristos
33342542f5fSchristos	return 1;
33442542f5fSchristos}
33542542f5fSchristos
33642542f5fSchristosstatic GC get_gc(Display *dpy, Drawable d, int depth)
33742542f5fSchristos{
33842542f5fSchristos	static GC gc[33];
33942542f5fSchristos	if (gc[depth] == NULL) {
34042542f5fSchristos		XGCValues gcv;
34142542f5fSchristos
34242542f5fSchristos		gcv.graphics_exposures = False;
34342542f5fSchristos		gc[depth] = XCreateGC(dpy, d, GCGraphicsExposures, &gcv);
34442542f5fSchristos	}
34542542f5fSchristos	return gc[depth];
34642542f5fSchristos}
34742542f5fSchristos
34842542f5fSchristosstatic int
34942542f5fSchristoscan_use_shm(Display *dpy)
35042542f5fSchristos{
35142542f5fSchristos	int major, minor, has_pixmap;
35242542f5fSchristos
35342542f5fSchristos	if (!XShmQueryExtension(dpy))
35442542f5fSchristos		return 0;
35542542f5fSchristos
35642542f5fSchristos	XShmQueryVersion(dpy, &major, &minor, &has_pixmap);
35742542f5fSchristos	return has_pixmap;
35842542f5fSchristos}
35942542f5fSchristos
36042542f5fSchristosstatic int gpu_fill(int device, int handle, int width, int height, int pitch, int bpp, int tiling, uint32_t pixel)
36142542f5fSchristos{
36242542f5fSchristos	struct drm_i915_gem_execbuffer2 execbuf;
36342542f5fSchristos	struct drm_i915_gem_relocation_entry gem_reloc[2];
36442542f5fSchristos	struct drm_i915_gem_exec_object2 gem_exec[2];
36542542f5fSchristos	uint32_t batch[10];
36642542f5fSchristos	int gen = i915_gen(device);
36742542f5fSchristos	int len = 0;
36842542f5fSchristos	int ret;
36942542f5fSchristos
37042542f5fSchristos	if (gen == 0)
37142542f5fSchristos		return -ENODEV;
37242542f5fSchristos
37342542f5fSchristos	batch[0] = 2 << 29 | 0x50 << 22;
37442542f5fSchristos	batch[0] |= (gen >= 0100 ? 5 : 4);
37542542f5fSchristos	batch[1] = pitch;
37642542f5fSchristos	if (gen >= 040 && tiling) {
37742542f5fSchristos		batch[0] |= 1 << 11;
37842542f5fSchristos		batch[1] >>= 2;
37942542f5fSchristos	}
38042542f5fSchristos
38142542f5fSchristos	batch[1] |= 0xf0 << 16;
38242542f5fSchristos	switch (bpp) {
38342542f5fSchristos	default: assert(0);
38442542f5fSchristos	case 32: batch[0] |= 1 << 21 | 1 << 20;
38542542f5fSchristos		 batch[1] |= 1 << 25; /* RGB8888 */
38642542f5fSchristos	case 16: batch[1] |= 1 << 24; /* RGB565 */
38742542f5fSchristos	case 8: break;
38842542f5fSchristos	}
38942542f5fSchristos
39042542f5fSchristos	batch[2] = 0;
39142542f5fSchristos	batch[3] = height << 16 | width;
39242542f5fSchristos	batch[4] = 0;
39342542f5fSchristos	len = 5;
39442542f5fSchristos	if (gen >= 0100)
39542542f5fSchristos		batch[len++] = 0;
39642542f5fSchristos	batch[len++] = pixel;
39742542f5fSchristos	batch[len++] = 0xA << 23;
39842542f5fSchristos	if (len & 1)
39942542f5fSchristos		len++;
40042542f5fSchristos
40142542f5fSchristos	gem_reloc[0].offset = 4 * sizeof(uint32_t);
40242542f5fSchristos	gem_reloc[0].delta = 0;
40342542f5fSchristos	gem_reloc[0].target_handle = handle;
40442542f5fSchristos	gem_reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;
40542542f5fSchristos	gem_reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
40642542f5fSchristos	gem_reloc[0].presumed_offset = 0;
40742542f5fSchristos
40842542f5fSchristos	memset(gem_exec, 0, sizeof(gem_exec));
40942542f5fSchristos	gem_exec[0].handle = handle;
41042542f5fSchristos	gem_exec[1].handle = gem_create(device, 4096);
41142542f5fSchristos	gem_exec[1].relocation_count = 1;
41242542f5fSchristos	gem_exec[1].relocs_ptr = (uintptr_t)gem_reloc;
41342542f5fSchristos
41442542f5fSchristos	memset(&execbuf, 0, sizeof(execbuf));
41542542f5fSchristos	execbuf.buffers_ptr = (uintptr_t)gem_exec;
41642542f5fSchristos	execbuf.buffer_count = 2;
41742542f5fSchristos	execbuf.batch_len = len * sizeof(uint32_t);
41842542f5fSchristos	execbuf.flags = gen >= 060 ? I915_EXEC_BLT : 0;
41942542f5fSchristos
42042542f5fSchristos	ret = gem_write(device, gem_exec[1].handle, 0, batch, execbuf.batch_len);
42142542f5fSchristos	if (ret == 0)
42242542f5fSchristos		ret = drmIoctl(device, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
42342542f5fSchristos	if (ret < 0)
42442542f5fSchristos		ret = -errno;
42542542f5fSchristos
42642542f5fSchristos	gem_close(device, gem_exec[1].handle);
42742542f5fSchristos	return ret;
42842542f5fSchristos}
42942542f5fSchristos
43042542f5fSchristosstatic int test_shm(Display *dpy, int device,
43142542f5fSchristos		    int width, int height)
43242542f5fSchristos{
43342542f5fSchristos	const int x_loc[] = {0, width/2, width-1};
43442542f5fSchristos	const int y_loc[] = {0, height/2, height-1};
43542542f5fSchristos	uint32_t pixel = 0xffff00ff;
43642542f5fSchristos	XShmSegmentInfo shm;
43742542f5fSchristos	Pixmap pixmap;
43842542f5fSchristos	uint32_t handle = 0;
43942542f5fSchristos	uint32_t *ptr;
44042542f5fSchristos	int stride, fd;
44142542f5fSchristos	int x, y;
44242542f5fSchristos	int line;
44342542f5fSchristos
44442542f5fSchristos	if (!can_use_shm(dpy))
44542542f5fSchristos		return 0;
44642542f5fSchristos
44742542f5fSchristos	printf("Creating %dx%d SHM pixmap\n", width, height);
44842542f5fSchristos	_x_error_occurred = 0;
44942542f5fSchristos
45042542f5fSchristos	shm.shmid = shmget(IPC_PRIVATE, height * 4*width, IPC_CREAT | 0666);
45142542f5fSchristos	if (shm.shmid == -1)
45242542f5fSchristos		return 0;
45342542f5fSchristos
45442542f5fSchristos	shm.shmaddr = shmat(shm.shmid, 0, 0);
45542542f5fSchristos	if (shm.shmaddr == (char *) -1) {
45642542f5fSchristos		shmctl(shm.shmid, IPC_RMID, NULL);
45742542f5fSchristos		return 0;
45842542f5fSchristos	}
45942542f5fSchristos
46042542f5fSchristos	shm.readOnly = False;
46142542f5fSchristos	XShmAttach(dpy, &shm);
46242542f5fSchristos
46342542f5fSchristos	pixmap = XShmCreatePixmap(dpy, DefaultRootWindow(dpy),
46442542f5fSchristos				  shm.shmaddr, &shm, width, height, 24);
46542542f5fSchristos	XSync(dpy, False);
46642542f5fSchristos	shmctl(shm.shmid, IPC_RMID, NULL);
46742542f5fSchristos
46842542f5fSchristos	if (_x_error_occurred) {
46942542f5fSchristos		XShmDetach(dpy, &shm);
47042542f5fSchristos		shmdt(shm.shmaddr);
47142542f5fSchristos		return 0;
47242542f5fSchristos	}
47342542f5fSchristos
47442542f5fSchristos	printf("Testing write of %dx%d SHM pixmap via DRI3 fd\n", width, height);
47542542f5fSchristos
47642542f5fSchristos	fd = dri3_create_fd(dpy, pixmap, &stride);
47742542f5fSchristos	if (fd < 0) {
47842542f5fSchristos		line = __LINE__;
47942542f5fSchristos		goto fail;
48042542f5fSchristos	}
48142542f5fSchristos
48242542f5fSchristos	handle = gem_import(device, fd);
48342542f5fSchristos	close(fd);
48442542f5fSchristos	if (handle == 0) {
48542542f5fSchristos		line = __LINE__;
48642542f5fSchristos		goto fail;
48742542f5fSchristos	}
48842542f5fSchristos
48942542f5fSchristos	if (gpu_fill(device, handle, width, height, stride, 32, I915_TILING_NONE, pixel)) {
49042542f5fSchristos		line = __LINE__;
49142542f5fSchristos		goto fail;
49242542f5fSchristos	}
49342542f5fSchristos
49442542f5fSchristos	gem_sync(device, handle, CPU);
49542542f5fSchristos	ptr = (uint32_t *)shm.shmaddr;
49642542f5fSchristos	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
49742542f5fSchristos		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
49842542f5fSchristos			if (ptr[y_loc[y]*width + x_loc[x]] != pixel) {
49942542f5fSchristos				printf("pixel[%d, %d]:%d = %08x\n", x, y, 32, ptr[y_loc[y] * width + x_loc[x]]);
50042542f5fSchristos				line = __LINE__;
50142542f5fSchristos				goto fail;
50242542f5fSchristos			}
50342542f5fSchristos
50442542f5fSchristos	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
50542542f5fSchristos		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
50642542f5fSchristos			if (!check_pixmap(dpy, pixmap,
50742542f5fSchristos					  x_loc[x], y_loc[y],
50842542f5fSchristos					  pixel, 32)) {
50942542f5fSchristos				line = __LINE__;
51042542f5fSchristos				goto fail;
51142542f5fSchristos			}
51242542f5fSchristos
51342542f5fSchristos	if (_x_error_occurred) {
51442542f5fSchristos		line = __LINE__;
51542542f5fSchristos		goto fail;
51642542f5fSchristos	}
51742542f5fSchristos
51842542f5fSchristosout:
51942542f5fSchristos	gem_close(device, handle);
52042542f5fSchristos	XFreePixmap(dpy, pixmap);
52142542f5fSchristos	XShmDetach(dpy, &shm);
52242542f5fSchristos	shmdt(shm.shmaddr);
52342542f5fSchristos	return fd != -1;
52442542f5fSchristos
52542542f5fSchristosfail:
52642542f5fSchristos	printf("%s failed at (%dx%d), line %d\n",
52742542f5fSchristos	       __func__, width, height, line);
52842542f5fSchristos	fd = -1;
52942542f5fSchristos	goto out;
53042542f5fSchristos}
53142542f5fSchristos
53242542f5fSchristosstatic int test_read_after_write(Display *dpy, int device,
53342542f5fSchristos				 int width, int height, int depth,
53442542f5fSchristos				 int domain)
53542542f5fSchristos{
53642542f5fSchristos	const uint32_t pixel = 0xffff00ff;
53742542f5fSchristos	const int x_loc[] = {0, width/2, width-1};
53842542f5fSchristos	const int y_loc[] = {0, height/2, height-1};
53942542f5fSchristos	Window root = RootWindow(dpy, DefaultScreen(dpy));
54042542f5fSchristos	uint32_t src, dst;
54142542f5fSchristos	int src_fd, dst_fd;
54242542f5fSchristos	int src_stride, src_size;
54342542f5fSchristos	int dst_stride, dst_size;
54442542f5fSchristos	Pixmap src_pix, dst_pix;
54542542f5fSchristos	struct dri3_fence fence;
54642542f5fSchristos	int x, y, bpp;
54742542f5fSchristos
54842542f5fSchristos	_x_error_occurred = 0;
54942542f5fSchristos
55042542f5fSchristos	switch (depth) {
55142542f5fSchristos	case 8: bpp = 8; break;
55242542f5fSchristos	case 16: bpp = 16; break;
55342542f5fSchristos	case 24: bpp = 32; break;
55442542f5fSchristos	case 32: bpp = 32; break;
55542542f5fSchristos	default: return 0;
55642542f5fSchristos	}
55742542f5fSchristos
55842542f5fSchristos	src_stride = width * bpp/8;
55942542f5fSchristos	src_size = PAGE_ALIGN(src_stride * height);
56042542f5fSchristos	printf("Creating %dx%d (source stride=%d, size=%d, domain=%d)\n",
56142542f5fSchristos	       width, height, src_stride, src_size, domain);
56242542f5fSchristos
56342542f5fSchristos	src = gem_create(device, src_size);
56442542f5fSchristos	if (!src)
56542542f5fSchristos		goto fail;
56642542f5fSchristos
56742542f5fSchristos	if (domain == CPU)
56842542f5fSchristos		gem_set_caching(device, src, 1);
56942542f5fSchristos
57042542f5fSchristos	gem_fill(device, src, pixel, src_size, domain);
57142542f5fSchristos
57242542f5fSchristos	src_fd = gem_export(device, src);
57342542f5fSchristos	if (src_fd < 0)
57442542f5fSchristos		goto fail;
57542542f5fSchristos
57642542f5fSchristos	src_pix = dri3_create_pixmap(dpy, root,
57742542f5fSchristos				     width, height, depth,
57842542f5fSchristos				     src_fd, bpp, src_stride, src_size);
57942542f5fSchristos
58042542f5fSchristos	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
58142542f5fSchristos		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
58242542f5fSchristos			if (!check_pixmap(dpy, src_pix,
58342542f5fSchristos					  x_loc[x], y_loc[y],
58442542f5fSchristos					  pixel, bpp))
58542542f5fSchristos				goto fail;
58642542f5fSchristos	close(src_fd);
58742542f5fSchristos
58842542f5fSchristos	dst_pix = XCreatePixmap(dpy, root, width, height, depth);
58942542f5fSchristos	if (dri3_create_fence(dpy, dst_pix, &fence))
59042542f5fSchristos		goto fail;
59142542f5fSchristos
59242542f5fSchristos	dst_fd = dri3_create_fd(dpy, dst_pix, &dst_stride);
59342542f5fSchristos	if (dst_fd < 0)
59442542f5fSchristos		goto fail;
59542542f5fSchristos	dst_size = lseek(dst_fd, 0, SEEK_END);
59642542f5fSchristos	printf("Comparing %dx%d (destination stride=%d, size=%d)\n",
59742542f5fSchristos	       width, height, dst_stride, dst_size);
59842542f5fSchristos	dst = gem_import(device, dst_fd);
59942542f5fSchristos	if (dst == 0)
60042542f5fSchristos		goto fail;
60142542f5fSchristos	close(dst_fd);
60242542f5fSchristos
60342542f5fSchristos	XCopyArea(dpy, src_pix, dst_pix,
60442542f5fSchristos		  get_gc(dpy, dst_pix, depth),
60542542f5fSchristos		  0, 0, width, height, 0, 0);
60642542f5fSchristos	dri3_fence_sync(dpy, &fence);
60742542f5fSchristos	dri3_fence_free(dpy, &fence);
60842542f5fSchristos
60942542f5fSchristos	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
61042542f5fSchristos		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
61142542f5fSchristos			if (!check_pixel(device, dst, dst_stride, dst_size,
61242542f5fSchristos					 x_loc[x], y_loc[y],
61342542f5fSchristos					 pixel, bpp, GTT))
61442542f5fSchristos				goto fail;
61542542f5fSchristos
61642542f5fSchristos	XFreePixmap(dpy, dst_pix);
61742542f5fSchristos	XFreePixmap(dpy, src_pix);
61842542f5fSchristos
61942542f5fSchristos	gem_close(device, src);
62042542f5fSchristos	gem_close(device, dst);
62142542f5fSchristos
62242542f5fSchristos	if (_x_error_occurred)
62342542f5fSchristos		goto fail;
62442542f5fSchristos
62542542f5fSchristos	return 0;
62642542f5fSchristos
62742542f5fSchristosfail:
62842542f5fSchristos	printf("%s failed at (%dx%d), depth=%d, domain=%d\n",
62942542f5fSchristos	       __func__, width, height, depth, domain);
63042542f5fSchristos	return 1;
63142542f5fSchristos}
63242542f5fSchristos
63342542f5fSchristosstatic XRenderPictFormat *format_for_depth(Display *dpy, int depth)
63442542f5fSchristos{
63542542f5fSchristos	switch (depth) {
63642542f5fSchristos	case 8: return XRenderFindStandardFormat(dpy, PictStandardA8);
63742542f5fSchristos	case 24: return XRenderFindStandardFormat(dpy, PictStandardRGB24);
63842542f5fSchristos	case 32: return XRenderFindStandardFormat(dpy, PictStandardARGB32);
63942542f5fSchristos	default: assert(0); return NULL;
64042542f5fSchristos	}
64142542f5fSchristos}
64242542f5fSchristos
64342542f5fSchristosstatic int test_read(Display *dpy, int device,
64442542f5fSchristos		     int width, int height,
64542542f5fSchristos		     int domain)
64642542f5fSchristos{
64742542f5fSchristos	const uint32_t pixel = 0xffff00ff;
64842542f5fSchristos	const XRenderColor color = { 0xffff, 0x0000, 0xffff, 0xffff };
64942542f5fSchristos	const int x_loc[] = {0, width/2, width-1};
65042542f5fSchristos	const int y_loc[] = {0, height/2, height-1};
65142542f5fSchristos	Window root = RootWindow(dpy, DefaultScreen(dpy));
65242542f5fSchristos	uint32_t dst;
65342542f5fSchristos	int dst_stride, dst_size, dst_fd;
65442542f5fSchristos	Pixmap src_pix, dst_pix;
65542542f5fSchristos	Picture src_pic;
65642542f5fSchristos	struct dri3_fence fence;
65742542f5fSchristos	int depth = 32, bpp = 32;
65842542f5fSchristos	int x, y;
65942542f5fSchristos
66042542f5fSchristos	_x_error_occurred = 0;
66142542f5fSchristos
66242542f5fSchristos	dst_stride = width * bpp/8;
66342542f5fSchristos	dst_size = PAGE_ALIGN(dst_stride * height);
66442542f5fSchristos	printf("Creating %dx%d (destination stride=%d, size=%d, domain=%d)\n",
66542542f5fSchristos	       width, height, dst_stride, dst_size, domain);
66642542f5fSchristos
66742542f5fSchristos	dst = gem_create(device, dst_size);
66842542f5fSchristos	if (!dst)
66942542f5fSchristos		goto fail;
67042542f5fSchristos
67142542f5fSchristos	if (domain == CPU)
67242542f5fSchristos		gem_set_caching(device, dst, 1);
67342542f5fSchristos
67442542f5fSchristos	gem_fill(device, dst, ~pixel, dst_size, domain);
67542542f5fSchristos
67642542f5fSchristos	dst_fd = gem_export(device, dst);
67742542f5fSchristos	if (dst_fd < 0)
67842542f5fSchristos		goto fail;
67942542f5fSchristos
68042542f5fSchristos	dst_pix = dri3_create_pixmap(dpy, root,
68142542f5fSchristos				     width, height, depth,
68242542f5fSchristos				     dst_fd, bpp, dst_stride, dst_size);
68342542f5fSchristos	XSync(dpy, True);
68442542f5fSchristos	if (_x_error_occurred)
68542542f5fSchristos		goto fail;
68642542f5fSchristos	if (dri3_create_fence(dpy, dst_pix, &fence))
68742542f5fSchristos		goto fail;
68842542f5fSchristos
68942542f5fSchristos	src_pix = XCreatePixmap(dpy, root, width, height, depth);
69042542f5fSchristos	src_pic = XRenderCreatePicture(dpy, src_pix, format_for_depth(dpy, depth), 0, NULL);
69142542f5fSchristos	XRenderFillRectangle(dpy, PictOpSrc, src_pic, &color, 0, 0, width, height);
69242542f5fSchristos	XCopyArea(dpy, src_pix, dst_pix,
69342542f5fSchristos		  get_gc(dpy, dst_pix, depth),
69442542f5fSchristos		  0, 0, width, height, 0, 0);
69542542f5fSchristos	dri3_fence_sync(dpy, &fence);
69642542f5fSchristos	dri3_fence_free(dpy, &fence);
69742542f5fSchristos
69842542f5fSchristos	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
69942542f5fSchristos		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
70042542f5fSchristos			if (!check_pixel(device, dst, dst_stride, dst_size,
70142542f5fSchristos					 x_loc[x], y_loc[y],
70242542f5fSchristos					 pixel, bpp, domain))
70342542f5fSchristos				goto fail;
70442542f5fSchristos
70542542f5fSchristos	XFreePixmap(dpy, dst_pix);
70642542f5fSchristos	XRenderFreePicture(dpy, src_pic);
70742542f5fSchristos	XFreePixmap(dpy, src_pix);
70842542f5fSchristos
70942542f5fSchristos	gem_close(device, dst);
71042542f5fSchristos
71142542f5fSchristos	if (_x_error_occurred)
71242542f5fSchristos		goto fail;
71342542f5fSchristos
71442542f5fSchristos	return 0;
71542542f5fSchristos
71642542f5fSchristosfail:
71742542f5fSchristos	printf("%s failed at (%dx%d), depth=%d, domain=%d\n",
71842542f5fSchristos	       __func__, width, height, depth, domain);
71942542f5fSchristos	return 1;
72042542f5fSchristos}
72142542f5fSchristos
72242542f5fSchristosstatic int test_dup_pixmap(Display *dpy, int device)
72342542f5fSchristos{
72442542f5fSchristos	const uint32_t pixel = 0xffff00ff;
72542542f5fSchristos	const XRenderColor color = { 0xffff, 0x0000, 0xffff, 0xffff };
72642542f5fSchristos	const XRenderColor inverse = { 0, 0xffff, 0, 0 };
72742542f5fSchristos	int width = 400, height = 400;
72842542f5fSchristos	const int x_loc[] = {0, width/2, width-1};
72942542f5fSchristos	const int y_loc[] = {0, height/2, height-1};
73042542f5fSchristos	Window root = RootWindow(dpy, DefaultScreen(dpy));
73142542f5fSchristos	uint32_t handle;
73242542f5fSchristos	int stride, size, fd;
73342542f5fSchristos	Pixmap src_pix, dst_pix;
73442542f5fSchristos	Picture src_pic, dst_pic;
73542542f5fSchristos	struct dri3_fence fence;
73642542f5fSchristos	int depth = 32, bpp = 32;
73742542f5fSchristos	int x, y;
73842542f5fSchristos
73942542f5fSchristos	_x_error_occurred = 0;
74042542f5fSchristos
74142542f5fSchristos	printf("%s: Creating %dx%d pixmap\n", __func__, width, height);
74242542f5fSchristos	src_pix = XCreatePixmap(dpy, root, width, height, depth);
74342542f5fSchristos	src_pic = XRenderCreatePicture(dpy, src_pix, format_for_depth(dpy, depth), 0, NULL);
74442542f5fSchristos	fd = dri3_create_fd(dpy, src_pix, &stride);
74542542f5fSchristos	if (fd < 0)
74642542f5fSchristos		goto fail;
74742542f5fSchristos
74842542f5fSchristos	size = lseek(fd, 0, SEEK_END);
74942542f5fSchristos	handle = gem_import(device, fd);
75042542f5fSchristos
75142542f5fSchristos	printf("%s: Creating duplicate from pixmap exported fd\n", __func__);
75242542f5fSchristos	dst_pix = dri3_create_pixmap(dpy, root,
75342542f5fSchristos				     width, height, depth,
75442542f5fSchristos				     fd, bpp, stride, size);
75542542f5fSchristos	dst_pic = XRenderCreatePicture(dpy, dst_pix, format_for_depth(dpy, depth), 0, NULL);
75642542f5fSchristos	XSync(dpy, True);
75742542f5fSchristos	if (_x_error_occurred)
75842542f5fSchristos		goto fail;
75942542f5fSchristos
76042542f5fSchristos	printf("%s: Filling src with %08x, reading dst\n", __func__, pixel);
76142542f5fSchristos	XRenderFillRectangle(dpy, PictOpSrc, src_pic, &color, 0, 0, width, height);
76242542f5fSchristos	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
76342542f5fSchristos		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
76442542f5fSchristos			if (!check_pixmap(dpy, dst_pix,
76542542f5fSchristos					  x_loc[x], y_loc[y],
76642542f5fSchristos					  pixel, 32))
76742542f5fSchristos				goto fail;
76842542f5fSchristos
76942542f5fSchristos	printf("%s: Filling dst with %08x, reading src\n", __func__, ~pixel);
77042542f5fSchristos	XRenderFillRectangle(dpy, PictOpSrc, dst_pic, &inverse, 0, 0, width, height);
77142542f5fSchristos	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
77242542f5fSchristos		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
77342542f5fSchristos			if (!check_pixmap(dpy, dst_pix,
77442542f5fSchristos					  x_loc[x], y_loc[y],
77542542f5fSchristos					  ~pixel, 32))
77642542f5fSchristos				goto fail;
77742542f5fSchristos
77842542f5fSchristos	if (dri3_create_fence(dpy, src_pix, &fence))
77942542f5fSchristos		goto fail;
78042542f5fSchristos
78142542f5fSchristos	printf("%s: Filling src with %08x, reading fd\n", __func__, pixel);
78242542f5fSchristos	XRenderFillRectangle(dpy, PictOpSrc, src_pic, &color, 0, 0, width, height);
78342542f5fSchristos	dri3_fence_sync(dpy, &fence);
78442542f5fSchristos	dri3_fence_free(dpy, &fence);
78542542f5fSchristos	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
78642542f5fSchristos		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
78742542f5fSchristos			if (!check_pixel(device, handle, stride, size,
78842542f5fSchristos					 x_loc[x], y_loc[y],
78942542f5fSchristos					 pixel, bpp, GTT))
79042542f5fSchristos				goto fail;
79142542f5fSchristos
79242542f5fSchristos	printf("%s: Filling fd with %08x, reading src\n", __func__, ~pixel);
79342542f5fSchristos	if (gpu_fill(device, handle, width, height, stride, 32, gem_get_tiling(device, handle), ~pixel))
79442542f5fSchristos		goto fail;
79542542f5fSchristos	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
79642542f5fSchristos		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
79742542f5fSchristos			if (!check_pixmap(dpy, src_pix,
79842542f5fSchristos					  x_loc[x], y_loc[y],
79942542f5fSchristos					  ~pixel, 32))
80042542f5fSchristos				goto fail;
80142542f5fSchristos
80242542f5fSchristos	if (dri3_create_fence(dpy, dst_pix, &fence))
80342542f5fSchristos		goto fail;
80442542f5fSchristos
80542542f5fSchristos	printf("%s: Filling dst with %08x, reading fd\n", __func__, pixel);
80642542f5fSchristos	XRenderFillRectangle(dpy, PictOpSrc, dst_pic, &color, 0, 0, width, height);
80742542f5fSchristos	dri3_fence_sync(dpy, &fence);
80842542f5fSchristos	dri3_fence_free(dpy, &fence);
80942542f5fSchristos	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
81042542f5fSchristos		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
81142542f5fSchristos			if (!check_pixel(device, handle, stride, size,
81242542f5fSchristos					 x_loc[x], y_loc[y],
81342542f5fSchristos					 pixel, bpp, GTT))
81442542f5fSchristos				goto fail;
81542542f5fSchristos
81642542f5fSchristos	printf("%s: Filling fd with %08x, reading dst\n", __func__, ~pixel);
81742542f5fSchristos	if (gpu_fill(device, handle, width, height, stride, 32, gem_get_tiling(device, handle), ~pixel))
81842542f5fSchristos		goto fail;
81942542f5fSchristos	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
82042542f5fSchristos		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
82142542f5fSchristos			if (!check_pixmap(dpy, dst_pix,
82242542f5fSchristos					  x_loc[x], y_loc[y],
82342542f5fSchristos					  ~pixel, 32))
82442542f5fSchristos				goto fail;
82542542f5fSchristos
82642542f5fSchristos	XRenderFreePicture(dpy, src_pic);
82742542f5fSchristos	XFreePixmap(dpy, src_pix);
82842542f5fSchristos
82942542f5fSchristos	if (dri3_create_fence(dpy, dst_pix, &fence))
83042542f5fSchristos		goto fail;
83142542f5fSchristos
83242542f5fSchristos	printf("%s: Closed original src, filling dst with %08x, reading fd\n", __func__, pixel);
83342542f5fSchristos	XRenderFillRectangle(dpy, PictOpSrc, dst_pic, &color, 0, 0, width, height);
83442542f5fSchristos	dri3_fence_sync(dpy, &fence);
83542542f5fSchristos	dri3_fence_free(dpy, &fence);
83642542f5fSchristos	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
83742542f5fSchristos		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
83842542f5fSchristos			if (!check_pixel(device, handle, stride, size,
83942542f5fSchristos					 x_loc[x], y_loc[y],
84042542f5fSchristos					 pixel, bpp, GTT))
84142542f5fSchristos				goto fail;
84242542f5fSchristos
84342542f5fSchristos	XRenderFreePicture(dpy, dst_pic);
84442542f5fSchristos	XFreePixmap(dpy, dst_pix);
84542542f5fSchristos
84642542f5fSchristos	gem_close(device, handle);
84742542f5fSchristos
84842542f5fSchristos	if (_x_error_occurred)
84942542f5fSchristos		goto fail;
85042542f5fSchristos
85142542f5fSchristos	return 0;
85242542f5fSchristos
85342542f5fSchristosfail:
85442542f5fSchristos	printf("%s failed at (%dx%d), depth=%d\n",
85542542f5fSchristos	       __func__, width, height, depth);
85642542f5fSchristos	return 1;
85742542f5fSchristos}
85842542f5fSchristos
85942542f5fSchristosstatic int test_bad_size(Display *dpy, int device)
86042542f5fSchristos{
86142542f5fSchristos	Window root = RootWindow(dpy, DefaultScreen(dpy));
86242542f5fSchristos	uint32_t src;
86342542f5fSchristos	int src_fd;
86442542f5fSchristos	Pixmap src_pix;
86542542f5fSchristos	int line = -1;
86642542f5fSchristos
86742542f5fSchristos	_x_error_occurred = 0;
86842542f5fSchristos
86942542f5fSchristos	src = gem_create(device, 4096);
87042542f5fSchristos	if (!src)
87142542f5fSchristos		goto fail;
87242542f5fSchristos
87342542f5fSchristos	src_fd = gem_export(device, src);
87442542f5fSchristos	if (src_fd < 0)
87542542f5fSchristos		goto fail;
87642542f5fSchristos
87742542f5fSchristos	src_pix = dri3_create_pixmap(dpy, root,
87842542f5fSchristos				     16, 16, 32,
87942542f5fSchristos				     dup(src_fd), 32, 16*4, 4096);
88042542f5fSchristos	line = __LINE__;
88142542f5fSchristos	XSync(dpy, True);
88242542f5fSchristos	if (_x_error_occurred)
88342542f5fSchristos		goto fail;
88442542f5fSchristos	XFreePixmap(dpy, src_pix);
88542542f5fSchristos	_x_error_occurred = 0;
88642542f5fSchristos
88742542f5fSchristos	src_pix = dri3_create_pixmap(dpy, root,
88842542f5fSchristos				     32, 32, 32,
88942542f5fSchristos				     dup(src_fd), 32, 32*4, 4096);
89042542f5fSchristos	line = __LINE__;
89142542f5fSchristos	XSync(dpy, True);
89242542f5fSchristos	if (_x_error_occurred)
89342542f5fSchristos		goto fail;
89442542f5fSchristos	XFreePixmap(dpy, src_pix);
89542542f5fSchristos	_x_error_occurred = 0;
89642542f5fSchristos
89742542f5fSchristos	src_pix = dri3_create_pixmap(dpy, root,
89842542f5fSchristos				     64, 64, 32,
89942542f5fSchristos				     dup(src_fd), 32, 64*4, 4096);
90042542f5fSchristos	line = __LINE__;
90142542f5fSchristos	XSync(dpy, True);
90242542f5fSchristos	if (!_x_error_occurred)
90342542f5fSchristos		goto fail;
90442542f5fSchristos	_x_error_occurred = 0;
90542542f5fSchristos
90642542f5fSchristos	src_pix = dri3_create_pixmap(dpy, root,
90742542f5fSchristos				     64, 64, 32,
90842542f5fSchristos				     dup(src_fd), 32, 64*4, 64*64*4);
90942542f5fSchristos	line = __LINE__;
91042542f5fSchristos	XSync(dpy, True);
91142542f5fSchristos	if (!_x_error_occurred)
91242542f5fSchristos		goto fail;
91342542f5fSchristos	_x_error_occurred = 0;
91442542f5fSchristos
91542542f5fSchristos	src_pix = dri3_create_pixmap(dpy, root,
91642542f5fSchristos				     INT16_MAX, INT16_MAX, 8,
91742542f5fSchristos				     dup(src_fd), 8, INT16_MAX, UINT32_MAX);
91842542f5fSchristos	line = __LINE__;
91942542f5fSchristos	XSync(dpy, True);
92042542f5fSchristos	if (!_x_error_occurred)
92142542f5fSchristos		goto fail;
92242542f5fSchristos	_x_error_occurred = 0;
92342542f5fSchristos
92442542f5fSchristos	close(src_fd);
92542542f5fSchristos	gem_close(device, src);
92642542f5fSchristos
92742542f5fSchristos	return 0;
92842542f5fSchristos
92942542f5fSchristosfail:
93042542f5fSchristos	printf("%s failed at line %d\n", __func__, line);
93142542f5fSchristos	return 1;
93242542f5fSchristos}
93342542f5fSchristos
93442542f5fSchristosstatic int test_bad_pitch(Display *dpy, int device)
93542542f5fSchristos{
93642542f5fSchristos	Window root = RootWindow(dpy, DefaultScreen(dpy));
93742542f5fSchristos	uint32_t src;
93842542f5fSchristos	int src_fd;
93942542f5fSchristos	Pixmap src_pix;
94042542f5fSchristos	int line = -1;
94142542f5fSchristos
94242542f5fSchristos	_x_error_occurred = 0;
94342542f5fSchristos
94442542f5fSchristos	src = gem_create(device, 4096);
94542542f5fSchristos	if (!src)
94642542f5fSchristos		goto fail;
94742542f5fSchristos
94842542f5fSchristos	src_fd = gem_export(device, src);
94942542f5fSchristos	if (src_fd < 0)
95042542f5fSchristos		goto fail;
95142542f5fSchristos
95242542f5fSchristos	src_pix = dri3_create_pixmap(dpy, root,
95342542f5fSchristos				     16, 16, 32,
95442542f5fSchristos				     dup(src_fd), 32, 16*4, 4096);
95542542f5fSchristos	line = __LINE__;
95642542f5fSchristos	XSync(dpy, True);
95742542f5fSchristos	if (_x_error_occurred)
95842542f5fSchristos		goto fail;
95942542f5fSchristos	XFreePixmap(dpy, src_pix);
96042542f5fSchristos	_x_error_occurred = 0;
96142542f5fSchristos
96242542f5fSchristos	src_pix = dri3_create_pixmap(dpy, root,
96342542f5fSchristos				     256, 2, 32,
96442542f5fSchristos				     dup(src_fd), 32, 256*4, 4096);
96542542f5fSchristos	line = __LINE__;
96642542f5fSchristos	XSync(dpy, True);
96742542f5fSchristos	if (_x_error_occurred)
96842542f5fSchristos		goto fail;
96942542f5fSchristos	XFreePixmap(dpy, src_pix);
97042542f5fSchristos	_x_error_occurred = 0;
97142542f5fSchristos
97242542f5fSchristos	src_pix = dri3_create_pixmap(dpy, root,
97342542f5fSchristos				     256, 2, 32,
97442542f5fSchristos				     dup(src_fd), 32, 256, 4096);
97542542f5fSchristos	line = __LINE__;
97642542f5fSchristos	XSync(dpy, True);
97742542f5fSchristos	if (!_x_error_occurred)
97842542f5fSchristos		goto fail;
97942542f5fSchristos	_x_error_occurred = 0;
98042542f5fSchristos
98142542f5fSchristos	src_pix = dri3_create_pixmap(dpy, root,
98242542f5fSchristos				     256, 2, 32,
98342542f5fSchristos				     dup(src_fd), 32, 16384, 4096);
98442542f5fSchristos	line = __LINE__;
98542542f5fSchristos	XSync(dpy, True);
98642542f5fSchristos	if (!_x_error_occurred)
98742542f5fSchristos		goto fail;
98842542f5fSchristos	_x_error_occurred = 0;
98942542f5fSchristos
99042542f5fSchristos	src_pix = dri3_create_pixmap(dpy, root,
99142542f5fSchristos				     256, 2, 32,
99242542f5fSchristos				     dup(src_fd), 32, 1023, 4096);
99342542f5fSchristos	line = __LINE__;
99442542f5fSchristos	XSync(dpy, True);
99542542f5fSchristos	if (!_x_error_occurred)
99642542f5fSchristos		goto fail;
99742542f5fSchristos	_x_error_occurred = 0;
99842542f5fSchristos
99942542f5fSchristos	src_pix = dri3_create_pixmap(dpy, root,
100042542f5fSchristos				     256, 2, 32,
100142542f5fSchristos				     dup(src_fd), 32, 1025, 4096);
100242542f5fSchristos	line = __LINE__;
100342542f5fSchristos	XSync(dpy, True);
100442542f5fSchristos	if (!_x_error_occurred)
100542542f5fSchristos		goto fail;
100642542f5fSchristos	_x_error_occurred = 0;
100742542f5fSchristos
100842542f5fSchristos	close(src_fd);
100942542f5fSchristos	gem_close(device, src);
101042542f5fSchristos
101142542f5fSchristos	return 0;
101242542f5fSchristos
101342542f5fSchristosfail:
101442542f5fSchristos	printf("%s failed at line %d\n", __func__, line);
101542542f5fSchristos	return 1;
101642542f5fSchristos}
101742542f5fSchristos
1018fe8aea9eSmrgstatic int gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
1019fe8aea9eSmrg{
1020fe8aea9eSmrg	struct drm_i915_gem_set_tiling set_tiling;
1021fe8aea9eSmrg
1022fe8aea9eSmrg	set_tiling.handle = handle;
1023fe8aea9eSmrg	set_tiling.tiling_mode = tiling;
1024fe8aea9eSmrg	set_tiling.stride = stride;
1025fe8aea9eSmrg
1026fe8aea9eSmrg	return drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0;
1027fe8aea9eSmrg}
1028fe8aea9eSmrg
1029fe8aea9eSmrgstatic int test_tiling(Display *dpy, int device)
1030fe8aea9eSmrg{
1031fe8aea9eSmrg	Window root = RootWindow(dpy, DefaultScreen(dpy));
1032fe8aea9eSmrg	const int tiling[] = { I915_TILING_NONE, I915_TILING_X, I915_TILING_Y };
1033fe8aea9eSmrg	int line = -1;
1034fe8aea9eSmrg	int t;
1035fe8aea9eSmrg
1036fe8aea9eSmrg	_x_error_occurred = 0;
1037fe8aea9eSmrg
1038fe8aea9eSmrg	for (t = 0; t < sizeof(tiling)/sizeof(tiling[0]); t++) {
1039fe8aea9eSmrg		uint32_t src;
1040fe8aea9eSmrg		int src_fd;
1041fe8aea9eSmrg		Pixmap src_pix;
1042fe8aea9eSmrg
1043fe8aea9eSmrg		src = gem_create(device, 4*4096);
1044fe8aea9eSmrg		if (!src) {
1045fe8aea9eSmrg			line = __LINE__;
1046fe8aea9eSmrg			goto fail;
1047fe8aea9eSmrg		}
1048fe8aea9eSmrg
1049fe8aea9eSmrg		gem_set_tiling(device, src, tiling[t], 512);
1050fe8aea9eSmrg
1051fe8aea9eSmrg		src_fd = gem_export(device, src);
1052fe8aea9eSmrg		if (src_fd < 0) {
1053fe8aea9eSmrg			line = __LINE__;
1054fe8aea9eSmrg			goto fail;
1055fe8aea9eSmrg		}
1056fe8aea9eSmrg
1057fe8aea9eSmrg		src_pix = dri3_create_pixmap(dpy, root,
1058fe8aea9eSmrg					     128, 32, 32,
1059fe8aea9eSmrg					     src_fd, 32, 512, 4*4096);
1060fe8aea9eSmrg		XSync(dpy, True);
1061fe8aea9eSmrg		if (_x_error_occurred) {
1062fe8aea9eSmrg			line = __LINE__;
1063fe8aea9eSmrg			goto fail;
1064fe8aea9eSmrg		}
1065fe8aea9eSmrg		XFreePixmap(dpy, src_pix);
1066fe8aea9eSmrg		_x_error_occurred = 0;
1067fe8aea9eSmrg
1068fe8aea9eSmrg		close(src_fd);
1069fe8aea9eSmrg		gem_close(device, src);
1070fe8aea9eSmrg	}
1071fe8aea9eSmrg
1072fe8aea9eSmrg	return 0;
1073fe8aea9eSmrg
1074fe8aea9eSmrgfail:
1075fe8aea9eSmrg	printf("%s failed with tiling %d, line %d\n", __func__, tiling[t], line);
1076fe8aea9eSmrg	return 1;
1077fe8aea9eSmrg}
1078fe8aea9eSmrg
107942542f5fSchristosstatic int
108042542f5fSchristos_check_error_handler(Display     *display,
108142542f5fSchristos		     XErrorEvent *event)
108242542f5fSchristos{
108342542f5fSchristos	printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
108442542f5fSchristos	       DisplayString(display),
108542542f5fSchristos	       event->serial,
108642542f5fSchristos	       event->error_code,
108742542f5fSchristos	       event->request_code,
108842542f5fSchristos	       event->minor_code);
108942542f5fSchristos	_x_error_occurred++;
109042542f5fSchristos	return False; /* ignored */
109142542f5fSchristos}
109242542f5fSchristos
109342542f5fSchristosint main(void)
109442542f5fSchristos{
109542542f5fSchristos	Display *dpy;
109642542f5fSchristos	int device;
109742542f5fSchristos	int error = 0;
109842542f5fSchristos
109942542f5fSchristos	dpy = XOpenDisplay(NULL);
110042542f5fSchristos	if (dpy == NULL)
110142542f5fSchristos		return 77;
110242542f5fSchristos
110342542f5fSchristos	if (DefaultDepth(dpy, DefaultScreen(dpy)) != 24)
110442542f5fSchristos		return 77;
110542542f5fSchristos
110642542f5fSchristos	XSetErrorHandler(_check_error_handler);
110742542f5fSchristos
110842542f5fSchristos	device = dri3_open(dpy);
110942542f5fSchristos	if (device < 0)
111042542f5fSchristos		return 127;
111142542f5fSchristos
111242542f5fSchristos	if (!is_intel(device))
111342542f5fSchristos		return 77;
111442542f5fSchristos
111542542f5fSchristos	printf("Opened Intel DRI3 device\n");
111642542f5fSchristos
111742542f5fSchristos	error += test_bad_size(dpy, device);
111842542f5fSchristos	error += test_bad_pitch(dpy, device);
1119fe8aea9eSmrg	error += test_tiling(dpy, device);
112042542f5fSchristos
112142542f5fSchristos	error += test_shm(dpy, device, 400, 300);
112242542f5fSchristos	error += test_shm(dpy, device, 300, 400);
112342542f5fSchristos
112442542f5fSchristos	error += test_read(dpy, device, 400, 200, GTT);
112542542f5fSchristos	error += test_read(dpy, device, 4000, 20, GTT);
112642542f5fSchristos	error += test_read(dpy, device, 16000, 10, GTT);
112742542f5fSchristos	error += test_read(dpy, device, 30000, 10, GTT);
112842542f5fSchristos
112942542f5fSchristos	error += test_read(dpy, device, 200, 400, GTT);
113042542f5fSchristos	error += test_read(dpy, device, 20, 4000, GTT);
113142542f5fSchristos	error += test_read(dpy, device, 16, 16000, GTT);
113242542f5fSchristos	error += test_read(dpy, device, 16, 30000, GTT);
113342542f5fSchristos
113442542f5fSchristos	error += test_read(dpy, device, 400, 200, CPU);
113542542f5fSchristos	error += test_read(dpy, device, 4000, 20, CPU);
113642542f5fSchristos	error += test_read(dpy, device, 16000, 10, CPU);
113742542f5fSchristos	error += test_read(dpy, device, 30000, 10, CPU);
113842542f5fSchristos
113942542f5fSchristos	error += test_read(dpy, device, 200, 400, CPU);
114042542f5fSchristos	error += test_read(dpy, device, 20, 4000, CPU);
114142542f5fSchristos	error += test_read(dpy, device, 16, 16000, CPU);
114242542f5fSchristos	error += test_read(dpy, device, 16, 30000, CPU);
114342542f5fSchristos
114442542f5fSchristos	error += test_read_after_write(dpy, device, 400, 200, 24, GTT);
114542542f5fSchristos	error += test_read_after_write(dpy, device, 4000, 20, 24, GTT);
114642542f5fSchristos	error += test_read_after_write(dpy, device, 16000, 10, 24, GTT);
114742542f5fSchristos	error += test_read_after_write(dpy, device, 30000, 10, 24, GTT);
114842542f5fSchristos	error += test_read_after_write(dpy, device, 30000, 10, 8, GTT);
114942542f5fSchristos
115042542f5fSchristos	error += test_read_after_write(dpy, device, 200, 400, 24, GTT);
115142542f5fSchristos	error += test_read_after_write(dpy, device, 20, 4000, 24, GTT);
115242542f5fSchristos	error += test_read_after_write(dpy, device, 16, 16000, 24, GTT);
115342542f5fSchristos	error += test_read_after_write(dpy, device, 16, 30000, 24, GTT);
115442542f5fSchristos
115542542f5fSchristos	error += test_read_after_write(dpy, device, 400, 200, 24, CPU);
115642542f5fSchristos	error += test_read_after_write(dpy, device, 4000, 20, 24, CPU);
115742542f5fSchristos	error += test_read_after_write(dpy, device, 16000, 10, 24, CPU);
115842542f5fSchristos	error += test_read_after_write(dpy, device, 30000, 10, 24, CPU);
115942542f5fSchristos	error += test_read_after_write(dpy, device, 30000, 10, 8, CPU);
116042542f5fSchristos
116142542f5fSchristos	error += test_read_after_write(dpy, device, 200, 400, 24, CPU);
116242542f5fSchristos	error += test_read_after_write(dpy, device, 20, 4000, 24, CPU);
116342542f5fSchristos	error += test_read_after_write(dpy, device, 16, 16000, 24, CPU);
116442542f5fSchristos	error += test_read_after_write(dpy, device, 16, 30000, 24, CPU);
116542542f5fSchristos
116642542f5fSchristos	error += test_dup_pixmap(dpy, device);
116742542f5fSchristos
116842542f5fSchristos	return !!error;
116942542f5fSchristos}
1170