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