sna_io.c revision 42542f5f
1/*
2 * Copyright (c) 2011 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 *    Chris Wilson <chris@chris-wilson.co.uk>
25 *
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include "sna.h"
33#include "sna_render.h"
34#include "sna_reg.h"
35
36#include <sys/mman.h>
37
38#define PITCH(x, y) ALIGN((x)*(y), 4)
39
40#define FORCE_INPLACE 0 /* 1 upload directly, -1 force indirect */
41
42/* XXX Need to avoid using GTT fenced access for I915_TILING_Y on 855GM */
43
44static inline bool upload_too_large(struct sna *sna, int width, int height)
45{
46	return width * height * 4 > sna->kgem.max_upload_tile_size;
47}
48
49static inline bool must_tile(struct sna *sna, int width, int height)
50{
51	return (width  > sna->render.max_3d_size ||
52		height > sna->render.max_3d_size ||
53		upload_too_large(sna, width, height));
54}
55
56static bool download_inplace__cpu(struct kgem *kgem,
57				  PixmapPtr p, struct kgem_bo *bo,
58				  const BoxRec *box, int nbox)
59{
60	BoxRec extents;
61
62	switch (bo->tiling) {
63	case I915_TILING_X:
64		if (!kgem->memcpy_from_tiled_x)
65			return false;
66	case I915_TILING_NONE:
67		break;
68	default:
69		return false;
70	}
71
72	if (!kgem_bo_can_map__cpu(kgem, bo, false))
73		return false;
74
75	if (kgem->has_llc)
76		return true;
77
78	extents = *box;
79	while (--nbox) {
80		++box;
81		if (box->x1 < extents.x1)
82			extents.x1 = box->x1;
83		if (box->x2 > extents.x2)
84			extents.x2 = box->x2;
85		extents.y2 = box->y2;
86	}
87
88	if (extents.x2 - extents.x1 == p->drawable.width &&
89	    extents.y2 - extents.y1 == p->drawable.height)
90		return true;
91
92	return __kgem_bo_size(bo) <= PAGE_SIZE;
93}
94
95static bool
96read_boxes_inplace__cpu(struct kgem *kgem,
97			PixmapPtr pixmap, struct kgem_bo *bo,
98			const BoxRec *box, int n)
99{
100	int bpp = pixmap->drawable.bitsPerPixel;
101	void *src, *dst = pixmap->devPrivate.ptr;
102	int src_pitch = bo->pitch;
103	int dst_pitch = pixmap->devKind;
104
105	if (!download_inplace__cpu(kgem, dst, bo, box, n))
106		return false;
107
108	assert(kgem_bo_can_map__cpu(kgem, bo, false));
109	assert(bo->tiling != I915_TILING_Y);
110
111	src = kgem_bo_map__cpu(kgem, bo);
112	if (src == NULL)
113		return false;
114
115	kgem_bo_sync__cpu_full(kgem, bo, 0);
116
117	if (sigtrap_get())
118		return false;
119
120	DBG(("%s x %d\n", __FUNCTION__, n));
121
122	if (bo->tiling == I915_TILING_X) {
123		do {
124			memcpy_from_tiled_x(kgem, src, dst, bpp, src_pitch, dst_pitch,
125					    box->x1, box->y1,
126					    box->x1, box->y1,
127					    box->x2 - box->x1, box->y2 - box->y1);
128			box++;
129		} while (--n);
130	} else {
131		do {
132			memcpy_blt(src, dst, bpp, src_pitch, dst_pitch,
133				   box->x1, box->y1,
134				   box->x1, box->y1,
135				   box->x2 - box->x1, box->y2 - box->y1);
136			box++;
137		} while (--n);
138	}
139
140	sigtrap_put();
141	return true;
142}
143
144static void read_boxes_inplace(struct kgem *kgem,
145			       PixmapPtr pixmap, struct kgem_bo *bo,
146			       const BoxRec *box, int n)
147{
148	int bpp = pixmap->drawable.bitsPerPixel;
149	void *src, *dst = pixmap->devPrivate.ptr;
150	int src_pitch = bo->pitch;
151	int dst_pitch = pixmap->devKind;
152
153	if (read_boxes_inplace__cpu(kgem, pixmap, bo, box, n))
154		return;
155
156	DBG(("%s x %d, tiling=%d\n", __FUNCTION__, n, bo->tiling));
157
158	if (!kgem_bo_can_map(kgem, bo))
159		return;
160
161	kgem_bo_submit(kgem, bo);
162
163	src = kgem_bo_map(kgem, bo);
164	if (src == NULL)
165		return;
166
167	if (sigtrap_get())
168		return;
169
170	assert(src != dst);
171	do {
172		DBG(("%s: copying box (%d, %d), (%d, %d)\n",
173		     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
174
175		assert(box->x2 > box->x1);
176		assert(box->y2 > box->y1);
177
178		assert(box->x1 >= 0);
179		assert(box->y1 >= 0);
180		assert(box->x2 <= pixmap->drawable.width);
181		assert(box->y2 <= pixmap->drawable.height);
182
183		assert(box->x1 >= 0);
184		assert(box->y1 >= 0);
185		assert(box->x2 <= pixmap->drawable.width);
186		assert(box->y2 <= pixmap->drawable.height);
187
188		memcpy_blt(src, dst, bpp,
189			   src_pitch, dst_pitch,
190			   box->x1, box->y1,
191			   box->x1, box->y1,
192			   box->x2 - box->x1, box->y2 - box->y1);
193		box++;
194	} while (--n);
195
196	sigtrap_put();
197}
198
199static bool download_inplace(struct kgem *kgem,
200			     PixmapPtr p, struct kgem_bo *bo,
201			     const BoxRec *box, int nbox)
202{
203	bool cpu;
204
205	if (unlikely(kgem->wedged))
206		return true;
207
208	cpu = download_inplace__cpu(kgem, p, bo, box, nbox);
209	if (!cpu && !kgem_bo_can_map(kgem, bo))
210		return false;
211
212	if (FORCE_INPLACE)
213		return FORCE_INPLACE > 0;
214
215	if (cpu)
216		return true;
217
218	if (kgem->can_blt_cpu && kgem->max_cpu_size)
219		return false;
220
221	return !__kgem_bo_is_busy(kgem, bo);
222}
223
224void sna_read_boxes(struct sna *sna, PixmapPtr dst, struct kgem_bo *src_bo,
225		    const BoxRec *box, int nbox)
226{
227	struct kgem *kgem = &sna->kgem;
228	struct kgem_bo *dst_bo;
229	BoxRec extents;
230	const BoxRec *tmp_box;
231	int tmp_nbox;
232	void *ptr;
233	int src_pitch, cpp, offset;
234	int n, cmd, br13;
235	bool can_blt;
236
237	DBG(("%s x %d, src=(handle=%d), dst=(size=(%d, %d)\n",
238	     __FUNCTION__, nbox, src_bo->handle,
239	     dst->drawable.width, dst->drawable.height));
240
241#ifndef NDEBUG
242	for (n = 0; n < nbox; n++) {
243		if (box[n].x1 < 0 || box[n].y1 < 0 ||
244		    box[n].x2 * dst->drawable.bitsPerPixel/8 > src_bo->pitch ||
245		    box[n].y2 * src_bo->pitch > kgem_bo_size(src_bo))
246		{
247			FatalError("source out-of-bounds box[%d]=(%d, %d), (%d, %d), pitch=%d, size=%d\n", n,
248				   box[n].x1, box[n].y1,
249				   box[n].x2, box[n].y2,
250				   src_bo->pitch, kgem_bo_size(src_bo));
251		}
252	}
253#endif
254
255	/* XXX The gpu is faster to perform detiling in bulk, but takes
256	 * longer to setup and retrieve the results, with an additional
257	 * copy. The long term solution is to use snoopable bo and avoid
258	 * this path.
259	 */
260
261	if (download_inplace(kgem, dst, src_bo, box, nbox)) {
262fallback:
263		read_boxes_inplace(kgem, dst, src_bo, box, nbox);
264		return;
265	}
266
267	can_blt = kgem_bo_can_blt(kgem, src_bo) &&
268		(box[0].x2 - box[0].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4);
269	extents = box[0];
270	for (n = 1; n < nbox; n++) {
271		if (box[n].x1 < extents.x1)
272			extents.x1 = box[n].x1;
273		if (box[n].x2 > extents.x2)
274			extents.x2 = box[n].x2;
275
276		if (can_blt)
277			can_blt = (box[n].x2 - box[n].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4);
278
279		if (box[n].y1 < extents.y1)
280			extents.y1 = box[n].y1;
281		if (box[n].y2 > extents.y2)
282			extents.y2 = box[n].y2;
283	}
284	if (kgem_bo_can_map(kgem, src_bo)) {
285		/* Is it worth detiling? */
286		if ((extents.y2 - extents.y1 - 1) * src_bo->pitch < 4096)
287			goto fallback;
288	}
289
290	/* Try to avoid switching rings... */
291	if (!can_blt || kgem->ring == KGEM_RENDER ||
292	    upload_too_large(sna, extents.x2 - extents.x1, extents.y2 - extents.y1)) {
293		DrawableRec tmp;
294
295		tmp.width  = extents.x2 - extents.x1;
296		tmp.height = extents.y2 - extents.y1;
297		tmp.depth  = dst->drawable.depth;
298		tmp.bitsPerPixel = dst->drawable.bitsPerPixel;
299
300		assert(tmp.width);
301		assert(tmp.height);
302
303		if (must_tile(sna, tmp.width, tmp.height)) {
304			BoxRec tile, stack[64], *clipped, *c;
305			int step;
306
307			if (n > ARRAY_SIZE(stack)) {
308				clipped = malloc(sizeof(BoxRec) * n);
309				if (clipped == NULL)
310					goto fallback;
311			} else
312				clipped = stack;
313
314			step = MIN(sna->render.max_3d_size,
315				   8*(MAXSHORT&~63) / dst->drawable.bitsPerPixel);
316			while (step * step * 4 > sna->kgem.max_upload_tile_size)
317				step /= 2;
318
319			DBG(("%s: tiling download, using %dx%d tiles\n",
320			     __FUNCTION__, step, step));
321			assert(step);
322
323			for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) {
324				int y2 = tile.y1 + step;
325				if (y2 > extents.y2)
326					y2 = extents.y2;
327				tile.y2 = y2;
328
329				for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) {
330					int x2 = tile.x1 + step;
331					if (x2 > extents.x2)
332						x2 = extents.x2;
333					tile.x2 = x2;
334
335					tmp.width  = tile.x2 - tile.x1;
336					tmp.height = tile.y2 - tile.y1;
337
338					c = clipped;
339					for (n = 0; n < nbox; n++) {
340						*c = box[n];
341						if (!box_intersect(c, &tile))
342							continue;
343
344						DBG(("%s: box(%d, %d), (%d, %d),, dst=(%d, %d)\n",
345						     __FUNCTION__,
346						     c->x1, c->y1,
347						     c->x2, c->y2,
348						     c->x1 - tile.x1,
349						     c->y1 - tile.y1));
350						c++;
351					}
352					if (c == clipped)
353						continue;
354
355					dst_bo = kgem_create_buffer_2d(kgem,
356								       tmp.width,
357								       tmp.height,
358								       tmp.bitsPerPixel,
359								       KGEM_BUFFER_LAST,
360								       &ptr);
361					if (!dst_bo) {
362						if (clipped != stack)
363							free(clipped);
364						goto fallback;
365					}
366
367					if (!sna->render.copy_boxes(sna, GXcopy,
368								    &dst->drawable, src_bo, 0, 0,
369								    &tmp, dst_bo, -tile.x1, -tile.y1,
370								    clipped, c-clipped, COPY_LAST)) {
371						kgem_bo_destroy(&sna->kgem, dst_bo);
372						if (clipped != stack)
373							free(clipped);
374						goto fallback;
375					}
376
377					kgem_bo_submit(&sna->kgem, dst_bo);
378					kgem_buffer_read_sync(kgem, dst_bo);
379
380					if (sigtrap_get() == 0) {
381						while (c-- != clipped) {
382							memcpy_blt(ptr, dst->devPrivate.ptr, tmp.bitsPerPixel,
383								   dst_bo->pitch, dst->devKind,
384								   c->x1 - tile.x1,
385								   c->y1 - tile.y1,
386								   c->x1, c->y1,
387								   c->x2 - c->x1,
388								   c->y2 - c->y1);
389						}
390						sigtrap_put();
391					}
392
393					kgem_bo_destroy(&sna->kgem, dst_bo);
394				}
395			}
396
397			if (clipped != stack)
398				free(clipped);
399		} else {
400			dst_bo = kgem_create_buffer_2d(kgem,
401						       tmp.width,
402						       tmp.height,
403						       tmp.bitsPerPixel,
404						       KGEM_BUFFER_LAST,
405						       &ptr);
406			if (!dst_bo)
407				goto fallback;
408
409			if (!sna->render.copy_boxes(sna, GXcopy,
410						    &dst->drawable, src_bo, 0, 0,
411						    &tmp, dst_bo, -extents.x1, -extents.y1,
412						    box, nbox, COPY_LAST)) {
413				kgem_bo_destroy(&sna->kgem, dst_bo);
414				goto fallback;
415			}
416
417			kgem_bo_submit(&sna->kgem, dst_bo);
418			kgem_buffer_read_sync(kgem, dst_bo);
419
420			if (sigtrap_get() == 0) {
421				for (n = 0; n < nbox; n++) {
422					memcpy_blt(ptr, dst->devPrivate.ptr, tmp.bitsPerPixel,
423						   dst_bo->pitch, dst->devKind,
424						   box[n].x1 - extents.x1,
425						   box[n].y1 - extents.y1,
426						   box[n].x1, box[n].y1,
427						   box[n].x2 - box[n].x1,
428						   box[n].y2 - box[n].y1);
429				}
430				sigtrap_put();
431			}
432
433			kgem_bo_destroy(&sna->kgem, dst_bo);
434		}
435		return;
436	}
437
438	/* count the total number of bytes to be read and allocate a bo */
439	cpp = dst->drawable.bitsPerPixel / 8;
440	offset = 0;
441	for (n = 0; n < nbox; n++) {
442		int height = box[n].y2 - box[n].y1;
443		int width = box[n].x2 - box[n].x1;
444		offset += PITCH(width, cpp) * height;
445	}
446
447	DBG(("    read buffer size=%d\n", offset));
448
449	dst_bo = kgem_create_buffer(kgem, offset, KGEM_BUFFER_LAST, &ptr);
450	if (!dst_bo) {
451		read_boxes_inplace(kgem, dst, src_bo, box, nbox);
452		return;
453	}
454
455	cmd = XY_SRC_COPY_BLT_CMD;
456	src_pitch = src_bo->pitch;
457	if (kgem->gen >= 040 && src_bo->tiling) {
458		cmd |= BLT_SRC_TILED;
459		src_pitch >>= 2;
460	}
461
462	br13 = 0xcc << 16;
463	switch (cpp) {
464	default:
465	case 4: cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB;
466		br13 |= 1 << 25; /* RGB8888 */
467	case 2: br13 |= 1 << 24; /* RGB565 */
468	case 1: break;
469	}
470
471	kgem_set_mode(kgem, KGEM_BLT, dst_bo);
472	if (!kgem_check_batch(kgem, 10) ||
473	    !kgem_check_reloc_and_exec(kgem, 2) ||
474	    !kgem_check_many_bo_fenced(kgem, dst_bo, src_bo, NULL)) {
475		kgem_submit(kgem);
476		if (!kgem_check_many_bo_fenced(kgem, dst_bo, src_bo, NULL))
477			goto fallback;
478		_kgem_set_mode(kgem, KGEM_BLT);
479	}
480
481	tmp_nbox = nbox;
482	tmp_box = box;
483	offset = 0;
484	if (sna->kgem.gen >= 0100) {
485		cmd |= 8;
486		do {
487			int nbox_this_time;
488
489			nbox_this_time = tmp_nbox;
490			if (10*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED)
491				nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8;
492			if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc)
493				nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2;
494			assert(nbox_this_time);
495			tmp_nbox -= nbox_this_time;
496
497			assert(kgem->mode == KGEM_BLT);
498			for (n = 0; n < nbox_this_time; n++) {
499				int height = tmp_box[n].y2 - tmp_box[n].y1;
500				int width = tmp_box[n].x2 - tmp_box[n].x1;
501				int pitch = PITCH(width, cpp);
502				uint32_t *b = kgem->batch + kgem->nbatch;
503
504				DBG(("    blt offset %x: (%d, %d) x (%d, %d), pitch=%d\n",
505				     offset,
506				     tmp_box[n].x1, tmp_box[n].y1,
507				     width, height, pitch));
508
509				assert(tmp_box[n].x1 >= 0);
510				assert(tmp_box[n].x2 * dst->drawable.bitsPerPixel/8 <= src_bo->pitch);
511				assert(tmp_box[n].y1 >= 0);
512				assert(tmp_box[n].y2 * src_bo->pitch <= kgem_bo_size(src_bo));
513
514				b[0] = cmd;
515				b[1] = br13 | pitch;
516				b[2] = 0;
517				b[3] = height << 16 | width;
518				*(uint64_t *)(b+4) =
519					kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo,
520							 I915_GEM_DOMAIN_RENDER << 16 |
521							 I915_GEM_DOMAIN_RENDER |
522							 KGEM_RELOC_FENCED,
523							 offset);
524				b[6] = tmp_box[n].y1 << 16 | tmp_box[n].x1;
525				b[7] = src_pitch;
526				*(uint64_t *)(b+8) =
527					kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo,
528							 I915_GEM_DOMAIN_RENDER << 16 |
529							 KGEM_RELOC_FENCED,
530							 0);
531				kgem->nbatch += 10;
532
533				offset += pitch * height;
534			}
535
536			_kgem_submit(kgem);
537			if (!tmp_nbox)
538				break;
539
540			_kgem_set_mode(kgem, KGEM_BLT);
541			tmp_box += nbox_this_time;
542		} while (1);
543	} else {
544		cmd |= 6;
545		do {
546			int nbox_this_time;
547
548			nbox_this_time = tmp_nbox;
549			if (8*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED)
550				nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8;
551			if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc)
552				nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2;
553			assert(nbox_this_time);
554			tmp_nbox -= nbox_this_time;
555
556			assert(kgem->mode == KGEM_BLT);
557			for (n = 0; n < nbox_this_time; n++) {
558				int height = tmp_box[n].y2 - tmp_box[n].y1;
559				int width = tmp_box[n].x2 - tmp_box[n].x1;
560				int pitch = PITCH(width, cpp);
561				uint32_t *b = kgem->batch + kgem->nbatch;
562
563				DBG(("    blt offset %x: (%d, %d) x (%d, %d), pitch=%d\n",
564				     offset,
565				     tmp_box[n].x1, tmp_box[n].y1,
566				     width, height, pitch));
567
568				assert(tmp_box[n].x1 >= 0);
569				assert(tmp_box[n].x2 * dst->drawable.bitsPerPixel/8 <= src_bo->pitch);
570				assert(tmp_box[n].y1 >= 0);
571				assert(tmp_box[n].y2 * src_bo->pitch <= kgem_bo_size(src_bo));
572
573				b[0] = cmd;
574				b[1] = br13 | pitch;
575				b[2] = 0;
576				b[3] = height << 16 | width;
577				b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo,
578						      I915_GEM_DOMAIN_RENDER << 16 |
579						      I915_GEM_DOMAIN_RENDER |
580						      KGEM_RELOC_FENCED,
581						      offset);
582				b[5] = tmp_box[n].y1 << 16 | tmp_box[n].x1;
583				b[6] = src_pitch;
584				b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo,
585						      I915_GEM_DOMAIN_RENDER << 16 |
586						      KGEM_RELOC_FENCED,
587						      0);
588				kgem->nbatch += 8;
589
590				offset += pitch * height;
591			}
592
593			_kgem_submit(kgem);
594			if (!tmp_nbox)
595				break;
596
597			_kgem_set_mode(kgem, KGEM_BLT);
598			tmp_box += nbox_this_time;
599		} while (1);
600	}
601	assert(offset == __kgem_buffer_size(dst_bo));
602
603	kgem_buffer_read_sync(kgem, dst_bo);
604
605	if (sigtrap_get() == 0) {
606		char *src = ptr;
607		do {
608			int height = box->y2 - box->y1;
609			int width  = box->x2 - box->x1;
610			int pitch = PITCH(width, cpp);
611
612			DBG(("    copy offset %lx [%08x...%08x...%08x]: (%d, %d) x (%d, %d), src pitch=%d, dst pitch=%d, bpp=%d\n",
613			     (long)((char *)src - (char *)ptr),
614			     *(uint32_t*)src, *(uint32_t*)(src+pitch*height/2 + pitch/2 - 4), *(uint32_t*)(src+pitch*height - 4),
615			     box->x1, box->y1,
616			     width, height,
617			     pitch, dst->devKind, cpp*8));
618
619			assert(box->x1 >= 0);
620			assert(box->x2 <= dst->drawable.width);
621			assert(box->y1 >= 0);
622			assert(box->y2 <= dst->drawable.height);
623
624			memcpy_blt(src, dst->devPrivate.ptr, cpp*8,
625				   pitch, dst->devKind,
626				   0, 0,
627				   box->x1, box->y1,
628				   width, height);
629			box++;
630
631			src += pitch * height;
632		} while (--nbox);
633		assert(src - (char *)ptr == __kgem_buffer_size(dst_bo));
634		sigtrap_put();
635	}
636	kgem_bo_destroy(kgem, dst_bo);
637	sna->blt_state.fill_bo = 0;
638}
639
640static bool upload_inplace__tiled(struct kgem *kgem, struct kgem_bo *bo)
641{
642	DBG(("%s: tiling=%d\n", __FUNCTION__, bo->tiling));
643	switch (bo->tiling) {
644	case I915_TILING_Y:
645		return false;
646	case I915_TILING_X:
647		if (!kgem->memcpy_to_tiled_x)
648			return false;
649	default:
650		break;
651	}
652
653	return kgem_bo_can_map__cpu(kgem, bo, true);
654}
655
656static bool
657write_boxes_inplace__tiled(struct kgem *kgem,
658                           const uint8_t *src, int stride, int bpp, int16_t src_dx, int16_t src_dy,
659                           struct kgem_bo *bo, int16_t dst_dx, int16_t dst_dy,
660                           const BoxRec *box, int n)
661{
662	uint8_t *dst;
663
664	assert(kgem_bo_can_map__cpu(kgem, bo, true));
665	assert(bo->tiling != I915_TILING_Y);
666
667	dst = kgem_bo_map__cpu(kgem, bo);
668	if (dst == NULL)
669		return false;
670
671	kgem_bo_sync__cpu(kgem, bo);
672
673	if (sigtrap_get())
674		return false;
675
676	if (bo->tiling) {
677		do {
678			memcpy_to_tiled_x(kgem, src, dst, bpp, stride, bo->pitch,
679					  box->x1 + src_dx, box->y1 + src_dy,
680					  box->x1 + dst_dx, box->y1 + dst_dy,
681					  box->x2 - box->x1, box->y2 - box->y1);
682			box++;
683		} while (--n);
684	} else {
685		do {
686			memcpy_blt(src, dst, bpp, stride, bo->pitch,
687				   box->x1 + src_dx, box->y1 + src_dy,
688				   box->x1 + dst_dx, box->y1 + dst_dy,
689				   box->x2 - box->x1, box->y2 - box->y1);
690			box++;
691		} while (--n);
692	}
693
694	sigtrap_put();
695	return true;
696}
697
698static bool write_boxes_inplace(struct kgem *kgem,
699				const void *src, int stride, int bpp, int16_t src_dx, int16_t src_dy,
700				struct kgem_bo *bo, int16_t dst_dx, int16_t dst_dy,
701				const BoxRec *box, int n)
702{
703	void *dst;
704
705	DBG(("%s x %d, handle=%d, tiling=%d\n",
706	     __FUNCTION__, n, bo->handle, bo->tiling));
707
708	if (upload_inplace__tiled(kgem, bo) &&
709	    write_boxes_inplace__tiled(kgem, src, stride, bpp, src_dx, src_dy,
710				       bo, dst_dx, dst_dy, box, n))
711		return true;
712
713	if (!kgem_bo_can_map(kgem, bo))
714		return false;
715
716	kgem_bo_submit(kgem, bo);
717
718	dst = kgem_bo_map(kgem, bo);
719	if (dst == NULL)
720		return false;
721
722	assert(dst != src);
723
724	if (sigtrap_get())
725		return false;
726
727	do {
728		DBG(("%s: (%d, %d) -> (%d, %d) x (%d, %d) [bpp=%d, src_pitch=%d, dst_pitch=%d]\n", __FUNCTION__,
729		     box->x1 + src_dx, box->y1 + src_dy,
730		     box->x1 + dst_dx, box->y1 + dst_dy,
731		     box->x2 - box->x1, box->y2 - box->y1,
732		     bpp, stride, bo->pitch));
733
734		assert(box->x2 > box->x1);
735		assert(box->y2 > box->y1);
736
737		assert(box->x1 + dst_dx >= 0);
738		assert((box->x2 + dst_dx)*bpp <= 8*bo->pitch);
739		assert(box->y1 + dst_dy >= 0);
740		assert((box->y2 + dst_dy)*bo->pitch <= kgem_bo_size(bo));
741
742		assert(box->x1 + src_dx >= 0);
743		assert((box->x2 + src_dx)*bpp <= 8*stride);
744		assert(box->y1 + src_dy >= 0);
745
746		memcpy_blt(src, dst, bpp,
747			   stride, bo->pitch,
748			   box->x1 + src_dx, box->y1 + src_dy,
749			   box->x1 + dst_dx, box->y1 + dst_dy,
750			   box->x2 - box->x1, box->y2 - box->y1);
751		box++;
752	} while (--n);
753
754	sigtrap_put();
755	return true;
756}
757
758static bool __upload_inplace(struct kgem *kgem,
759			     struct kgem_bo *bo,
760			     const BoxRec *box,
761			     int n, int bpp)
762{
763	unsigned int bytes;
764
765	if (FORCE_INPLACE)
766		return FORCE_INPLACE > 0;
767
768	/* If we are writing through the GTT, check first if we might be
769	 * able to almagamate a series of small writes into a single
770	 * operation.
771	 */
772	bytes = 0;
773	while (n--) {
774		bytes += (box->x2 - box->x1) * (box->y2 - box->y1);
775		box++;
776	}
777	if (__kgem_bo_is_busy(kgem, bo))
778		return bytes * bpp >> 12 >= kgem->half_cpu_cache_pages;
779	else
780		return bytes * bpp >> 12;
781}
782
783static bool upload_inplace(struct kgem *kgem,
784			   struct kgem_bo *bo,
785			   const BoxRec *box,
786			   int n, int bpp)
787{
788	if (unlikely(kgem->wedged))
789		return true;
790
791	if (!kgem_bo_can_map(kgem, bo) && !upload_inplace__tiled(kgem, bo))
792		return false;
793
794	return __upload_inplace(kgem, bo, box, n,bpp);
795}
796
797bool sna_write_boxes(struct sna *sna, PixmapPtr dst,
798		     struct kgem_bo * const dst_bo, int16_t const dst_dx, int16_t const dst_dy,
799		     const void * const src, int const stride, int16_t const src_dx, int16_t const src_dy,
800		     const BoxRec *box, int nbox)
801{
802	struct kgem *kgem = &sna->kgem;
803	struct kgem_bo *src_bo;
804	BoxRec extents;
805	void *ptr;
806	int offset;
807	int n, cmd, br13;
808	bool can_blt;
809
810	DBG(("%s x %d, src stride=%d,  src dx=(%d, %d)\n", __FUNCTION__, nbox, stride, src_dx, src_dy));
811
812	if (upload_inplace(kgem, dst_bo, box, nbox, dst->drawable.bitsPerPixel) &&
813	    write_boxes_inplace(kgem,
814				src, stride, dst->drawable.bitsPerPixel, src_dx, src_dy,
815				dst_bo, dst_dx, dst_dy,
816				box, nbox))
817		return true;
818
819	if (wedged(sna))
820		return false;
821
822	can_blt = kgem_bo_can_blt(kgem, dst_bo) &&
823		(box[0].x2 - box[0].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4);
824	extents = box[0];
825	for (n = 1; n < nbox; n++) {
826		if (box[n].x1 < extents.x1)
827			extents.x1 = box[n].x1;
828		if (box[n].x2 > extents.x2)
829			extents.x2 = box[n].x2;
830
831		if (can_blt)
832			can_blt = (box[n].x2 - box[n].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4);
833
834		if (box[n].y1 < extents.y1)
835			extents.y1 = box[n].y1;
836		if (box[n].y2 > extents.y2)
837			extents.y2 = box[n].y2;
838	}
839
840	/* Try to avoid switching rings... */
841	if (!can_blt || kgem->ring == KGEM_RENDER ||
842	    upload_too_large(sna, extents.x2 - extents.x1, extents.y2 - extents.y1)) {
843		DrawableRec tmp;
844
845		tmp.width  = extents.x2 - extents.x1;
846		tmp.height = extents.y2 - extents.y1;
847		tmp.depth  = dst->drawable.depth;
848		tmp.bitsPerPixel = dst->drawable.bitsPerPixel;
849
850		assert(tmp.width);
851		assert(tmp.height);
852
853		DBG(("%s: upload (%d, %d)x(%d, %d), max %dx%d\n",
854		     __FUNCTION__,
855		     extents.x1, extents.y1,
856		     tmp.width, tmp.height,
857		     sna->render.max_3d_size, sna->render.max_3d_size));
858		if (must_tile(sna, tmp.width, tmp.height)) {
859			BoxRec tile, stack[64], *clipped;
860			int cpp, step;
861
862tile:
863			cpp = dst->drawable.bitsPerPixel / 8;
864			step = MIN(sna->render.max_3d_size,
865				   (MAXSHORT&~63) / cpp);
866			while (step * step * cpp > sna->kgem.max_upload_tile_size)
867				step /= 2;
868
869			if (step * cpp > 4096)
870				step = 4096 / cpp;
871			assert(step);
872
873			DBG(("%s: tiling upload, using %dx%d tiles\n",
874			     __FUNCTION__, step, step));
875
876			if (n > ARRAY_SIZE(stack)) {
877				clipped = malloc(sizeof(BoxRec) * n);
878				if (clipped == NULL)
879					goto fallback;
880			} else
881				clipped = stack;
882
883			for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) {
884				int y2 = tile.y1 + step;
885				if (y2 > extents.y2)
886					y2 = extents.y2;
887				tile.y2 = y2;
888
889				for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) {
890					int x2 = tile.x1 + step;
891					if (x2 > extents.x2)
892						x2 = extents.x2;
893					tile.x2 = x2;
894
895					tmp.width  = tile.x2 - tile.x1;
896					tmp.height = tile.y2 - tile.y1;
897
898					src_bo = kgem_create_buffer_2d(kgem,
899								       tmp.width,
900								       tmp.height,
901								       tmp.bitsPerPixel,
902								       KGEM_BUFFER_WRITE_INPLACE,
903								       &ptr);
904					if (!src_bo) {
905						if (clipped != stack)
906							free(clipped);
907						goto fallback;
908					}
909
910					if (sigtrap_get() == 0) {
911						BoxRec *c = clipped;
912						for (n = 0; n < nbox; n++) {
913							*c = box[n];
914							if (!box_intersect(c, &tile))
915								continue;
916
917							DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n",
918							     __FUNCTION__,
919							     c->x1, c->y1,
920							     c->x2, c->y2,
921							     src_dx, src_dy,
922							     c->x1 - tile.x1,
923							     c->y1 - tile.y1));
924							memcpy_blt(src, ptr, tmp.bitsPerPixel,
925								   stride, src_bo->pitch,
926								   c->x1 + src_dx,
927								   c->y1 + src_dy,
928								   c->x1 - tile.x1,
929								   c->y1 - tile.y1,
930								   c->x2 - c->x1,
931								   c->y2 - c->y1);
932							c++;
933						}
934
935						if (c != clipped)
936							n = sna->render.copy_boxes(sna, GXcopy,
937										   &tmp, src_bo, -tile.x1, -tile.y1,
938										   &dst->drawable, dst_bo, dst_dx, dst_dy,
939										   clipped, c - clipped, 0);
940						else
941							n = 1;
942						sigtrap_put();
943					} else
944						n = 0;
945
946					kgem_bo_destroy(&sna->kgem, src_bo);
947
948					if (!n) {
949						if (clipped != stack)
950							free(clipped);
951						goto fallback;
952					}
953				}
954			}
955
956			if (clipped != stack)
957				free(clipped);
958		} else {
959			src_bo = kgem_create_buffer_2d(kgem,
960						       tmp.width,
961						       tmp.height,
962						       tmp.bitsPerPixel,
963						       KGEM_BUFFER_WRITE_INPLACE,
964						       &ptr);
965			if (!src_bo)
966				goto fallback;
967
968			if (sigtrap_get() == 0) {
969				for (n = 0; n < nbox; n++) {
970					DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n",
971					     __FUNCTION__,
972					     box[n].x1, box[n].y1,
973					     box[n].x2, box[n].y2,
974					     src_dx, src_dy,
975					     box[n].x1 - extents.x1,
976					     box[n].y1 - extents.y1));
977					memcpy_blt(src, ptr, tmp.bitsPerPixel,
978						   stride, src_bo->pitch,
979						   box[n].x1 + src_dx,
980						   box[n].y1 + src_dy,
981						   box[n].x1 - extents.x1,
982						   box[n].y1 - extents.y1,
983						   box[n].x2 - box[n].x1,
984						   box[n].y2 - box[n].y1);
985				}
986
987				n = sna->render.copy_boxes(sna, GXcopy,
988							   &tmp, src_bo, -extents.x1, -extents.y1,
989							   &dst->drawable, dst_bo, dst_dx, dst_dy,
990							   box, nbox, 0);
991				sigtrap_put();
992			} else
993				n = 0;
994
995			kgem_bo_destroy(&sna->kgem, src_bo);
996
997			if (!n)
998				goto tile;
999		}
1000
1001		return true;
1002	}
1003
1004	cmd = XY_SRC_COPY_BLT_CMD;
1005	br13 = dst_bo->pitch;
1006	if (kgem->gen >= 040 && dst_bo->tiling) {
1007		cmd |= BLT_DST_TILED;
1008		br13 >>= 2;
1009	}
1010	br13 |= 0xcc << 16;
1011	switch (dst->drawable.bitsPerPixel) {
1012	default:
1013	case 32: cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB;
1014		 br13 |= 1 << 25; /* RGB8888 */
1015	case 16: br13 |= 1 << 24; /* RGB565 */
1016	case 8: break;
1017	}
1018
1019	kgem_set_mode(kgem, KGEM_BLT, dst_bo);
1020	if (!kgem_check_batch(kgem, 10) ||
1021	    !kgem_check_reloc_and_exec(kgem, 2) ||
1022	    !kgem_check_bo_fenced(kgem, dst_bo)) {
1023		kgem_submit(kgem);
1024		if (!kgem_check_bo_fenced(kgem, dst_bo))
1025			goto fallback;
1026		_kgem_set_mode(kgem, KGEM_BLT);
1027	}
1028
1029	if (kgem->gen >= 0100) {
1030		cmd |= 8;
1031		do {
1032			int nbox_this_time;
1033
1034			nbox_this_time = nbox;
1035			if (10*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED)
1036				nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8;
1037			if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc)
1038				nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2;
1039			assert(nbox_this_time);
1040			nbox -= nbox_this_time;
1041
1042			/* Count the total number of bytes to be read and allocate a
1043			 * single buffer large enough. Or if it is very small, combine
1044			 * with other allocations. */
1045			offset = 0;
1046			for (n = 0; n < nbox_this_time; n++) {
1047				int height = box[n].y2 - box[n].y1;
1048				int width = box[n].x2 - box[n].x1;
1049				offset += PITCH(width, dst->drawable.bitsPerPixel >> 3) * height;
1050			}
1051
1052			src_bo = kgem_create_buffer(kgem, offset,
1053						    KGEM_BUFFER_WRITE_INPLACE | (nbox ? KGEM_BUFFER_LAST : 0),
1054						    &ptr);
1055			if (!src_bo)
1056				break;
1057
1058			if (sigtrap_get() == 0) {
1059				offset = 0;
1060				do {
1061					int height = box->y2 - box->y1;
1062					int width = box->x2 - box->x1;
1063					int pitch = PITCH(width, dst->drawable.bitsPerPixel >> 3);
1064					uint32_t *b;
1065
1066					DBG(("  %s: box src=(%d, %d), dst=(%d, %d) size=(%d, %d), dst offset=%d, dst pitch=%d\n",
1067					     __FUNCTION__,
1068					     box->x1 + src_dx, box->y1 + src_dy,
1069					     box->x1 + dst_dx, box->y1 + dst_dy,
1070					     width, height,
1071					     offset, pitch));
1072
1073					assert(box->x1 + src_dx >= 0);
1074					assert((box->x2 + src_dx)*dst->drawable.bitsPerPixel <= 8*stride);
1075					assert(box->y1 + src_dy >= 0);
1076
1077					assert(box->x1 + dst_dx >= 0);
1078					assert(box->y1 + dst_dy >= 0);
1079
1080					memcpy_blt(src, (char *)ptr + offset,
1081						   dst->drawable.bitsPerPixel,
1082						   stride, pitch,
1083						   box->x1 + src_dx, box->y1 + src_dy,
1084						   0, 0,
1085						   width, height);
1086
1087					assert(kgem->mode == KGEM_BLT);
1088					b = kgem->batch + kgem->nbatch;
1089					b[0] = cmd;
1090					b[1] = br13;
1091					b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx);
1092					b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx);
1093					*(uint64_t *)(b+4) =
1094						kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo,
1095								 I915_GEM_DOMAIN_RENDER << 16 |
1096								 I915_GEM_DOMAIN_RENDER |
1097								 KGEM_RELOC_FENCED,
1098								 0);
1099					b[6] = 0;
1100					b[7] = pitch;
1101					*(uint64_t *)(b+8) =
1102						kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo,
1103								 I915_GEM_DOMAIN_RENDER << 16 |
1104								 KGEM_RELOC_FENCED,
1105								 offset);
1106					kgem->nbatch += 10;
1107
1108					box++;
1109					offset += pitch * height;
1110				} while (--nbox_this_time);
1111				assert(offset == __kgem_buffer_size(src_bo));
1112				sigtrap_put();
1113			}
1114
1115			if (nbox) {
1116				_kgem_submit(kgem);
1117				_kgem_set_mode(kgem, KGEM_BLT);
1118			}
1119
1120			kgem_bo_destroy(kgem, src_bo);
1121		} while (nbox);
1122	} else {
1123		cmd |= 6;
1124		do {
1125			int nbox_this_time;
1126
1127			nbox_this_time = nbox;
1128			if (8*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED)
1129				nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8;
1130			if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc)
1131				nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2;
1132			assert(nbox_this_time);
1133			nbox -= nbox_this_time;
1134
1135			/* Count the total number of bytes to be read and allocate a
1136			 * single buffer large enough. Or if it is very small, combine
1137			 * with other allocations. */
1138			offset = 0;
1139			for (n = 0; n < nbox_this_time; n++) {
1140				int height = box[n].y2 - box[n].y1;
1141				int width = box[n].x2 - box[n].x1;
1142				offset += PITCH(width, dst->drawable.bitsPerPixel >> 3) * height;
1143			}
1144
1145			src_bo = kgem_create_buffer(kgem, offset,
1146						    KGEM_BUFFER_WRITE_INPLACE | (nbox ? KGEM_BUFFER_LAST : 0),
1147						    &ptr);
1148			if (!src_bo)
1149				break;
1150
1151			if (sigtrap_get()) {
1152				kgem_bo_destroy(kgem, src_bo);
1153				goto fallback;
1154			}
1155
1156			offset = 0;
1157			do {
1158				int height = box->y2 - box->y1;
1159				int width = box->x2 - box->x1;
1160				int pitch = PITCH(width, dst->drawable.bitsPerPixel >> 3);
1161				uint32_t *b;
1162
1163				DBG(("  %s: box src=(%d, %d), dst=(%d, %d) size=(%d, %d), dst offset=%d, dst pitch=%d\n",
1164				     __FUNCTION__,
1165				     box->x1 + src_dx, box->y1 + src_dy,
1166				     box->x1 + dst_dx, box->y1 + dst_dy,
1167				     width, height,
1168				     offset, pitch));
1169
1170				assert(box->x1 + src_dx >= 0);
1171				assert((box->x2 + src_dx)*dst->drawable.bitsPerPixel <= 8*stride);
1172				assert(box->y1 + src_dy >= 0);
1173
1174				assert(box->x1 + dst_dx >= 0);
1175				assert(box->y1 + dst_dy >= 0);
1176
1177				memcpy_blt(src, (char *)ptr + offset,
1178					   dst->drawable.bitsPerPixel,
1179					   stride, pitch,
1180					   box->x1 + src_dx, box->y1 + src_dy,
1181					   0, 0,
1182					   width, height);
1183
1184				assert(kgem->mode == KGEM_BLT);
1185				b = kgem->batch + kgem->nbatch;
1186				b[0] = cmd;
1187				b[1] = br13;
1188				b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx);
1189				b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx);
1190				b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo,
1191						      I915_GEM_DOMAIN_RENDER << 16 |
1192						      I915_GEM_DOMAIN_RENDER |
1193						      KGEM_RELOC_FENCED,
1194						      0);
1195				b[5] = 0;
1196				b[6] = pitch;
1197				b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo,
1198						      I915_GEM_DOMAIN_RENDER << 16 |
1199						      KGEM_RELOC_FENCED,
1200						      offset);
1201				kgem->nbatch += 8;
1202
1203				box++;
1204				offset += pitch * height;
1205			} while (--nbox_this_time);
1206			assert(offset == __kgem_buffer_size(src_bo));
1207			sigtrap_put();
1208
1209			if (nbox) {
1210				_kgem_submit(kgem);
1211				_kgem_set_mode(kgem, KGEM_BLT);
1212			}
1213
1214			kgem_bo_destroy(kgem, src_bo);
1215		} while (nbox);
1216	}
1217
1218	sna->blt_state.fill_bo = 0;
1219	return true;
1220
1221fallback:
1222	return write_boxes_inplace(kgem,
1223				   src, stride, dst->drawable.bitsPerPixel, src_dx, src_dy,
1224				   dst_bo, dst_dx, dst_dy,
1225				   box, nbox);
1226}
1227
1228static bool
1229write_boxes_inplace__xor(struct kgem *kgem,
1230			 const void *src, int stride, int bpp, int16_t src_dx, int16_t src_dy,
1231			 struct kgem_bo *bo, int16_t dst_dx, int16_t dst_dy,
1232			 const BoxRec *box, int n,
1233			 uint32_t and, uint32_t or)
1234{
1235	void *dst;
1236
1237	DBG(("%s x %d, tiling=%d\n", __FUNCTION__, n, bo->tiling));
1238
1239	if (!kgem_bo_can_map(kgem, bo))
1240		return false;
1241
1242	kgem_bo_submit(kgem, bo);
1243
1244	dst = kgem_bo_map(kgem, bo);
1245	if (dst == NULL)
1246		return false;
1247
1248	if (sigtrap_get())
1249		return false;
1250
1251	do {
1252		DBG(("%s: (%d, %d) -> (%d, %d) x (%d, %d) [bpp=%d, src_pitch=%d, dst_pitch=%d]\n", __FUNCTION__,
1253		     box->x1 + src_dx, box->y1 + src_dy,
1254		     box->x1 + dst_dx, box->y1 + dst_dy,
1255		     box->x2 - box->x1, box->y2 - box->y1,
1256		     bpp, stride, bo->pitch));
1257
1258		assert(box->x2 > box->x1);
1259		assert(box->y2 > box->y1);
1260
1261		assert(box->x1 + dst_dx >= 0);
1262		assert((box->x2 + dst_dx)*bpp <= 8*bo->pitch);
1263		assert(box->y1 + dst_dy >= 0);
1264		assert((box->y2 + dst_dy)*bo->pitch <= kgem_bo_size(bo));
1265
1266		assert(box->x1 + src_dx >= 0);
1267		assert((box->x2 + src_dx)*bpp <= 8*stride);
1268		assert(box->y1 + src_dy >= 0);
1269
1270		memcpy_xor(src, dst, bpp,
1271			   stride, bo->pitch,
1272			   box->x1 + src_dx, box->y1 + src_dy,
1273			   box->x1 + dst_dx, box->y1 + dst_dy,
1274			   box->x2 - box->x1, box->y2 - box->y1,
1275			   and, or);
1276		box++;
1277	} while (--n);
1278
1279	sigtrap_put();
1280	return true;
1281}
1282
1283static bool upload_inplace__xor(struct kgem *kgem,
1284				struct kgem_bo *bo,
1285				const BoxRec *box,
1286				int n, int bpp)
1287{
1288	if (unlikely(kgem->wedged))
1289		return true;
1290
1291	if (!kgem_bo_can_map(kgem, bo))
1292		return false;
1293
1294	return __upload_inplace(kgem, bo, box, n, bpp);
1295}
1296
1297bool sna_write_boxes__xor(struct sna *sna, PixmapPtr dst,
1298			  struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
1299			  const void *src, int stride, int16_t src_dx, int16_t src_dy,
1300			  const BoxRec *box, int nbox,
1301			  uint32_t and, uint32_t or)
1302{
1303	struct kgem *kgem = &sna->kgem;
1304	struct kgem_bo *src_bo;
1305	BoxRec extents;
1306	bool can_blt;
1307	void *ptr;
1308	int offset;
1309	int n, cmd, br13;
1310
1311	DBG(("%s x %d\n", __FUNCTION__, nbox));
1312
1313	if (upload_inplace__xor(kgem, dst_bo, box, nbox, dst->drawable.bitsPerPixel) &&
1314	    write_boxes_inplace__xor(kgem,
1315				     src, stride, dst->drawable.bitsPerPixel, src_dx, src_dy,
1316				     dst_bo, dst_dx, dst_dy,
1317				     box, nbox,
1318				     and, or))
1319		return true;
1320
1321	if (wedged(sna))
1322		return false;
1323
1324	can_blt = kgem_bo_can_blt(kgem, dst_bo) &&
1325		(box[0].x2 - box[0].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4);
1326	extents = box[0];
1327	for (n = 1; n < nbox; n++) {
1328		if (box[n].x1 < extents.x1)
1329			extents.x1 = box[n].x1;
1330		if (box[n].x2 > extents.x2)
1331			extents.x2 = box[n].x2;
1332
1333		if (can_blt)
1334			can_blt = (box[n].x2 - box[n].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4);
1335
1336		if (box[n].y1 < extents.y1)
1337			extents.y1 = box[n].y1;
1338		if (box[n].y2 > extents.y2)
1339			extents.y2 = box[n].y2;
1340	}
1341
1342	/* Try to avoid switching rings... */
1343	if (!can_blt || kgem->ring == KGEM_RENDER ||
1344	    upload_too_large(sna, extents.x2 - extents.x1, extents.y2 - extents.y1)) {
1345		DrawableRec tmp;
1346
1347		tmp.width  = extents.x2 - extents.x1;
1348		tmp.height = extents.y2 - extents.y1;
1349		tmp.depth  = dst->drawable.depth;
1350		tmp.bitsPerPixel = dst->drawable.bitsPerPixel;
1351
1352		assert(tmp.width);
1353		assert(tmp.height);
1354
1355		DBG(("%s: upload (%d, %d)x(%d, %d), max %dx%d\n",
1356		     __FUNCTION__,
1357		     extents.x1, extents.y1,
1358		     tmp.width, tmp.height,
1359		     sna->render.max_3d_size, sna->render.max_3d_size));
1360		if (must_tile(sna, tmp.width, tmp.height)) {
1361			BoxRec tile, stack[64], *clipped;
1362			int step;
1363
1364tile:
1365			step = MIN(sna->render.max_3d_size - 4096 / dst->drawable.bitsPerPixel,
1366				   8*(MAXSHORT&~63) / dst->drawable.bitsPerPixel);
1367			while (step * step * 4 > sna->kgem.max_upload_tile_size)
1368				step /= 2;
1369
1370			DBG(("%s: tiling upload, using %dx%d tiles\n",
1371			     __FUNCTION__, step, step));
1372			assert(step);
1373
1374			if (n > ARRAY_SIZE(stack)) {
1375				clipped = malloc(sizeof(BoxRec) * n);
1376				if (clipped == NULL)
1377					goto fallback;
1378			} else
1379				clipped = stack;
1380
1381			for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) {
1382				int y2 = tile.y1 + step;
1383				if (y2 > extents.y2)
1384					y2 = extents.y2;
1385				tile.y2 = y2;
1386
1387				for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) {
1388					int x2 = tile.x1 + step;
1389					if (x2 > extents.x2)
1390						x2 = extents.x2;
1391					tile.x2 = x2;
1392
1393					tmp.width  = tile.x2 - tile.x1;
1394					tmp.height = tile.y2 - tile.y1;
1395
1396					src_bo = kgem_create_buffer_2d(kgem,
1397								       tmp.width,
1398								       tmp.height,
1399								       tmp.bitsPerPixel,
1400								       KGEM_BUFFER_WRITE_INPLACE,
1401								       &ptr);
1402					if (!src_bo) {
1403						if (clipped != stack)
1404							free(clipped);
1405						goto fallback;
1406					}
1407
1408					if (sigtrap_get() == 0) {
1409						BoxRec *c = clipped;
1410						for (n = 0; n < nbox; n++) {
1411							*c = box[n];
1412							if (!box_intersect(c, &tile))
1413								continue;
1414
1415							DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n",
1416							     __FUNCTION__,
1417							     c->x1, c->y1,
1418							     c->x2, c->y2,
1419							     src_dx, src_dy,
1420							     c->x1 - tile.x1,
1421							     c->y1 - tile.y1));
1422							memcpy_xor(src, ptr, tmp.bitsPerPixel,
1423								   stride, src_bo->pitch,
1424								   c->x1 + src_dx,
1425								   c->y1 + src_dy,
1426								   c->x1 - tile.x1,
1427								   c->y1 - tile.y1,
1428								   c->x2 - c->x1,
1429								   c->y2 - c->y1,
1430								   and, or);
1431							c++;
1432						}
1433
1434						if (c != clipped)
1435							n = sna->render.copy_boxes(sna, GXcopy,
1436										   &tmp, src_bo, -tile.x1, -tile.y1,
1437										   &dst->drawable, dst_bo, dst_dx, dst_dy,
1438										   clipped, c - clipped, 0);
1439						else
1440							n = 1;
1441
1442						sigtrap_put();
1443					} else
1444						n = 0;
1445
1446					kgem_bo_destroy(&sna->kgem, src_bo);
1447
1448					if (!n) {
1449						if (clipped != stack)
1450							free(clipped);
1451						goto fallback;
1452					}
1453				}
1454			}
1455
1456			if (clipped != stack)
1457				free(clipped);
1458		} else {
1459			src_bo = kgem_create_buffer_2d(kgem,
1460						       tmp.width,
1461						       tmp.height,
1462						       tmp.bitsPerPixel,
1463						       KGEM_BUFFER_WRITE_INPLACE,
1464						       &ptr);
1465			if (!src_bo)
1466				goto fallback;
1467
1468			if (sigtrap_get() == 0) {
1469				for (n = 0; n < nbox; n++) {
1470					DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n",
1471					     __FUNCTION__,
1472					     box[n].x1, box[n].y1,
1473					     box[n].x2, box[n].y2,
1474					     src_dx, src_dy,
1475					     box[n].x1 - extents.x1,
1476					     box[n].y1 - extents.y1));
1477					memcpy_xor(src, ptr, tmp.bitsPerPixel,
1478						   stride, src_bo->pitch,
1479						   box[n].x1 + src_dx,
1480						   box[n].y1 + src_dy,
1481						   box[n].x1 - extents.x1,
1482						   box[n].y1 - extents.y1,
1483						   box[n].x2 - box[n].x1,
1484						   box[n].y2 - box[n].y1,
1485						   and, or);
1486				}
1487
1488				n = sna->render.copy_boxes(sna, GXcopy,
1489							   &tmp, src_bo, -extents.x1, -extents.y1,
1490							   &dst->drawable, dst_bo, dst_dx, dst_dy,
1491							   box, nbox, 0);
1492				sigtrap_put();
1493			} else
1494				n = 0;
1495
1496			kgem_bo_destroy(&sna->kgem, src_bo);
1497
1498			if (!n)
1499				goto tile;
1500		}
1501
1502		return true;
1503	}
1504
1505	cmd = XY_SRC_COPY_BLT_CMD;
1506	br13 = dst_bo->pitch;
1507	if (kgem->gen >= 040 && dst_bo->tiling) {
1508		cmd |= BLT_DST_TILED;
1509		br13 >>= 2;
1510	}
1511	br13 |= 0xcc << 16;
1512	switch (dst->drawable.bitsPerPixel) {
1513	default:
1514	case 32: cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB;
1515		 br13 |= 1 << 25; /* RGB8888 */
1516	case 16: br13 |= 1 << 24; /* RGB565 */
1517	case 8: break;
1518	}
1519
1520	kgem_set_mode(kgem, KGEM_BLT, dst_bo);
1521	if (!kgem_check_batch(kgem, 10) ||
1522	    !kgem_check_reloc_and_exec(kgem, 2) ||
1523	    !kgem_check_bo_fenced(kgem, dst_bo)) {
1524		kgem_submit(kgem);
1525		if (!kgem_check_bo_fenced(kgem, dst_bo))
1526			goto fallback;
1527		_kgem_set_mode(kgem, KGEM_BLT);
1528	}
1529
1530	if (sna->kgem.gen >= 0100) {
1531		cmd |= 8;
1532		do {
1533			int nbox_this_time;
1534
1535			nbox_this_time = nbox;
1536			if (10*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED)
1537				nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8;
1538			if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc)
1539				nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2;
1540			assert(nbox_this_time);
1541			nbox -= nbox_this_time;
1542
1543			/* Count the total number of bytes to be read and allocate a
1544			 * single buffer large enough. Or if it is very small, combine
1545			 * with other allocations. */
1546			offset = 0;
1547			for (n = 0; n < nbox_this_time; n++) {
1548				int height = box[n].y2 - box[n].y1;
1549				int width = box[n].x2 - box[n].x1;
1550				offset += PITCH(width, dst->drawable.bitsPerPixel >> 3) * height;
1551			}
1552
1553			src_bo = kgem_create_buffer(kgem, offset,
1554						    KGEM_BUFFER_WRITE_INPLACE | (nbox ? KGEM_BUFFER_LAST : 0),
1555						    &ptr);
1556			if (!src_bo)
1557				goto fallback;
1558
1559			if (sigtrap_get()) {
1560				kgem_bo_destroy(kgem, src_bo);
1561				goto fallback;
1562			}
1563
1564			offset = 0;
1565			do {
1566				int height = box->y2 - box->y1;
1567				int width = box->x2 - box->x1;
1568				int pitch = PITCH(width, dst->drawable.bitsPerPixel >> 3);
1569				uint32_t *b;
1570
1571				DBG(("  %s: box src=(%d, %d), dst=(%d, %d) size=(%d, %d), dst offset=%d, dst pitch=%d\n",
1572				     __FUNCTION__,
1573				     box->x1 + src_dx, box->y1 + src_dy,
1574				     box->x1 + dst_dx, box->y1 + dst_dy,
1575				     width, height,
1576				     offset, pitch));
1577
1578				assert(box->x1 + src_dx >= 0);
1579				assert((box->x2 + src_dx)*dst->drawable.bitsPerPixel <= 8*stride);
1580				assert(box->y1 + src_dy >= 0);
1581
1582				assert(box->x1 + dst_dx >= 0);
1583				assert(box->y1 + dst_dy >= 0);
1584
1585				memcpy_xor(src, (char *)ptr + offset,
1586					   dst->drawable.bitsPerPixel,
1587					   stride, pitch,
1588					   box->x1 + src_dx, box->y1 + src_dy,
1589					   0, 0,
1590					   width, height,
1591					   and, or);
1592
1593				assert(kgem->mode == KGEM_BLT);
1594				b = kgem->batch + kgem->nbatch;
1595				b[0] = cmd;
1596				b[1] = br13;
1597				b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx);
1598				b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx);
1599				*(uint64_t *)(b+4) =
1600					kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo,
1601							 I915_GEM_DOMAIN_RENDER << 16 |
1602							 I915_GEM_DOMAIN_RENDER |
1603							 KGEM_RELOC_FENCED,
1604							 0);
1605				b[6] = 0;
1606				b[7] = pitch;
1607				*(uint64_t *)(b+8) =
1608					kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo,
1609							 I915_GEM_DOMAIN_RENDER << 16 |
1610							 KGEM_RELOC_FENCED,
1611							 offset);
1612				kgem->nbatch += 10;
1613
1614				box++;
1615				offset += pitch * height;
1616			} while (--nbox_this_time);
1617			assert(offset == __kgem_buffer_size(src_bo));
1618			sigtrap_put();
1619
1620			if (nbox) {
1621				_kgem_submit(kgem);
1622				_kgem_set_mode(kgem, KGEM_BLT);
1623			}
1624
1625			kgem_bo_destroy(kgem, src_bo);
1626		} while (nbox);
1627	} else {
1628		cmd |= 6;
1629		do {
1630			int nbox_this_time;
1631
1632			nbox_this_time = nbox;
1633			if (8*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED)
1634				nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8;
1635			if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc)
1636				nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2;
1637			assert(nbox_this_time);
1638			nbox -= nbox_this_time;
1639
1640			/* Count the total number of bytes to be read and allocate a
1641			 * single buffer large enough. Or if it is very small, combine
1642			 * with other allocations. */
1643			offset = 0;
1644			for (n = 0; n < nbox_this_time; n++) {
1645				int height = box[n].y2 - box[n].y1;
1646				int width = box[n].x2 - box[n].x1;
1647				offset += PITCH(width, dst->drawable.bitsPerPixel >> 3) * height;
1648			}
1649
1650			src_bo = kgem_create_buffer(kgem, offset,
1651						    KGEM_BUFFER_WRITE_INPLACE | (nbox ? KGEM_BUFFER_LAST : 0),
1652						    &ptr);
1653			if (!src_bo)
1654				goto fallback;
1655
1656			if (sigtrap_get()) {
1657				kgem_bo_destroy(kgem, src_bo);
1658				goto fallback;
1659			}
1660
1661			offset = 0;
1662			do {
1663				int height = box->y2 - box->y1;
1664				int width = box->x2 - box->x1;
1665				int pitch = PITCH(width, dst->drawable.bitsPerPixel >> 3);
1666				uint32_t *b;
1667
1668				DBG(("  %s: box src=(%d, %d), dst=(%d, %d) size=(%d, %d), dst offset=%d, dst pitch=%d\n",
1669				     __FUNCTION__,
1670				     box->x1 + src_dx, box->y1 + src_dy,
1671				     box->x1 + dst_dx, box->y1 + dst_dy,
1672				     width, height,
1673				     offset, pitch));
1674
1675				assert(box->x1 + src_dx >= 0);
1676				assert((box->x2 + src_dx)*dst->drawable.bitsPerPixel <= 8*stride);
1677				assert(box->y1 + src_dy >= 0);
1678
1679				assert(box->x1 + dst_dx >= 0);
1680				assert(box->y1 + dst_dy >= 0);
1681
1682				memcpy_xor(src, (char *)ptr + offset,
1683					   dst->drawable.bitsPerPixel,
1684					   stride, pitch,
1685					   box->x1 + src_dx, box->y1 + src_dy,
1686					   0, 0,
1687					   width, height,
1688					   and, or);
1689
1690				assert(kgem->mode == KGEM_BLT);
1691				b = kgem->batch + kgem->nbatch;
1692				b[0] = cmd;
1693				b[1] = br13;
1694				b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx);
1695				b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx);
1696				b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo,
1697						      I915_GEM_DOMAIN_RENDER << 16 |
1698						      I915_GEM_DOMAIN_RENDER |
1699						      KGEM_RELOC_FENCED,
1700						      0);
1701				b[5] = 0;
1702				b[6] = pitch;
1703				b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo,
1704						      I915_GEM_DOMAIN_RENDER << 16 |
1705						      KGEM_RELOC_FENCED,
1706						      offset);
1707				kgem->nbatch += 8;
1708
1709				box++;
1710				offset += pitch * height;
1711			} while (--nbox_this_time);
1712			assert(offset == __kgem_buffer_size(src_bo));
1713			sigtrap_put();
1714
1715			if (nbox) {
1716				_kgem_submit(kgem);
1717				_kgem_set_mode(kgem, KGEM_BLT);
1718			}
1719
1720			kgem_bo_destroy(kgem, src_bo);
1721		} while (nbox);
1722	}
1723
1724	sna->blt_state.fill_bo = 0;
1725	return true;
1726
1727fallback:
1728	return write_boxes_inplace__xor(kgem,
1729					src, stride, dst->drawable.bitsPerPixel, src_dx, src_dy,
1730					dst_bo, dst_dx, dst_dy,
1731					box, nbox,
1732					and, or);
1733}
1734
1735static bool
1736indirect_replace(struct sna *sna,
1737		 PixmapPtr pixmap,
1738		 struct kgem_bo *bo,
1739		 const void *src, int stride)
1740{
1741	struct kgem *kgem = &sna->kgem;
1742	struct kgem_bo *src_bo;
1743	BoxRec box;
1744	void *ptr;
1745	bool ret;
1746
1747	DBG(("%s: size=%d vs %d\n",
1748	     __FUNCTION__,
1749	     stride * pixmap->drawable.height >> 12,
1750	     kgem->half_cpu_cache_pages));
1751
1752	if (stride * pixmap->drawable.height >> 12 > kgem->half_cpu_cache_pages)
1753		return false;
1754
1755	if (!kgem_bo_can_blt(kgem, bo) &&
1756	    must_tile(sna, pixmap->drawable.width, pixmap->drawable.height))
1757		return false;
1758
1759	src_bo = kgem_create_buffer_2d(kgem,
1760				       pixmap->drawable.width,
1761				       pixmap->drawable.height,
1762				       pixmap->drawable.bitsPerPixel,
1763				       KGEM_BUFFER_WRITE_INPLACE,
1764				       &ptr);
1765	if (!src_bo)
1766		return false;
1767
1768	if (sigtrap_get() == 0) {
1769		memcpy_blt(src, ptr, pixmap->drawable.bitsPerPixel,
1770			   stride, src_bo->pitch,
1771			   0, 0,
1772			   0, 0,
1773			   pixmap->drawable.width,
1774			   pixmap->drawable.height);
1775
1776		box.x1 = box.y1 = 0;
1777		box.x2 = pixmap->drawable.width;
1778		box.y2 = pixmap->drawable.height;
1779
1780		ret = sna->render.copy_boxes(sna, GXcopy,
1781					     &pixmap->drawable, src_bo, 0, 0,
1782					     &pixmap->drawable, bo, 0, 0,
1783					     &box, 1, 0);
1784		sigtrap_put();
1785	} else
1786		ret = false;
1787
1788	kgem_bo_destroy(kgem, src_bo);
1789
1790	return ret;
1791}
1792
1793bool sna_replace(struct sna *sna, PixmapPtr pixmap,
1794		 const void *src, int stride)
1795{
1796	struct sna_pixmap *priv = sna_pixmap(pixmap);
1797	struct kgem_bo *bo = priv->gpu_bo;
1798	void *dst;
1799
1800	assert(bo);
1801	DBG(("%s(handle=%d, %dx%d, bpp=%d, tiling=%d) busy?=%d\n",
1802	     __FUNCTION__, bo->handle,
1803	     pixmap->drawable.width,
1804	     pixmap->drawable.height,
1805	     pixmap->drawable.bitsPerPixel,
1806	     bo->tiling,
1807	     __kgem_bo_is_busy(&sna->kgem, bo)));
1808
1809	assert(!priv->pinned);
1810
1811	kgem_bo_undo(&sna->kgem, bo);
1812
1813	if (__kgem_bo_is_busy(&sna->kgem, bo)) {
1814		struct kgem_bo *new_bo;
1815
1816		if (indirect_replace(sna, pixmap, bo, src, stride))
1817			return true;
1818
1819		new_bo = kgem_create_2d(&sna->kgem,
1820					pixmap->drawable.width,
1821					pixmap->drawable.height,
1822					pixmap->drawable.bitsPerPixel,
1823					bo->tiling,
1824					CREATE_GTT_MAP | CREATE_INACTIVE);
1825		if (new_bo)
1826			bo = new_bo;
1827	}
1828
1829	if (bo->tiling == I915_TILING_NONE && bo->pitch == stride &&
1830	    kgem_bo_write(&sna->kgem, bo, src,
1831			  (pixmap->drawable.height-1)*stride + pixmap->drawable.width*pixmap->drawable.bitsPerPixel/8))
1832			goto done;
1833
1834	if (upload_inplace__tiled(&sna->kgem, bo)) {
1835		BoxRec box;
1836
1837		box.x1 = box.y1 = 0;
1838		box.x2 = pixmap->drawable.width;
1839		box.y2 = pixmap->drawable.height;
1840
1841		if (write_boxes_inplace__tiled(&sna->kgem, src,
1842					       stride, pixmap->drawable.bitsPerPixel, 0, 0,
1843					       bo, 0, 0, &box, 1))
1844			goto done;
1845	}
1846
1847	if (kgem_bo_can_map(&sna->kgem, bo) &&
1848	    (dst = kgem_bo_map(&sna->kgem, bo)) != NULL &&
1849	    sigtrap_get() == 0) {
1850		memcpy_blt(src, dst, pixmap->drawable.bitsPerPixel,
1851			   stride, bo->pitch,
1852			   0, 0,
1853			   0, 0,
1854			   pixmap->drawable.width,
1855			   pixmap->drawable.height);
1856		sigtrap_put();
1857	} else {
1858		BoxRec box;
1859
1860		if (bo != priv->gpu_bo) {
1861			kgem_bo_destroy(&sna->kgem, bo);
1862			bo = priv->gpu_bo;
1863		}
1864
1865		box.x1 = box.y1 = 0;
1866		box.x2 = pixmap->drawable.width;
1867		box.y2 = pixmap->drawable.height;
1868
1869		if (!sna_write_boxes(sna, pixmap,
1870				     bo, 0, 0,
1871				     src, stride, 0, 0,
1872				     &box, 1))
1873			return false;
1874	}
1875
1876done:
1877	if (bo != priv->gpu_bo) {
1878		sna_pixmap_unmap(pixmap, priv);
1879		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1880		priv->gpu_bo = bo;
1881	}
1882
1883	return true;
1884}
1885
1886bool
1887sna_replace__xor(struct sna *sna, PixmapPtr pixmap,
1888		 const void *src, int stride,
1889		 uint32_t and, uint32_t or)
1890{
1891	struct sna_pixmap *priv = sna_pixmap(pixmap);
1892	struct kgem_bo *bo = priv->gpu_bo;
1893	void *dst;
1894
1895	DBG(("%s(handle=%d, %dx%d, bpp=%d, tiling=%d)\n",
1896	     __FUNCTION__, bo->handle,
1897	     pixmap->drawable.width,
1898	     pixmap->drawable.height,
1899	     pixmap->drawable.bitsPerPixel,
1900	     bo->tiling));
1901
1902	assert(!priv->pinned);
1903
1904	kgem_bo_undo(&sna->kgem, bo);
1905
1906	if (!kgem_bo_can_map(&sna->kgem, bo) ||
1907	    __kgem_bo_is_busy(&sna->kgem, bo)) {
1908		struct kgem_bo *new_bo;
1909
1910		new_bo = kgem_create_2d(&sna->kgem,
1911					pixmap->drawable.width,
1912					pixmap->drawable.height,
1913					pixmap->drawable.bitsPerPixel,
1914					bo->tiling,
1915					CREATE_GTT_MAP | CREATE_INACTIVE);
1916		if (new_bo)
1917			bo = new_bo;
1918	}
1919
1920	if (kgem_bo_can_map(&sna->kgem, bo) &&
1921	    (dst = kgem_bo_map(&sna->kgem, bo)) != NULL &&
1922	    sigtrap_get() == 0) {
1923		memcpy_xor(src, dst, pixmap->drawable.bitsPerPixel,
1924			   stride, bo->pitch,
1925			   0, 0,
1926			   0, 0,
1927			   pixmap->drawable.width,
1928			   pixmap->drawable.height,
1929			   and, or);
1930		sigtrap_put();
1931	} else {
1932		BoxRec box;
1933
1934		if (bo != priv->gpu_bo) {
1935			kgem_bo_destroy(&sna->kgem, bo);
1936			bo = priv->gpu_bo;
1937		}
1938
1939		box.x1 = box.y1 = 0;
1940		box.x2 = pixmap->drawable.width;
1941		box.y2 = pixmap->drawable.height;
1942
1943		if (!sna_write_boxes__xor(sna, pixmap,
1944					  bo, 0, 0,
1945					  src, stride, 0, 0,
1946					  &box, 1,
1947					  and, or))
1948			return false;
1949	}
1950
1951	if (bo != priv->gpu_bo) {
1952		sna_pixmap_unmap(pixmap, priv);
1953		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1954		priv->gpu_bo = bo;
1955	}
1956
1957	return true;
1958}
1959