1428d7b3dSmrg/* 2428d7b3dSmrg * Copyright (c) 2014 Intel Corporation 3428d7b3dSmrg * 4428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5428d7b3dSmrg * copy of this software and associated documentation files (the "Software"), 6428d7b3dSmrg * to deal in the Software without restriction, including without limitation 7428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the 9428d7b3dSmrg * Software is furnished to do so, subject to the following conditions: 10428d7b3dSmrg * 11428d7b3dSmrg * The above copyright notice and this permission notice (including the next 12428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the 13428d7b3dSmrg * Software. 14428d7b3dSmrg * 15428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20428d7b3dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21428d7b3dSmrg * SOFTWARE. 22428d7b3dSmrg * 23428d7b3dSmrg */ 24428d7b3dSmrg 25428d7b3dSmrg#ifdef HAVE_CONFIG_H 26428d7b3dSmrg#include "config.h" 27428d7b3dSmrg#endif 28428d7b3dSmrg 29428d7b3dSmrg#include <X11/Xlib.h> 30428d7b3dSmrg#include <X11/Xutil.h> 31428d7b3dSmrg#include <X11/Xlibint.h> 32428d7b3dSmrg#include <X11/extensions/Xrender.h> 33428d7b3dSmrg#include <X11/extensions/XShm.h> 34428d7b3dSmrg#if HAVE_X11_EXTENSIONS_SHMPROTO_H 35428d7b3dSmrg#include <X11/extensions/shmproto.h> 36428d7b3dSmrg#elif HAVE_X11_EXTENSIONS_SHMSTR_H 37428d7b3dSmrg#include <X11/extensions/shmstr.h> 38428d7b3dSmrg#else 39428d7b3dSmrg#error Failed to find the right header for X11 MIT-SHM protocol definitions 40428d7b3dSmrg#endif 41428d7b3dSmrg#include <xf86drm.h> 42428d7b3dSmrg#include <i915_drm.h> 43428d7b3dSmrg 44428d7b3dSmrg#include <stdio.h> 45428d7b3dSmrg#include <string.h> 46428d7b3dSmrg#include <fcntl.h> 47428d7b3dSmrg#include <unistd.h> 48428d7b3dSmrg#include <assert.h> 49428d7b3dSmrg#include <errno.h> 50428d7b3dSmrg 51428d7b3dSmrg#include <sys/mman.h> 52428d7b3dSmrg#include <sys/ipc.h> 53428d7b3dSmrg#include <sys/shm.h> 54428d7b3dSmrg#include <pciaccess.h> 55428d7b3dSmrg 56428d7b3dSmrg#include "dri3.h" 57428d7b3dSmrg#include "../src/i915_pciids.h" 58428d7b3dSmrg 59428d7b3dSmrg#define ALIGN(x, y) (((x) + (y) - 1) & -(y)) 60428d7b3dSmrg#define PAGE_ALIGN(x) ALIGN(x, 4096) 61428d7b3dSmrg 62428d7b3dSmrg#define GTT I915_GEM_DOMAIN_GTT 63428d7b3dSmrg#define CPU I915_GEM_DOMAIN_CPU 64428d7b3dSmrg 65428d7b3dSmrgstatic int _x_error_occurred; 66428d7b3dSmrg 67428d7b3dSmrgstatic const struct pci_id_match ids[] = { 68428d7b3dSmrg INTEL_I830_IDS(020), 69428d7b3dSmrg INTEL_I845G_IDS(021), 70428d7b3dSmrg INTEL_I85X_IDS(022), 71428d7b3dSmrg INTEL_I865G_IDS(023), 72428d7b3dSmrg 73428d7b3dSmrg INTEL_I915G_IDS(030), 74428d7b3dSmrg INTEL_I915GM_IDS(030), 75428d7b3dSmrg INTEL_I945G_IDS(031), 76428d7b3dSmrg INTEL_I945GM_IDS(031), 77428d7b3dSmrg 78428d7b3dSmrg INTEL_G33_IDS(033), 79428d7b3dSmrg INTEL_PINEVIEW_IDS(033), 80428d7b3dSmrg 81428d7b3dSmrg INTEL_I965G_IDS(040), 82428d7b3dSmrg INTEL_I965GM_IDS(040), 83428d7b3dSmrg 84428d7b3dSmrg INTEL_G45_IDS(045), 85428d7b3dSmrg INTEL_GM45_IDS(045), 86428d7b3dSmrg 87428d7b3dSmrg INTEL_IRONLAKE_D_IDS(050), 88428d7b3dSmrg INTEL_IRONLAKE_M_IDS(050), 89428d7b3dSmrg 90428d7b3dSmrg INTEL_SNB_D_IDS(060), 91428d7b3dSmrg INTEL_SNB_M_IDS(060), 92428d7b3dSmrg 93428d7b3dSmrg INTEL_IVB_D_IDS(070), 94428d7b3dSmrg INTEL_IVB_M_IDS(070), 95428d7b3dSmrg 96428d7b3dSmrg INTEL_HSW_D_IDS(075), 97428d7b3dSmrg INTEL_HSW_M_IDS(075), 98428d7b3dSmrg 99428d7b3dSmrg INTEL_VLV_D_IDS(071), 100428d7b3dSmrg INTEL_VLV_M_IDS(071), 101428d7b3dSmrg 102428d7b3dSmrg INTEL_BDW_D_IDS(0100), 103428d7b3dSmrg INTEL_BDW_M_IDS(0100), 104428d7b3dSmrg}; 105428d7b3dSmrg 106428d7b3dSmrgstatic int i915_gen(int device) 107428d7b3dSmrg{ 108428d7b3dSmrg struct drm_i915_getparam gp; 109428d7b3dSmrg int devid = 0; 110428d7b3dSmrg int n; 111428d7b3dSmrg 112428d7b3dSmrg gp.param = I915_PARAM_CHIPSET_ID; 113428d7b3dSmrg gp.value = &devid; 114428d7b3dSmrg 115428d7b3dSmrg if (drmIoctl(device, DRM_IOCTL_I915_GETPARAM, &gp)) 116428d7b3dSmrg return 0; 117428d7b3dSmrg 118428d7b3dSmrg for (n = 0; n < sizeof(ids)/sizeof(ids[0]); n++) { 119428d7b3dSmrg if (devid == ids[n].device_id) 120428d7b3dSmrg return ids[n].match_data; 121428d7b3dSmrg } 122428d7b3dSmrg 123428d7b3dSmrg return 0; 124428d7b3dSmrg} 125428d7b3dSmrg 126428d7b3dSmrgstatic int is_i915_device(int fd) 127428d7b3dSmrg{ 128428d7b3dSmrg drm_version_t version; 129428d7b3dSmrg char name[5] = ""; 130428d7b3dSmrg 131428d7b3dSmrg memset(&version, 0, sizeof(version)); 132428d7b3dSmrg version.name_len = 4; 133428d7b3dSmrg version.name = name; 134428d7b3dSmrg 135428d7b3dSmrg if (drmIoctl(fd, DRM_IOCTL_VERSION, &version)) 136428d7b3dSmrg return 0; 137428d7b3dSmrg 138428d7b3dSmrg return strcmp("i915", name) == 0; 139428d7b3dSmrg} 140428d7b3dSmrg 141428d7b3dSmrgstatic int is_intel(int fd) 142428d7b3dSmrg{ 143428d7b3dSmrg struct drm_i915_getparam gp; 144428d7b3dSmrg int ret; 145428d7b3dSmrg 146428d7b3dSmrg /* Confirm that this is a i915.ko device with GEM/KMS enabled */ 147428d7b3dSmrg ret = is_i915_device(fd); 148428d7b3dSmrg if (ret) { 149428d7b3dSmrg gp.param = I915_PARAM_HAS_GEM; 150428d7b3dSmrg gp.value = &ret; 151428d7b3dSmrg if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) 152428d7b3dSmrg ret = 0; 153428d7b3dSmrg } 154428d7b3dSmrg return ret; 155428d7b3dSmrg} 156428d7b3dSmrg 157428d7b3dSmrgstatic uint32_t gem_create(int fd, int size) 158428d7b3dSmrg{ 159428d7b3dSmrg struct drm_i915_gem_create create; 160428d7b3dSmrg 161428d7b3dSmrg create.handle = 0; 162428d7b3dSmrg create.size = size; 163428d7b3dSmrg (void)drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create); 164428d7b3dSmrg 165428d7b3dSmrg return create.handle; 166428d7b3dSmrg} 167428d7b3dSmrg 168428d7b3dSmrgstruct local_i915_gem_caching { 169428d7b3dSmrg uint32_t handle; 170428d7b3dSmrg uint32_t caching; 171428d7b3dSmrg}; 172428d7b3dSmrg 173428d7b3dSmrg#define LOCAL_I915_GEM_SET_CACHING 0x2f 174428d7b3dSmrg#define LOCAL_IOCTL_I915_GEM_SET_CACHING DRM_IOW(DRM_COMMAND_BASE + LOCAL_I915_GEM_SET_CACHING, struct local_i915_gem_caching) 175428d7b3dSmrg 176428d7b3dSmrgstatic int gem_set_caching(int fd, uint32_t handle, int caching) 177428d7b3dSmrg{ 178428d7b3dSmrg struct local_i915_gem_caching arg; 179428d7b3dSmrg 180428d7b3dSmrg arg.handle = handle; 181428d7b3dSmrg arg.caching = caching; 182428d7b3dSmrg 183428d7b3dSmrg return drmIoctl(fd, LOCAL_IOCTL_I915_GEM_SET_CACHING, &arg) == 0; 184428d7b3dSmrg} 185428d7b3dSmrg 186428d7b3dSmrgstatic int gem_export(int fd, uint32_t handle) 187428d7b3dSmrg{ 188428d7b3dSmrg struct drm_prime_handle args; 189428d7b3dSmrg 190428d7b3dSmrg args.handle = handle; 191428d7b3dSmrg args.flags = O_CLOEXEC; 192428d7b3dSmrg 193428d7b3dSmrg if (drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args)) 194428d7b3dSmrg return -1; 195428d7b3dSmrg 196428d7b3dSmrg return args.fd; 197428d7b3dSmrg} 198428d7b3dSmrg 199428d7b3dSmrgstatic uint32_t gem_import(int fd, int name) 200428d7b3dSmrg{ 201428d7b3dSmrg struct drm_prime_handle args; 202428d7b3dSmrg 203428d7b3dSmrg args.fd = name; 204428d7b3dSmrg args.flags = 0; 205428d7b3dSmrg if (drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args)) 206428d7b3dSmrg return 0; 207428d7b3dSmrg 208428d7b3dSmrg return args.handle; 209428d7b3dSmrg} 210428d7b3dSmrg 211428d7b3dSmrgstatic int gem_write(int fd, uint32_t handle, int offset, void *data, int len) 212428d7b3dSmrg{ 213428d7b3dSmrg struct drm_i915_gem_pwrite gem_pwrite; 214428d7b3dSmrg 215428d7b3dSmrg gem_pwrite.handle = handle; 216428d7b3dSmrg gem_pwrite.offset = offset; 217428d7b3dSmrg gem_pwrite.size = len; 218428d7b3dSmrg gem_pwrite.data_ptr = (uintptr_t)data; 219428d7b3dSmrg return drmIoctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &gem_pwrite); 220428d7b3dSmrg} 221428d7b3dSmrg 222428d7b3dSmrgstatic void *gem_mmap(int fd, uint32_t handle, int size, unsigned prot, int domain) 223428d7b3dSmrg{ 224428d7b3dSmrg struct drm_i915_gem_set_domain set_domain; 225428d7b3dSmrg void *ptr; 226428d7b3dSmrg 227428d7b3dSmrg if (domain == CPU) { 228428d7b3dSmrg struct drm_i915_gem_mmap mmap_arg; 229428d7b3dSmrg 230428d7b3dSmrg mmap_arg.handle = handle; 231428d7b3dSmrg mmap_arg.offset = 0; 232428d7b3dSmrg mmap_arg.size = size; 233428d7b3dSmrg if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg)) 234428d7b3dSmrg return NULL; 235428d7b3dSmrg 236428d7b3dSmrg ptr = (void *)(uintptr_t)mmap_arg.addr_ptr; 237428d7b3dSmrg } else { 238428d7b3dSmrg struct drm_i915_gem_mmap_gtt mmap_arg; 239428d7b3dSmrg 240428d7b3dSmrg mmap_arg.handle = handle; 241428d7b3dSmrg if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg)) 242428d7b3dSmrg return NULL; 243428d7b3dSmrg 244428d7b3dSmrg ptr = mmap(0, size, prot, MAP_SHARED, fd, mmap_arg.offset); 245428d7b3dSmrg if (ptr == MAP_FAILED) 246428d7b3dSmrg return NULL; 247428d7b3dSmrg } 248428d7b3dSmrg 249428d7b3dSmrg set_domain.handle = handle; 250428d7b3dSmrg set_domain.read_domains = domain; 251428d7b3dSmrg set_domain.write_domain = prot & PROT_WRITE ? set_domain.read_domains : 0; 252428d7b3dSmrg if (drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) { 253428d7b3dSmrg munmap(ptr, size); 254428d7b3dSmrg return NULL; 255428d7b3dSmrg } 256428d7b3dSmrg 257428d7b3dSmrg return ptr; 258428d7b3dSmrg} 259428d7b3dSmrg 260428d7b3dSmrgstatic void gem_sync(int fd, uint32_t handle, int read) 261428d7b3dSmrg{ 262428d7b3dSmrg struct drm_i915_gem_set_domain set_domain; 263428d7b3dSmrg 264428d7b3dSmrg set_domain.handle = handle; 265428d7b3dSmrg set_domain.read_domains = read; 266428d7b3dSmrg set_domain.write_domain = 0; 267428d7b3dSmrg drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain); 268428d7b3dSmrg} 269428d7b3dSmrg 270428d7b3dSmrgstatic int gem_get_tiling(int fd, uint32_t handle) 271428d7b3dSmrg{ 272428d7b3dSmrg struct drm_i915_gem_get_tiling tiling; 273428d7b3dSmrg 274428d7b3dSmrg tiling.handle = handle; 275428d7b3dSmrg tiling.tiling_mode = -1; 276428d7b3dSmrg (void)drmIoctl(fd, DRM_IOCTL_I915_GEM_GET_TILING, &tiling); 277428d7b3dSmrg return tiling.tiling_mode; 278428d7b3dSmrg} 279428d7b3dSmrg 280428d7b3dSmrgstatic void gem_close(int fd, uint32_t handle) 281428d7b3dSmrg{ 282428d7b3dSmrg struct drm_gem_close close; 283428d7b3dSmrg 284428d7b3dSmrg close.handle = handle; 285428d7b3dSmrg (void)drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close); 286428d7b3dSmrg} 287428d7b3dSmrg 288428d7b3dSmrgstatic void gem_fill(int fd, uint32_t handle, uint32_t pixel, uint32_t size, int domain) 289428d7b3dSmrg{ 290428d7b3dSmrg uint32_t *ptr, s; 291428d7b3dSmrg 292428d7b3dSmrg ptr = gem_mmap(fd, handle, size, PROT_READ | PROT_WRITE, domain); 293428d7b3dSmrg if (ptr == NULL) 294428d7b3dSmrg return; 295428d7b3dSmrg 296428d7b3dSmrg for (s = 0; s < size; s += 4) 297428d7b3dSmrg ptr[s/4] = pixel; 298428d7b3dSmrg munmap(ptr, size); 299428d7b3dSmrg} 300428d7b3dSmrg 301428d7b3dSmrgstatic int check_pixmap(Display *dpy, Pixmap pix, 302428d7b3dSmrg int x, int y, uint32_t expected, int bpp) 303428d7b3dSmrg{ 304428d7b3dSmrg XImage *image; 305428d7b3dSmrg int w = 32 / bpp; 306428d7b3dSmrg 307428d7b3dSmrg image = XGetImage(dpy, pix, x - (x % w), y, w, 1, AllPlanes, ZPixmap); 308428d7b3dSmrg if (image == NULL) 309428d7b3dSmrg return 0; 310428d7b3dSmrg 311428d7b3dSmrg if (*(uint32_t *)image->data != expected) { 312428d7b3dSmrg printf("pixmap[%d, %d]:%d = %08x\n", x, y, bpp, *(uint32_t *)image->data); 313428d7b3dSmrg return 0; 314428d7b3dSmrg } 315428d7b3dSmrg XDestroyImage(image); 316428d7b3dSmrg 317428d7b3dSmrg return 1; 318428d7b3dSmrg} 319428d7b3dSmrg 320428d7b3dSmrgstatic int check_pixel(int fd, uint32_t handle, uint32_t stride, uint32_t size, 321428d7b3dSmrg int x, int y, uint32_t expected, int bpp, int domain) 322428d7b3dSmrg{ 323428d7b3dSmrg uint32_t *ptr; 324428d7b3dSmrg int w = 32 / bpp; 325428d7b3dSmrg 326428d7b3dSmrg assert((stride & 3) == 0); 327428d7b3dSmrg 328428d7b3dSmrg ptr = gem_mmap(fd, handle, size, PROT_READ, domain); 329428d7b3dSmrg if (ptr == NULL) 330428d7b3dSmrg return 0; 331428d7b3dSmrg 332428d7b3dSmrg if (ptr[(y*stride + x - (x % w))/4] != expected) { 333428d7b3dSmrg printf("pixel[%d, %d]:%d = %08x\n", x, y, bpp, ptr[(y * stride + x)/4]); 334428d7b3dSmrg return 0; 335428d7b3dSmrg } 336428d7b3dSmrg munmap(ptr, size); 337428d7b3dSmrg 338428d7b3dSmrg return 1; 339428d7b3dSmrg} 340428d7b3dSmrg 341428d7b3dSmrgstatic GC get_gc(Display *dpy, Drawable d, int depth) 342428d7b3dSmrg{ 343428d7b3dSmrg static GC gc[33]; 344428d7b3dSmrg if (gc[depth] == NULL) { 345428d7b3dSmrg XGCValues gcv; 346428d7b3dSmrg 347428d7b3dSmrg gcv.graphics_exposures = False; 348428d7b3dSmrg gc[depth] = XCreateGC(dpy, d, GCGraphicsExposures, &gcv); 349428d7b3dSmrg } 350428d7b3dSmrg return gc[depth]; 351428d7b3dSmrg} 352428d7b3dSmrg 353428d7b3dSmrgstatic int 354428d7b3dSmrgcan_use_shm(Display *dpy) 355428d7b3dSmrg{ 356428d7b3dSmrg int major, minor, has_pixmap; 357428d7b3dSmrg 358428d7b3dSmrg if (!XShmQueryExtension(dpy)) 359428d7b3dSmrg return 0; 360428d7b3dSmrg 361428d7b3dSmrg XShmQueryVersion(dpy, &major, &minor, &has_pixmap); 362428d7b3dSmrg return has_pixmap; 363428d7b3dSmrg} 364428d7b3dSmrg 365428d7b3dSmrgstatic int gpu_fill(int device, int handle, int width, int height, int pitch, int bpp, int tiling, uint32_t pixel) 366428d7b3dSmrg{ 367428d7b3dSmrg struct drm_i915_gem_execbuffer2 execbuf; 368428d7b3dSmrg struct drm_i915_gem_relocation_entry gem_reloc[2]; 369428d7b3dSmrg struct drm_i915_gem_exec_object2 gem_exec[2]; 370428d7b3dSmrg uint32_t batch[10]; 371428d7b3dSmrg int gen = i915_gen(device); 372428d7b3dSmrg int len = 0; 373428d7b3dSmrg int ret; 374428d7b3dSmrg 375428d7b3dSmrg if (gen == 0) 376428d7b3dSmrg return -ENODEV; 377428d7b3dSmrg 378428d7b3dSmrg batch[0] = 2 << 29 | 0x50 << 22; 379428d7b3dSmrg batch[0] |= (gen >= 0100 ? 5 : 4); 380428d7b3dSmrg batch[1] = pitch; 381428d7b3dSmrg if (gen >= 040 && tiling) { 382428d7b3dSmrg batch[0] |= 1 << 11; 383428d7b3dSmrg batch[1] >>= 2; 384428d7b3dSmrg } 385428d7b3dSmrg 386428d7b3dSmrg batch[1] |= 0xf0 << 16; 387428d7b3dSmrg switch (bpp) { 388428d7b3dSmrg default: assert(0); 389428d7b3dSmrg case 32: batch[0] |= 1 << 21 | 1 << 20; 390428d7b3dSmrg batch[1] |= 1 << 25; /* RGB8888 */ 391428d7b3dSmrg case 16: batch[1] |= 1 << 24; /* RGB565 */ 392428d7b3dSmrg case 8: break; 393428d7b3dSmrg } 394428d7b3dSmrg 395428d7b3dSmrg batch[2] = 0; 396428d7b3dSmrg batch[3] = height << 16 | width; 397428d7b3dSmrg batch[4] = 0; 398428d7b3dSmrg len = 5; 399428d7b3dSmrg if (gen >= 0100) 400428d7b3dSmrg batch[len++] = 0; 401428d7b3dSmrg batch[len++] = pixel; 402428d7b3dSmrg batch[len++] = 0xA << 23; 403428d7b3dSmrg if (len & 1) 404428d7b3dSmrg len++; 405428d7b3dSmrg 406428d7b3dSmrg gem_reloc[0].offset = 4 * sizeof(uint32_t); 407428d7b3dSmrg gem_reloc[0].delta = 0; 408428d7b3dSmrg gem_reloc[0].target_handle = handle; 409428d7b3dSmrg gem_reloc[0].read_domains = I915_GEM_DOMAIN_RENDER; 410428d7b3dSmrg gem_reloc[0].write_domain = I915_GEM_DOMAIN_RENDER; 411428d7b3dSmrg gem_reloc[0].presumed_offset = 0; 412428d7b3dSmrg 413428d7b3dSmrg memset(gem_exec, 0, sizeof(gem_exec)); 414428d7b3dSmrg gem_exec[0].handle = handle; 415428d7b3dSmrg gem_exec[1].handle = gem_create(device, 4096); 416428d7b3dSmrg gem_exec[1].relocation_count = 1; 417428d7b3dSmrg gem_exec[1].relocs_ptr = (uintptr_t)gem_reloc; 418428d7b3dSmrg 419428d7b3dSmrg memset(&execbuf, 0, sizeof(execbuf)); 420428d7b3dSmrg execbuf.buffers_ptr = (uintptr_t)gem_exec; 421428d7b3dSmrg execbuf.buffer_count = 2; 422428d7b3dSmrg execbuf.batch_len = len * sizeof(uint32_t); 423428d7b3dSmrg execbuf.flags = gen >= 060 ? I915_EXEC_BLT : 0; 424428d7b3dSmrg 425428d7b3dSmrg ret = gem_write(device, gem_exec[1].handle, 0, batch, execbuf.batch_len); 426428d7b3dSmrg if (ret == 0) 427428d7b3dSmrg ret = drmIoctl(device, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf); 428428d7b3dSmrg if (ret < 0) 429428d7b3dSmrg ret = -errno; 430428d7b3dSmrg 431428d7b3dSmrg gem_close(device, gem_exec[1].handle); 432428d7b3dSmrg return ret; 433428d7b3dSmrg} 434428d7b3dSmrg 435428d7b3dSmrgstatic int test_shm(Display *dpy, int device, 436428d7b3dSmrg int width, int height) 437428d7b3dSmrg{ 438428d7b3dSmrg const int x_loc[] = {0, width/2, width-1}; 439428d7b3dSmrg const int y_loc[] = {0, height/2, height-1}; 440428d7b3dSmrg uint32_t pixel = 0xffff00ff; 441428d7b3dSmrg XShmSegmentInfo shm; 442428d7b3dSmrg Pixmap pixmap; 443428d7b3dSmrg uint32_t handle = 0; 444428d7b3dSmrg uint32_t *ptr; 445428d7b3dSmrg int stride, fd; 446428d7b3dSmrg int x, y; 447428d7b3dSmrg int line; 448428d7b3dSmrg 449428d7b3dSmrg if (!can_use_shm(dpy)) 450428d7b3dSmrg return 0; 451428d7b3dSmrg 452428d7b3dSmrg printf("Creating %dx%d SHM pixmap\n", width, height); 453428d7b3dSmrg _x_error_occurred = 0; 454428d7b3dSmrg 455428d7b3dSmrg shm.shmid = shmget(IPC_PRIVATE, height * 4*width, IPC_CREAT | 0666); 456428d7b3dSmrg if (shm.shmid == -1) 457428d7b3dSmrg return 0; 458428d7b3dSmrg 459428d7b3dSmrg shm.shmaddr = shmat(shm.shmid, 0, 0); 460428d7b3dSmrg if (shm.shmaddr == (char *) -1) { 461428d7b3dSmrg shmctl(shm.shmid, IPC_RMID, NULL); 462428d7b3dSmrg return 0; 463428d7b3dSmrg } 464428d7b3dSmrg 465428d7b3dSmrg shm.readOnly = False; 466428d7b3dSmrg XShmAttach(dpy, &shm); 467428d7b3dSmrg 468428d7b3dSmrg pixmap = XShmCreatePixmap(dpy, DefaultRootWindow(dpy), 469428d7b3dSmrg shm.shmaddr, &shm, width, height, 24); 470428d7b3dSmrg XSync(dpy, False); 471428d7b3dSmrg shmctl(shm.shmid, IPC_RMID, NULL); 472428d7b3dSmrg 473428d7b3dSmrg if (_x_error_occurred) { 474428d7b3dSmrg XShmDetach(dpy, &shm); 475428d7b3dSmrg shmdt(shm.shmaddr); 476428d7b3dSmrg return 0; 477428d7b3dSmrg } 478428d7b3dSmrg 479428d7b3dSmrg printf("Testing write of %dx%d SHM pixmap via DRI3 fd\n", width, height); 480428d7b3dSmrg 481428d7b3dSmrg fd = dri3_create_fd(dpy, pixmap, &stride); 482428d7b3dSmrg if (fd < 0) { 483428d7b3dSmrg line = __LINE__; 484428d7b3dSmrg goto fail; 485428d7b3dSmrg } 486428d7b3dSmrg 487428d7b3dSmrg handle = gem_import(device, fd); 488428d7b3dSmrg close(fd); 489428d7b3dSmrg if (handle == 0) { 490428d7b3dSmrg line = __LINE__; 491428d7b3dSmrg goto fail; 492428d7b3dSmrg } 493428d7b3dSmrg 494428d7b3dSmrg if (gpu_fill(device, handle, width, height, stride, 32, I915_TILING_NONE, pixel)) { 495428d7b3dSmrg line = __LINE__; 496428d7b3dSmrg goto fail; 497428d7b3dSmrg } 498428d7b3dSmrg 499428d7b3dSmrg gem_sync(device, handle, CPU); 500428d7b3dSmrg ptr = (uint32_t *)shm.shmaddr; 501428d7b3dSmrg for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++) 502428d7b3dSmrg for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++) 503428d7b3dSmrg if (ptr[y_loc[y]*width + x_loc[x]] != pixel) { 504428d7b3dSmrg printf("pixel[%d, %d]:%d = %08x\n", x, y, 32, ptr[y_loc[y] * width + x_loc[x]]); 505428d7b3dSmrg line = __LINE__; 506428d7b3dSmrg goto fail; 507428d7b3dSmrg } 508428d7b3dSmrg 509428d7b3dSmrg for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++) 510428d7b3dSmrg for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++) 511428d7b3dSmrg if (!check_pixmap(dpy, pixmap, 512428d7b3dSmrg x_loc[x], y_loc[y], 513428d7b3dSmrg pixel, 32)) { 514428d7b3dSmrg line = __LINE__; 515428d7b3dSmrg goto fail; 516428d7b3dSmrg } 517428d7b3dSmrg 518428d7b3dSmrg if (_x_error_occurred) { 519428d7b3dSmrg line = __LINE__; 520428d7b3dSmrg goto fail; 521428d7b3dSmrg } 522428d7b3dSmrg 523428d7b3dSmrgout: 524428d7b3dSmrg gem_close(device, handle); 525428d7b3dSmrg XFreePixmap(dpy, pixmap); 526428d7b3dSmrg XShmDetach(dpy, &shm); 527428d7b3dSmrg shmdt(shm.shmaddr); 528428d7b3dSmrg return fd != -1; 529428d7b3dSmrg 530428d7b3dSmrgfail: 531428d7b3dSmrg printf("%s failed at (%dx%d), line %d\n", 532428d7b3dSmrg __func__, width, height, line); 533428d7b3dSmrg fd = -1; 534428d7b3dSmrg goto out; 535428d7b3dSmrg} 536428d7b3dSmrg 537428d7b3dSmrgstatic int test_read_after_write(Display *dpy, int device, 538428d7b3dSmrg int width, int height, int depth, 539428d7b3dSmrg int domain) 540428d7b3dSmrg{ 541428d7b3dSmrg const uint32_t pixel = 0xffff00ff; 542428d7b3dSmrg const int x_loc[] = {0, width/2, width-1}; 543428d7b3dSmrg const int y_loc[] = {0, height/2, height-1}; 544428d7b3dSmrg Window root = RootWindow(dpy, DefaultScreen(dpy)); 545428d7b3dSmrg uint32_t src, dst; 546428d7b3dSmrg int src_fd, dst_fd; 547428d7b3dSmrg int src_stride, src_size; 548428d7b3dSmrg int dst_stride, dst_size; 549428d7b3dSmrg Pixmap src_pix, dst_pix; 550428d7b3dSmrg struct dri3_fence fence; 551428d7b3dSmrg int x, y, bpp; 552428d7b3dSmrg 553428d7b3dSmrg _x_error_occurred = 0; 554428d7b3dSmrg 555428d7b3dSmrg switch (depth) { 556428d7b3dSmrg case 8: bpp = 8; break; 557428d7b3dSmrg case 16: bpp = 16; break; 558428d7b3dSmrg case 24: bpp = 32; break; 559428d7b3dSmrg case 32: bpp = 32; break; 560428d7b3dSmrg default: return 0; 561428d7b3dSmrg } 562428d7b3dSmrg 563428d7b3dSmrg src_stride = width * bpp/8; 564428d7b3dSmrg src_size = PAGE_ALIGN(src_stride * height); 565428d7b3dSmrg printf("Creating %dx%d (source stride=%d, size=%d, domain=%d)\n", 566428d7b3dSmrg width, height, src_stride, src_size, domain); 567428d7b3dSmrg 568428d7b3dSmrg src = gem_create(device, src_size); 569428d7b3dSmrg if (!src) 570428d7b3dSmrg goto fail; 571428d7b3dSmrg 572428d7b3dSmrg if (domain == CPU) 573428d7b3dSmrg gem_set_caching(device, src, 1); 574428d7b3dSmrg 575428d7b3dSmrg gem_fill(device, src, pixel, src_size, domain); 576428d7b3dSmrg 577428d7b3dSmrg src_fd = gem_export(device, src); 578428d7b3dSmrg if (src_fd < 0) 579428d7b3dSmrg goto fail; 580428d7b3dSmrg 581428d7b3dSmrg src_pix = dri3_create_pixmap(dpy, root, 582428d7b3dSmrg width, height, depth, 583428d7b3dSmrg src_fd, bpp, src_stride, src_size); 584428d7b3dSmrg 585428d7b3dSmrg for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++) 586428d7b3dSmrg for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++) 587428d7b3dSmrg if (!check_pixmap(dpy, src_pix, 588428d7b3dSmrg x_loc[x], y_loc[y], 589428d7b3dSmrg pixel, bpp)) 590428d7b3dSmrg goto fail; 591428d7b3dSmrg close(src_fd); 592428d7b3dSmrg 593428d7b3dSmrg dst_pix = XCreatePixmap(dpy, root, width, height, depth); 594428d7b3dSmrg if (dri3_create_fence(dpy, dst_pix, &fence)) 595428d7b3dSmrg goto fail; 596428d7b3dSmrg 597428d7b3dSmrg dst_fd = dri3_create_fd(dpy, dst_pix, &dst_stride); 598428d7b3dSmrg if (dst_fd < 0) 599428d7b3dSmrg goto fail; 600428d7b3dSmrg dst_size = lseek(dst_fd, 0, SEEK_END); 601428d7b3dSmrg printf("Comparing %dx%d (destination stride=%d, size=%d)\n", 602428d7b3dSmrg width, height, dst_stride, dst_size); 603428d7b3dSmrg dst = gem_import(device, dst_fd); 604428d7b3dSmrg if (dst == 0) 605428d7b3dSmrg goto fail; 606428d7b3dSmrg close(dst_fd); 607428d7b3dSmrg 608428d7b3dSmrg XCopyArea(dpy, src_pix, dst_pix, 609428d7b3dSmrg get_gc(dpy, dst_pix, depth), 610428d7b3dSmrg 0, 0, width, height, 0, 0); 611428d7b3dSmrg dri3_fence_sync(dpy, &fence); 612428d7b3dSmrg dri3_fence_free(dpy, &fence); 613428d7b3dSmrg 614428d7b3dSmrg for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++) 615428d7b3dSmrg for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++) 616428d7b3dSmrg if (!check_pixel(device, dst, dst_stride, dst_size, 617428d7b3dSmrg x_loc[x], y_loc[y], 618428d7b3dSmrg pixel, bpp, GTT)) 619428d7b3dSmrg goto fail; 620428d7b3dSmrg 621428d7b3dSmrg XFreePixmap(dpy, dst_pix); 622428d7b3dSmrg XFreePixmap(dpy, src_pix); 623428d7b3dSmrg 624428d7b3dSmrg gem_close(device, src); 625428d7b3dSmrg gem_close(device, dst); 626428d7b3dSmrg 627428d7b3dSmrg if (_x_error_occurred) 628428d7b3dSmrg goto fail; 629428d7b3dSmrg 630428d7b3dSmrg return 0; 631428d7b3dSmrg 632428d7b3dSmrgfail: 633428d7b3dSmrg printf("%s failed at (%dx%d), depth=%d, domain=%d\n", 634428d7b3dSmrg __func__, width, height, depth, domain); 635428d7b3dSmrg return 1; 636428d7b3dSmrg} 637428d7b3dSmrg 638428d7b3dSmrgstatic XRenderPictFormat *format_for_depth(Display *dpy, int depth) 639428d7b3dSmrg{ 640428d7b3dSmrg switch (depth) { 641428d7b3dSmrg case 8: return XRenderFindStandardFormat(dpy, PictStandardA8); 642428d7b3dSmrg case 24: return XRenderFindStandardFormat(dpy, PictStandardRGB24); 643428d7b3dSmrg case 32: return XRenderFindStandardFormat(dpy, PictStandardARGB32); 644428d7b3dSmrg default: assert(0); return NULL; 645428d7b3dSmrg } 646428d7b3dSmrg} 647428d7b3dSmrg 648428d7b3dSmrgstatic int test_read(Display *dpy, int device, 649428d7b3dSmrg int width, int height, 650428d7b3dSmrg int domain) 651428d7b3dSmrg{ 652428d7b3dSmrg const uint32_t pixel = 0xffff00ff; 653428d7b3dSmrg const XRenderColor color = { 0xffff, 0x0000, 0xffff, 0xffff }; 654428d7b3dSmrg const int x_loc[] = {0, width/2, width-1}; 655428d7b3dSmrg const int y_loc[] = {0, height/2, height-1}; 656428d7b3dSmrg Window root = RootWindow(dpy, DefaultScreen(dpy)); 657428d7b3dSmrg uint32_t dst; 658428d7b3dSmrg int dst_stride, dst_size, dst_fd; 659428d7b3dSmrg Pixmap src_pix, dst_pix; 660428d7b3dSmrg Picture src_pic; 661428d7b3dSmrg struct dri3_fence fence; 662428d7b3dSmrg int depth = 32, bpp = 32; 663428d7b3dSmrg int x, y; 664428d7b3dSmrg 665428d7b3dSmrg _x_error_occurred = 0; 666428d7b3dSmrg 667428d7b3dSmrg dst_stride = width * bpp/8; 668428d7b3dSmrg dst_size = PAGE_ALIGN(dst_stride * height); 669428d7b3dSmrg printf("Creating %dx%d (destination stride=%d, size=%d, domain=%d)\n", 670428d7b3dSmrg width, height, dst_stride, dst_size, domain); 671428d7b3dSmrg 672428d7b3dSmrg dst = gem_create(device, dst_size); 673428d7b3dSmrg if (!dst) 674428d7b3dSmrg goto fail; 675428d7b3dSmrg 676428d7b3dSmrg if (domain == CPU) 677428d7b3dSmrg gem_set_caching(device, dst, 1); 678428d7b3dSmrg 679428d7b3dSmrg gem_fill(device, dst, ~pixel, dst_size, domain); 680428d7b3dSmrg 681428d7b3dSmrg dst_fd = gem_export(device, dst); 682428d7b3dSmrg if (dst_fd < 0) 683428d7b3dSmrg goto fail; 684428d7b3dSmrg 685428d7b3dSmrg dst_pix = dri3_create_pixmap(dpy, root, 686428d7b3dSmrg width, height, depth, 687428d7b3dSmrg dst_fd, bpp, dst_stride, dst_size); 688428d7b3dSmrg XSync(dpy, True); 689428d7b3dSmrg if (_x_error_occurred) 690428d7b3dSmrg goto fail; 691428d7b3dSmrg if (dri3_create_fence(dpy, dst_pix, &fence)) 692428d7b3dSmrg goto fail; 693428d7b3dSmrg 694428d7b3dSmrg src_pix = XCreatePixmap(dpy, root, width, height, depth); 695428d7b3dSmrg src_pic = XRenderCreatePicture(dpy, src_pix, format_for_depth(dpy, depth), 0, NULL); 696428d7b3dSmrg XRenderFillRectangle(dpy, PictOpSrc, src_pic, &color, 0, 0, width, height); 697428d7b3dSmrg XCopyArea(dpy, src_pix, dst_pix, 698428d7b3dSmrg get_gc(dpy, dst_pix, depth), 699428d7b3dSmrg 0, 0, width, height, 0, 0); 700428d7b3dSmrg dri3_fence_sync(dpy, &fence); 701428d7b3dSmrg dri3_fence_free(dpy, &fence); 702428d7b3dSmrg 703428d7b3dSmrg for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++) 704428d7b3dSmrg for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++) 705428d7b3dSmrg if (!check_pixel(device, dst, dst_stride, dst_size, 706428d7b3dSmrg x_loc[x], y_loc[y], 707428d7b3dSmrg pixel, bpp, domain)) 708428d7b3dSmrg goto fail; 709428d7b3dSmrg 710428d7b3dSmrg XFreePixmap(dpy, dst_pix); 711428d7b3dSmrg XRenderFreePicture(dpy, src_pic); 712428d7b3dSmrg XFreePixmap(dpy, src_pix); 713428d7b3dSmrg 714428d7b3dSmrg gem_close(device, dst); 715428d7b3dSmrg 716428d7b3dSmrg if (_x_error_occurred) 717428d7b3dSmrg goto fail; 718428d7b3dSmrg 719428d7b3dSmrg return 0; 720428d7b3dSmrg 721428d7b3dSmrgfail: 722428d7b3dSmrg printf("%s failed at (%dx%d), depth=%d, domain=%d\n", 723428d7b3dSmrg __func__, width, height, depth, domain); 724428d7b3dSmrg return 1; 725428d7b3dSmrg} 726428d7b3dSmrg 727428d7b3dSmrgstatic int test_dup_pixmap(Display *dpy, int device) 728428d7b3dSmrg{ 729428d7b3dSmrg const uint32_t pixel = 0xffff00ff; 730428d7b3dSmrg const XRenderColor color = { 0xffff, 0x0000, 0xffff, 0xffff }; 731428d7b3dSmrg const XRenderColor inverse = { 0, 0xffff, 0, 0 }; 732428d7b3dSmrg int width = 400, height = 400; 733428d7b3dSmrg const int x_loc[] = {0, width/2, width-1}; 734428d7b3dSmrg const int y_loc[] = {0, height/2, height-1}; 735428d7b3dSmrg Window root = RootWindow(dpy, DefaultScreen(dpy)); 736428d7b3dSmrg uint32_t handle; 737428d7b3dSmrg int stride, size, fd; 738428d7b3dSmrg Pixmap src_pix, dst_pix; 739428d7b3dSmrg Picture src_pic, dst_pic; 740428d7b3dSmrg struct dri3_fence fence; 741428d7b3dSmrg int depth = 32, bpp = 32; 742428d7b3dSmrg int x, y; 743428d7b3dSmrg 744428d7b3dSmrg _x_error_occurred = 0; 745428d7b3dSmrg 746428d7b3dSmrg printf("%s: Creating %dx%d pixmap\n", __func__, width, height); 747428d7b3dSmrg src_pix = XCreatePixmap(dpy, root, width, height, depth); 748428d7b3dSmrg src_pic = XRenderCreatePicture(dpy, src_pix, format_for_depth(dpy, depth), 0, NULL); 749428d7b3dSmrg fd = dri3_create_fd(dpy, src_pix, &stride); 750428d7b3dSmrg if (fd < 0) 751428d7b3dSmrg goto fail; 752428d7b3dSmrg 753428d7b3dSmrg size = lseek(fd, 0, SEEK_END); 754428d7b3dSmrg handle = gem_import(device, fd); 755428d7b3dSmrg 756428d7b3dSmrg printf("%s: Creating duplicate from pixmap exported fd\n", __func__); 757428d7b3dSmrg dst_pix = dri3_create_pixmap(dpy, root, 758428d7b3dSmrg width, height, depth, 759428d7b3dSmrg fd, bpp, stride, size); 760428d7b3dSmrg dst_pic = XRenderCreatePicture(dpy, dst_pix, format_for_depth(dpy, depth), 0, NULL); 761428d7b3dSmrg XSync(dpy, True); 762428d7b3dSmrg if (_x_error_occurred) 763428d7b3dSmrg goto fail; 764428d7b3dSmrg 765428d7b3dSmrg printf("%s: Filling src with %08x, reading dst\n", __func__, pixel); 766428d7b3dSmrg XRenderFillRectangle(dpy, PictOpSrc, src_pic, &color, 0, 0, width, height); 767428d7b3dSmrg for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++) 768428d7b3dSmrg for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++) 769428d7b3dSmrg if (!check_pixmap(dpy, dst_pix, 770428d7b3dSmrg x_loc[x], y_loc[y], 771428d7b3dSmrg pixel, 32)) 772428d7b3dSmrg goto fail; 773428d7b3dSmrg 774428d7b3dSmrg printf("%s: Filling dst with %08x, reading src\n", __func__, ~pixel); 775428d7b3dSmrg XRenderFillRectangle(dpy, PictOpSrc, dst_pic, &inverse, 0, 0, width, height); 776428d7b3dSmrg for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++) 777428d7b3dSmrg for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++) 778428d7b3dSmrg if (!check_pixmap(dpy, dst_pix, 779428d7b3dSmrg x_loc[x], y_loc[y], 780428d7b3dSmrg ~pixel, 32)) 781428d7b3dSmrg goto fail; 782428d7b3dSmrg 783428d7b3dSmrg if (dri3_create_fence(dpy, src_pix, &fence)) 784428d7b3dSmrg goto fail; 785428d7b3dSmrg 786428d7b3dSmrg printf("%s: Filling src with %08x, reading fd\n", __func__, pixel); 787428d7b3dSmrg XRenderFillRectangle(dpy, PictOpSrc, src_pic, &color, 0, 0, width, height); 788428d7b3dSmrg dri3_fence_sync(dpy, &fence); 789428d7b3dSmrg dri3_fence_free(dpy, &fence); 790428d7b3dSmrg for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++) 791428d7b3dSmrg for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++) 792428d7b3dSmrg if (!check_pixel(device, handle, stride, size, 793428d7b3dSmrg x_loc[x], y_loc[y], 794428d7b3dSmrg pixel, bpp, GTT)) 795428d7b3dSmrg goto fail; 796428d7b3dSmrg 797428d7b3dSmrg printf("%s: Filling fd with %08x, reading src\n", __func__, ~pixel); 798428d7b3dSmrg if (gpu_fill(device, handle, width, height, stride, 32, gem_get_tiling(device, handle), ~pixel)) 799428d7b3dSmrg goto fail; 800428d7b3dSmrg for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++) 801428d7b3dSmrg for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++) 802428d7b3dSmrg if (!check_pixmap(dpy, src_pix, 803428d7b3dSmrg x_loc[x], y_loc[y], 804428d7b3dSmrg ~pixel, 32)) 805428d7b3dSmrg goto fail; 806428d7b3dSmrg 807428d7b3dSmrg if (dri3_create_fence(dpy, dst_pix, &fence)) 808428d7b3dSmrg goto fail; 809428d7b3dSmrg 810428d7b3dSmrg printf("%s: Filling dst with %08x, reading fd\n", __func__, pixel); 811428d7b3dSmrg XRenderFillRectangle(dpy, PictOpSrc, dst_pic, &color, 0, 0, width, height); 812428d7b3dSmrg dri3_fence_sync(dpy, &fence); 813428d7b3dSmrg dri3_fence_free(dpy, &fence); 814428d7b3dSmrg for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++) 815428d7b3dSmrg for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++) 816428d7b3dSmrg if (!check_pixel(device, handle, stride, size, 817428d7b3dSmrg x_loc[x], y_loc[y], 818428d7b3dSmrg pixel, bpp, GTT)) 819428d7b3dSmrg goto fail; 820428d7b3dSmrg 821428d7b3dSmrg printf("%s: Filling fd with %08x, reading dst\n", __func__, ~pixel); 822428d7b3dSmrg if (gpu_fill(device, handle, width, height, stride, 32, gem_get_tiling(device, handle), ~pixel)) 823428d7b3dSmrg goto fail; 824428d7b3dSmrg for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++) 825428d7b3dSmrg for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++) 826428d7b3dSmrg if (!check_pixmap(dpy, dst_pix, 827428d7b3dSmrg x_loc[x], y_loc[y], 828428d7b3dSmrg ~pixel, 32)) 829428d7b3dSmrg goto fail; 830428d7b3dSmrg 831428d7b3dSmrg XRenderFreePicture(dpy, src_pic); 832428d7b3dSmrg XFreePixmap(dpy, src_pix); 833428d7b3dSmrg 834428d7b3dSmrg if (dri3_create_fence(dpy, dst_pix, &fence)) 835428d7b3dSmrg goto fail; 836428d7b3dSmrg 837428d7b3dSmrg printf("%s: Closed original src, filling dst with %08x, reading fd\n", __func__, pixel); 838428d7b3dSmrg XRenderFillRectangle(dpy, PictOpSrc, dst_pic, &color, 0, 0, width, height); 839428d7b3dSmrg dri3_fence_sync(dpy, &fence); 840428d7b3dSmrg dri3_fence_free(dpy, &fence); 841428d7b3dSmrg for (x = 0; x < sizeof(x_loc)/sizeof(x_loc[0]); x++) 842428d7b3dSmrg for (y = 0; y < sizeof(y_loc)/sizeof(y_loc[0]); y++) 843428d7b3dSmrg if (!check_pixel(device, handle, stride, size, 844428d7b3dSmrg x_loc[x], y_loc[y], 845428d7b3dSmrg pixel, bpp, GTT)) 846428d7b3dSmrg goto fail; 847428d7b3dSmrg 848428d7b3dSmrg XRenderFreePicture(dpy, dst_pic); 849428d7b3dSmrg XFreePixmap(dpy, dst_pix); 850428d7b3dSmrg 851428d7b3dSmrg gem_close(device, handle); 852428d7b3dSmrg 853428d7b3dSmrg if (_x_error_occurred) 854428d7b3dSmrg goto fail; 855428d7b3dSmrg 856428d7b3dSmrg return 0; 857428d7b3dSmrg 858428d7b3dSmrgfail: 859428d7b3dSmrg printf("%s failed at (%dx%d), depth=%d\n", 860428d7b3dSmrg __func__, width, height, depth); 861428d7b3dSmrg return 1; 862428d7b3dSmrg} 863428d7b3dSmrg 864428d7b3dSmrgstatic int test_bad_size(Display *dpy, int device) 865428d7b3dSmrg{ 866428d7b3dSmrg Window root = RootWindow(dpy, DefaultScreen(dpy)); 867428d7b3dSmrg uint32_t src; 868428d7b3dSmrg int src_fd; 869428d7b3dSmrg Pixmap src_pix; 870428d7b3dSmrg int line = -1; 871428d7b3dSmrg 872428d7b3dSmrg _x_error_occurred = 0; 873428d7b3dSmrg 874428d7b3dSmrg src = gem_create(device, 4096); 875428d7b3dSmrg if (!src) 876428d7b3dSmrg goto fail; 877428d7b3dSmrg 878428d7b3dSmrg src_fd = gem_export(device, src); 879428d7b3dSmrg if (src_fd < 0) 880428d7b3dSmrg goto fail; 881428d7b3dSmrg 882428d7b3dSmrg src_pix = dri3_create_pixmap(dpy, root, 883428d7b3dSmrg 16, 16, 32, 884428d7b3dSmrg dup(src_fd), 32, 16*4, 4096); 885428d7b3dSmrg line = __LINE__; 886428d7b3dSmrg XSync(dpy, True); 887428d7b3dSmrg if (_x_error_occurred) 888428d7b3dSmrg goto fail; 889428d7b3dSmrg XFreePixmap(dpy, src_pix); 890428d7b3dSmrg _x_error_occurred = 0; 891428d7b3dSmrg 892428d7b3dSmrg src_pix = dri3_create_pixmap(dpy, root, 893428d7b3dSmrg 32, 32, 32, 894428d7b3dSmrg dup(src_fd), 32, 32*4, 4096); 895428d7b3dSmrg line = __LINE__; 896428d7b3dSmrg XSync(dpy, True); 897428d7b3dSmrg if (_x_error_occurred) 898428d7b3dSmrg goto fail; 899428d7b3dSmrg XFreePixmap(dpy, src_pix); 900428d7b3dSmrg _x_error_occurred = 0; 901428d7b3dSmrg 902428d7b3dSmrg src_pix = dri3_create_pixmap(dpy, root, 903428d7b3dSmrg 64, 64, 32, 904428d7b3dSmrg dup(src_fd), 32, 64*4, 4096); 905428d7b3dSmrg line = __LINE__; 906428d7b3dSmrg XSync(dpy, True); 907428d7b3dSmrg if (!_x_error_occurred) 908428d7b3dSmrg goto fail; 909428d7b3dSmrg _x_error_occurred = 0; 910428d7b3dSmrg 911428d7b3dSmrg src_pix = dri3_create_pixmap(dpy, root, 912428d7b3dSmrg 64, 64, 32, 913428d7b3dSmrg dup(src_fd), 32, 64*4, 64*64*4); 914428d7b3dSmrg line = __LINE__; 915428d7b3dSmrg XSync(dpy, True); 916428d7b3dSmrg if (!_x_error_occurred) 917428d7b3dSmrg goto fail; 918428d7b3dSmrg _x_error_occurred = 0; 919428d7b3dSmrg 920428d7b3dSmrg src_pix = dri3_create_pixmap(dpy, root, 921428d7b3dSmrg INT16_MAX, INT16_MAX, 8, 922428d7b3dSmrg dup(src_fd), 8, INT16_MAX, UINT32_MAX); 923428d7b3dSmrg line = __LINE__; 924428d7b3dSmrg XSync(dpy, True); 925428d7b3dSmrg if (!_x_error_occurred) 926428d7b3dSmrg goto fail; 927428d7b3dSmrg _x_error_occurred = 0; 928428d7b3dSmrg 929428d7b3dSmrg close(src_fd); 930428d7b3dSmrg gem_close(device, src); 931428d7b3dSmrg 932428d7b3dSmrg return 0; 933428d7b3dSmrg 934428d7b3dSmrgfail: 935428d7b3dSmrg printf("%s failed at line %d\n", __func__, line); 936428d7b3dSmrg return 1; 937428d7b3dSmrg} 938428d7b3dSmrg 939428d7b3dSmrgstatic int test_bad_pitch(Display *dpy, int device) 940428d7b3dSmrg{ 941428d7b3dSmrg Window root = RootWindow(dpy, DefaultScreen(dpy)); 942428d7b3dSmrg uint32_t src; 943428d7b3dSmrg int src_fd; 944428d7b3dSmrg Pixmap src_pix; 945428d7b3dSmrg int line = -1; 946428d7b3dSmrg 947428d7b3dSmrg _x_error_occurred = 0; 948428d7b3dSmrg 949428d7b3dSmrg src = gem_create(device, 4096); 950428d7b3dSmrg if (!src) 951428d7b3dSmrg goto fail; 952428d7b3dSmrg 953428d7b3dSmrg src_fd = gem_export(device, src); 954428d7b3dSmrg if (src_fd < 0) 955428d7b3dSmrg goto fail; 956428d7b3dSmrg 957428d7b3dSmrg src_pix = dri3_create_pixmap(dpy, root, 958428d7b3dSmrg 16, 16, 32, 959428d7b3dSmrg dup(src_fd), 32, 16*4, 4096); 960428d7b3dSmrg line = __LINE__; 961428d7b3dSmrg XSync(dpy, True); 962428d7b3dSmrg if (_x_error_occurred) 963428d7b3dSmrg goto fail; 964428d7b3dSmrg XFreePixmap(dpy, src_pix); 965428d7b3dSmrg _x_error_occurred = 0; 966428d7b3dSmrg 967428d7b3dSmrg src_pix = dri3_create_pixmap(dpy, root, 968428d7b3dSmrg 256, 2, 32, 969428d7b3dSmrg dup(src_fd), 32, 256*4, 4096); 970428d7b3dSmrg line = __LINE__; 971428d7b3dSmrg XSync(dpy, True); 972428d7b3dSmrg if (_x_error_occurred) 973428d7b3dSmrg goto fail; 974428d7b3dSmrg XFreePixmap(dpy, src_pix); 975428d7b3dSmrg _x_error_occurred = 0; 976428d7b3dSmrg 977428d7b3dSmrg src_pix = dri3_create_pixmap(dpy, root, 978428d7b3dSmrg 256, 2, 32, 979428d7b3dSmrg dup(src_fd), 32, 256, 4096); 980428d7b3dSmrg line = __LINE__; 981428d7b3dSmrg XSync(dpy, True); 982428d7b3dSmrg if (!_x_error_occurred) 983428d7b3dSmrg goto fail; 984428d7b3dSmrg _x_error_occurred = 0; 985428d7b3dSmrg 986428d7b3dSmrg src_pix = dri3_create_pixmap(dpy, root, 987428d7b3dSmrg 256, 2, 32, 988428d7b3dSmrg dup(src_fd), 32, 16384, 4096); 989428d7b3dSmrg line = __LINE__; 990428d7b3dSmrg XSync(dpy, True); 991428d7b3dSmrg if (!_x_error_occurred) 992428d7b3dSmrg goto fail; 993428d7b3dSmrg _x_error_occurred = 0; 994428d7b3dSmrg 995428d7b3dSmrg src_pix = dri3_create_pixmap(dpy, root, 996428d7b3dSmrg 256, 2, 32, 997428d7b3dSmrg dup(src_fd), 32, 1023, 4096); 998428d7b3dSmrg line = __LINE__; 999428d7b3dSmrg XSync(dpy, True); 1000428d7b3dSmrg if (!_x_error_occurred) 1001428d7b3dSmrg goto fail; 1002428d7b3dSmrg _x_error_occurred = 0; 1003428d7b3dSmrg 1004428d7b3dSmrg src_pix = dri3_create_pixmap(dpy, root, 1005428d7b3dSmrg 256, 2, 32, 1006428d7b3dSmrg dup(src_fd), 32, 1025, 4096); 1007428d7b3dSmrg line = __LINE__; 1008428d7b3dSmrg XSync(dpy, True); 1009428d7b3dSmrg if (!_x_error_occurred) 1010428d7b3dSmrg goto fail; 1011428d7b3dSmrg _x_error_occurred = 0; 1012428d7b3dSmrg 1013428d7b3dSmrg close(src_fd); 1014428d7b3dSmrg gem_close(device, src); 1015428d7b3dSmrg 1016428d7b3dSmrg return 0; 1017428d7b3dSmrg 1018428d7b3dSmrgfail: 1019428d7b3dSmrg printf("%s failed at line %d\n", __func__, line); 1020428d7b3dSmrg return 1; 1021428d7b3dSmrg} 1022428d7b3dSmrg 1023428d7b3dSmrgstatic int 1024428d7b3dSmrg_check_error_handler(Display *display, 1025428d7b3dSmrg XErrorEvent *event) 1026428d7b3dSmrg{ 1027428d7b3dSmrg printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n", 1028428d7b3dSmrg DisplayString(display), 1029428d7b3dSmrg event->serial, 1030428d7b3dSmrg event->error_code, 1031428d7b3dSmrg event->request_code, 1032428d7b3dSmrg event->minor_code); 1033428d7b3dSmrg _x_error_occurred++; 1034428d7b3dSmrg return False; /* ignored */ 1035428d7b3dSmrg} 1036428d7b3dSmrg 1037428d7b3dSmrgint main(void) 1038428d7b3dSmrg{ 1039428d7b3dSmrg Display *dpy; 1040428d7b3dSmrg int device; 1041428d7b3dSmrg int error = 0; 1042428d7b3dSmrg 1043428d7b3dSmrg dpy = XOpenDisplay(NULL); 1044428d7b3dSmrg if (dpy == NULL) 1045428d7b3dSmrg return 77; 1046428d7b3dSmrg 1047428d7b3dSmrg if (DefaultDepth(dpy, DefaultScreen(dpy)) != 24) 1048428d7b3dSmrg return 77; 1049428d7b3dSmrg 1050428d7b3dSmrg XSetErrorHandler(_check_error_handler); 1051428d7b3dSmrg 1052428d7b3dSmrg device = dri3_open(dpy); 1053428d7b3dSmrg if (device < 0) 1054428d7b3dSmrg return 127; 1055428d7b3dSmrg 1056428d7b3dSmrg if (!is_intel(device)) 1057428d7b3dSmrg return 77; 1058428d7b3dSmrg 1059428d7b3dSmrg printf("Opened Intel DRI3 device\n"); 1060428d7b3dSmrg 1061428d7b3dSmrg error += test_bad_size(dpy, device); 1062428d7b3dSmrg error += test_bad_pitch(dpy, device); 1063428d7b3dSmrg 1064428d7b3dSmrg error += test_shm(dpy, device, 400, 300); 1065428d7b3dSmrg error += test_shm(dpy, device, 300, 400); 1066428d7b3dSmrg 1067428d7b3dSmrg error += test_read(dpy, device, 400, 200, GTT); 1068428d7b3dSmrg error += test_read(dpy, device, 4000, 20, GTT); 1069428d7b3dSmrg error += test_read(dpy, device, 16000, 10, GTT); 1070428d7b3dSmrg error += test_read(dpy, device, 30000, 10, GTT); 1071428d7b3dSmrg 1072428d7b3dSmrg error += test_read(dpy, device, 200, 400, GTT); 1073428d7b3dSmrg error += test_read(dpy, device, 20, 4000, GTT); 1074428d7b3dSmrg error += test_read(dpy, device, 16, 16000, GTT); 1075428d7b3dSmrg error += test_read(dpy, device, 16, 30000, GTT); 1076428d7b3dSmrg 1077428d7b3dSmrg error += test_read(dpy, device, 400, 200, CPU); 1078428d7b3dSmrg error += test_read(dpy, device, 4000, 20, CPU); 1079428d7b3dSmrg error += test_read(dpy, device, 16000, 10, CPU); 1080428d7b3dSmrg error += test_read(dpy, device, 30000, 10, CPU); 1081428d7b3dSmrg 1082428d7b3dSmrg error += test_read(dpy, device, 200, 400, CPU); 1083428d7b3dSmrg error += test_read(dpy, device, 20, 4000, CPU); 1084428d7b3dSmrg error += test_read(dpy, device, 16, 16000, CPU); 1085428d7b3dSmrg error += test_read(dpy, device, 16, 30000, CPU); 1086428d7b3dSmrg 1087428d7b3dSmrg error += test_read_after_write(dpy, device, 400, 200, 24, GTT); 1088428d7b3dSmrg error += test_read_after_write(dpy, device, 4000, 20, 24, GTT); 1089428d7b3dSmrg error += test_read_after_write(dpy, device, 16000, 10, 24, GTT); 1090428d7b3dSmrg error += test_read_after_write(dpy, device, 30000, 10, 24, GTT); 1091428d7b3dSmrg error += test_read_after_write(dpy, device, 30000, 10, 8, GTT); 1092428d7b3dSmrg 1093428d7b3dSmrg error += test_read_after_write(dpy, device, 200, 400, 24, GTT); 1094428d7b3dSmrg error += test_read_after_write(dpy, device, 20, 4000, 24, GTT); 1095428d7b3dSmrg error += test_read_after_write(dpy, device, 16, 16000, 24, GTT); 1096428d7b3dSmrg error += test_read_after_write(dpy, device, 16, 30000, 24, GTT); 1097428d7b3dSmrg 1098428d7b3dSmrg error += test_read_after_write(dpy, device, 400, 200, 24, CPU); 1099428d7b3dSmrg error += test_read_after_write(dpy, device, 4000, 20, 24, CPU); 1100428d7b3dSmrg error += test_read_after_write(dpy, device, 16000, 10, 24, CPU); 1101428d7b3dSmrg error += test_read_after_write(dpy, device, 30000, 10, 24, CPU); 1102428d7b3dSmrg error += test_read_after_write(dpy, device, 30000, 10, 8, CPU); 1103428d7b3dSmrg 1104428d7b3dSmrg error += test_read_after_write(dpy, device, 200, 400, 24, CPU); 1105428d7b3dSmrg error += test_read_after_write(dpy, device, 20, 4000, 24, CPU); 1106428d7b3dSmrg error += test_read_after_write(dpy, device, 16, 16000, 24, CPU); 1107428d7b3dSmrg error += test_read_after_write(dpy, device, 16, 30000, 24, CPU); 1108428d7b3dSmrg 1109428d7b3dSmrg error += test_dup_pixmap(dpy, device); 1110428d7b3dSmrg 1111428d7b3dSmrg return !!error; 1112428d7b3dSmrg} 1113