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