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