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