sna_accel.c 472 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
 * Copyright (c) 2011 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Authors:
 *    Chris Wilson <chris@chris-wilson.co.uk>
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "sna.h"
33
#include "sna_reg.h"
34
#include "sna_video.h"
35
#include "rop.h"
36

37
38
#include "intel_options.h"

39
40
41
42
43
#include <X11/fonts/font.h>
#include <X11/fonts/fontstruct.h>

#include <dixfontstr.h>

Chris Wilson's avatar
Chris Wilson committed
44
45
46
47
#include <mi.h>
#include <migc.h>
#include <miline.h>
#include <micmap.h>
48
49
50
#ifdef RENDER
#include <mipict.h>
#endif
Chris Wilson's avatar
Chris Wilson committed
51
#include <shmint.h>
52

53
54
#include <X11/extensions/damageproto.h>

55
56
#include <sys/time.h>
#include <sys/mman.h>
57
#include <sys/ioctl.h>
58
59
#include <unistd.h>

60
61
62
63
64
#ifdef HAVE_VALGRIND
#include <valgrind.h>
#include <memcheck.h>
#endif

65
66
#define FAULT_INJECTION 0

67
#define FORCE_INPLACE 0
68
#define FORCE_FALLBACK 0
69
#define FORCE_FLUSH 0
70
#define FORCE_FULL_SYNC 0 /* https://bugs.freedesktop.org/show_bug.cgi?id=61628 */
71

72
73
#define DEFAULT_PIXMAP_TILING I915_TILING_X
#define DEFAULT_SCANOUT_TILING I915_TILING_X
74

75
#define USE_INPLACE 1
76
#define USE_SPANS 0 /* -1 force CPU, 1 force GPU */
77
#define USE_CPU_BO 1
78
#define USE_USERPTR_UPLOADS 1
79
#define USE_USERPTR_DOWNLOADS 1
Chris Wilson's avatar
Chris Wilson committed
80
#define USE_COW 1
81
#define UNDO 1
82

83
#define MIGRATE_ALL 0
84
#define DBG_NO_PARTIAL_MOVE_TO_CPU 0
85
86
#define DBG_NO_CPU_UPLOAD 0
#define DBG_NO_CPU_DOWNLOAD 0
87

88
89
#define ACCEL_FILL_SPANS 1
#define ACCEL_SET_SPANS 1
90
#define ACCEL_PUT_IMAGE 1
91
#define ACCEL_GET_IMAGE 1
92
93
#define ACCEL_COPY_AREA 1
#define ACCEL_COPY_PLANE 1
Chris Wilson's avatar
Chris Wilson committed
94
#define ACCEL_COPY_WINDOW 1
95
96
97
98
99
#define ACCEL_POLY_POINT 1
#define ACCEL_POLY_LINE 1
#define ACCEL_POLY_SEGMENT 1
#define ACCEL_POLY_RECTANGLE 1
#define ACCEL_POLY_ARC 1
Chris Wilson's avatar
Chris Wilson committed
100
#define ACCEL_POLY_FILL_POLYGON 1
101
#define ACCEL_POLY_FILL_RECT 1
Chris Wilson's avatar
Chris Wilson committed
102
#define ACCEL_POLY_FILL_ARC 1
103
104
#define ACCEL_POLY_TEXT8 1
#define ACCEL_POLY_TEXT16 1
105
#define ACCEL_POLY_GLYPH 1
106
107
108
109
#define ACCEL_IMAGE_TEXT8 1
#define ACCEL_IMAGE_TEXT16 1
#define ACCEL_IMAGE_GLYPH 1
#define ACCEL_PUSH_PIXELS 1
110

111
112
113
#define NO_TILE_8x8 0
#define NO_STIPPLE_8x8 0

114
115
116
117
#define IS_COW_OWNER(ptr) ((uintptr_t)(ptr) & 1)
#define MAKE_COW_OWNER(ptr) ((void*)((uintptr_t)(ptr) | 1))
#define COW(ptr) (void *)((uintptr_t)(ptr) & ~1)

118
119
120
121
#define IS_CLIPPED	0x2
#define RECTILINEAR	0x4
#define OVERWRITES	0x8

Chris Wilson's avatar
Chris Wilson committed
122
123
#if XFONT2_CLIENT_FUNCS_VERSION >= 1
#define AllocateFontPrivateIndex() xfont2_allocate_font_private_index()
124
#undef FontSetPrivate
Chris Wilson's avatar
Chris Wilson committed
125
126
127
#define FontSetPrivate(font, idx, data) xfont2_font_set_private(font, idx, data)
#endif

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#if 0
static void __sna_fallback_flush(DrawablePtr d)
{
	PixmapPtr pixmap = get_drawable_pixmap(d);
	struct sna *sna = to_sna_from_pixmap(pixmap);
	struct sna_pixmap *priv;
	BoxRec box;
	PixmapPtr tmp;
	int i, j;
	char *src, *dst;

	DBG(("%s: uploading CPU damage...\n", __FUNCTION__));
	priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ);
	if (priv == NULL)
		return;

	DBG(("%s: downloading GPU damage...\n", __FUNCTION__));
	if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
		return;

	box.x1 = box.y1 = 0;
	box.x2 = pixmap->drawable.width;
	box.y2 = pixmap->drawable.height;

Chris Wilson's avatar
Chris Wilson committed
152
153
154
155
156
	tmp = sna_pixmap_create_unattached(pixmap->drawable.pScreen,
					   pixmap->drawable.width,
					   pixmap->drawable.height,
					   pixmap->drawable.depth,
					   0);
157
158

	DBG(("%s: comparing with direct read...\n", __FUNCTION__));
159
	sna_read_boxes(sna, tmp, priv->gpu_bo, &box, 1);
160
161
162
163
164
165
166

	src = pixmap->devPrivate.ptr;
	dst = tmp->devPrivate.ptr;
	for (i = 0; i < tmp->drawable.height; i++) {
		if (memcmp(src, dst, tmp->drawable.width * tmp->drawable.bitsPerPixel >> 3)) {
			for (j = 0; src[j] == dst[j]; j++)
				;
167
168
			ERR(("mismatch at (%d, %d)\n",
			     8*j / tmp->drawable.bitsPerPixel, i));
169
170
171
172
173
			abort();
		}
		src += pixmap->devKind;
		dst += tmp->devKind;
	}
Chris Wilson's avatar
Chris Wilson committed
174
	tmp->drawable.pScreen->DestroyPixmap(tmp);
175
176
177
178
179
180
}
#define FALLBACK_FLUSH(d) __sna_fallback_flush(d)
#else
#define FALLBACK_FLUSH(d)
#endif

181
static int sna_font_key;
182

Chris Wilson's avatar
Chris Wilson committed
183
static const uint8_t copy_ROP[] = {
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
	ROP_0,		/* GXclear */
	ROP_DSa,	/* GXand */
	ROP_SDna,	/* GXandReverse */
	ROP_S,		/* GXcopy */
	ROP_DSna,	/* GXandInverted */
	ROP_D,		/* GXnoop */
	ROP_DSx,	/* GXxor */
	ROP_DSo,	/* GXor */
	ROP_DSon,	/* GXnor */
	ROP_DSxn,	/* GXequiv */
	ROP_Dn,		/* GXinvert */
	ROP_SDno,	/* GXorReverse */
	ROP_Sn,		/* GXcopyInverted */
	ROP_DSno,	/* GXorInverted */
	ROP_DSan,	/* GXnand */
	ROP_1		/* GXset */
Chris Wilson's avatar
Chris Wilson committed
200
};
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
static const uint8_t fill_ROP[] = {
	ROP_0,
	ROP_DPa,
	ROP_PDna,
	ROP_P,
	ROP_DPna,
	ROP_D,
	ROP_DPx,
	ROP_DPo,
	ROP_DPon,
	ROP_PDxn,
	ROP_Dn,
	ROP_PDno,
	ROP_Pn,
	ROP_DPno,
	ROP_DPan,
	ROP_1
};
Chris Wilson's avatar
Chris Wilson committed
219

220
221
222
static const GCOps sna_gc_ops;
static const GCOps sna_gc_ops__cpu;
static GCOps sna_gc_ops__tmp;
Chris Wilson's avatar
Chris Wilson committed
223
224
static const GCFuncs sna_gc_funcs;
static const GCFuncs sna_gc_funcs__cpu;
225

226
static void sna_shm_watch_flush(struct sna *sna, int enable);
227
228
229
static void
sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect);

230
231
232
233
234
235
static inline void region_set(RegionRec *r, const BoxRec *b)
{
	r->extents = *b;
	r->data = NULL;
}

Chris Wilson's avatar
Chris Wilson committed
236
static inline bool region_maybe_clip(RegionRec *r, RegionRec *clip)
237
{
Chris Wilson's avatar
Chris Wilson committed
238
239
240
241
	if (clip->data && !RegionIntersect(r, r, clip))
		return false;

	return !box_empty(&r->extents);
242
243
}

244
245
246
247
248
static inline bool region_is_singular(const RegionRec *r)
{
	return r->data == NULL;
}

249
250
251
252
253
254
255
static inline bool region_is_unclipped(const RegionRec *r, int w, int h)
{
	return (region_is_singular(r) &&
		w == r->extents.x2 - r->extents.x1 &&
		h == r->extents.y2 - r->extents.y1);
}

256
257
258
259
typedef struct box32 {
	int32_t x1, y1, x2, y2;
} Box32Rec;

260
261
262
#define PM_IS_SOLID(_draw, _pm) \
	(((_pm) & FbFullMask((_draw)->depth)) == FbFullMask((_draw)->depth))

263
#ifndef NDEBUG
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
static void _assert_pixmap_contains_box(PixmapPtr pixmap, const BoxRec *box, const char *function)
{
	if (box->x1 < 0 || box->y1 < 0 ||
	    box->x2 > pixmap->drawable.width ||
	    box->y2 > pixmap->drawable.height)
	{
		FatalError("%s: damage box [(%d, %d), (%d, %d)] is beyond the pixmap=%ld size=%dx%d\n",
			   function, box->x1, box->y1, box->x2, box->y2,
			   pixmap->drawable.serialNumber,
			   pixmap->drawable.width,
			   pixmap->drawable.height);
	}
}

static void
_assert_pixmap_contains_damage(PixmapPtr pixmap, struct sna_damage *damage, const char *function)
280
281
{
	if (damage == NULL)
282
		return;
283

284
	_assert_pixmap_contains_box(pixmap, &DAMAGE_PTR(damage)->extents, function);
285
}
286
287
288
#define assert_pixmap_contains_damage(p,d) _assert_pixmap_contains_damage(p, d, __FUNCTION__)
#else
#define assert_pixmap_contains_damage(p,d)
289
290
291
292
293
294
295
296
#endif

#define __assert_pixmap_damage(p) do { \
	struct sna_pixmap *priv__ = sna_pixmap(p); \
	if (priv__) { \
		assert(priv__->gpu_damage == NULL || priv__->gpu_bo); \
		assert(priv__->gpu_bo == NULL || priv__->gpu_bo->refcnt); \
		assert(priv__->cpu_bo == NULL || priv__->cpu_bo->refcnt); \
297
298
		assert_pixmap_contains_damage(p, priv__->gpu_damage); \
		assert_pixmap_contains_damage(p, priv__->cpu_damage); \
299
300
301
302
		assert_pixmap_map(p, priv__); \
	} \
} while (0)

303
#ifdef DEBUG_PIXMAP
304
305
306
307
308
309
310
311
static void _assert_pixmap_contains_box_with_offset(PixmapPtr pixmap, const BoxRec *box, int dx, int dy, const char *function)
{
	BoxRec b = *box;
	b.x1 += dx; b.x2 += dx;
	b.y1 += dy; b.y2 += dy;
	_assert_pixmap_contains_box(pixmap, &b, function);
}

Chris Wilson's avatar
Chris Wilson committed
312
static void _assert_pixmap_contains_boxes(PixmapPtr pixmap, const BoxRec *box, int n, int dx, int dy, const char *function)
313
314
315
316
317
{
	BoxRec extents;

	extents = *box;
	while (--n) {
318
319
		++box;

320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
		if (box->x1 < extents.x1)
			extents.x1 = box->x1;
		if (box->x2 > extents.x2)
			extents.x2 = box->x2;

		if (box->y1 < extents.y1)
			extents.y1 = box->y1;
		if (box->y2 > extents.y2)
			extents.y2 = box->y2;
	}
	extents.x1 += dx;
	extents.x2 += dx;
	extents.y1 += dy;
	extents.y2 += dy;
	_assert_pixmap_contains_box(pixmap, &extents, function);
}


Chris Wilson's avatar
Chris Wilson committed
338
static void _assert_pixmap_contains_points(PixmapPtr pixmap, const DDXPointRec *pt, int n, int dx, int dy, const char *function)
339
340
341
342
343
344
{
	BoxRec extents;

	extents.x2 = extents.x1 = pt->x;
	extents.y2 = extents.y1 = pt->y;
	while (--n) {
345
346
		++pt;

347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
		if (pt->x < extents.x1)
			extents.x1 = pt->x;
		else if (pt->x > extents.x2)
			extents.x2 = pt->x;

		if (pt->y < extents.y1)
			extents.y1 = pt->y;
		else if (pt->y > extents.y2)
			extents.y2 = pt->y;
	}
	extents.x1 += dx;
	extents.x2 += dx + 1;
	extents.y1 += dy;
	extents.y2 += dy + 1;
	_assert_pixmap_contains_box(pixmap, &extents, function);
}

364
365
366
367
368
369
370
static void _assert_drawable_contains_box(DrawablePtr drawable, const BoxRec *box, const char *function)
{
	if (box->x1 < drawable->x ||
	    box->y1 < drawable->y ||
	    box->x2 > drawable->x + drawable->width ||
	    box->y2 > drawable->y + drawable->height)
	{
371
372
373
374
375
		FatalError("%s: damage box is beyond the drawable: box=(%d, %d), (%d, %d), drawable=(%d, %d)x(%d, %d)\n",
			   function,
			   box->x1, box->y1, box->x2, box->y2,
			   drawable->x, drawable->y,
			   drawable->width, drawable->height);
376
377
	}
}
378
379
380
381
382
383
384
385
386
387

static void assert_pixmap_damage(PixmapPtr p)
{
	struct sna_pixmap *priv;
	RegionRec reg, cpu, gpu;

	priv = sna_pixmap(p);
	if (priv == NULL)
		return;

388
	__assert_pixmap_damage(p);
389

390
391
392
393
394
	if (priv->clear) {
		assert(DAMAGE_IS_ALL(priv->gpu_damage));
		assert(priv->cpu_damage == NULL);
	}

395
	if (DAMAGE_IS_ALL(priv->gpu_damage) && DAMAGE_IS_ALL(priv->cpu_damage)) {
396
		/* special upload buffer */
397
398
		assert(priv->gpu_bo && priv->gpu_bo->proxy);
		assert(priv->cpu_bo == NULL);
399
		return;
400
	}
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416

	assert(!DAMAGE_IS_ALL(priv->gpu_damage) || priv->cpu_damage == NULL);
	assert(!DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL);

	/* Avoid reducing damage to minimise interferrence */
	RegionNull(&reg);
	RegionNull(&gpu);
	RegionNull(&cpu);

	if (priv->gpu_damage)
		_sna_damage_debug_get_region(DAMAGE_PTR(priv->gpu_damage), &gpu);

	if (priv->cpu_damage)
		_sna_damage_debug_get_region(DAMAGE_PTR(priv->cpu_damage), &cpu);

	RegionIntersect(&reg, &cpu, &gpu);
417
	assert(RegionNil(&reg));
418
419
420
421
422
423

	RegionUninit(&reg);
	RegionUninit(&gpu);
	RegionUninit(&cpu);
}

424
#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__)
425
#define assert_pixmap_contains_box_with_offset(p, b, dx, dy) _assert_pixmap_contains_box_with_offset(p, b, dx, dy, __FUNCTION__)
426
#define assert_drawable_contains_box(d, b) _assert_drawable_contains_box(d, b, __FUNCTION__)
427
428
#define assert_pixmap_contains_boxes(p, b, n, x, y) _assert_pixmap_contains_boxes(p, b, n, x, y, __FUNCTION__)
#define assert_pixmap_contains_points(p, pt, n, x, y) _assert_pixmap_contains_points(p, pt, n, x, y, __FUNCTION__)
429

430
431
#else
#define assert_pixmap_contains_box(p, b)
432
#define assert_pixmap_contains_box_with_offset(p, b, dx, dy)
433
434
#define assert_pixmap_contains_boxes(p, b, n, x, y)
#define assert_pixmap_contains_points(p, pt, n, x, y)
435
#define assert_drawable_contains_box(d, b)
436
#ifndef NDEBUG
437
#define assert_pixmap_damage(p) __assert_pixmap_damage(p)
438
#else
439
#define assert_pixmap_damage(p)
440
#endif
441
#endif
442

443
jmp_buf sigjmp[4];
444
445
446
447
volatile sig_atomic_t sigtrap;

static int sigtrap_handler(int sig)
{
448
449
450
451
452
	/* XXX rate-limited squawk? */
	DBG(("%s(sig=%d) sigtrap=%d\n", __FUNCTION__, sig, sigtrap));
	sna_threads_trap(sig);

	if (sigtrap)
453
		siglongjmp(sigjmp[--sigtrap], sig);
454

455
	return -1;
456
457
458
459
}

static void sigtrap_init(void)
{
460
#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0)
461
	OsRegisterSigWrapper(sigtrap_handler);
462
#endif
463
464
}

465
466
467
468
469
470
inline static bool
sna_fill_init_blt(struct sna_fill_op *fill,
		  struct sna *sna,
		  PixmapPtr pixmap,
		  struct kgem_bo *bo,
		  uint8_t alu,
471
472
		  uint32_t pixel,
		  unsigned flags)
473
{
474
	return sna->render.fill(sna, alu, pixmap, bo, pixel, flags, fill);
475
476
}

477
static bool
478
479
480
481
482
483
484
485
486
487
sna_copy_init_blt(struct sna_copy_op *copy,
		  struct sna *sna,
		  PixmapPtr src, struct kgem_bo *src_bo,
		  PixmapPtr dst, struct kgem_bo *dst_bo,
		  uint8_t alu)
{
	memset(copy, 0, sizeof(*copy));
	return sna->render.copy(sna, alu, src, src_bo, dst, dst_bo, copy);
}

488
static void sna_pixmap_free_gpu(struct sna *sna, struct sna_pixmap *priv)
489
{
490
	DBG(("%s: handle=%d (pinned? %d)\n", __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->pinned));
491
	assert(priv->gpu_damage == NULL || priv->gpu_bo);
492
493

	if (priv->cow)
494
		sna_pixmap_undo_cow(sna, priv, MOVE_WRITE);
495
496
	assert(priv->cow == NULL);

497
498
	if (priv->move_to_gpu) {
		sna_pixmap_discard_shadow_damage(priv, NULL);
499
		priv->move_to_gpu(sna, priv, MOVE_WRITE);
500
	}
501

502
	sna_damage_destroy(&priv->gpu_damage);
503
	priv->clear = false;
504

505
506
507
508
509
510
511
512
513
	if (priv->gpu_bo) {
		if (!priv->pinned) {
			assert(!priv->flush);
			assert(!priv->move_to_gpu);
			sna_pixmap_unmap(priv->pixmap, priv);
			kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
			priv->gpu_bo = NULL;
		} else
			kgem_bo_undo(&sna->kgem, priv->gpu_bo);
514
	}
515
516
517

	/* and reset the upload counter */
	priv->source_count = SOURCE_BIAS;
518
519
}

520
521
522
static bool must_check
sna_pixmap_alloc_cpu(struct sna *sna,
		     PixmapPtr pixmap,
523
		     struct sna_pixmap *priv,
524
		     unsigned flags)
525
{
526
	/* Restore after a GTT mapping? */
527
	assert(priv->gpu_damage == NULL || priv->gpu_bo);
528
	assert(!priv->shm);
529
530
531
	if (priv->ptr)
		goto done;

532
	DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
533
	assert(priv->stride);
534

Chris Wilson's avatar
Chris Wilson committed
535
	if (priv->create & KGEM_CAN_CREATE_CPU) {
536
537
		unsigned hint;

538
539
540
		DBG(("%s: allocating CPU buffer (%dx%d)\n", __FUNCTION__,
		     pixmap->drawable.width, pixmap->drawable.height));

541
542
543
544
		hint = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE;
		if ((flags & MOVE_ASYNC_HINT) ||
		    (priv->gpu_damage && !priv->clear && kgem_bo_is_busy(priv->gpu_bo) && sna->kgem.can_blt_cpu))
			hint = 0;
545

Chris Wilson's avatar
Chris Wilson committed
546
547
548
549
		priv->cpu_bo = kgem_create_cpu_2d(&sna->kgem,
						  pixmap->drawable.width,
						  pixmap->drawable.height,
						  pixmap->drawable.bitsPerPixel,
550
						  hint);
551
552
		if (priv->cpu_bo) {
			priv->ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo);
553
554
555
			if (priv->ptr) {
				DBG(("%s: allocated CPU handle=%d (snooped? %d)\n", __FUNCTION__,
				     priv->cpu_bo->handle, priv->cpu_bo->snoop));
556
				priv->stride = priv->cpu_bo->pitch;
557
#ifdef DEBUG_MEMORY
558
559
				sna->debug_memory.cpu_bo_allocs++;
				sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo);
560
#endif
561
562
563
564
			} else {
				kgem_bo_destroy(&sna->kgem, priv->cpu_bo);
				priv->cpu_bo = NULL;
			}
565
566
567
		}
	}

568
569
570
	if (priv->ptr == NULL) {
		DBG(("%s: allocating ordinary memory for shadow pixels [%d bytes]\n",
		     __FUNCTION__, priv->stride * pixmap->drawable.height));
571
		priv->ptr = malloc(priv->stride * pixmap->drawable.height);
572
	}
573

574
done:
575
	assert(priv->stride);
576
	assert(!priv->mapped);
577
578
	pixmap->devPrivate.ptr = PTR(priv->ptr);
	pixmap->devKind = priv->stride;
579
	return priv->ptr != NULL;
580
581
}

582
static void __sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv)
583
584
{
	if (priv->cpu_bo) {
585
		DBG(("%s: discarding CPU buffer, handle=%d, size=%d\n",
586
		     __FUNCTION__, priv->cpu_bo->handle, kgem_bo_size(priv->cpu_bo)));
Chris Wilson's avatar
Chris Wilson committed
587
588
589
590
#ifdef DEBUG_MEMORY
		sna->debug_memory.cpu_bo_allocs--;
		sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
#endif
Chris Wilson's avatar
Chris Wilson committed
591
592
		if (priv->cpu_bo->flush) {
			assert(!priv->cpu_bo->reusable);
Chris Wilson's avatar
Chris Wilson committed
593
			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
594
			sna_shm_watch_flush(sna, -1);
595
		}
596
		kgem_bo_destroy(&sna->kgem, priv->cpu_bo);
597
	} else if (!IS_STATIC_PTR(priv->ptr))
598
		free(priv->ptr);
599
600
}

601
static bool sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv, bool active)
602
{
603
	if (active)
604
		return false;
605

606
	if (IS_STATIC_PTR(priv->ptr))
607
608
609
		return false;

	if (priv->ptr == NULL)
610
		return true;
611

612
	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, priv->pixmap->drawable.serialNumber));
613
614
615
	__sna_pixmap_free_cpu(sna, priv);

	priv->cpu_bo = NULL;
616
	priv->ptr = NULL;
617

618
	if (priv->mapped == MAPPED_NONE)
619
		priv->pixmap->devPrivate.ptr = NULL;
620
621

	return true;
622
623
}

624
static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap)
625
{
626
#if DEFAULT_PIXMAP_TILING == I915_TILING_NONE
627
	return I915_TILING_NONE;
628
#elif DEFAULT_PIXMAP_TILING == I915_TILING_X
629
630
	return I915_TILING_X;
#else
631
	/* Try to avoid hitting the Y-tiling GTT mapping bug on 855GM */
632
	if (sna->kgem.gen == 021)
633
634
		return I915_TILING_X;

635
636
637
638
	/* Only on later generations was the render pipeline
	 * more flexible than the BLT. So on gen2/3, prefer to
	 * keep large objects accessible through the BLT.
	 */
639
	if (sna->kgem.gen < 040 &&
640
641
642
643
	    (pixmap->drawable.width  > sna->render.max_3d_size ||
	     pixmap->drawable.height > sna->render.max_3d_size))
		return I915_TILING_X;

644
645
	return I915_TILING_Y;
#endif
646
647
}

648
pure static uint32_t sna_pixmap_default_tiling(struct sna *sna, PixmapPtr pixmap)
649
650
651
652
{
	/* Also adjust tiling if it is not supported or likely to
	 * slow us down,
	 */
653
654
	return kgem_choose_tiling(&sna->kgem,
				  default_tiling(sna, pixmap),
655
656
657
658
659
				  pixmap->drawable.width,
				  pixmap->drawable.height,
				  pixmap->drawable.bitsPerPixel);
}

660
struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling)
661
662
663
664
665
666
{
	struct sna_pixmap *priv = sna_pixmap(pixmap);
	struct sna *sna = to_sna_from_pixmap(pixmap);
	struct kgem_bo *bo;
	BoxRec box;

667
668
669
	DBG(("%s: changing tiling %d -> %d for %dx%d pixmap\n",
	     __FUNCTION__, priv->gpu_bo->tiling, tiling,
	     pixmap->drawable.width, pixmap->drawable.height));
670
	assert(priv->gpu_damage == NULL || priv->gpu_bo);
671
	assert(priv->gpu_bo->tiling != tiling);
672
673
674

	if (priv->pinned) {
		DBG(("%s: can't convert pinned bo\n", __FUNCTION__));
675
		return NULL;
676
	}
677

678
679
680
681
682
	if (wedged(sna)) {
		DBG(("%s: can't convert bo, wedged\n", __FUNCTION__));
		return NULL;
	}

683
	assert_pixmap_damage(pixmap);
684
	assert(!priv->move_to_gpu);
685

686
687
688
689
690
	bo = kgem_create_2d(&sna->kgem,
			    pixmap->drawable.width,
			    pixmap->drawable.height,
			    pixmap->drawable.bitsPerPixel,
			    tiling, 0);
691
692
	if (bo == NULL) {
		DBG(("%s: allocation failed\n", __FUNCTION__));
693
		return NULL;
694
	}
695

696
697
698
699
700
701
	if (bo->tiling == priv->gpu_bo->tiling) {
		DBG(("%s: tiling request failed\n", __FUNCTION__));
		kgem_bo_destroy(&sna->kgem, bo);
		return NULL;
	}

702
703
704
705
706
	box.x1 = box.y1 = 0;
	box.x2 = pixmap->drawable.width;
	box.y2 = pixmap->drawable.height;

	if (!sna->render.copy_boxes(sna, GXcopy,
707
708
				    &pixmap->drawable, priv->gpu_bo, 0, 0,
				    &pixmap->drawable, bo, 0, 0,
709
				    &box, 1, 0)) {
710
		DBG(("%s: copy failed\n", __FUNCTION__));
711
		kgem_bo_destroy(&sna->kgem, bo);
712
		return NULL;
713
714
	}

Chris Wilson's avatar
Chris Wilson committed
715
	sna_pixmap_unmap(pixmap, priv);
716
	kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
717

718
	return priv->gpu_bo = bo;
719
720
}

721
722
static inline void sna_set_pixmap(PixmapPtr pixmap, struct sna_pixmap *sna)
{
723
	((void **)__get_private(pixmap, sna_pixmap_key))[1] = sna;
724
	assert(sna_pixmap(pixmap) == sna);
725
726
}

727
728
729
static struct sna_pixmap *
_sna_pixmap_init(struct sna_pixmap *priv, PixmapPtr pixmap)
{
730
	list_init(&priv->flush_list);
Chris Wilson's avatar
Chris Wilson committed
731
	list_init(&priv->cow_list);
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
	priv->source_count = SOURCE_BIAS;
	priv->pixmap = pixmap;

	return priv;
}

static struct sna_pixmap *
_sna_pixmap_reset(PixmapPtr pixmap)
{
	struct sna_pixmap *priv;

	assert(pixmap->drawable.type == DRAWABLE_PIXMAP);
	assert(pixmap->drawable.class == 0);
	assert(pixmap->drawable.x == 0);
	assert(pixmap->drawable.y == 0);

	priv = sna_pixmap(pixmap);
	assert(priv != NULL);

	memset(priv, 0, sizeof(*priv));
	return _sna_pixmap_init(priv, pixmap);
}

755
static struct sna_pixmap *sna_pixmap_attach(PixmapPtr pixmap)
756
757
758
759
760
761
762
763
{
	struct sna_pixmap *priv;

	priv = calloc(1, sizeof(*priv));
	if (!priv)
		return NULL;

	sna_set_pixmap(pixmap, priv);
764
	return _sna_pixmap_init(priv, pixmap);
765
766
}

Chris Wilson's avatar
Chris Wilson committed
767
struct sna_pixmap *sna_pixmap_attach_to_bo(PixmapPtr pixmap, struct kgem_bo *bo)
768
769
770
{
	struct sna_pixmap *priv;

771
	assert(bo);
Chris Wilson's avatar
Chris Wilson committed
772
773
	assert(bo->proxy == NULL);
	assert(bo->unique_id);
774

775
776
	priv = sna_pixmap_attach(pixmap);
	if (!priv)
Chris Wilson's avatar
Chris Wilson committed
777
778
779
780
		return NULL;

	DBG(("%s: attaching %s handle=%d to pixmap=%ld\n",
	     __FUNCTION__, bo->snoop ? "CPU" : "GPU", bo->handle, pixmap->drawable.serialNumber));
781

782
	assert(!priv->mapped);
783
784
	assert(!priv->move_to_gpu);

Chris Wilson's avatar
Chris Wilson committed
785
786
	if (bo->snoop) {
		priv->cpu_bo = bo;
787
		sna_damage_all(&priv->cpu_damage, pixmap);
Chris Wilson's avatar
Chris Wilson committed
788
789
	} else {
		priv->gpu_bo = bo;
790
		sna_damage_all(&priv->gpu_damage, pixmap);
Chris Wilson's avatar
Chris Wilson committed
791
	}
792

Chris Wilson's avatar
Chris Wilson committed
793
	return priv;
794
795
}

Chris Wilson's avatar
Chris Wilson committed
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
static int bits_per_pixel(int depth)
{
	switch (depth) {
	case 1: return 1;
	case 4:
	case 8: return 8;
	case 15:
	case 16: return 16;
	case 24:
	case 30:
	case 32: return 32;
	default: return 0;
	}
}
static PixmapPtr
811
812
create_pixmap(struct sna *sna, ScreenPtr screen,
	      int width, int height, int depth,
Chris Wilson's avatar
Chris Wilson committed
813
	      unsigned usage_hint)
814
815
{
	PixmapPtr pixmap;
Chris Wilson's avatar
Chris Wilson committed
816
817
818
819
820
821
822
823
824
825
826
827
828
829
	size_t datasize;
	size_t stride;
	int base, bpp;

	bpp = bits_per_pixel(depth);
	if (bpp == 0)
		return NullPixmap;

	stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
	if (stride / 4 > 32767 || height > 32767)
		return NullPixmap;

	datasize = height * stride;
	base = screen->totalPixmapSize;
830
	if (datasize && base & 15) {
Chris Wilson's avatar
Chris Wilson committed
831
832
833
834
		int adjust = 16 - (base & 15);
		base += adjust;
		datasize += adjust;
	}
835

836
837
	DBG(("%s: allocating pixmap %dx%d, depth=%d/%d, size=%ld\n",
	     __FUNCTION__, width, height, depth, bpp, (long)datasize));
Chris Wilson's avatar
Chris Wilson committed
838
839
	pixmap = AllocatePixmap(screen, datasize);
	if (!pixmap)
840
841
		return NullPixmap;

842
	((void **)__get_private(pixmap, sna_pixmap_key))[0] = sna;
Chris Wilson's avatar
Chris Wilson committed
843
	assert(to_sna_from_pixmap(pixmap) == sna);
Chris Wilson's avatar
Chris Wilson committed
844
845
846
847
848
849
850
851
852
853
854
855
856
857

	pixmap->drawable.type = DRAWABLE_PIXMAP;
	pixmap->drawable.class = 0;
	pixmap->drawable.pScreen = screen;
	pixmap->drawable.depth = depth;
	pixmap->drawable.bitsPerPixel = bpp;
	pixmap->drawable.id = 0;
	pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
	pixmap->drawable.x = 0;
	pixmap->drawable.y = 0;
	pixmap->drawable.width = width;
	pixmap->drawable.height = height;
	pixmap->devKind = stride;
	pixmap->refcnt = 1;
858
	pixmap->devPrivate.ptr = datasize ? (char *)pixmap + base : NULL;
Chris Wilson's avatar
Chris Wilson committed
859
860
861
862
863
864
865

#ifdef COMPOSITE
	pixmap->screen_x = 0;
	pixmap->screen_y = 0;
#endif

	pixmap->usage_hint = usage_hint;
866
867
868
#if DEBUG_MEMORY
	sna->debug_memory.pixmap_allocs++;
#endif
Chris Wilson's avatar
Chris Wilson committed
869

870
871
872
873
874
875
876
	DBG(("%s: serial=%ld, usage=%d, %dx%d\n",
	     __FUNCTION__,
	     pixmap->drawable.serialNumber,
	     pixmap->usage_hint,
	     pixmap->drawable.width,
	     pixmap->drawable.height));

877
878
879
	return pixmap;
}

880
static PixmapPtr
881
__pop_freed_pixmap(struct sna *sna)
882
883
884
{
	PixmapPtr pixmap;

885
886
	assert(sna->freed_pixmap);

887
888
	pixmap = sna->freed_pixmap;
	sna->freed_pixmap = pixmap->devPrivate.ptr;
889

890
891
892
	DBG(("%s: reusing freed pixmap=%ld header\n",
	     __FUNCTION__, pixmap->drawable.serialNumber));

893
	assert(pixmap->refcnt == 0);
894
	assert(pixmap->devKind = 0xdeadbeef);
895
896
897
898
899
900
901
902
903
904
	assert(sna_pixmap(pixmap));
	assert(sna_pixmap(pixmap)->header);

#if DEBUG_MEMORY
	sna->debug_memory.pixmap_cached--;
#endif

	return pixmap;
}

905
906
907
908
inline static PixmapPtr
create_pixmap_hdr(struct sna *sna, ScreenPtr screen,
		  int width, int height, int depth, int usage,
		  struct sna_pixmap **priv)
909
{
910
	PixmapPtr pixmap;
911

912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
	if (sna->freed_pixmap == NULL) {
		pixmap = create_pixmap(sna, screen, 0, 0, depth, usage);
		if (pixmap == NullPixmap)
			return NullPixmap;

		*priv = sna_pixmap_attach(pixmap);
		if (!*priv) {
			FreePixmap(pixmap);
			return NullPixmap;
		}
	} else {
		pixmap = __pop_freed_pixmap(sna);
		*priv = _sna_pixmap_reset(pixmap);

		assert(pixmap->drawable.type == DRAWABLE_PIXMAP);
		assert(pixmap->drawable.class == 0);
		assert(pixmap->drawable.pScreen == screen);
		assert(pixmap->drawable.x == 0);
		assert(pixmap->drawable.y == 0);

932
933
		pixmap->drawable.id = 0;

934
935
936
937
938
939
940
941
942
943
944
		pixmap->drawable.depth = depth;
		pixmap->drawable.bitsPerPixel = bits_per_pixel(depth);
		pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;

		pixmap->devKind = 0;
		pixmap->devPrivate.ptr = NULL;

#ifdef COMPOSITE
		pixmap->screen_x = 0;
		pixmap->screen_y = 0;
#endif
945
946

#if DEBUG_MEMORY
947
		sna->debug_memory.pixmap_allocs++;
948
949
#endif

950
951
952
		pixmap->refcnt = 1;
	}

953
954
	DBG(("%s: pixmap=%ld, width=%d, height=%d, usage=%d\n", __FUNCTION__,
	     pixmap->drawable.serialNumber, width, height, usage));
955
956
957
958
	pixmap->drawable.width = width;
	pixmap->drawable.height = height;
	pixmap->usage_hint = usage;

959
	(*priv)->header = true;
960
961
962
	return pixmap;
}

Chris Wilson's avatar
Chris Wilson committed
963
964
965
966
967
968
static PixmapPtr
sna_pixmap_create_shm(ScreenPtr screen,
		      int width, int height, int depth,
		      char *addr)
{
	struct sna *sna = to_sna_from_screen(screen);
Chris Wilson's avatar
Chris Wilson committed
969
	int bpp = bits_per_pixel(depth);
Chris Wilson's avatar
Chris Wilson committed
970
971
972
973
	int pitch = PixmapBytePad(width, depth);
	struct sna_pixmap *priv;
	PixmapPtr pixmap;

974
975
	DBG(("%s(%dx%d, depth=%d, bpp=%d, pitch=%d)\n",
	     __FUNCTION__, width, height, depth, bpp, pitch));
976

977
	if (wedged(sna) || bpp == 0 || pitch*height < 4096) {
978
fallback:
979
980
981
982
983
984
985
986
987
988
989
990
		pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth);
		if (pixmap == NULL)
			return NULL;

		if (!screen->ModifyPixmapHeader(pixmap, width, height, depth,
						bpp, pitch, addr)) {
			screen->DestroyPixmap(pixmap);
			return NULL;
		}

		return pixmap;
	}
Chris Wilson's avatar
Chris Wilson committed
991

992
	pixmap = create_pixmap_hdr(sna, screen, width, height, depth, 0, &priv);
993
994
	if (pixmap == NullPixmap) {
		DBG(("%s: allocation failed\n", __FUNCTION__));
995
		goto fallback;
996
	}
997

998
	priv->cpu_bo = kgem_create_map(&sna->kgem, addr, pitch*height, false);
Chris Wilson's avatar
Chris Wilson committed
999
	if (priv->cpu_bo == NULL) {
1000
		DBG(("%s: mapping SHM segment failed\n", __FUNCTION__));
1001
1002
		sna_pixmap_destroy(pixmap);
		goto fallback;
Chris Wilson's avatar
Chris Wilson committed
1003
1004
	}
	priv->cpu_bo->pitch = pitch;
1005
	kgem_bo_mark_unreusable(priv->cpu_bo);
1006
	sna_shm_watch_flush(sna, 1);
1007
1008
1009
1010
#ifdef DEBUG_MEMORY
	sna->debug_memory.cpu_bo_allocs++;
	sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo);
#endif
Chris Wilson's avatar
Chris Wilson committed
1011

1012
	/* Be wary as we cannot cache SHM Pixmap in our freed cache */
1013
	priv->header = false;
1014
	priv->cpu = true;
1015
	priv->shm = true;
1016
1017
	priv->stride = pitch;
	priv->ptr = MAKE_STATIC_PTR(addr);
1018
	sna_damage_all(&priv->cpu_damage, pixmap);
Chris Wilson's avatar
Chris Wilson committed
1019
1020
1021

	pixmap->devKind = pitch;
	pixmap->devPrivate.ptr = addr;
1022
1023
1024
1025
1026
1027
1028

	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
	     __FUNCTION__,
	     pixmap->drawable.serialNumber,
	     pixmap->drawable.width,
	     pixmap->drawable.height,
	     pixmap->usage_hint));
Chris Wilson's avatar
Chris Wilson committed
1029
1030
1031
	return pixmap;
}

1032
1033
1034
1035
1036
1037
PixmapPtr
sna_pixmap_create_unattached(ScreenPtr screen,
			     int width, int height, int depth)
{
	return create_pixmap(to_sna_from_screen(screen),
			     screen, width, height, depth,
1038
			     -1);
1039
1040
}

1041
1042
1043
1044
1045
1046
1047
static PixmapPtr
sna_pixmap_create_scratch(ScreenPtr screen,
			  int width, int height, int depth,
			  uint32_t tiling)
{
	struct sna *sna = to_sna_from_screen(screen);
	struct sna_pixmap *priv;
1048
1049
	PixmapPtr pixmap;
	int bpp;
1050
1051
1052
1053

	DBG(("%s(%d, %d, %d, tiling=%d)\n", __FUNCTION__,
	     width, height, depth, tiling));

Chris Wilson's avatar
Chris Wilson committed
1054
	bpp = bits_per_pixel(depth);
1055
1056
	if (tiling == I915_TILING_Y &&
	    (sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0)
1057
1058
		tiling = I915_TILING_X;

1059
1060
1061
1062
	if (tiling == I915_TILING_Y &&
	    (width > sna->render.max_3d_size ||
	     height > sna->render.max_3d_size))
		tiling = I915_TILING_X;
1063

1064
1065
1066
	tiling = kgem_choose_tiling(&sna->kgem, tiling, width, height, bpp);

	/* you promise never to access this via the cpu... */
1067
1068
1069
	pixmap = create_pixmap_hdr(sna, screen, width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH, &priv);
	if (pixmap == NullPixmap)
		return NullPixmap;
1070
1071
1072

	priv->stride = PixmapBytePad(width, depth);

1073
1074
	priv->gpu_bo = kgem_create_2d(&sna->kgem,
				      width, height, bpp, tiling,
1075
				      CREATE_TEMPORARY);
1076
1077
	if (priv->gpu_bo == NULL) {
		free(priv);
Chris Wilson's avatar
Chris Wilson committed
1078
		FreePixmap(pixmap);
1079
1080
1081
		return NullPixmap;
	}

1082
	sna_damage_all(&priv->gpu_damage, pixmap);
1083

1084
1085
	assert(to_sna_from_pixmap(pixmap) == sna);
	assert(pixmap->drawable.pScreen == screen);
1086
	assert(pixmap->refcnt == 1);
1087

1088
1089
1090
1091
1092
1093
	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
	     __FUNCTION__,
	     pixmap->drawable.serialNumber,
	     pixmap->drawable.width,
	     pixmap->drawable.height,
	     pixmap->usage_hint));
1094
1095
1096
	return pixmap;
}

1097
1098
static unsigned small_copy(const RegionRec *region)
{
Chris Wilson's avatar
Chris Wilson committed
1099
1100
1101
1102
	if ((region->extents.x2 - region->extents.x1)*(region->extents.y2 - region->extents.y1) < 1024) {
		DBG(("%s: region:%dx%d\n", __FUNCTION__,
		     (region->extents.x2 - region->extents.x1),
		     (region->extents.y2 - region->extents.y1)));
1103
		return COPY_SMALL;
Chris Wilson's avatar
Chris Wilson committed
1104
	}
1105
1106
1107
1108

	return 0;
}

Chris Wilson's avatar
Chris Wilson committed
1109
1110
1111
1112
1113
1114
1115
1116
#ifdef CREATE_PIXMAP_USAGE_SHARED
static Bool
sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle)
{
	struct sna *sna = to_sna_from_pixmap(pixmap);
	struct sna_pixmap *priv;
	int fd;

1117
1118
	DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));

Chris Wilson's avatar
Chris Wilson committed
1119
	priv = sna_pixmap_move_to_gpu(pixmap,
1120
				      MOVE_READ | MOVE_WRITE | __MOVE_DRI | __MOVE_PRIME | __MOVE_FORCE);
Chris Wilson's avatar
Chris Wilson committed
1121
1122
1123
	if (priv == NULL)
		return FALSE;

1124
	assert(!priv->shm);
Chris Wilson's avatar
Chris Wilson committed
1125
	assert(priv->gpu_bo);
1126
	assert(priv->stride);
Chris Wilson's avatar
Chris Wilson committed
1127

1128
	/* XXX negotiate format and stride restrictions */
1129
1130
	if (priv->gpu_bo->tiling != I915_TILING_NONE ||
	    priv->gpu_bo->pitch & 255) {
1131
		struct kgem_bo *bo;
1132
1133
		BoxRec box;

1134
1135
		DBG(("%s: removing tiling %d, and aligning pitch %d for %dx%d pixmap=%ld\n",
		     __FUNCTION__, priv->gpu_bo->tiling, priv->gpu_bo->pitch,
1136
1137
		     pixmap->drawable.width, pixmap->drawable.height,
		     pixmap->drawable.serialNumber));
1138

1139
		if (priv->pinned) {
1140
1141
			DBG(("%s: can't convert pinned %x bo\n", __FUNCTION__,
			     priv->pinned));
1142
1143
1144
			return FALSE;
		}

1145
1146
1147
1148
1149
1150
1151
		assert_pixmap_damage(pixmap);

		bo = kgem_create_2d(&sna->kgem,
				    pixmap->drawable.width,
				    pixmap->drawable.height,
				    pixmap->drawable.bitsPerPixel,
				    I915_TILING_NONE,
1152
				    CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT);
1153
		if (bo == NULL) {
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
			DBG(("%s: allocation failed\n", __FUNCTION__));
			return FALSE;
		}

		box.x1 = box.y1 = 0;
		box.x2 = pixmap->drawable.width;
		box.y2 = pixmap->drawable.height;

		assert(!wedged(sna)); /* XXX */
		if (!sna->render.copy_boxes(sna, GXcopy,
1164
1165
					    &pixmap->drawable, priv->gpu_bo, 0, 0,
					    &pixmap->drawable, bo, 0, 0,
1166
1167
1168
					    &box, 1, 0)) {
			DBG(("%s: copy failed\n", __FUNCTION__));
			kgem_bo_destroy(&sna->kgem, bo);
1169
			return FALSE;
1170
		}
1171

1172
		sna_pixmap_unmap(pixmap, priv);
1173
1174
1175
		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
		priv->gpu_bo = bo;
	}
Chris Wilson's avatar
Chris Wilson committed
1176
	assert(priv->gpu_bo->tiling == I915_TILING_NONE);
1177
	assert((priv->gpu_bo->pitch & 255) == 0);
Chris Wilson's avatar
Chris Wilson committed
1178
1179

	/* And export the bo->pitch via pixmap->devKind */
1180
	if (!priv->mapped) {
1181
		void *ptr;
Chris Wilson's avatar
Chris Wilson committed
1182

1183
1184
1185
1186
1187
1188
		ptr = kgem_bo_map__async(&sna->kgem, priv->gpu_bo);
		if (ptr == NULL)
			return FALSE;

		pixmap->devPrivate.ptr = ptr;
		pixmap->devKind = priv->gpu_bo->pitch;
1189
		priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
1190
	}
1191
	assert_pixmap_map(pixmap, priv);
Chris Wilson's avatar
Chris Wilson committed
1192
1193
1194
1195
1196

	fd = kgem_bo_export_to_prime(&sna->kgem, priv->gpu_bo);
	if (fd == -1)
		return FALSE;

1197
	priv->pinned |= PIN_PRIME;
Chris Wilson's avatar
Chris Wilson committed
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209

	*fd_handle = (void *)(intptr_t)fd;
	return TRUE;
}

static Bool
sna_set_shared_pixmap_backing(PixmapPtr pixmap, void *fd_handle)
{
	struct sna *sna = to_sna_from_pixmap(pixmap);
	struct sna_pixmap *priv;
	struct kgem_bo *bo;

1210
1211
1212
1213
1214
	DBG(("%s: pixmap=%ld, size=%dx%d, depth=%d/%d, stride=%d\n",
	     __FUNCTION__, pixmap->drawable.serialNumber,
	     pixmap->drawable.width, pixmap->drawable.height,
	     pixmap->drawable.depth, pixmap->drawable.bitsPerPixel,
	     pixmap->devKind));
1215

Chris Wilson's avatar
Chris Wilson committed
1216
1217
1218
1219
	priv = sna_pixmap(pixmap);
	if (priv == NULL)
		return FALSE;

1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
	if (priv->pinned & ~PIN_PRIME)
		return FALSE;

	assert(!priv->flush);

	if (priv->gpu_bo) {
		priv->clear = false;
		sna_damage_destroy(&priv->gpu_damage);
		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
		priv->gpu_bo = NULL;
		priv->pinned = 0;
	}

Chris Wilson's avatar
Chris Wilson committed
1233
	assert(!priv->pinned);
1234

Chris Wilson's avatar
Chris Wilson committed
1235
1236
	assert(priv->cpu_bo == NULL);
	assert(priv->cpu_damage == NULL);
1237
1238

	assert(priv->gpu_bo == NULL);
Chris Wilson's avatar
Chris Wilson committed
1239
1240
	assert(priv->gpu_damage == NULL);