sna_io.c revision 13496ba1
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, rem;
488
489			nbox_this_time = tmp_nbox;
490			rem = kgem_batch_space(kgem);
491			if (10*nbox_this_time > rem)
492				nbox_this_time = rem / 8;
493			if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc)
494				nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2;
495			assert(nbox_this_time);
496			tmp_nbox -= nbox_this_time;
497
498			assert(kgem->mode == KGEM_BLT);
499			for (n = 0; n < nbox_this_time; n++) {
500				int height = tmp_box[n].y2 - tmp_box[n].y1;
501				int width = tmp_box[n].x2 - tmp_box[n].x1;
502				int pitch = PITCH(width, cpp);
503				uint32_t *b = kgem->batch + kgem->nbatch;
504
505				DBG(("    blt offset %x: (%d, %d) x (%d, %d), pitch=%d\n",
506				     offset,
507				     tmp_box[n].x1, tmp_box[n].y1,
508				     width, height, pitch));
509
510				assert(tmp_box[n].x1 >= 0);
511				assert(tmp_box[n].x2 * dst->drawable.bitsPerPixel/8 <= src_bo->pitch);
512				assert(tmp_box[n].y1 >= 0);
513				assert(tmp_box[n].y2 * src_bo->pitch <= kgem_bo_size(src_bo));
514
515				b[0] = cmd;
516				b[1] = br13 | pitch;
517				b[2] = 0;
518				b[3] = height << 16 | width;
519				*(uint64_t *)(b+4) =
520					kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo,
521							 I915_GEM_DOMAIN_RENDER << 16 |
522							 I915_GEM_DOMAIN_RENDER |
523							 KGEM_RELOC_FENCED,
524							 offset);
525				b[6] = tmp_box[n].y1 << 16 | tmp_box[n].x1;
526				b[7] = src_pitch;
527				*(uint64_t *)(b+8) =
528					kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo,
529							 I915_GEM_DOMAIN_RENDER << 16 |
530							 KGEM_RELOC_FENCED,
531							 0);
532				kgem->nbatch += 10;
533
534				offset += pitch * height;
535			}
536
537			_kgem_submit(kgem);
538			if (!tmp_nbox)
539				break;
540
541			_kgem_set_mode(kgem, KGEM_BLT);
542			tmp_box += nbox_this_time;
543		} while (1);
544	} else {
545		cmd |= 6;
546		do {
547			int nbox_this_time, rem;
548
549			nbox_this_time = tmp_nbox;
550			rem = kgem_batch_space(kgem);
551			if (8*nbox_this_time > rem)
552				nbox_this_time = rem / 8;
553			if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc)
554				nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2;
555			assert(nbox_this_time);
556			tmp_nbox -= nbox_this_time;
557
558			assert(kgem->mode == KGEM_BLT);
559			for (n = 0; n < nbox_this_time; n++) {
560				int height = tmp_box[n].y2 - tmp_box[n].y1;
561				int width = tmp_box[n].x2 - tmp_box[n].x1;
562				int pitch = PITCH(width, cpp);
563				uint32_t *b = kgem->batch + kgem->nbatch;
564
565				DBG(("    blt offset %x: (%d, %d) x (%d, %d), pitch=%d\n",
566				     offset,
567				     tmp_box[n].x1, tmp_box[n].y1,
568				     width, height, pitch));
569
570				assert(tmp_box[n].x1 >= 0);
571				assert(tmp_box[n].x2 * dst->drawable.bitsPerPixel/8 <= src_bo->pitch);
572				assert(tmp_box[n].y1 >= 0);
573				assert(tmp_box[n].y2 * src_bo->pitch <= kgem_bo_size(src_bo));
574
575				b[0] = cmd;
576				b[1] = br13 | pitch;
577				b[2] = 0;
578				b[3] = height << 16 | width;
579				b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo,
580						      I915_GEM_DOMAIN_RENDER << 16 |
581						      I915_GEM_DOMAIN_RENDER |
582						      KGEM_RELOC_FENCED,
583						      offset);
584				b[5] = tmp_box[n].y1 << 16 | tmp_box[n].x1;
585				b[6] = src_pitch;
586				b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo,
587						      I915_GEM_DOMAIN_RENDER << 16 |
588						      KGEM_RELOC_FENCED,
589						      0);
590				kgem->nbatch += 8;
591
592				offset += pitch * height;
593			}
594
595			_kgem_submit(kgem);
596			if (!tmp_nbox)
597				break;
598
599			_kgem_set_mode(kgem, KGEM_BLT);
600			tmp_box += nbox_this_time;
601		} while (1);
602	}
603	assert(offset == __kgem_buffer_size(dst_bo));
604
605	kgem_buffer_read_sync(kgem, dst_bo);
606
607	if (sigtrap_get() == 0) {
608		char *src = ptr;
609		do {
610			int height = box->y2 - box->y1;
611			int width  = box->x2 - box->x1;
612			int pitch = PITCH(width, cpp);
613
614			DBG(("    copy offset %lx [%08x...%08x...%08x]: (%d, %d) x (%d, %d), src pitch=%d, dst pitch=%d, bpp=%d\n",
615			     (long)((char *)src - (char *)ptr),
616			     *(uint32_t*)src, *(uint32_t*)(src+pitch*height/2 + pitch/2 - 4), *(uint32_t*)(src+pitch*height - 4),
617			     box->x1, box->y1,
618			     width, height,
619			     pitch, dst->devKind, cpp*8));
620
621			assert(box->x1 >= 0);
622			assert(box->x2 <= dst->drawable.width);
623			assert(box->y1 >= 0);
624			assert(box->y2 <= dst->drawable.height);
625
626			memcpy_blt(src, dst->devPrivate.ptr, cpp*8,
627				   pitch, dst->devKind,
628				   0, 0,
629				   box->x1, box->y1,
630				   width, height);
631			box++;
632
633			src += pitch * height;
634		} while (--nbox);
635		assert(src - (char *)ptr == __kgem_buffer_size(dst_bo));
636		sigtrap_put();
637	}
638	kgem_bo_destroy(kgem, dst_bo);
639	sna->blt_state.fill_bo = 0;
640}
641
642static bool upload_inplace__tiled(struct kgem *kgem, struct kgem_bo *bo)
643{
644	DBG(("%s: tiling=%d\n", __FUNCTION__, bo->tiling));
645	switch (bo->tiling) {
646	case I915_TILING_Y:
647		return false;
648	case I915_TILING_X:
649		if (!kgem->memcpy_to_tiled_x)
650			return false;
651	default:
652		break;
653	}
654
655	if (kgem->has_wc_mmap)
656		return true;
657
658	return kgem_bo_can_map__cpu(kgem, bo, true);
659}
660
661static bool
662write_boxes_inplace__tiled(struct kgem *kgem,
663                           const uint8_t *src, int stride, int bpp, int16_t src_dx, int16_t src_dy,
664                           struct kgem_bo *bo, int16_t dst_dx, int16_t dst_dy,
665                           const BoxRec *box, int n)
666{
667	uint8_t *dst;
668
669	assert(kgem->has_wc_mmap || kgem_bo_can_map__cpu(kgem, bo, true));
670	assert(bo->tiling != I915_TILING_Y);
671
672	if (kgem_bo_can_map__cpu(kgem, bo, true)) {
673		dst = kgem_bo_map__cpu(kgem, bo);
674		if (dst == NULL)
675			return false;
676
677		kgem_bo_sync__cpu(kgem, bo);
678	} else {
679		dst = kgem_bo_map__wc(kgem, bo);
680		if (dst == NULL)
681			return false;
682
683		kgem_bo_sync__gtt(kgem, bo);
684	}
685
686	if (sigtrap_get())
687		return false;
688
689	if (bo->tiling) {
690		do {
691			memcpy_to_tiled_x(kgem, src, dst, bpp, stride, bo->pitch,
692					  box->x1 + src_dx, box->y1 + src_dy,
693					  box->x1 + dst_dx, box->y1 + dst_dy,
694					  box->x2 - box->x1, box->y2 - box->y1);
695			box++;
696		} while (--n);
697	} else {
698		do {
699			memcpy_blt(src, dst, bpp, stride, bo->pitch,
700				   box->x1 + src_dx, box->y1 + src_dy,
701				   box->x1 + dst_dx, box->y1 + dst_dy,
702				   box->x2 - box->x1, box->y2 - box->y1);
703			box++;
704		} while (--n);
705	}
706
707	sigtrap_put();
708	return true;
709}
710
711static bool write_boxes_inplace(struct kgem *kgem,
712				const void *src, int stride, int bpp, int16_t src_dx, int16_t src_dy,
713				struct kgem_bo *bo, int16_t dst_dx, int16_t dst_dy,
714				const BoxRec *box, int n)
715{
716	void *dst;
717
718	DBG(("%s x %d, handle=%d, tiling=%d\n",
719	     __FUNCTION__, n, bo->handle, bo->tiling));
720
721	if (upload_inplace__tiled(kgem, bo) &&
722	    write_boxes_inplace__tiled(kgem, src, stride, bpp, src_dx, src_dy,
723				       bo, dst_dx, dst_dy, box, n))
724		return true;
725
726	if (!kgem_bo_can_map(kgem, bo))
727		return false;
728
729	kgem_bo_submit(kgem, bo);
730
731	dst = kgem_bo_map(kgem, bo);
732	if (dst == NULL)
733		return false;
734
735	assert(dst != src);
736
737	if (sigtrap_get())
738		return false;
739
740	do {
741		DBG(("%s: (%d, %d) -> (%d, %d) x (%d, %d) [bpp=%d, src_pitch=%d, dst_pitch=%d]\n", __FUNCTION__,
742		     box->x1 + src_dx, box->y1 + src_dy,
743		     box->x1 + dst_dx, box->y1 + dst_dy,
744		     box->x2 - box->x1, box->y2 - box->y1,
745		     bpp, stride, bo->pitch));
746
747		assert(box->x2 > box->x1);
748		assert(box->y2 > box->y1);
749
750		assert(box->x1 + dst_dx >= 0);
751		assert((box->x2 + dst_dx)*bpp <= 8*bo->pitch);
752		assert(box->y1 + dst_dy >= 0);
753		assert((box->y2 + dst_dy)*bo->pitch <= kgem_bo_size(bo));
754
755		assert(box->x1 + src_dx >= 0);
756		assert((box->x2 + src_dx)*bpp <= 8*stride);
757		assert(box->y1 + src_dy >= 0);
758
759		memcpy_blt(src, dst, bpp,
760			   stride, bo->pitch,
761			   box->x1 + src_dx, box->y1 + src_dy,
762			   box->x1 + dst_dx, box->y1 + dst_dy,
763			   box->x2 - box->x1, box->y2 - box->y1);
764		box++;
765	} while (--n);
766
767	sigtrap_put();
768	return true;
769}
770
771static bool __upload_inplace(struct kgem *kgem,
772			     struct kgem_bo *bo,
773			     const BoxRec *box,
774			     int n, int bpp)
775{
776	unsigned int bytes;
777
778	if (FORCE_INPLACE)
779		return FORCE_INPLACE > 0;
780
781	/* If we are writing through the GTT, check first if we might be
782	 * able to almagamate a series of small writes into a single
783	 * operation.
784	 */
785	bytes = 0;
786	while (n--) {
787		bytes += (box->x2 - box->x1) * (box->y2 - box->y1);
788		box++;
789	}
790	if (__kgem_bo_is_busy(kgem, bo))
791		return bytes * bpp >> 12 >= kgem->half_cpu_cache_pages;
792	else
793		return bytes * bpp >> 12;
794}
795
796static bool upload_inplace(struct kgem *kgem,
797			   struct kgem_bo *bo,
798			   const BoxRec *box,
799			   int n, int bpp)
800{
801	if (unlikely(kgem->wedged))
802		return true;
803
804	if (!kgem_bo_can_map(kgem, bo) && !upload_inplace__tiled(kgem, bo))
805		return false;
806
807	return __upload_inplace(kgem, bo, box, n,bpp);
808}
809
810bool sna_write_boxes(struct sna *sna, PixmapPtr dst,
811		     struct kgem_bo * const dst_bo, int16_t const dst_dx, int16_t const dst_dy,
812		     const void * const src, int const stride, int16_t const src_dx, int16_t const src_dy,
813		     const BoxRec *box, int nbox)
814{
815	struct kgem *kgem = &sna->kgem;
816	struct kgem_bo *src_bo;
817	BoxRec extents;
818	void *ptr;
819	int offset;
820	int n, cmd, br13;
821	bool can_blt;
822
823	DBG(("%s x %d, src stride=%d,  src dx=(%d, %d)\n", __FUNCTION__, nbox, stride, src_dx, src_dy));
824
825	if (upload_inplace(kgem, dst_bo, box, nbox, dst->drawable.bitsPerPixel) &&
826	    write_boxes_inplace(kgem,
827				src, stride, dst->drawable.bitsPerPixel, src_dx, src_dy,
828				dst_bo, dst_dx, dst_dy,
829				box, nbox))
830		return true;
831
832	if (wedged(sna))
833		return false;
834
835	can_blt = kgem_bo_can_blt(kgem, dst_bo) &&
836		(box[0].x2 - box[0].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4);
837	extents = box[0];
838	for (n = 1; n < nbox; n++) {
839		if (box[n].x1 < extents.x1)
840			extents.x1 = box[n].x1;
841		if (box[n].x2 > extents.x2)
842			extents.x2 = box[n].x2;
843
844		if (can_blt)
845			can_blt = (box[n].x2 - box[n].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4);
846
847		if (box[n].y1 < extents.y1)
848			extents.y1 = box[n].y1;
849		if (box[n].y2 > extents.y2)
850			extents.y2 = box[n].y2;
851	}
852
853	/* Try to avoid switching rings... */
854	if (!can_blt || kgem->ring == KGEM_RENDER ||
855	    upload_too_large(sna, extents.x2 - extents.x1, extents.y2 - extents.y1)) {
856		DrawableRec tmp;
857
858		tmp.width  = extents.x2 - extents.x1;
859		tmp.height = extents.y2 - extents.y1;
860		tmp.depth  = dst->drawable.depth;
861		tmp.bitsPerPixel = dst->drawable.bitsPerPixel;
862
863		assert(tmp.width);
864		assert(tmp.height);
865
866		DBG(("%s: upload (%d, %d)x(%d, %d), max %dx%d\n",
867		     __FUNCTION__,
868		     extents.x1, extents.y1,
869		     tmp.width, tmp.height,
870		     sna->render.max_3d_size, sna->render.max_3d_size));
871		if (must_tile(sna, tmp.width, tmp.height)) {
872			BoxRec tile, stack[64], *clipped;
873			int cpp, step;
874
875tile:
876			cpp = dst->drawable.bitsPerPixel / 8;
877			step = MIN(sna->render.max_3d_size,
878				   (MAXSHORT&~63) / cpp);
879			while (step * step * cpp > sna->kgem.max_upload_tile_size)
880				step /= 2;
881
882			if (step * cpp > 4096)
883				step = 4096 / cpp;
884			assert(step);
885
886			DBG(("%s: tiling upload, using %dx%d tiles\n",
887			     __FUNCTION__, step, step));
888
889			if (n > ARRAY_SIZE(stack)) {
890				clipped = malloc(sizeof(BoxRec) * n);
891				if (clipped == NULL)
892					goto fallback;
893			} else
894				clipped = stack;
895
896			for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) {
897				int y2 = tile.y1 + step;
898				if (y2 > extents.y2)
899					y2 = extents.y2;
900				tile.y2 = y2;
901
902				for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) {
903					int x2 = tile.x1 + step;
904					if (x2 > extents.x2)
905						x2 = extents.x2;
906					tile.x2 = x2;
907
908					tmp.width  = tile.x2 - tile.x1;
909					tmp.height = tile.y2 - tile.y1;
910
911					src_bo = kgem_create_buffer_2d(kgem,
912								       tmp.width,
913								       tmp.height,
914								       tmp.bitsPerPixel,
915								       KGEM_BUFFER_WRITE_INPLACE,
916								       &ptr);
917					if (!src_bo) {
918						if (clipped != stack)
919							free(clipped);
920						goto fallback;
921					}
922
923					if (sigtrap_get() == 0) {
924						BoxRec *c = clipped;
925						for (n = 0; n < nbox; n++) {
926							*c = box[n];
927							if (!box_intersect(c, &tile))
928								continue;
929
930							DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n",
931							     __FUNCTION__,
932							     c->x1, c->y1,
933							     c->x2, c->y2,
934							     src_dx, src_dy,
935							     c->x1 - tile.x1,
936							     c->y1 - tile.y1));
937							memcpy_blt(src, ptr, tmp.bitsPerPixel,
938								   stride, src_bo->pitch,
939								   c->x1 + src_dx,
940								   c->y1 + src_dy,
941								   c->x1 - tile.x1,
942								   c->y1 - tile.y1,
943								   c->x2 - c->x1,
944								   c->y2 - c->y1);
945							c++;
946						}
947
948						if (c != clipped)
949							n = sna->render.copy_boxes(sna, GXcopy,
950										   &tmp, src_bo, -tile.x1, -tile.y1,
951										   &dst->drawable, dst_bo, dst_dx, dst_dy,
952										   clipped, c - clipped, 0);
953						else
954							n = 1;
955						sigtrap_put();
956					} else
957						n = 0;
958
959					kgem_bo_destroy(&sna->kgem, src_bo);
960
961					if (!n) {
962						if (clipped != stack)
963							free(clipped);
964						goto fallback;
965					}
966				}
967			}
968
969			if (clipped != stack)
970				free(clipped);
971		} else {
972			src_bo = kgem_create_buffer_2d(kgem,
973						       tmp.width,
974						       tmp.height,
975						       tmp.bitsPerPixel,
976						       KGEM_BUFFER_WRITE_INPLACE,
977						       &ptr);
978			if (!src_bo)
979				goto fallback;
980
981			if (sigtrap_get() == 0) {
982				for (n = 0; n < nbox; n++) {
983					DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n",
984					     __FUNCTION__,
985					     box[n].x1, box[n].y1,
986					     box[n].x2, box[n].y2,
987					     src_dx, src_dy,
988					     box[n].x1 - extents.x1,
989					     box[n].y1 - extents.y1));
990					memcpy_blt(src, ptr, tmp.bitsPerPixel,
991						   stride, src_bo->pitch,
992						   box[n].x1 + src_dx,
993						   box[n].y1 + src_dy,
994						   box[n].x1 - extents.x1,
995						   box[n].y1 - extents.y1,
996						   box[n].x2 - box[n].x1,
997						   box[n].y2 - box[n].y1);
998				}
999
1000				n = sna->render.copy_boxes(sna, GXcopy,
1001							   &tmp, src_bo, -extents.x1, -extents.y1,
1002							   &dst->drawable, dst_bo, dst_dx, dst_dy,
1003							   box, nbox, 0);
1004				sigtrap_put();
1005			} else
1006				n = 0;
1007
1008			kgem_bo_destroy(&sna->kgem, src_bo);
1009
1010			if (!n)
1011				goto tile;
1012		}
1013
1014		return true;
1015	}
1016
1017	cmd = XY_SRC_COPY_BLT_CMD;
1018	br13 = dst_bo->pitch;
1019	if (kgem->gen >= 040 && dst_bo->tiling) {
1020		cmd |= BLT_DST_TILED;
1021		br13 >>= 2;
1022	}
1023	br13 |= 0xcc << 16;
1024	switch (dst->drawable.bitsPerPixel) {
1025	default:
1026	case 32: cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB;
1027		 br13 |= 1 << 25; /* RGB8888 */
1028	case 16: br13 |= 1 << 24; /* RGB565 */
1029	case 8: break;
1030	}
1031
1032	kgem_set_mode(kgem, KGEM_BLT, dst_bo);
1033	if (!kgem_check_batch(kgem, 10) ||
1034	    !kgem_check_reloc_and_exec(kgem, 2) ||
1035	    !kgem_check_bo_fenced(kgem, dst_bo)) {
1036		kgem_submit(kgem);
1037		if (!kgem_check_bo_fenced(kgem, dst_bo))
1038			goto fallback;
1039		_kgem_set_mode(kgem, KGEM_BLT);
1040	}
1041
1042	if (kgem->gen >= 0100) {
1043		cmd |= 8;
1044		do {
1045			int nbox_this_time, rem;
1046
1047			nbox_this_time = nbox;
1048			rem = kgem_batch_space(kgem);
1049			if (10*nbox_this_time > rem)
1050				nbox_this_time = rem / 8;
1051			if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc)
1052				nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2;
1053			assert(nbox_this_time);
1054			nbox -= nbox_this_time;
1055
1056			/* Count the total number of bytes to be read and allocate a
1057			 * single buffer large enough. Or if it is very small, combine
1058			 * with other allocations. */
1059			offset = 0;
1060			for (n = 0; n < nbox_this_time; n++) {
1061				int height = box[n].y2 - box[n].y1;
1062				int width = box[n].x2 - box[n].x1;
1063				offset += PITCH(width, dst->drawable.bitsPerPixel >> 3) * height;
1064			}
1065
1066			src_bo = kgem_create_buffer(kgem, offset,
1067						    KGEM_BUFFER_WRITE_INPLACE | (nbox ? KGEM_BUFFER_LAST : 0),
1068						    &ptr);
1069			if (!src_bo)
1070				break;
1071
1072			if (sigtrap_get() == 0) {
1073				offset = 0;
1074				do {
1075					int height = box->y2 - box->y1;
1076					int width = box->x2 - box->x1;
1077					int pitch = PITCH(width, dst->drawable.bitsPerPixel >> 3);
1078					uint32_t *b;
1079
1080					DBG(("  %s: box src=(%d, %d), dst=(%d, %d) size=(%d, %d), dst offset=%d, dst pitch=%d\n",
1081					     __FUNCTION__,
1082					     box->x1 + src_dx, box->y1 + src_dy,
1083					     box->x1 + dst_dx, box->y1 + dst_dy,
1084					     width, height,
1085					     offset, pitch));
1086
1087					assert(box->x1 + src_dx >= 0);
1088					assert((box->x2 + src_dx)*dst->drawable.bitsPerPixel <= 8*stride);
1089					assert(box->y1 + src_dy >= 0);
1090
1091					assert(box->x1 + dst_dx >= 0);
1092					assert(box->y1 + dst_dy >= 0);
1093
1094					memcpy_blt(src, (char *)ptr + offset,
1095						   dst->drawable.bitsPerPixel,
1096						   stride, pitch,
1097						   box->x1 + src_dx, box->y1 + src_dy,
1098						   0, 0,
1099						   width, height);
1100
1101					assert(kgem->mode == KGEM_BLT);
1102					b = kgem->batch + kgem->nbatch;
1103					b[0] = cmd;
1104					b[1] = br13;
1105					b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx);
1106					b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx);
1107					*(uint64_t *)(b+4) =
1108						kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo,
1109								 I915_GEM_DOMAIN_RENDER << 16 |
1110								 I915_GEM_DOMAIN_RENDER |
1111								 KGEM_RELOC_FENCED,
1112								 0);
1113					b[6] = 0;
1114					b[7] = pitch;
1115					*(uint64_t *)(b+8) =
1116						kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo,
1117								 I915_GEM_DOMAIN_RENDER << 16 |
1118								 KGEM_RELOC_FENCED,
1119								 offset);
1120					kgem->nbatch += 10;
1121
1122					box++;
1123					offset += pitch * height;
1124				} while (--nbox_this_time);
1125				assert(offset == __kgem_buffer_size(src_bo));
1126				sigtrap_put();
1127			}
1128
1129			if (nbox) {
1130				_kgem_submit(kgem);
1131				_kgem_set_mode(kgem, KGEM_BLT);
1132			}
1133
1134			kgem_bo_destroy(kgem, src_bo);
1135		} while (nbox);
1136	} else {
1137		cmd |= 6;
1138		do {
1139			int nbox_this_time, rem;
1140
1141			nbox_this_time = nbox;
1142			rem = kgem_batch_space(kgem);
1143			if (8*nbox_this_time > rem)
1144				nbox_this_time = rem / 8;
1145			if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc)
1146				nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2;
1147			assert(nbox_this_time);
1148			nbox -= nbox_this_time;
1149
1150			/* Count the total number of bytes to be read and allocate a
1151			 * single buffer large enough. Or if it is very small, combine
1152			 * with other allocations. */
1153			offset = 0;
1154			for (n = 0; n < nbox_this_time; n++) {
1155				int height = box[n].y2 - box[n].y1;
1156				int width = box[n].x2 - box[n].x1;
1157				offset += PITCH(width, dst->drawable.bitsPerPixel >> 3) * height;
1158			}
1159
1160			src_bo = kgem_create_buffer(kgem, offset,
1161						    KGEM_BUFFER_WRITE_INPLACE | (nbox ? KGEM_BUFFER_LAST : 0),
1162						    &ptr);
1163			if (!src_bo)
1164				break;
1165
1166			if (sigtrap_get()) {
1167				kgem_bo_destroy(kgem, src_bo);
1168				goto fallback;
1169			}
1170
1171			offset = 0;
1172			do {
1173				int height = box->y2 - box->y1;
1174				int width = box->x2 - box->x1;
1175				int pitch = PITCH(width, dst->drawable.bitsPerPixel >> 3);
1176				uint32_t *b;
1177
1178				DBG(("  %s: box src=(%d, %d), dst=(%d, %d) size=(%d, %d), dst offset=%d, dst pitch=%d\n",
1179				     __FUNCTION__,
1180				     box->x1 + src_dx, box->y1 + src_dy,
1181				     box->x1 + dst_dx, box->y1 + dst_dy,
1182				     width, height,
1183				     offset, pitch));
1184
1185				assert(box->x1 + src_dx >= 0);
1186				assert((box->x2 + src_dx)*dst->drawable.bitsPerPixel <= 8*stride);
1187				assert(box->y1 + src_dy >= 0);
1188
1189				assert(box->x1 + dst_dx >= 0);
1190				assert(box->y1 + dst_dy >= 0);
1191
1192				memcpy_blt(src, (char *)ptr + offset,
1193					   dst->drawable.bitsPerPixel,
1194					   stride, pitch,
1195					   box->x1 + src_dx, box->y1 + src_dy,
1196					   0, 0,
1197					   width, height);
1198
1199				assert(kgem->mode == KGEM_BLT);
1200				b = kgem->batch + kgem->nbatch;
1201				b[0] = cmd;
1202				b[1] = br13;
1203				b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx);
1204				b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx);
1205				b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo,
1206						      I915_GEM_DOMAIN_RENDER << 16 |
1207						      I915_GEM_DOMAIN_RENDER |
1208						      KGEM_RELOC_FENCED,
1209						      0);
1210				b[5] = 0;
1211				b[6] = pitch;
1212				b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo,
1213						      I915_GEM_DOMAIN_RENDER << 16 |
1214						      KGEM_RELOC_FENCED,
1215						      offset);
1216				kgem->nbatch += 8;
1217
1218				box++;
1219				offset += pitch * height;
1220			} while (--nbox_this_time);
1221			assert(offset == __kgem_buffer_size(src_bo));
1222			sigtrap_put();
1223
1224			if (nbox) {
1225				_kgem_submit(kgem);
1226				_kgem_set_mode(kgem, KGEM_BLT);
1227			}
1228
1229			kgem_bo_destroy(kgem, src_bo);
1230		} while (nbox);
1231	}
1232
1233	sna->blt_state.fill_bo = 0;
1234	return true;
1235
1236fallback:
1237	return write_boxes_inplace(kgem,
1238				   src, stride, dst->drawable.bitsPerPixel, src_dx, src_dy,
1239				   dst_bo, dst_dx, dst_dy,
1240				   box, nbox);
1241}
1242
1243static bool
1244write_boxes_inplace__xor(struct kgem *kgem,
1245			 const void *src, int stride, int bpp, int16_t src_dx, int16_t src_dy,
1246			 struct kgem_bo *bo, int16_t dst_dx, int16_t dst_dy,
1247			 const BoxRec *box, int n,
1248			 uint32_t and, uint32_t or)
1249{
1250	void *dst;
1251
1252	DBG(("%s x %d, tiling=%d\n", __FUNCTION__, n, bo->tiling));
1253
1254	if (!kgem_bo_can_map(kgem, bo))
1255		return false;
1256
1257	kgem_bo_submit(kgem, bo);
1258
1259	dst = kgem_bo_map(kgem, bo);
1260	if (dst == NULL)
1261		return false;
1262
1263	if (sigtrap_get())
1264		return false;
1265
1266	do {
1267		DBG(("%s: (%d, %d) -> (%d, %d) x (%d, %d) [bpp=%d, src_pitch=%d, dst_pitch=%d]\n", __FUNCTION__,
1268		     box->x1 + src_dx, box->y1 + src_dy,
1269		     box->x1 + dst_dx, box->y1 + dst_dy,
1270		     box->x2 - box->x1, box->y2 - box->y1,
1271		     bpp, stride, bo->pitch));
1272
1273		assert(box->x2 > box->x1);
1274		assert(box->y2 > box->y1);
1275
1276		assert(box->x1 + dst_dx >= 0);
1277		assert((box->x2 + dst_dx)*bpp <= 8*bo->pitch);
1278		assert(box->y1 + dst_dy >= 0);
1279		assert((box->y2 + dst_dy)*bo->pitch <= kgem_bo_size(bo));
1280
1281		assert(box->x1 + src_dx >= 0);
1282		assert((box->x2 + src_dx)*bpp <= 8*stride);
1283		assert(box->y1 + src_dy >= 0);
1284
1285		memcpy_xor(src, dst, bpp,
1286			   stride, bo->pitch,
1287			   box->x1 + src_dx, box->y1 + src_dy,
1288			   box->x1 + dst_dx, box->y1 + dst_dy,
1289			   box->x2 - box->x1, box->y2 - box->y1,
1290			   and, or);
1291		box++;
1292	} while (--n);
1293
1294	sigtrap_put();
1295	return true;
1296}
1297
1298static bool upload_inplace__xor(struct kgem *kgem,
1299				struct kgem_bo *bo,
1300				const BoxRec *box,
1301				int n, int bpp)
1302{
1303	if (unlikely(kgem->wedged))
1304		return true;
1305
1306	if (!kgem_bo_can_map(kgem, bo))
1307		return false;
1308
1309	return __upload_inplace(kgem, bo, box, n, bpp);
1310}
1311
1312bool sna_write_boxes__xor(struct sna *sna, PixmapPtr dst,
1313			  struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
1314			  const void *src, int stride, int16_t src_dx, int16_t src_dy,
1315			  const BoxRec *box, int nbox,
1316			  uint32_t and, uint32_t or)
1317{
1318	struct kgem *kgem = &sna->kgem;
1319	struct kgem_bo *src_bo;
1320	BoxRec extents;
1321	bool can_blt;
1322	void *ptr;
1323	int offset;
1324	int n, cmd, br13;
1325
1326	DBG(("%s x %d\n", __FUNCTION__, nbox));
1327
1328	if (upload_inplace__xor(kgem, dst_bo, box, nbox, dst->drawable.bitsPerPixel) &&
1329	    write_boxes_inplace__xor(kgem,
1330				     src, stride, dst->drawable.bitsPerPixel, src_dx, src_dy,
1331				     dst_bo, dst_dx, dst_dy,
1332				     box, nbox,
1333				     and, or))
1334		return true;
1335
1336	if (wedged(sna))
1337		return false;
1338
1339	can_blt = kgem_bo_can_blt(kgem, dst_bo) &&
1340		(box[0].x2 - box[0].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4);
1341	extents = box[0];
1342	for (n = 1; n < nbox; n++) {
1343		if (box[n].x1 < extents.x1)
1344			extents.x1 = box[n].x1;
1345		if (box[n].x2 > extents.x2)
1346			extents.x2 = box[n].x2;
1347
1348		if (can_blt)
1349			can_blt = (box[n].x2 - box[n].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4);
1350
1351		if (box[n].y1 < extents.y1)
1352			extents.y1 = box[n].y1;
1353		if (box[n].y2 > extents.y2)
1354			extents.y2 = box[n].y2;
1355	}
1356
1357	/* Try to avoid switching rings... */
1358	if (!can_blt || kgem->ring == KGEM_RENDER ||
1359	    upload_too_large(sna, extents.x2 - extents.x1, extents.y2 - extents.y1)) {
1360		DrawableRec tmp;
1361
1362		tmp.width  = extents.x2 - extents.x1;
1363		tmp.height = extents.y2 - extents.y1;
1364		tmp.depth  = dst->drawable.depth;
1365		tmp.bitsPerPixel = dst->drawable.bitsPerPixel;
1366
1367		assert(tmp.width);
1368		assert(tmp.height);
1369
1370		DBG(("%s: upload (%d, %d)x(%d, %d), max %dx%d\n",
1371		     __FUNCTION__,
1372		     extents.x1, extents.y1,
1373		     tmp.width, tmp.height,
1374		     sna->render.max_3d_size, sna->render.max_3d_size));
1375		if (must_tile(sna, tmp.width, tmp.height)) {
1376			BoxRec tile, stack[64], *clipped;
1377			int step;
1378
1379tile:
1380			step = MIN(sna->render.max_3d_size - 4096 / dst->drawable.bitsPerPixel,
1381				   8*(MAXSHORT&~63) / dst->drawable.bitsPerPixel);
1382			while (step * step * 4 > sna->kgem.max_upload_tile_size)
1383				step /= 2;
1384
1385			DBG(("%s: tiling upload, using %dx%d tiles\n",
1386			     __FUNCTION__, step, step));
1387			assert(step);
1388
1389			if (n > ARRAY_SIZE(stack)) {
1390				clipped = malloc(sizeof(BoxRec) * n);
1391				if (clipped == NULL)
1392					goto fallback;
1393			} else
1394				clipped = stack;
1395
1396			for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) {
1397				int y2 = tile.y1 + step;
1398				if (y2 > extents.y2)
1399					y2 = extents.y2;
1400				tile.y2 = y2;
1401
1402				for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) {
1403					int x2 = tile.x1 + step;
1404					if (x2 > extents.x2)
1405						x2 = extents.x2;
1406					tile.x2 = x2;
1407
1408					tmp.width  = tile.x2 - tile.x1;
1409					tmp.height = tile.y2 - tile.y1;
1410
1411					src_bo = kgem_create_buffer_2d(kgem,
1412								       tmp.width,
1413								       tmp.height,
1414								       tmp.bitsPerPixel,
1415								       KGEM_BUFFER_WRITE_INPLACE,
1416								       &ptr);
1417					if (!src_bo) {
1418						if (clipped != stack)
1419							free(clipped);
1420						goto fallback;
1421					}
1422
1423					if (sigtrap_get() == 0) {
1424						BoxRec *c = clipped;
1425						for (n = 0; n < nbox; n++) {
1426							*c = box[n];
1427							if (!box_intersect(c, &tile))
1428								continue;
1429
1430							DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n",
1431							     __FUNCTION__,
1432							     c->x1, c->y1,
1433							     c->x2, c->y2,
1434							     src_dx, src_dy,
1435							     c->x1 - tile.x1,
1436							     c->y1 - tile.y1));
1437							memcpy_xor(src, ptr, tmp.bitsPerPixel,
1438								   stride, src_bo->pitch,
1439								   c->x1 + src_dx,
1440								   c->y1 + src_dy,
1441								   c->x1 - tile.x1,
1442								   c->y1 - tile.y1,
1443								   c->x2 - c->x1,
1444								   c->y2 - c->y1,
1445								   and, or);
1446							c++;
1447						}
1448
1449						if (c != clipped)
1450							n = sna->render.copy_boxes(sna, GXcopy,
1451										   &tmp, src_bo, -tile.x1, -tile.y1,
1452										   &dst->drawable, dst_bo, dst_dx, dst_dy,
1453										   clipped, c - clipped, 0);
1454						else
1455							n = 1;
1456
1457						sigtrap_put();
1458					} else
1459						n = 0;
1460
1461					kgem_bo_destroy(&sna->kgem, src_bo);
1462
1463					if (!n) {
1464						if (clipped != stack)
1465							free(clipped);
1466						goto fallback;
1467					}
1468				}
1469			}
1470
1471			if (clipped != stack)
1472				free(clipped);
1473		} else {
1474			src_bo = kgem_create_buffer_2d(kgem,
1475						       tmp.width,
1476						       tmp.height,
1477						       tmp.bitsPerPixel,
1478						       KGEM_BUFFER_WRITE_INPLACE,
1479						       &ptr);
1480			if (!src_bo)
1481				goto fallback;
1482
1483			if (sigtrap_get() == 0) {
1484				for (n = 0; n < nbox; n++) {
1485					DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n",
1486					     __FUNCTION__,
1487					     box[n].x1, box[n].y1,
1488					     box[n].x2, box[n].y2,
1489					     src_dx, src_dy,
1490					     box[n].x1 - extents.x1,
1491					     box[n].y1 - extents.y1));
1492					memcpy_xor(src, ptr, tmp.bitsPerPixel,
1493						   stride, src_bo->pitch,
1494						   box[n].x1 + src_dx,
1495						   box[n].y1 + src_dy,
1496						   box[n].x1 - extents.x1,
1497						   box[n].y1 - extents.y1,
1498						   box[n].x2 - box[n].x1,
1499						   box[n].y2 - box[n].y1,
1500						   and, or);
1501				}
1502
1503				n = sna->render.copy_boxes(sna, GXcopy,
1504							   &tmp, src_bo, -extents.x1, -extents.y1,
1505							   &dst->drawable, dst_bo, dst_dx, dst_dy,
1506							   box, nbox, 0);
1507				sigtrap_put();
1508			} else
1509				n = 0;
1510
1511			kgem_bo_destroy(&sna->kgem, src_bo);
1512
1513			if (!n)
1514				goto tile;
1515		}
1516
1517		return true;
1518	}
1519
1520	cmd = XY_SRC_COPY_BLT_CMD;
1521	br13 = dst_bo->pitch;
1522	if (kgem->gen >= 040 && dst_bo->tiling) {
1523		cmd |= BLT_DST_TILED;
1524		br13 >>= 2;
1525	}
1526	br13 |= 0xcc << 16;
1527	switch (dst->drawable.bitsPerPixel) {
1528	default:
1529	case 32: cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB;
1530		 br13 |= 1 << 25; /* RGB8888 */
1531	case 16: br13 |= 1 << 24; /* RGB565 */
1532	case 8: break;
1533	}
1534
1535	kgem_set_mode(kgem, KGEM_BLT, dst_bo);
1536	if (!kgem_check_batch(kgem, 10) ||
1537	    !kgem_check_reloc_and_exec(kgem, 2) ||
1538	    !kgem_check_bo_fenced(kgem, dst_bo)) {
1539		kgem_submit(kgem);
1540		if (!kgem_check_bo_fenced(kgem, dst_bo))
1541			goto fallback;
1542		_kgem_set_mode(kgem, KGEM_BLT);
1543	}
1544
1545	if (sna->kgem.gen >= 0100) {
1546		cmd |= 8;
1547		do {
1548			int nbox_this_time, rem;
1549
1550			nbox_this_time = nbox;
1551			rem = kgem_batch_space(kgem);
1552			if (10*nbox_this_time > rem)
1553				nbox_this_time = rem / 8;
1554			if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc)
1555				nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2;
1556			assert(nbox_this_time);
1557			nbox -= nbox_this_time;
1558
1559			/* Count the total number of bytes to be read and allocate a
1560			 * single buffer large enough. Or if it is very small, combine
1561			 * with other allocations. */
1562			offset = 0;
1563			for (n = 0; n < nbox_this_time; n++) {
1564				int height = box[n].y2 - box[n].y1;
1565				int width = box[n].x2 - box[n].x1;
1566				offset += PITCH(width, dst->drawable.bitsPerPixel >> 3) * height;
1567			}
1568
1569			src_bo = kgem_create_buffer(kgem, offset,
1570						    KGEM_BUFFER_WRITE_INPLACE | (nbox ? KGEM_BUFFER_LAST : 0),
1571						    &ptr);
1572			if (!src_bo)
1573				goto fallback;
1574
1575			if (sigtrap_get()) {
1576				kgem_bo_destroy(kgem, src_bo);
1577				goto fallback;
1578			}
1579
1580			offset = 0;
1581			do {
1582				int height = box->y2 - box->y1;
1583				int width = box->x2 - box->x1;
1584				int pitch = PITCH(width, dst->drawable.bitsPerPixel >> 3);
1585				uint32_t *b;
1586
1587				DBG(("  %s: box src=(%d, %d), dst=(%d, %d) size=(%d, %d), dst offset=%d, dst pitch=%d\n",
1588				     __FUNCTION__,
1589				     box->x1 + src_dx, box->y1 + src_dy,
1590				     box->x1 + dst_dx, box->y1 + dst_dy,
1591				     width, height,
1592				     offset, pitch));
1593
1594				assert(box->x1 + src_dx >= 0);
1595				assert((box->x2 + src_dx)*dst->drawable.bitsPerPixel <= 8*stride);
1596				assert(box->y1 + src_dy >= 0);
1597
1598				assert(box->x1 + dst_dx >= 0);
1599				assert(box->y1 + dst_dy >= 0);
1600
1601				memcpy_xor(src, (char *)ptr + offset,
1602					   dst->drawable.bitsPerPixel,
1603					   stride, pitch,
1604					   box->x1 + src_dx, box->y1 + src_dy,
1605					   0, 0,
1606					   width, height,
1607					   and, or);
1608
1609				assert(kgem->mode == KGEM_BLT);
1610				b = kgem->batch + kgem->nbatch;
1611				b[0] = cmd;
1612				b[1] = br13;
1613				b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx);
1614				b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx);
1615				*(uint64_t *)(b+4) =
1616					kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo,
1617							 I915_GEM_DOMAIN_RENDER << 16 |
1618							 I915_GEM_DOMAIN_RENDER |
1619							 KGEM_RELOC_FENCED,
1620							 0);
1621				b[6] = 0;
1622				b[7] = pitch;
1623				*(uint64_t *)(b+8) =
1624					kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo,
1625							 I915_GEM_DOMAIN_RENDER << 16 |
1626							 KGEM_RELOC_FENCED,
1627							 offset);
1628				kgem->nbatch += 10;
1629
1630				box++;
1631				offset += pitch * height;
1632			} while (--nbox_this_time);
1633			assert(offset == __kgem_buffer_size(src_bo));
1634			sigtrap_put();
1635
1636			if (nbox) {
1637				_kgem_submit(kgem);
1638				_kgem_set_mode(kgem, KGEM_BLT);
1639			}
1640
1641			kgem_bo_destroy(kgem, src_bo);
1642		} while (nbox);
1643	} else {
1644		cmd |= 6;
1645		do {
1646			int nbox_this_time, rem;
1647
1648			nbox_this_time = nbox;
1649			rem = kgem_batch_space(kgem);
1650			if (8*nbox_this_time > rem)
1651				nbox_this_time = rem / 8;
1652			if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc)
1653				nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2;
1654			assert(nbox_this_time);
1655			nbox -= nbox_this_time;
1656
1657			/* Count the total number of bytes to be read and allocate a
1658			 * single buffer large enough. Or if it is very small, combine
1659			 * with other allocations. */
1660			offset = 0;
1661			for (n = 0; n < nbox_this_time; n++) {
1662				int height = box[n].y2 - box[n].y1;
1663				int width = box[n].x2 - box[n].x1;
1664				offset += PITCH(width, dst->drawable.bitsPerPixel >> 3) * height;
1665			}
1666
1667			src_bo = kgem_create_buffer(kgem, offset,
1668						    KGEM_BUFFER_WRITE_INPLACE | (nbox ? KGEM_BUFFER_LAST : 0),
1669						    &ptr);
1670			if (!src_bo)
1671				goto fallback;
1672
1673			if (sigtrap_get()) {
1674				kgem_bo_destroy(kgem, src_bo);
1675				goto fallback;
1676			}
1677
1678			offset = 0;
1679			do {
1680				int height = box->y2 - box->y1;
1681				int width = box->x2 - box->x1;
1682				int pitch = PITCH(width, dst->drawable.bitsPerPixel >> 3);
1683				uint32_t *b;
1684
1685				DBG(("  %s: box src=(%d, %d), dst=(%d, %d) size=(%d, %d), dst offset=%d, dst pitch=%d\n",
1686				     __FUNCTION__,
1687				     box->x1 + src_dx, box->y1 + src_dy,
1688				     box->x1 + dst_dx, box->y1 + dst_dy,
1689				     width, height,
1690				     offset, pitch));
1691
1692				assert(box->x1 + src_dx >= 0);
1693				assert((box->x2 + src_dx)*dst->drawable.bitsPerPixel <= 8*stride);
1694				assert(box->y1 + src_dy >= 0);
1695
1696				assert(box->x1 + dst_dx >= 0);
1697				assert(box->y1 + dst_dy >= 0);
1698
1699				memcpy_xor(src, (char *)ptr + offset,
1700					   dst->drawable.bitsPerPixel,
1701					   stride, pitch,
1702					   box->x1 + src_dx, box->y1 + src_dy,
1703					   0, 0,
1704					   width, height,
1705					   and, or);
1706
1707				assert(kgem->mode == KGEM_BLT);
1708				b = kgem->batch + kgem->nbatch;
1709				b[0] = cmd;
1710				b[1] = br13;
1711				b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx);
1712				b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx);
1713				b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo,
1714						      I915_GEM_DOMAIN_RENDER << 16 |
1715						      I915_GEM_DOMAIN_RENDER |
1716						      KGEM_RELOC_FENCED,
1717						      0);
1718				b[5] = 0;
1719				b[6] = pitch;
1720				b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo,
1721						      I915_GEM_DOMAIN_RENDER << 16 |
1722						      KGEM_RELOC_FENCED,
1723						      offset);
1724				kgem->nbatch += 8;
1725
1726				box++;
1727				offset += pitch * height;
1728			} while (--nbox_this_time);
1729			assert(offset == __kgem_buffer_size(src_bo));
1730			sigtrap_put();
1731
1732			if (nbox) {
1733				_kgem_submit(kgem);
1734				_kgem_set_mode(kgem, KGEM_BLT);
1735			}
1736
1737			kgem_bo_destroy(kgem, src_bo);
1738		} while (nbox);
1739	}
1740
1741	sna->blt_state.fill_bo = 0;
1742	return true;
1743
1744fallback:
1745	return write_boxes_inplace__xor(kgem,
1746					src, stride, dst->drawable.bitsPerPixel, src_dx, src_dy,
1747					dst_bo, dst_dx, dst_dy,
1748					box, nbox,
1749					and, or);
1750}
1751
1752static bool
1753indirect_replace(struct sna *sna,
1754		 PixmapPtr pixmap,
1755		 struct kgem_bo *bo,
1756		 const void *src, int stride)
1757{
1758	struct kgem *kgem = &sna->kgem;
1759	struct kgem_bo *src_bo;
1760	BoxRec box;
1761	void *ptr;
1762	bool ret;
1763
1764	DBG(("%s: size=%d vs %d\n",
1765	     __FUNCTION__,
1766	     stride * pixmap->drawable.height >> 12,
1767	     kgem->half_cpu_cache_pages));
1768
1769	if (stride * pixmap->drawable.height >> 12 > kgem->half_cpu_cache_pages)
1770		return false;
1771
1772	if (!kgem_bo_can_blt(kgem, bo) &&
1773	    must_tile(sna, pixmap->drawable.width, pixmap->drawable.height))
1774		return false;
1775
1776	src_bo = kgem_create_buffer_2d(kgem,
1777				       pixmap->drawable.width,
1778				       pixmap->drawable.height,
1779				       pixmap->drawable.bitsPerPixel,
1780				       KGEM_BUFFER_WRITE_INPLACE,
1781				       &ptr);
1782	if (!src_bo)
1783		return false;
1784
1785	ret = false;
1786	if (sigtrap_get() == 0) {
1787		memcpy_blt(src, ptr, pixmap->drawable.bitsPerPixel,
1788			   stride, src_bo->pitch,
1789			   0, 0,
1790			   0, 0,
1791			   pixmap->drawable.width,
1792			   pixmap->drawable.height);
1793
1794		box.x1 = box.y1 = 0;
1795		box.x2 = pixmap->drawable.width;
1796		box.y2 = pixmap->drawable.height;
1797
1798		ret = sna->render.copy_boxes(sna, GXcopy,
1799					     &pixmap->drawable, src_bo, 0, 0,
1800					     &pixmap->drawable, bo, 0, 0,
1801					     &box, 1, 0);
1802		sigtrap_put();
1803	}
1804
1805	kgem_bo_destroy(kgem, src_bo);
1806
1807	return ret;
1808}
1809
1810bool sna_replace(struct sna *sna, PixmapPtr pixmap,
1811		 const void *src, int stride)
1812{
1813	struct sna_pixmap *priv = sna_pixmap(pixmap);
1814	struct kgem_bo *bo = priv->gpu_bo;
1815	void *dst;
1816
1817	assert(bo);
1818	DBG(("%s(handle=%d, %dx%d, bpp=%d, tiling=%d) busy?=%d\n",
1819	     __FUNCTION__, bo->handle,
1820	     pixmap->drawable.width,
1821	     pixmap->drawable.height,
1822	     pixmap->drawable.bitsPerPixel,
1823	     bo->tiling,
1824	     __kgem_bo_is_busy(&sna->kgem, bo)));
1825
1826	assert(!priv->pinned);
1827
1828	kgem_bo_undo(&sna->kgem, bo);
1829
1830	if (__kgem_bo_is_busy(&sna->kgem, bo)) {
1831		struct kgem_bo *new_bo;
1832
1833		if (indirect_replace(sna, pixmap, bo, src, stride))
1834			return true;
1835
1836		new_bo = kgem_create_2d(&sna->kgem,
1837					pixmap->drawable.width,
1838					pixmap->drawable.height,
1839					pixmap->drawable.bitsPerPixel,
1840					bo->tiling,
1841					CREATE_GTT_MAP | CREATE_INACTIVE);
1842		if (new_bo)
1843			bo = new_bo;
1844	}
1845
1846	if (bo->tiling == I915_TILING_NONE && bo->pitch == stride &&
1847	    kgem_bo_write(&sna->kgem, bo, src,
1848			  (pixmap->drawable.height-1)*stride + pixmap->drawable.width*pixmap->drawable.bitsPerPixel/8))
1849			goto done;
1850
1851	if (upload_inplace__tiled(&sna->kgem, bo)) {
1852		BoxRec box;
1853
1854		box.x1 = box.y1 = 0;
1855		box.x2 = pixmap->drawable.width;
1856		box.y2 = pixmap->drawable.height;
1857
1858		if (write_boxes_inplace__tiled(&sna->kgem, src,
1859					       stride, pixmap->drawable.bitsPerPixel, 0, 0,
1860					       bo, 0, 0, &box, 1))
1861			goto done;
1862	}
1863
1864	if (kgem_bo_can_map(&sna->kgem, bo) &&
1865	    (dst = kgem_bo_map(&sna->kgem, bo)) != NULL &&
1866	    sigtrap_get() == 0) {
1867		memcpy_blt(src, dst, pixmap->drawable.bitsPerPixel,
1868			   stride, bo->pitch,
1869			   0, 0,
1870			   0, 0,
1871			   pixmap->drawable.width,
1872			   pixmap->drawable.height);
1873		sigtrap_put();
1874	} else {
1875		BoxRec box;
1876
1877		if (bo != priv->gpu_bo) {
1878			kgem_bo_destroy(&sna->kgem, bo);
1879			bo = priv->gpu_bo;
1880		}
1881
1882		box.x1 = box.y1 = 0;
1883		box.x2 = pixmap->drawable.width;
1884		box.y2 = pixmap->drawable.height;
1885
1886		if (!sna_write_boxes(sna, pixmap,
1887				     bo, 0, 0,
1888				     src, stride, 0, 0,
1889				     &box, 1))
1890			return false;
1891	}
1892
1893done:
1894	if (bo != priv->gpu_bo) {
1895		sna_pixmap_unmap(pixmap, priv);
1896		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1897		priv->gpu_bo = bo;
1898	}
1899
1900	return true;
1901}
1902
1903bool
1904sna_replace__xor(struct sna *sna, PixmapPtr pixmap,
1905		 const void *src, int stride,
1906		 uint32_t and, uint32_t or)
1907{
1908	struct sna_pixmap *priv = sna_pixmap(pixmap);
1909	struct kgem_bo *bo = priv->gpu_bo;
1910	void *dst;
1911
1912	DBG(("%s(handle=%d, %dx%d, bpp=%d, tiling=%d)\n",
1913	     __FUNCTION__, bo->handle,
1914	     pixmap->drawable.width,
1915	     pixmap->drawable.height,
1916	     pixmap->drawable.bitsPerPixel,
1917	     bo->tiling));
1918
1919	assert(!priv->pinned);
1920
1921	kgem_bo_undo(&sna->kgem, bo);
1922
1923	if (!kgem_bo_can_map(&sna->kgem, bo) ||
1924	    __kgem_bo_is_busy(&sna->kgem, bo)) {
1925		struct kgem_bo *new_bo;
1926
1927		new_bo = kgem_create_2d(&sna->kgem,
1928					pixmap->drawable.width,
1929					pixmap->drawable.height,
1930					pixmap->drawable.bitsPerPixel,
1931					bo->tiling,
1932					CREATE_GTT_MAP | CREATE_INACTIVE);
1933		if (new_bo)
1934			bo = new_bo;
1935	}
1936
1937	if (kgem_bo_can_map(&sna->kgem, bo) &&
1938	    (dst = kgem_bo_map(&sna->kgem, bo)) != NULL &&
1939	    sigtrap_get() == 0) {
1940		memcpy_xor(src, dst, pixmap->drawable.bitsPerPixel,
1941			   stride, bo->pitch,
1942			   0, 0,
1943			   0, 0,
1944			   pixmap->drawable.width,
1945			   pixmap->drawable.height,
1946			   and, or);
1947		sigtrap_put();
1948	} else {
1949		BoxRec box;
1950
1951		if (bo != priv->gpu_bo) {
1952			kgem_bo_destroy(&sna->kgem, bo);
1953			bo = priv->gpu_bo;
1954		}
1955
1956		box.x1 = box.y1 = 0;
1957		box.x2 = pixmap->drawable.width;
1958		box.y2 = pixmap->drawable.height;
1959
1960		if (!sna_write_boxes__xor(sna, pixmap,
1961					  bo, 0, 0,
1962					  src, stride, 0, 0,
1963					  &box, 1,
1964					  and, or))
1965			return false;
1966	}
1967
1968	if (bo != priv->gpu_bo) {
1969		sna_pixmap_unmap(pixmap, priv);
1970		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1971		priv->gpu_bo = bo;
1972	}
1973
1974	return true;
1975}
1976