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#include <xf86drm.h>
42#include <i915_drm.h>
43
44#include <stdio.h>
45#include <string.h>
46#include <fcntl.h>
47#include <unistd.h>
48#include <assert.h>
49#include <errno.h>
50
51#include <sys/mman.h>
52#include <sys/ipc.h>
53#include <sys/shm.h>
54#include <pciaccess.h>
55
56#include "dri3.h"
57#include "../src/i915_pciids.h"
58
59#define ALIGN(x, y) (((x) + (y) - 1) & -(y))
60#define PAGE_ALIGN(x) ALIGN(x, 4096)
61
62#define GTT I915_GEM_DOMAIN_GTT
63#define CPU I915_GEM_DOMAIN_CPU
64
65static int _x_error_occurred;
66
67static const struct pci_id_match ids[] = {
68	INTEL_I830_IDS(020),
69	INTEL_I845G_IDS(021),
70	INTEL_I85X_IDS(022),
71	INTEL_I865G_IDS(023),
72
73	INTEL_I915G_IDS(030),
74	INTEL_I915GM_IDS(030),
75	INTEL_I945G_IDS(031),
76	INTEL_I945GM_IDS(031),
77
78	INTEL_G33_IDS(033),
79	INTEL_PINEVIEW_IDS(033),
80
81	INTEL_I965G_IDS(040),
82	INTEL_I965GM_IDS(040),
83
84	INTEL_G45_IDS(045),
85	INTEL_GM45_IDS(045),
86
87	INTEL_IRONLAKE_D_IDS(050),
88	INTEL_IRONLAKE_M_IDS(050),
89
90	INTEL_SNB_D_IDS(060),
91	INTEL_SNB_M_IDS(060),
92
93	INTEL_IVB_D_IDS(070),
94	INTEL_IVB_M_IDS(070),
95
96	INTEL_HSW_IDS(075),
97	INTEL_VLV_IDS(071),
98	INTEL_BDW_IDS(0100),
99};
100
101static int i915_gen(int device)
102{
103	struct drm_i915_getparam gp;
104	int devid = 0;
105	int n;
106
107	gp.param = I915_PARAM_CHIPSET_ID;
108	gp.value = &devid;
109
110	if (drmIoctl(device, DRM_IOCTL_I915_GETPARAM, &gp))
111		return 0;
112
113	for (n = 0; n < sizeof(ids)/sizeof(ids[0]); n++) {
114		if (devid == ids[n].device_id)
115			return ids[n].match_data;
116	}
117
118	return 0;
119}
120
121static int is_i915_device(int fd)
122{
123	drm_version_t version;
124	char name[5] = "";
125
126	memset(&version, 0, sizeof(version));
127	version.name_len = 4;
128	version.name = name;
129
130	if (drmIoctl(fd, DRM_IOCTL_VERSION, &version))
131		return 0;
132
133	return strcmp("i915", name) == 0;
134}
135
136static int is_intel(int fd)
137{
138	struct drm_i915_getparam gp;
139	int ret;
140
141	/* Confirm that this is a i915.ko device with GEM/KMS enabled */
142	ret = is_i915_device(fd);
143	if (ret) {
144		gp.param = I915_PARAM_HAS_GEM;
145		gp.value = &ret;
146		if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp))
147			ret = 0;
148	}
149	return ret;
150}
151
152static uint32_t gem_create(int fd, int size)
153{
154	struct drm_i915_gem_create create;
155
156	create.handle = 0;
157	create.size = size;
158	(void)drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
159
160	return create.handle;
161}
162
163struct local_i915_gem_caching {
164	uint32_t handle;
165	uint32_t caching;
166};
167
168#define LOCAL_I915_GEM_SET_CACHING	0x2f
169#define LOCAL_IOCTL_I915_GEM_SET_CACHING DRM_IOW(DRM_COMMAND_BASE + LOCAL_I915_GEM_SET_CACHING, struct local_i915_gem_caching)
170
171static int gem_set_caching(int fd, uint32_t handle, int caching)
172{
173	struct local_i915_gem_caching arg;
174
175	arg.handle = handle;
176	arg.caching = caching;
177
178	return drmIoctl(fd, LOCAL_IOCTL_I915_GEM_SET_CACHING, &arg) == 0;
179}
180
181static int gem_export(int fd, uint32_t handle)
182{
183	struct drm_prime_handle args;
184
185	args.handle = handle;
186	args.flags = O_CLOEXEC;
187
188	if (drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args))
189		return -1;
190
191	return args.fd;
192}
193
194static uint32_t gem_import(int fd, int name)
195{
196	struct drm_prime_handle args;
197
198	args.fd = name;
199	args.flags = 0;
200	if (drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args))
201		return 0;
202
203	return args.handle;
204}
205
206static int gem_write(int fd, uint32_t handle, int offset, void *data, int len)
207{
208	struct drm_i915_gem_pwrite gem_pwrite;
209
210	gem_pwrite.handle = handle;
211	gem_pwrite.offset = offset;
212	gem_pwrite.size = len;
213	gem_pwrite.data_ptr = (uintptr_t)data;
214	return drmIoctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &gem_pwrite);
215}
216
217static void *gem_mmap(int fd, uint32_t handle, int size, unsigned prot, int domain)
218{
219	struct drm_i915_gem_set_domain set_domain;
220	void *ptr;
221
222	if (domain == CPU) {
223		struct drm_i915_gem_mmap mmap_arg;
224
225		mmap_arg.handle = handle;
226		mmap_arg.offset = 0;
227		mmap_arg.size = size;
228		if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg))
229			return NULL;
230
231		ptr = (void *)(uintptr_t)mmap_arg.addr_ptr;
232	} else {
233		struct drm_i915_gem_mmap_gtt mmap_arg;
234
235		mmap_arg.handle = handle;
236		if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg))
237			return NULL;
238
239		ptr = mmap(0, size, prot, MAP_SHARED, fd, mmap_arg.offset);
240		if (ptr == MAP_FAILED)
241			return NULL;
242	}
243
244	set_domain.handle = handle;
245	set_domain.read_domains = domain;
246	set_domain.write_domain = prot & PROT_WRITE ? set_domain.read_domains : 0;
247	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) {
248		munmap(ptr, size);
249		return NULL;
250	}
251
252	return ptr;
253}
254
255static void gem_sync(int fd, uint32_t handle, int read)
256{
257	struct drm_i915_gem_set_domain set_domain;
258
259	set_domain.handle = handle;
260	set_domain.read_domains = read;
261	set_domain.write_domain = 0;
262	drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
263}
264
265static int gem_get_tiling(int fd, uint32_t handle)
266{
267	struct drm_i915_gem_get_tiling tiling;
268
269	tiling.handle = handle;
270	tiling.tiling_mode = -1;
271	(void)drmIoctl(fd, DRM_IOCTL_I915_GEM_GET_TILING, &tiling);
272	return tiling.tiling_mode;
273}
274
275static void gem_close(int fd, uint32_t handle)
276{
277	struct drm_gem_close close;
278
279	close.handle = handle;
280	(void)drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close);
281}
282
283static void gem_fill(int fd, uint32_t handle, uint32_t pixel, uint32_t size, int domain)
284{
285	uint32_t *ptr, s;
286
287	ptr = gem_mmap(fd, handle, size, PROT_READ | PROT_WRITE, domain);
288	if (ptr == NULL)
289		return;
290
291	for (s = 0; s < size; s += 4)
292		ptr[s/4] = pixel;
293	munmap(ptr, size);
294}
295
296static int check_pixmap(Display *dpy, Pixmap pix,
297			int x, int y, uint32_t expected, int bpp)
298{
299	XImage *image;
300	int w = 32 / bpp;
301
302	image = XGetImage(dpy, pix, x - (x % w), y, w, 1, AllPlanes, ZPixmap);
303	if (image == NULL)
304		return 0;
305
306	if (*(uint32_t *)image->data != expected) {
307		printf("pixmap[%d, %d]:%d = %08x\n", x, y, bpp, *(uint32_t *)image->data);
308		return 0;
309	}
310	XDestroyImage(image);
311
312	return 1;
313}
314
315static int check_pixel(int fd, uint32_t handle, uint32_t stride, uint32_t size,
316		       int x, int y, uint32_t expected, int bpp, int domain)
317{
318	uint32_t *ptr;
319	int w = 32 / bpp;
320
321	assert((stride & 3) == 0);
322
323	ptr = gem_mmap(fd, handle, size, PROT_READ, domain);
324	if (ptr == NULL)
325		return 0;
326
327	if (ptr[(y*stride + x - (x % w))/4] != expected) {
328		printf("pixel[%d, %d]:%d = %08x\n", x, y, bpp, ptr[(y * stride + x)/4]);
329		return 0;
330	}
331	munmap(ptr, size);
332
333	return 1;
334}
335
336static GC get_gc(Display *dpy, Drawable d, int depth)
337{
338	static GC gc[33];
339	if (gc[depth] == NULL) {
340		XGCValues gcv;
341
342		gcv.graphics_exposures = False;
343		gc[depth] = XCreateGC(dpy, d, GCGraphicsExposures, &gcv);
344	}
345	return gc[depth];
346}
347
348static int
349can_use_shm(Display *dpy)
350{
351	int major, minor, has_pixmap;
352
353	if (!XShmQueryExtension(dpy))
354		return 0;
355
356	XShmQueryVersion(dpy, &major, &minor, &has_pixmap);
357	return has_pixmap;
358}
359
360static int gpu_fill(int device, int handle, int width, int height, int pitch, int bpp, int tiling, uint32_t pixel)
361{
362	struct drm_i915_gem_execbuffer2 execbuf;
363	struct drm_i915_gem_relocation_entry gem_reloc[2];
364	struct drm_i915_gem_exec_object2 gem_exec[2];
365	uint32_t batch[10];
366	int gen = i915_gen(device);
367	int len = 0;
368	int ret;
369
370	if (gen == 0)
371		return -ENODEV;
372
373	batch[0] = 2 << 29 | 0x50 << 22;
374	batch[0] |= (gen >= 0100 ? 5 : 4);
375	batch[1] = pitch;
376	if (gen >= 040 && tiling) {
377		batch[0] |= 1 << 11;
378		batch[1] >>= 2;
379	}
380
381	batch[1] |= 0xf0 << 16;
382	switch (bpp) {
383	default: assert(0);
384	case 32: batch[0] |= 1 << 21 | 1 << 20;
385		 batch[1] |= 1 << 25; /* RGB8888 */
386	case 16: batch[1] |= 1 << 24; /* RGB565 */
387	case 8: break;
388	}
389
390	batch[2] = 0;
391	batch[3] = height << 16 | width;
392	batch[4] = 0;
393	len = 5;
394	if (gen >= 0100)
395		batch[len++] = 0;
396	batch[len++] = pixel;
397	batch[len++] = 0xA << 23;
398	if (len & 1)
399		len++;
400
401	gem_reloc[0].offset = 4 * sizeof(uint32_t);
402	gem_reloc[0].delta = 0;
403	gem_reloc[0].target_handle = handle;
404	gem_reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;
405	gem_reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
406	gem_reloc[0].presumed_offset = 0;
407
408	memset(gem_exec, 0, sizeof(gem_exec));
409	gem_exec[0].handle = handle;
410	gem_exec[1].handle = gem_create(device, 4096);
411	gem_exec[1].relocation_count = 1;
412	gem_exec[1].relocs_ptr = (uintptr_t)gem_reloc;
413
414	memset(&execbuf, 0, sizeof(execbuf));
415	execbuf.buffers_ptr = (uintptr_t)gem_exec;
416	execbuf.buffer_count = 2;
417	execbuf.batch_len = len * sizeof(uint32_t);
418	execbuf.flags = gen >= 060 ? I915_EXEC_BLT : 0;
419
420	ret = gem_write(device, gem_exec[1].handle, 0, batch, execbuf.batch_len);
421	if (ret == 0)
422		ret = drmIoctl(device, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
423	if (ret < 0)
424		ret = -errno;
425
426	gem_close(device, gem_exec[1].handle);
427	return ret;
428}
429
430static int test_shm(Display *dpy, int device,
431		    int width, int height)
432{
433	const int x_loc[] = {0, width/2, width-1};
434	const int y_loc[] = {0, height/2, height-1};
435	uint32_t pixel = 0xffff00ff;
436	XShmSegmentInfo shm;
437	Pixmap pixmap;
438	uint32_t handle = 0;
439	uint32_t *ptr;
440	int stride, fd;
441	int x, y;
442	int line;
443
444	if (!can_use_shm(dpy))
445		return 0;
446
447	printf("Creating %dx%d SHM pixmap\n", width, height);
448	_x_error_occurred = 0;
449
450	shm.shmid = shmget(IPC_PRIVATE, height * 4*width, IPC_CREAT | 0666);
451	if (shm.shmid == -1)
452		return 0;
453
454	shm.shmaddr = shmat(shm.shmid, 0, 0);
455	if (shm.shmaddr == (char *) -1) {
456		shmctl(shm.shmid, IPC_RMID, NULL);
457		return 0;
458	}
459
460	shm.readOnly = False;
461	XShmAttach(dpy, &shm);
462
463	pixmap = XShmCreatePixmap(dpy, DefaultRootWindow(dpy),
464				  shm.shmaddr, &shm, width, height, 24);
465	XSync(dpy, False);
466	shmctl(shm.shmid, IPC_RMID, NULL);
467
468	if (_x_error_occurred) {
469		XShmDetach(dpy, &shm);
470		shmdt(shm.shmaddr);
471		return 0;
472	}
473
474	printf("Testing write of %dx%d SHM pixmap via DRI3 fd\n", width, height);
475
476	fd = dri3_create_fd(dpy, pixmap, &stride);
477	if (fd < 0) {
478		line = __LINE__;
479		goto fail;
480	}
481
482	handle = gem_import(device, fd);
483	close(fd);
484	if (handle == 0) {
485		line = __LINE__;
486		goto fail;
487	}
488
489	if (gpu_fill(device, handle, width, height, stride, 32, I915_TILING_NONE, pixel)) {
490		line = __LINE__;
491		goto fail;
492	}
493
494	gem_sync(device, handle, CPU);
495	ptr = (uint32_t *)shm.shmaddr;
496	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
497		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
498			if (ptr[y_loc[y]*width + x_loc[x]] != pixel) {
499				printf("pixel[%d, %d]:%d = %08x\n", x, y, 32, ptr[y_loc[y] * width + x_loc[x]]);
500				line = __LINE__;
501				goto fail;
502			}
503
504	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
505		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
506			if (!check_pixmap(dpy, pixmap,
507					  x_loc[x], y_loc[y],
508					  pixel, 32)) {
509				line = __LINE__;
510				goto fail;
511			}
512
513	if (_x_error_occurred) {
514		line = __LINE__;
515		goto fail;
516	}
517
518out:
519	gem_close(device, handle);
520	XFreePixmap(dpy, pixmap);
521	XShmDetach(dpy, &shm);
522	shmdt(shm.shmaddr);
523	return fd != -1;
524
525fail:
526	printf("%s failed at (%dx%d), line %d\n",
527	       __func__, width, height, line);
528	fd = -1;
529	goto out;
530}
531
532static int test_read_after_write(Display *dpy, int device,
533				 int width, int height, int depth,
534				 int domain)
535{
536	const uint32_t pixel = 0xffff00ff;
537	const int x_loc[] = {0, width/2, width-1};
538	const int y_loc[] = {0, height/2, height-1};
539	Window root = RootWindow(dpy, DefaultScreen(dpy));
540	uint32_t src, dst;
541	int src_fd, dst_fd;
542	int src_stride, src_size;
543	int dst_stride, dst_size;
544	Pixmap src_pix, dst_pix;
545	struct dri3_fence fence;
546	int x, y, bpp;
547
548	_x_error_occurred = 0;
549
550	switch (depth) {
551	case 8: bpp = 8; break;
552	case 16: bpp = 16; break;
553	case 24: bpp = 32; break;
554	case 32: bpp = 32; break;
555	default: return 0;
556	}
557
558	src_stride = width * bpp/8;
559	src_size = PAGE_ALIGN(src_stride * height);
560	printf("Creating %dx%d (source stride=%d, size=%d, domain=%d)\n",
561	       width, height, src_stride, src_size, domain);
562
563	src = gem_create(device, src_size);
564	if (!src)
565		goto fail;
566
567	if (domain == CPU)
568		gem_set_caching(device, src, 1);
569
570	gem_fill(device, src, pixel, src_size, domain);
571
572	src_fd = gem_export(device, src);
573	if (src_fd < 0)
574		goto fail;
575
576	src_pix = dri3_create_pixmap(dpy, root,
577				     width, height, depth,
578				     src_fd, bpp, src_stride, src_size);
579
580	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
581		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
582			if (!check_pixmap(dpy, src_pix,
583					  x_loc[x], y_loc[y],
584					  pixel, bpp))
585				goto fail;
586	close(src_fd);
587
588	dst_pix = XCreatePixmap(dpy, root, width, height, depth);
589	if (dri3_create_fence(dpy, dst_pix, &fence))
590		goto fail;
591
592	dst_fd = dri3_create_fd(dpy, dst_pix, &dst_stride);
593	if (dst_fd < 0)
594		goto fail;
595	dst_size = lseek(dst_fd, 0, SEEK_END);
596	printf("Comparing %dx%d (destination stride=%d, size=%d)\n",
597	       width, height, dst_stride, dst_size);
598	dst = gem_import(device, dst_fd);
599	if (dst == 0)
600		goto fail;
601	close(dst_fd);
602
603	XCopyArea(dpy, src_pix, dst_pix,
604		  get_gc(dpy, dst_pix, depth),
605		  0, 0, width, height, 0, 0);
606	dri3_fence_sync(dpy, &fence);
607	dri3_fence_free(dpy, &fence);
608
609	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
610		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
611			if (!check_pixel(device, dst, dst_stride, dst_size,
612					 x_loc[x], y_loc[y],
613					 pixel, bpp, GTT))
614				goto fail;
615
616	XFreePixmap(dpy, dst_pix);
617	XFreePixmap(dpy, src_pix);
618
619	gem_close(device, src);
620	gem_close(device, dst);
621
622	if (_x_error_occurred)
623		goto fail;
624
625	return 0;
626
627fail:
628	printf("%s failed at (%dx%d), depth=%d, domain=%d\n",
629	       __func__, width, height, depth, domain);
630	return 1;
631}
632
633static XRenderPictFormat *format_for_depth(Display *dpy, int depth)
634{
635	switch (depth) {
636	case 8: return XRenderFindStandardFormat(dpy, PictStandardA8);
637	case 24: return XRenderFindStandardFormat(dpy, PictStandardRGB24);
638	case 32: return XRenderFindStandardFormat(dpy, PictStandardARGB32);
639	default: assert(0); return NULL;
640	}
641}
642
643static int test_read(Display *dpy, int device,
644		     int width, int height,
645		     int domain)
646{
647	const uint32_t pixel = 0xffff00ff;
648	const XRenderColor color = { 0xffff, 0x0000, 0xffff, 0xffff };
649	const int x_loc[] = {0, width/2, width-1};
650	const int y_loc[] = {0, height/2, height-1};
651	Window root = RootWindow(dpy, DefaultScreen(dpy));
652	uint32_t dst;
653	int dst_stride, dst_size, dst_fd;
654	Pixmap src_pix, dst_pix;
655	Picture src_pic;
656	struct dri3_fence fence;
657	int depth = 32, bpp = 32;
658	int x, y;
659
660	_x_error_occurred = 0;
661
662	dst_stride = width * bpp/8;
663	dst_size = PAGE_ALIGN(dst_stride * height);
664	printf("Creating %dx%d (destination stride=%d, size=%d, domain=%d)\n",
665	       width, height, dst_stride, dst_size, domain);
666
667	dst = gem_create(device, dst_size);
668	if (!dst)
669		goto fail;
670
671	if (domain == CPU)
672		gem_set_caching(device, dst, 1);
673
674	gem_fill(device, dst, ~pixel, dst_size, domain);
675
676	dst_fd = gem_export(device, dst);
677	if (dst_fd < 0)
678		goto fail;
679
680	dst_pix = dri3_create_pixmap(dpy, root,
681				     width, height, depth,
682				     dst_fd, bpp, dst_stride, dst_size);
683	XSync(dpy, True);
684	if (_x_error_occurred)
685		goto fail;
686	if (dri3_create_fence(dpy, dst_pix, &fence))
687		goto fail;
688
689	src_pix = XCreatePixmap(dpy, root, width, height, depth);
690	src_pic = XRenderCreatePicture(dpy, src_pix, format_for_depth(dpy, depth), 0, NULL);
691	XRenderFillRectangle(dpy, PictOpSrc, src_pic, &color, 0, 0, width, height);
692	XCopyArea(dpy, src_pix, dst_pix,
693		  get_gc(dpy, dst_pix, depth),
694		  0, 0, width, height, 0, 0);
695	dri3_fence_sync(dpy, &fence);
696	dri3_fence_free(dpy, &fence);
697
698	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
699		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
700			if (!check_pixel(device, dst, dst_stride, dst_size,
701					 x_loc[x], y_loc[y],
702					 pixel, bpp, domain))
703				goto fail;
704
705	XFreePixmap(dpy, dst_pix);
706	XRenderFreePicture(dpy, src_pic);
707	XFreePixmap(dpy, src_pix);
708
709	gem_close(device, dst);
710
711	if (_x_error_occurred)
712		goto fail;
713
714	return 0;
715
716fail:
717	printf("%s failed at (%dx%d), depth=%d, domain=%d\n",
718	       __func__, width, height, depth, domain);
719	return 1;
720}
721
722static int test_dup_pixmap(Display *dpy, int device)
723{
724	const uint32_t pixel = 0xffff00ff;
725	const XRenderColor color = { 0xffff, 0x0000, 0xffff, 0xffff };
726	const XRenderColor inverse = { 0, 0xffff, 0, 0 };
727	int width = 400, height = 400;
728	const int x_loc[] = {0, width/2, width-1};
729	const int y_loc[] = {0, height/2, height-1};
730	Window root = RootWindow(dpy, DefaultScreen(dpy));
731	uint32_t handle;
732	int stride, size, fd;
733	Pixmap src_pix, dst_pix;
734	Picture src_pic, dst_pic;
735	struct dri3_fence fence;
736	int depth = 32, bpp = 32;
737	int x, y;
738
739	_x_error_occurred = 0;
740
741	printf("%s: Creating %dx%d pixmap\n", __func__, width, height);
742	src_pix = XCreatePixmap(dpy, root, width, height, depth);
743	src_pic = XRenderCreatePicture(dpy, src_pix, format_for_depth(dpy, depth), 0, NULL);
744	fd = dri3_create_fd(dpy, src_pix, &stride);
745	if (fd < 0)
746		goto fail;
747
748	size = lseek(fd, 0, SEEK_END);
749	handle = gem_import(device, fd);
750
751	printf("%s: Creating duplicate from pixmap exported fd\n", __func__);
752	dst_pix = dri3_create_pixmap(dpy, root,
753				     width, height, depth,
754				     fd, bpp, stride, size);
755	dst_pic = XRenderCreatePicture(dpy, dst_pix, format_for_depth(dpy, depth), 0, NULL);
756	XSync(dpy, True);
757	if (_x_error_occurred)
758		goto fail;
759
760	printf("%s: Filling src with %08x, reading dst\n", __func__, pixel);
761	XRenderFillRectangle(dpy, PictOpSrc, src_pic, &color, 0, 0, width, height);
762	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
763		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
764			if (!check_pixmap(dpy, dst_pix,
765					  x_loc[x], y_loc[y],
766					  pixel, 32))
767				goto fail;
768
769	printf("%s: Filling dst with %08x, reading src\n", __func__, ~pixel);
770	XRenderFillRectangle(dpy, PictOpSrc, dst_pic, &inverse, 0, 0, width, height);
771	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
772		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
773			if (!check_pixmap(dpy, dst_pix,
774					  x_loc[x], y_loc[y],
775					  ~pixel, 32))
776				goto fail;
777
778	if (dri3_create_fence(dpy, src_pix, &fence))
779		goto fail;
780
781	printf("%s: Filling src with %08x, reading fd\n", __func__, pixel);
782	XRenderFillRectangle(dpy, PictOpSrc, src_pic, &color, 0, 0, width, height);
783	dri3_fence_sync(dpy, &fence);
784	dri3_fence_free(dpy, &fence);
785	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
786		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
787			if (!check_pixel(device, handle, stride, size,
788					 x_loc[x], y_loc[y],
789					 pixel, bpp, GTT))
790				goto fail;
791
792	printf("%s: Filling fd with %08x, reading src\n", __func__, ~pixel);
793	if (gpu_fill(device, handle, width, height, stride, 32, gem_get_tiling(device, handle), ~pixel))
794		goto fail;
795	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
796		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
797			if (!check_pixmap(dpy, src_pix,
798					  x_loc[x], y_loc[y],
799					  ~pixel, 32))
800				goto fail;
801
802	if (dri3_create_fence(dpy, dst_pix, &fence))
803		goto fail;
804
805	printf("%s: Filling dst with %08x, reading fd\n", __func__, pixel);
806	XRenderFillRectangle(dpy, PictOpSrc, dst_pic, &color, 0, 0, width, height);
807	dri3_fence_sync(dpy, &fence);
808	dri3_fence_free(dpy, &fence);
809	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
810		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
811			if (!check_pixel(device, handle, stride, size,
812					 x_loc[x], y_loc[y],
813					 pixel, bpp, GTT))
814				goto fail;
815
816	printf("%s: Filling fd with %08x, reading dst\n", __func__, ~pixel);
817	if (gpu_fill(device, handle, width, height, stride, 32, gem_get_tiling(device, handle), ~pixel))
818		goto fail;
819	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
820		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
821			if (!check_pixmap(dpy, dst_pix,
822					  x_loc[x], y_loc[y],
823					  ~pixel, 32))
824				goto fail;
825
826	XRenderFreePicture(dpy, src_pic);
827	XFreePixmap(dpy, src_pix);
828
829	if (dri3_create_fence(dpy, dst_pix, &fence))
830		goto fail;
831
832	printf("%s: Closed original src, filling dst with %08x, reading fd\n", __func__, pixel);
833	XRenderFillRectangle(dpy, PictOpSrc, dst_pic, &color, 0, 0, width, height);
834	dri3_fence_sync(dpy, &fence);
835	dri3_fence_free(dpy, &fence);
836	for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++)
837		for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++)
838			if (!check_pixel(device, handle, stride, size,
839					 x_loc[x], y_loc[y],
840					 pixel, bpp, GTT))
841				goto fail;
842
843	XRenderFreePicture(dpy, dst_pic);
844	XFreePixmap(dpy, dst_pix);
845
846	gem_close(device, handle);
847
848	if (_x_error_occurred)
849		goto fail;
850
851	return 0;
852
853fail:
854	printf("%s failed at (%dx%d), depth=%d\n",
855	       __func__, width, height, depth);
856	return 1;
857}
858
859static int test_bad_size(Display *dpy, int device)
860{
861	Window root = RootWindow(dpy, DefaultScreen(dpy));
862	uint32_t src;
863	int src_fd;
864	Pixmap src_pix;
865	int line = -1;
866
867	_x_error_occurred = 0;
868
869	src = gem_create(device, 4096);
870	if (!src)
871		goto fail;
872
873	src_fd = gem_export(device, src);
874	if (src_fd < 0)
875		goto fail;
876
877	src_pix = dri3_create_pixmap(dpy, root,
878				     16, 16, 32,
879				     dup(src_fd), 32, 16*4, 4096);
880	line = __LINE__;
881	XSync(dpy, True);
882	if (_x_error_occurred)
883		goto fail;
884	XFreePixmap(dpy, src_pix);
885	_x_error_occurred = 0;
886
887	src_pix = dri3_create_pixmap(dpy, root,
888				     32, 32, 32,
889				     dup(src_fd), 32, 32*4, 4096);
890	line = __LINE__;
891	XSync(dpy, True);
892	if (_x_error_occurred)
893		goto fail;
894	XFreePixmap(dpy, src_pix);
895	_x_error_occurred = 0;
896
897	src_pix = dri3_create_pixmap(dpy, root,
898				     64, 64, 32,
899				     dup(src_fd), 32, 64*4, 4096);
900	line = __LINE__;
901	XSync(dpy, True);
902	if (!_x_error_occurred)
903		goto fail;
904	_x_error_occurred = 0;
905
906	src_pix = dri3_create_pixmap(dpy, root,
907				     64, 64, 32,
908				     dup(src_fd), 32, 64*4, 64*64*4);
909	line = __LINE__;
910	XSync(dpy, True);
911	if (!_x_error_occurred)
912		goto fail;
913	_x_error_occurred = 0;
914
915	src_pix = dri3_create_pixmap(dpy, root,
916				     INT16_MAX, INT16_MAX, 8,
917				     dup(src_fd), 8, INT16_MAX, UINT32_MAX);
918	line = __LINE__;
919	XSync(dpy, True);
920	if (!_x_error_occurred)
921		goto fail;
922	_x_error_occurred = 0;
923
924	close(src_fd);
925	gem_close(device, src);
926
927	return 0;
928
929fail:
930	printf("%s failed at line %d\n", __func__, line);
931	return 1;
932}
933
934static int test_bad_pitch(Display *dpy, int device)
935{
936	Window root = RootWindow(dpy, DefaultScreen(dpy));
937	uint32_t src;
938	int src_fd;
939	Pixmap src_pix;
940	int line = -1;
941
942	_x_error_occurred = 0;
943
944	src = gem_create(device, 4096);
945	if (!src)
946		goto fail;
947
948	src_fd = gem_export(device, src);
949	if (src_fd < 0)
950		goto fail;
951
952	src_pix = dri3_create_pixmap(dpy, root,
953				     16, 16, 32,
954				     dup(src_fd), 32, 16*4, 4096);
955	line = __LINE__;
956	XSync(dpy, True);
957	if (_x_error_occurred)
958		goto fail;
959	XFreePixmap(dpy, src_pix);
960	_x_error_occurred = 0;
961
962	src_pix = dri3_create_pixmap(dpy, root,
963				     256, 2, 32,
964				     dup(src_fd), 32, 256*4, 4096);
965	line = __LINE__;
966	XSync(dpy, True);
967	if (_x_error_occurred)
968		goto fail;
969	XFreePixmap(dpy, src_pix);
970	_x_error_occurred = 0;
971
972	src_pix = dri3_create_pixmap(dpy, root,
973				     256, 2, 32,
974				     dup(src_fd), 32, 256, 4096);
975	line = __LINE__;
976	XSync(dpy, True);
977	if (!_x_error_occurred)
978		goto fail;
979	_x_error_occurred = 0;
980
981	src_pix = dri3_create_pixmap(dpy, root,
982				     256, 2, 32,
983				     dup(src_fd), 32, 16384, 4096);
984	line = __LINE__;
985	XSync(dpy, True);
986	if (!_x_error_occurred)
987		goto fail;
988	_x_error_occurred = 0;
989
990	src_pix = dri3_create_pixmap(dpy, root,
991				     256, 2, 32,
992				     dup(src_fd), 32, 1023, 4096);
993	line = __LINE__;
994	XSync(dpy, True);
995	if (!_x_error_occurred)
996		goto fail;
997	_x_error_occurred = 0;
998
999	src_pix = dri3_create_pixmap(dpy, root,
1000				     256, 2, 32,
1001				     dup(src_fd), 32, 1025, 4096);
1002	line = __LINE__;
1003	XSync(dpy, True);
1004	if (!_x_error_occurred)
1005		goto fail;
1006	_x_error_occurred = 0;
1007
1008	close(src_fd);
1009	gem_close(device, src);
1010
1011	return 0;
1012
1013fail:
1014	printf("%s failed at line %d\n", __func__, line);
1015	return 1;
1016}
1017
1018static int gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
1019{
1020	struct drm_i915_gem_set_tiling set_tiling;
1021
1022	set_tiling.handle = handle;
1023	set_tiling.tiling_mode = tiling;
1024	set_tiling.stride = stride;
1025
1026	return drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0;
1027}
1028
1029static int test_tiling(Display *dpy, int device)
1030{
1031	Window root = RootWindow(dpy, DefaultScreen(dpy));
1032	const int tiling[] = { I915_TILING_NONE, I915_TILING_X, I915_TILING_Y };
1033	int line = -1;
1034	int t;
1035
1036	_x_error_occurred = 0;
1037
1038	for (t = 0; t < sizeof(tiling)/sizeof(tiling[0]); t++) {
1039		uint32_t src;
1040		int src_fd;
1041		Pixmap src_pix;
1042
1043		src = gem_create(device, 4*4096);
1044		if (!src) {
1045			line = __LINE__;
1046			goto fail;
1047		}
1048
1049		gem_set_tiling(device, src, tiling[t], 512);
1050
1051		src_fd = gem_export(device, src);
1052		if (src_fd < 0) {
1053			line = __LINE__;
1054			goto fail;
1055		}
1056
1057		src_pix = dri3_create_pixmap(dpy, root,
1058					     128, 32, 32,
1059					     src_fd, 32, 512, 4*4096);
1060		XSync(dpy, True);
1061		if (_x_error_occurred) {
1062			line = __LINE__;
1063			goto fail;
1064		}
1065		XFreePixmap(dpy, src_pix);
1066		_x_error_occurred = 0;
1067
1068		close(src_fd);
1069		gem_close(device, src);
1070	}
1071
1072	return 0;
1073
1074fail:
1075	printf("%s failed with tiling %d, line %d\n", __func__, tiling[t], line);
1076	return 1;
1077}
1078
1079static int
1080_check_error_handler(Display     *display,
1081		     XErrorEvent *event)
1082{
1083	printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
1084	       DisplayString(display),
1085	       event->serial,
1086	       event->error_code,
1087	       event->request_code,
1088	       event->minor_code);
1089	_x_error_occurred++;
1090	return False; /* ignored */
1091}
1092
1093int main(void)
1094{
1095	Display *dpy;
1096	int device;
1097	int error = 0;
1098
1099	dpy = XOpenDisplay(NULL);
1100	if (dpy == NULL)
1101		return 77;
1102
1103	if (DefaultDepth(dpy, DefaultScreen(dpy)) != 24)
1104		return 77;
1105
1106	XSetErrorHandler(_check_error_handler);
1107
1108	device = dri3_open(dpy);
1109	if (device < 0)
1110		return 127;
1111
1112	if (!is_intel(device))
1113		return 77;
1114
1115	printf("Opened Intel DRI3 device\n");
1116
1117	error += test_bad_size(dpy, device);
1118	error += test_bad_pitch(dpy, device);
1119	error += test_tiling(dpy, device);
1120
1121	error += test_shm(dpy, device, 400, 300);
1122	error += test_shm(dpy, device, 300, 400);
1123
1124	error += test_read(dpy, device, 400, 200, GTT);
1125	error += test_read(dpy, device, 4000, 20, GTT);
1126	error += test_read(dpy, device, 16000, 10, GTT);
1127	error += test_read(dpy, device, 30000, 10, GTT);
1128
1129	error += test_read(dpy, device, 200, 400, GTT);
1130	error += test_read(dpy, device, 20, 4000, GTT);
1131	error += test_read(dpy, device, 16, 16000, GTT);
1132	error += test_read(dpy, device, 16, 30000, GTT);
1133
1134	error += test_read(dpy, device, 400, 200, CPU);
1135	error += test_read(dpy, device, 4000, 20, CPU);
1136	error += test_read(dpy, device, 16000, 10, CPU);
1137	error += test_read(dpy, device, 30000, 10, CPU);
1138
1139	error += test_read(dpy, device, 200, 400, CPU);
1140	error += test_read(dpy, device, 20, 4000, CPU);
1141	error += test_read(dpy, device, 16, 16000, CPU);
1142	error += test_read(dpy, device, 16, 30000, CPU);
1143
1144	error += test_read_after_write(dpy, device, 400, 200, 24, GTT);
1145	error += test_read_after_write(dpy, device, 4000, 20, 24, GTT);
1146	error += test_read_after_write(dpy, device, 16000, 10, 24, GTT);
1147	error += test_read_after_write(dpy, device, 30000, 10, 24, GTT);
1148	error += test_read_after_write(dpy, device, 30000, 10, 8, GTT);
1149
1150	error += test_read_after_write(dpy, device, 200, 400, 24, GTT);
1151	error += test_read_after_write(dpy, device, 20, 4000, 24, GTT);
1152	error += test_read_after_write(dpy, device, 16, 16000, 24, GTT);
1153	error += test_read_after_write(dpy, device, 16, 30000, 24, GTT);
1154
1155	error += test_read_after_write(dpy, device, 400, 200, 24, CPU);
1156	error += test_read_after_write(dpy, device, 4000, 20, 24, CPU);
1157	error += test_read_after_write(dpy, device, 16000, 10, 24, CPU);
1158	error += test_read_after_write(dpy, device, 30000, 10, 24, CPU);
1159	error += test_read_after_write(dpy, device, 30000, 10, 8, CPU);
1160
1161	error += test_read_after_write(dpy, device, 200, 400, 24, CPU);
1162	error += test_read_after_write(dpy, device, 20, 4000, 24, CPU);
1163	error += test_read_after_write(dpy, device, 16, 16000, 24, CPU);
1164	error += test_read_after_write(dpy, device, 16, 30000, 24, CPU);
1165
1166	error += test_dup_pixmap(dpy, device);
1167
1168	return !!error;
1169}
1170