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