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