sna_accel.c revision a7f02474
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_reg.h"
34#include "sna_video.h"
35#include "rop.h"
36
37#include "intel_options.h"
38
39#include <X11/fonts/font.h>
40#include <X11/fonts/fontstruct.h>
41#undef FontSetPrivate
42
43#include <dixfontstr.h>
44
45#include <mi.h>
46#include <migc.h>
47#include <miline.h>
48#include <micmap.h>
49#ifdef RENDER
50#include <mipict.h>
51#endif
52#include <shmint.h>
53
54#include <X11/extensions/damageproto.h>
55
56#include <sys/time.h>
57#include <sys/mman.h>
58#include <sys/ioctl.h>
59#include <unistd.h>
60
61#ifdef HAVE_VALGRIND
62#include <valgrind.h>
63#include <memcheck.h>
64#endif
65
66#define FAULT_INJECTION 0
67
68#define FORCE_INPLACE 0
69#define FORCE_FALLBACK 0
70#define FORCE_FLUSH 0
71#define FORCE_FULL_SYNC 0 /* https://bugs.freedesktop.org/show_bug.cgi?id=61628 */
72
73#define DEFAULT_PIXMAP_TILING I915_TILING_X
74#define DEFAULT_SCANOUT_TILING I915_TILING_X
75
76#define USE_INPLACE 1
77#define USE_SPANS 0 /* -1 force CPU, 1 force GPU */
78#define USE_CPU_BO 1
79#define USE_USERPTR_UPLOADS 1
80#define USE_USERPTR_DOWNLOADS 1
81#define USE_COW 1
82#define UNDO 1
83
84#define MIGRATE_ALL 0
85#define DBG_NO_PARTIAL_MOVE_TO_CPU 0
86#define DBG_NO_CPU_UPLOAD 0
87#define DBG_NO_CPU_DOWNLOAD 0
88
89#define ACCEL_FILL_SPANS 1
90#define ACCEL_SET_SPANS 1
91#define ACCEL_PUT_IMAGE 1
92#define ACCEL_GET_IMAGE 1
93#define ACCEL_COPY_AREA 1
94#define ACCEL_COPY_PLANE 1
95#define ACCEL_COPY_WINDOW 1
96#define ACCEL_POLY_POINT 1
97#define ACCEL_POLY_LINE 1
98#define ACCEL_POLY_SEGMENT 1
99#define ACCEL_POLY_RECTANGLE 1
100#define ACCEL_POLY_ARC 1
101#define ACCEL_POLY_FILL_POLYGON 1
102#define ACCEL_POLY_FILL_RECT 1
103#define ACCEL_POLY_FILL_ARC 1
104#define ACCEL_POLY_TEXT8 1
105#define ACCEL_POLY_TEXT16 1
106#define ACCEL_POLY_GLYPH 1
107#define ACCEL_IMAGE_TEXT8 1
108#define ACCEL_IMAGE_TEXT16 1
109#define ACCEL_IMAGE_GLYPH 1
110#define ACCEL_PUSH_PIXELS 1
111
112#define NO_TILE_8x8 0
113#define NO_STIPPLE_8x8 0
114
115#define IS_COW_OWNER(ptr) ((uintptr_t)(ptr) & 1)
116#define MAKE_COW_OWNER(ptr) ((void*)((uintptr_t)(ptr) | 1))
117#define COW(ptr) (void *)((uintptr_t)(ptr) & ~1)
118
119#define IS_CLIPPED	0x2
120#define RECTILINEAR	0x4
121#define OVERWRITES	0x8
122
123#if XFONT2_CLIENT_FUNCS_VERSION >= 1
124#define AllocateFontPrivateIndex() xfont2_allocate_font_private_index()
125#define FontSetPrivate(font, idx, data) xfont2_font_set_private(font, idx, data)
126#endif
127
128#if 0
129static void __sna_fallback_flush(DrawablePtr d)
130{
131	PixmapPtr pixmap = get_drawable_pixmap(d);
132	struct sna *sna = to_sna_from_pixmap(pixmap);
133	struct sna_pixmap *priv;
134	BoxRec box;
135	PixmapPtr tmp;
136	int i, j;
137	char *src, *dst;
138
139	DBG(("%s: uploading CPU damage...\n", __FUNCTION__));
140	priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ);
141	if (priv == NULL)
142		return;
143
144	DBG(("%s: downloading GPU damage...\n", __FUNCTION__));
145	if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
146		return;
147
148	box.x1 = box.y1 = 0;
149	box.x2 = pixmap->drawable.width;
150	box.y2 = pixmap->drawable.height;
151
152	tmp = sna_pixmap_create_unattached(pixmap->drawable.pScreen,
153					   pixmap->drawable.width,
154					   pixmap->drawable.height,
155					   pixmap->drawable.depth,
156					   0);
157
158	DBG(("%s: comparing with direct read...\n", __FUNCTION__));
159	sna_read_boxes(sna, tmp, priv->gpu_bo, &box, 1);
160
161	src = pixmap->devPrivate.ptr;
162	dst = tmp->devPrivate.ptr;
163	for (i = 0; i < tmp->drawable.height; i++) {
164		if (memcmp(src, dst, tmp->drawable.width * tmp->drawable.bitsPerPixel >> 3)) {
165			for (j = 0; src[j] == dst[j]; j++)
166				;
167			ERR(("mismatch at (%d, %d)\n",
168			     8*j / tmp->drawable.bitsPerPixel, i));
169			abort();
170		}
171		src += pixmap->devKind;
172		dst += tmp->devKind;
173	}
174	tmp->drawable.pScreen->DestroyPixmap(tmp);
175}
176#define FALLBACK_FLUSH(d) __sna_fallback_flush(d)
177#else
178#define FALLBACK_FLUSH(d)
179#endif
180
181static int sna_font_key;
182
183static const uint8_t copy_ROP[] = {
184	ROP_0,		/* GXclear */
185	ROP_DSa,	/* GXand */
186	ROP_SDna,	/* GXandReverse */
187	ROP_S,		/* GXcopy */
188	ROP_DSna,	/* GXandInverted */
189	ROP_D,		/* GXnoop */
190	ROP_DSx,	/* GXxor */
191	ROP_DSo,	/* GXor */
192	ROP_DSon,	/* GXnor */
193	ROP_DSxn,	/* GXequiv */
194	ROP_Dn,		/* GXinvert */
195	ROP_SDno,	/* GXorReverse */
196	ROP_Sn,		/* GXcopyInverted */
197	ROP_DSno,	/* GXorInverted */
198	ROP_DSan,	/* GXnand */
199	ROP_1		/* GXset */
200};
201static const uint8_t fill_ROP[] = {
202	ROP_0,
203	ROP_DPa,
204	ROP_PDna,
205	ROP_P,
206	ROP_DPna,
207	ROP_D,
208	ROP_DPx,
209	ROP_DPo,
210	ROP_DPon,
211	ROP_PDxn,
212	ROP_Dn,
213	ROP_PDno,
214	ROP_Pn,
215	ROP_DPno,
216	ROP_DPan,
217	ROP_1
218};
219
220static const GCOps sna_gc_ops;
221static const GCOps sna_gc_ops__cpu;
222static GCOps sna_gc_ops__tmp;
223static const GCFuncs sna_gc_funcs;
224static const GCFuncs sna_gc_funcs__cpu;
225
226static void sna_shm_watch_flush(struct sna *sna, int enable);
227static void
228sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect);
229
230static inline void region_set(RegionRec *r, const BoxRec *b)
231{
232	r->extents = *b;
233	r->data = NULL;
234}
235
236static inline bool region_maybe_clip(RegionRec *r, RegionRec *clip)
237{
238	if (clip->data && !RegionIntersect(r, r, clip))
239		return false;
240
241	return !box_empty(&r->extents);
242}
243
244static inline bool region_is_singular(const RegionRec *r)
245{
246	return r->data == NULL;
247}
248
249static inline bool region_is_unclipped(const RegionRec *r, int w, int h)
250{
251	return (region_is_singular(r) &&
252		w == r->extents.x2 - r->extents.x1 &&
253		h == r->extents.y2 - r->extents.y1);
254}
255
256typedef struct box32 {
257	int32_t x1, y1, x2, y2;
258} Box32Rec;
259
260#define PM_IS_SOLID(_draw, _pm) \
261	(((_pm) & FbFullMask((_draw)->depth)) == FbFullMask((_draw)->depth))
262
263#ifndef NDEBUG
264static void _assert_pixmap_contains_box(PixmapPtr pixmap, const BoxRec *box, const char *function)
265{
266	if (box->x1 < 0 || box->y1 < 0 ||
267	    box->x2 > pixmap->drawable.width ||
268	    box->y2 > pixmap->drawable.height)
269	{
270		FatalError("%s: damage box [(%d, %d), (%d, %d)] is beyond the pixmap=%ld size=%dx%d\n",
271			   function, box->x1, box->y1, box->x2, box->y2,
272			   pixmap->drawable.serialNumber,
273			   pixmap->drawable.width,
274			   pixmap->drawable.height);
275	}
276}
277
278static void
279_assert_pixmap_contains_damage(PixmapPtr pixmap, struct sna_damage *damage, const char *function)
280{
281	if (damage == NULL)
282		return;
283
284	_assert_pixmap_contains_box(pixmap, &DAMAGE_PTR(damage)->extents, function);
285}
286#define assert_pixmap_contains_damage(p,d) _assert_pixmap_contains_damage(p, d, __FUNCTION__)
287#else
288#define assert_pixmap_contains_damage(p,d)
289#endif
290
291#define __assert_pixmap_damage(p) do { \
292	struct sna_pixmap *priv__ = sna_pixmap(p); \
293	if (priv__) { \
294		assert(priv__->gpu_damage == NULL || priv__->gpu_bo); \
295		assert(priv__->gpu_bo == NULL || priv__->gpu_bo->refcnt); \
296		assert(priv__->cpu_bo == NULL || priv__->cpu_bo->refcnt); \
297		assert_pixmap_contains_damage(p, priv__->gpu_damage); \
298		assert_pixmap_contains_damage(p, priv__->cpu_damage); \
299		assert_pixmap_map(p, priv__); \
300	} \
301} while (0)
302
303#ifdef DEBUG_PIXMAP
304static void _assert_pixmap_contains_box_with_offset(PixmapPtr pixmap, const BoxRec *box, int dx, int dy, const char *function)
305{
306	BoxRec b = *box;
307	b.x1 += dx; b.x2 += dx;
308	b.y1 += dy; b.y2 += dy;
309	_assert_pixmap_contains_box(pixmap, &b, function);
310}
311
312static void _assert_pixmap_contains_boxes(PixmapPtr pixmap, const BoxRec *box, int n, int dx, int dy, const char *function)
313{
314	BoxRec extents;
315
316	extents = *box;
317	while (--n) {
318		++box;
319
320		if (box->x1 < extents.x1)
321			extents.x1 = box->x1;
322		if (box->x2 > extents.x2)
323			extents.x2 = box->x2;
324
325		if (box->y1 < extents.y1)
326			extents.y1 = box->y1;
327		if (box->y2 > extents.y2)
328			extents.y2 = box->y2;
329	}
330	extents.x1 += dx;
331	extents.x2 += dx;
332	extents.y1 += dy;
333	extents.y2 += dy;
334	_assert_pixmap_contains_box(pixmap, &extents, function);
335}
336
337
338static void _assert_pixmap_contains_points(PixmapPtr pixmap, const DDXPointRec *pt, int n, int dx, int dy, const char *function)
339{
340	BoxRec extents;
341
342	extents.x2 = extents.x1 = pt->x;
343	extents.y2 = extents.y1 = pt->y;
344	while (--n) {
345		++pt;
346
347		if (pt->x < extents.x1)
348			extents.x1 = pt->x;
349		else if (pt->x > extents.x2)
350			extents.x2 = pt->x;
351
352		if (pt->y < extents.y1)
353			extents.y1 = pt->y;
354		else if (pt->y > extents.y2)
355			extents.y2 = pt->y;
356	}
357	extents.x1 += dx;
358	extents.x2 += dx + 1;
359	extents.y1 += dy;
360	extents.y2 += dy + 1;
361	_assert_pixmap_contains_box(pixmap, &extents, function);
362}
363
364static void _assert_drawable_contains_box(DrawablePtr drawable, const BoxRec *box, const char *function)
365{
366	if (box->x1 < drawable->x ||
367	    box->y1 < drawable->y ||
368	    box->x2 > drawable->x + drawable->width ||
369	    box->y2 > drawable->y + drawable->height)
370	{
371		FatalError("%s: damage box is beyond the drawable: box=(%d, %d), (%d, %d), drawable=(%d, %d)x(%d, %d)\n",
372			   function,
373			   box->x1, box->y1, box->x2, box->y2,
374			   drawable->x, drawable->y,
375			   drawable->width, drawable->height);
376	}
377}
378
379static void assert_pixmap_damage(PixmapPtr p)
380{
381	struct sna_pixmap *priv;
382	RegionRec reg, cpu, gpu;
383
384	priv = sna_pixmap(p);
385	if (priv == NULL)
386		return;
387
388	__assert_pixmap_damage(p);
389
390	if (priv->clear) {
391		assert(DAMAGE_IS_ALL(priv->gpu_damage));
392		assert(priv->cpu_damage == NULL);
393	}
394
395	if (DAMAGE_IS_ALL(priv->gpu_damage) && DAMAGE_IS_ALL(priv->cpu_damage)) {
396		/* special upload buffer */
397		assert(priv->gpu_bo && priv->gpu_bo->proxy);
398		assert(priv->cpu_bo == NULL);
399		return;
400	}
401
402	assert(!DAMAGE_IS_ALL(priv->gpu_damage) || priv->cpu_damage == NULL);
403	assert(!DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL);
404
405	/* Avoid reducing damage to minimise interferrence */
406	RegionNull(&reg);
407	RegionNull(&gpu);
408	RegionNull(&cpu);
409
410	if (priv->gpu_damage)
411		_sna_damage_debug_get_region(DAMAGE_PTR(priv->gpu_damage), &gpu);
412
413	if (priv->cpu_damage)
414		_sna_damage_debug_get_region(DAMAGE_PTR(priv->cpu_damage), &cpu);
415
416	RegionIntersect(&reg, &cpu, &gpu);
417	assert(RegionNil(&reg));
418
419	RegionUninit(&reg);
420	RegionUninit(&gpu);
421	RegionUninit(&cpu);
422}
423
424#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__)
425#define assert_pixmap_contains_box_with_offset(p, b, dx, dy) _assert_pixmap_contains_box_with_offset(p, b, dx, dy, __FUNCTION__)
426#define assert_drawable_contains_box(d, b) _assert_drawable_contains_box(d, b, __FUNCTION__)
427#define assert_pixmap_contains_boxes(p, b, n, x, y) _assert_pixmap_contains_boxes(p, b, n, x, y, __FUNCTION__)
428#define assert_pixmap_contains_points(p, pt, n, x, y) _assert_pixmap_contains_points(p, pt, n, x, y, __FUNCTION__)
429
430#else
431#define assert_pixmap_contains_box(p, b)
432#define assert_pixmap_contains_box_with_offset(p, b, dx, dy)
433#define assert_pixmap_contains_boxes(p, b, n, x, y)
434#define assert_pixmap_contains_points(p, pt, n, x, y)
435#define assert_drawable_contains_box(d, b)
436#ifndef NDEBUG
437#define assert_pixmap_damage(p) __assert_pixmap_damage(p)
438#else
439#define assert_pixmap_damage(p)
440#endif
441#endif
442
443jmp_buf sigjmp[4];
444volatile sig_atomic_t sigtrap;
445
446static int sigtrap_handler(int sig)
447{
448	/* XXX rate-limited squawk? */
449	DBG(("%s(sig=%d) sigtrap=%d\n", __FUNCTION__, sig, sigtrap));
450	sna_threads_trap(sig);
451
452	if (sigtrap)
453		siglongjmp(sigjmp[--sigtrap], sig);
454
455	return -1;
456}
457
458static void sigtrap_init(void)
459{
460#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0)
461	OsRegisterSigWrapper(sigtrap_handler);
462#endif
463}
464
465inline static bool
466sna_fill_init_blt(struct sna_fill_op *fill,
467		  struct sna *sna,
468		  PixmapPtr pixmap,
469		  struct kgem_bo *bo,
470		  uint8_t alu,
471		  uint32_t pixel,
472		  unsigned flags)
473{
474	return sna->render.fill(sna, alu, pixmap, bo, pixel, flags, fill);
475}
476
477static bool
478sna_copy_init_blt(struct sna_copy_op *copy,
479		  struct sna *sna,
480		  PixmapPtr src, struct kgem_bo *src_bo,
481		  PixmapPtr dst, struct kgem_bo *dst_bo,
482		  uint8_t alu)
483{
484	memset(copy, 0, sizeof(*copy));
485	return sna->render.copy(sna, alu, src, src_bo, dst, dst_bo, copy);
486}
487
488static void sna_pixmap_free_gpu(struct sna *sna, struct sna_pixmap *priv)
489{
490	DBG(("%s: handle=%d (pinned? %d)\n", __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->pinned));
491	assert(priv->gpu_damage == NULL || priv->gpu_bo);
492
493	if (priv->cow)
494		sna_pixmap_undo_cow(sna, priv, MOVE_WRITE);
495	assert(priv->cow == NULL);
496
497	if (priv->move_to_gpu) {
498		sna_pixmap_discard_shadow_damage(priv, NULL);
499		priv->move_to_gpu(sna, priv, MOVE_WRITE);
500	}
501
502	sna_damage_destroy(&priv->gpu_damage);
503	priv->clear = false;
504
505	if (priv->gpu_bo) {
506		if (!priv->pinned) {
507			assert(!priv->flush);
508			assert(!priv->move_to_gpu);
509			sna_pixmap_unmap(priv->pixmap, priv);
510			kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
511			priv->gpu_bo = NULL;
512		} else
513			kgem_bo_undo(&sna->kgem, priv->gpu_bo);
514	}
515
516	/* and reset the upload counter */
517	priv->source_count = SOURCE_BIAS;
518}
519
520static bool must_check
521sna_pixmap_alloc_cpu(struct sna *sna,
522		     PixmapPtr pixmap,
523		     struct sna_pixmap *priv,
524		     unsigned flags)
525{
526	/* Restore after a GTT mapping? */
527	assert(priv->gpu_damage == NULL || priv->gpu_bo);
528	assert(!priv->shm);
529	if (priv->ptr)
530		goto done;
531
532	DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
533	assert(priv->stride);
534
535	if (priv->create & KGEM_CAN_CREATE_CPU) {
536		unsigned hint;
537
538		DBG(("%s: allocating CPU buffer (%dx%d)\n", __FUNCTION__,
539		     pixmap->drawable.width, pixmap->drawable.height));
540
541		hint = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE;
542		if ((flags & MOVE_ASYNC_HINT) ||
543		    (priv->gpu_damage && !priv->clear && kgem_bo_is_busy(priv->gpu_bo) && sna->kgem.can_blt_cpu))
544			hint = 0;
545
546		priv->cpu_bo = kgem_create_cpu_2d(&sna->kgem,
547						  pixmap->drawable.width,
548						  pixmap->drawable.height,
549						  pixmap->drawable.bitsPerPixel,
550						  hint);
551		if (priv->cpu_bo) {
552			priv->ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo);
553			if (priv->ptr) {
554				DBG(("%s: allocated CPU handle=%d (snooped? %d)\n", __FUNCTION__,
555				     priv->cpu_bo->handle, priv->cpu_bo->snoop));
556				priv->stride = priv->cpu_bo->pitch;
557#ifdef DEBUG_MEMORY
558				sna->debug_memory.cpu_bo_allocs++;
559				sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo);
560#endif
561			} else {
562				kgem_bo_destroy(&sna->kgem, priv->cpu_bo);
563				priv->cpu_bo = NULL;
564			}
565		}
566	}
567
568	if (priv->ptr == NULL) {
569		DBG(("%s: allocating ordinary memory for shadow pixels [%d bytes]\n",
570		     __FUNCTION__, priv->stride * pixmap->drawable.height));
571		priv->ptr = malloc(priv->stride * pixmap->drawable.height);
572	}
573
574done:
575	assert(priv->stride);
576	assert(!priv->mapped);
577	pixmap->devPrivate.ptr = PTR(priv->ptr);
578	pixmap->devKind = priv->stride;
579	return priv->ptr != NULL;
580}
581
582static void __sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv)
583{
584	if (priv->cpu_bo) {
585		DBG(("%s: discarding CPU buffer, handle=%d, size=%d\n",
586		     __FUNCTION__, priv->cpu_bo->handle, kgem_bo_size(priv->cpu_bo)));
587#ifdef DEBUG_MEMORY
588		sna->debug_memory.cpu_bo_allocs--;
589		sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
590#endif
591		if (priv->cpu_bo->flush) {
592			assert(!priv->cpu_bo->reusable);
593			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
594			sna_shm_watch_flush(sna, -1);
595		}
596		kgem_bo_destroy(&sna->kgem, priv->cpu_bo);
597	} else if (!IS_STATIC_PTR(priv->ptr))
598		free(priv->ptr);
599}
600
601static bool sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv, bool active)
602{
603	if (active)
604		return false;
605
606	if (IS_STATIC_PTR(priv->ptr))
607		return false;
608
609	if (priv->ptr == NULL)
610		return true;
611
612	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, priv->pixmap->drawable.serialNumber));
613	__sna_pixmap_free_cpu(sna, priv);
614
615	priv->cpu_bo = NULL;
616	priv->ptr = NULL;
617
618	if (priv->mapped == MAPPED_NONE)
619		priv->pixmap->devPrivate.ptr = NULL;
620
621	return true;
622}
623
624static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap)
625{
626#if DEFAULT_PIXMAP_TILING == I915_TILING_NONE
627	return I915_TILING_NONE;
628#elif DEFAULT_PIXMAP_TILING == I915_TILING_X
629	return I915_TILING_X;
630#else
631	/* Try to avoid hitting the Y-tiling GTT mapping bug on 855GM */
632	if (sna->kgem.gen == 021)
633		return I915_TILING_X;
634
635	/* Only on later generations was the render pipeline
636	 * more flexible than the BLT. So on gen2/3, prefer to
637	 * keep large objects accessible through the BLT.
638	 */
639	if (sna->kgem.gen < 040 &&
640	    (pixmap->drawable.width  > sna->render.max_3d_size ||
641	     pixmap->drawable.height > sna->render.max_3d_size))
642		return I915_TILING_X;
643
644	return I915_TILING_Y;
645#endif
646}
647
648pure static uint32_t sna_pixmap_default_tiling(struct sna *sna, PixmapPtr pixmap)
649{
650	/* Also adjust tiling if it is not supported or likely to
651	 * slow us down,
652	 */
653	return kgem_choose_tiling(&sna->kgem,
654				  default_tiling(sna, pixmap),
655				  pixmap->drawable.width,
656				  pixmap->drawable.height,
657				  pixmap->drawable.bitsPerPixel);
658}
659
660struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling)
661{
662	struct sna_pixmap *priv = sna_pixmap(pixmap);
663	struct sna *sna = to_sna_from_pixmap(pixmap);
664	struct kgem_bo *bo;
665	BoxRec box;
666
667	DBG(("%s: changing tiling %d -> %d for %dx%d pixmap\n",
668	     __FUNCTION__, priv->gpu_bo->tiling, tiling,
669	     pixmap->drawable.width, pixmap->drawable.height));
670	assert(priv->gpu_damage == NULL || priv->gpu_bo);
671	assert(priv->gpu_bo->tiling != tiling);
672
673	if (priv->pinned) {
674		DBG(("%s: can't convert pinned bo\n", __FUNCTION__));
675		return NULL;
676	}
677
678	if (wedged(sna)) {
679		DBG(("%s: can't convert bo, wedged\n", __FUNCTION__));
680		return NULL;
681	}
682
683	assert_pixmap_damage(pixmap);
684	assert(!priv->move_to_gpu);
685
686	bo = kgem_create_2d(&sna->kgem,
687			    pixmap->drawable.width,
688			    pixmap->drawable.height,
689			    pixmap->drawable.bitsPerPixel,
690			    tiling, 0);
691	if (bo == NULL) {
692		DBG(("%s: allocation failed\n", __FUNCTION__));
693		return NULL;
694	}
695
696	if (bo->tiling == priv->gpu_bo->tiling) {
697		DBG(("%s: tiling request failed\n", __FUNCTION__));
698		kgem_bo_destroy(&sna->kgem, bo);
699		return NULL;
700	}
701
702	box.x1 = box.y1 = 0;
703	box.x2 = pixmap->drawable.width;
704	box.y2 = pixmap->drawable.height;
705
706	if (!sna->render.copy_boxes(sna, GXcopy,
707				    &pixmap->drawable, priv->gpu_bo, 0, 0,
708				    &pixmap->drawable, bo, 0, 0,
709				    &box, 1, 0)) {
710		DBG(("%s: copy failed\n", __FUNCTION__));
711		kgem_bo_destroy(&sna->kgem, bo);
712		return NULL;
713	}
714
715	sna_pixmap_unmap(pixmap, priv);
716	kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
717
718	return priv->gpu_bo = bo;
719}
720
721static inline void sna_set_pixmap(PixmapPtr pixmap, struct sna_pixmap *sna)
722{
723	((void **)__get_private(pixmap, sna_pixmap_key))[1] = sna;
724	assert(sna_pixmap(pixmap) == sna);
725}
726
727static struct sna_pixmap *
728_sna_pixmap_init(struct sna_pixmap *priv, PixmapPtr pixmap)
729{
730	list_init(&priv->flush_list);
731	list_init(&priv->cow_list);
732	priv->source_count = SOURCE_BIAS;
733	priv->pixmap = pixmap;
734
735	return priv;
736}
737
738static struct sna_pixmap *
739_sna_pixmap_reset(PixmapPtr pixmap)
740{
741	struct sna_pixmap *priv;
742
743	assert(pixmap->drawable.type == DRAWABLE_PIXMAP);
744	assert(pixmap->drawable.class == 0);
745	assert(pixmap->drawable.x == 0);
746	assert(pixmap->drawable.y == 0);
747
748	priv = sna_pixmap(pixmap);
749	assert(priv != NULL);
750
751	memset(priv, 0, sizeof(*priv));
752	return _sna_pixmap_init(priv, pixmap);
753}
754
755static struct sna_pixmap *sna_pixmap_attach(PixmapPtr pixmap)
756{
757	struct sna_pixmap *priv;
758
759	priv = calloc(1, sizeof(*priv));
760	if (!priv)
761		return NULL;
762
763	sna_set_pixmap(pixmap, priv);
764	return _sna_pixmap_init(priv, pixmap);
765}
766
767struct sna_pixmap *sna_pixmap_attach_to_bo(PixmapPtr pixmap, struct kgem_bo *bo)
768{
769	struct sna_pixmap *priv;
770
771	assert(bo);
772	assert(bo->proxy == NULL);
773	assert(bo->unique_id);
774
775	priv = sna_pixmap_attach(pixmap);
776	if (!priv)
777		return NULL;
778
779	DBG(("%s: attaching %s handle=%d to pixmap=%ld\n",
780	     __FUNCTION__, bo->snoop ? "CPU" : "GPU", bo->handle, pixmap->drawable.serialNumber));
781
782	assert(!priv->mapped);
783	assert(!priv->move_to_gpu);
784
785	if (bo->snoop) {
786		priv->cpu_bo = bo;
787		sna_damage_all(&priv->cpu_damage, pixmap);
788	} else {
789		priv->gpu_bo = bo;
790		sna_damage_all(&priv->gpu_damage, pixmap);
791	}
792
793	return priv;
794}
795
796static int bits_per_pixel(int depth)
797{
798	switch (depth) {
799	case 1: return 1;
800	case 4:
801	case 8: return 8;
802	case 15:
803	case 16: return 16;
804	case 24:
805	case 30:
806	case 32: return 32;
807	default: return 0;
808	}
809}
810static PixmapPtr
811create_pixmap(struct sna *sna, ScreenPtr screen,
812	      int width, int height, int depth,
813	      unsigned usage_hint)
814{
815	PixmapPtr pixmap;
816	size_t datasize;
817	size_t stride;
818	int base, bpp;
819
820	bpp = bits_per_pixel(depth);
821	if (bpp == 0)
822		return NullPixmap;
823
824	stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
825	if (stride / 4 > 32767 || height > 32767)
826		return NullPixmap;
827
828	datasize = height * stride;
829	base = screen->totalPixmapSize;
830	if (datasize && base & 15) {
831		int adjust = 16 - (base & 15);
832		base += adjust;
833		datasize += adjust;
834	}
835
836	DBG(("%s: allocating pixmap %dx%d, depth=%d/%d, size=%ld\n",
837	     __FUNCTION__, width, height, depth, bpp, (long)datasize));
838	pixmap = AllocatePixmap(screen, datasize);
839	if (!pixmap)
840		return NullPixmap;
841
842	((void **)__get_private(pixmap, sna_pixmap_key))[0] = sna;
843	assert(to_sna_from_pixmap(pixmap) == sna);
844
845	pixmap->drawable.type = DRAWABLE_PIXMAP;
846	pixmap->drawable.class = 0;
847	pixmap->drawable.pScreen = screen;
848	pixmap->drawable.depth = depth;
849	pixmap->drawable.bitsPerPixel = bpp;
850	pixmap->drawable.id = 0;
851	pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
852	pixmap->drawable.x = 0;
853	pixmap->drawable.y = 0;
854	pixmap->drawable.width = width;
855	pixmap->drawable.height = height;
856	pixmap->devKind = stride;
857	pixmap->refcnt = 1;
858	pixmap->devPrivate.ptr = datasize ? (char *)pixmap + base : NULL;
859
860#ifdef COMPOSITE
861	pixmap->screen_x = 0;
862	pixmap->screen_y = 0;
863#endif
864
865	pixmap->usage_hint = usage_hint;
866#if DEBUG_MEMORY
867	sna->debug_memory.pixmap_allocs++;
868#endif
869
870	DBG(("%s: serial=%ld, usage=%d, %dx%d\n",
871	     __FUNCTION__,
872	     pixmap->drawable.serialNumber,
873	     pixmap->usage_hint,
874	     pixmap->drawable.width,
875	     pixmap->drawable.height));
876
877	return pixmap;
878}
879
880static PixmapPtr
881__pop_freed_pixmap(struct sna *sna)
882{
883	PixmapPtr pixmap;
884
885	assert(sna->freed_pixmap);
886
887	pixmap = sna->freed_pixmap;
888	sna->freed_pixmap = pixmap->devPrivate.ptr;
889
890	DBG(("%s: reusing freed pixmap=%ld header\n",
891	     __FUNCTION__, pixmap->drawable.serialNumber));
892
893	assert(pixmap->refcnt == 0);
894	assert(pixmap->devKind = 0xdeadbeef);
895	assert(sna_pixmap(pixmap));
896	assert(sna_pixmap(pixmap)->header);
897
898#if DEBUG_MEMORY
899	sna->debug_memory.pixmap_cached--;
900#endif
901
902	return pixmap;
903}
904
905inline static PixmapPtr
906create_pixmap_hdr(struct sna *sna, ScreenPtr screen,
907		  int width, int height, int depth, int usage,
908		  struct sna_pixmap **priv)
909{
910	PixmapPtr pixmap;
911
912	if (sna->freed_pixmap == NULL) {
913		pixmap = create_pixmap(sna, screen, 0, 0, depth, usage);
914		if (pixmap == NullPixmap)
915			return NullPixmap;
916
917		*priv = sna_pixmap_attach(pixmap);
918		if (!*priv) {
919			FreePixmap(pixmap);
920			return NullPixmap;
921		}
922	} else {
923		pixmap = __pop_freed_pixmap(sna);
924		*priv = _sna_pixmap_reset(pixmap);
925
926		assert(pixmap->drawable.type == DRAWABLE_PIXMAP);
927		assert(pixmap->drawable.class == 0);
928		assert(pixmap->drawable.pScreen == screen);
929		assert(pixmap->drawable.x == 0);
930		assert(pixmap->drawable.y == 0);
931
932		pixmap->drawable.id = 0;
933
934		pixmap->drawable.depth = depth;
935		pixmap->drawable.bitsPerPixel = bits_per_pixel(depth);
936		pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
937
938		pixmap->devKind = 0;
939		pixmap->devPrivate.ptr = NULL;
940
941#ifdef COMPOSITE
942		pixmap->screen_x = 0;
943		pixmap->screen_y = 0;
944#endif
945
946#if DEBUG_MEMORY
947		sna->debug_memory.pixmap_allocs++;
948#endif
949
950		pixmap->refcnt = 1;
951	}
952
953	DBG(("%s: pixmap=%ld, width=%d, height=%d, usage=%d\n", __FUNCTION__,
954	     pixmap->drawable.serialNumber, width, height, usage));
955	pixmap->drawable.width = width;
956	pixmap->drawable.height = height;
957	pixmap->usage_hint = usage;
958
959	(*priv)->header = true;
960	return pixmap;
961}
962
963static PixmapPtr
964sna_pixmap_create_shm(ScreenPtr screen,
965		      int width, int height, int depth,
966		      char *addr)
967{
968	struct sna *sna = to_sna_from_screen(screen);
969	int bpp = bits_per_pixel(depth);
970	int pitch = PixmapBytePad(width, depth);
971	struct sna_pixmap *priv;
972	PixmapPtr pixmap;
973
974	DBG(("%s(%dx%d, depth=%d, bpp=%d, pitch=%d)\n",
975	     __FUNCTION__, width, height, depth, bpp, pitch));
976
977	if (wedged(sna) || bpp == 0 || pitch*height < 4096) {
978fallback:
979		pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth);
980		if (pixmap == NULL)
981			return NULL;
982
983		if (!screen->ModifyPixmapHeader(pixmap, width, height, depth,
984						bpp, pitch, addr)) {
985			screen->DestroyPixmap(pixmap);
986			return NULL;
987		}
988
989		return pixmap;
990	}
991
992	pixmap = create_pixmap_hdr(sna, screen, width, height, depth, 0, &priv);
993	if (pixmap == NullPixmap) {
994		DBG(("%s: allocation failed\n", __FUNCTION__));
995		goto fallback;
996	}
997
998	priv->cpu_bo = kgem_create_map(&sna->kgem, addr, pitch*height, false);
999	if (priv->cpu_bo == NULL) {
1000		DBG(("%s: mapping SHM segment failed\n", __FUNCTION__));
1001		sna_pixmap_destroy(pixmap);
1002		goto fallback;
1003	}
1004	priv->cpu_bo->pitch = pitch;
1005	kgem_bo_mark_unreusable(priv->cpu_bo);
1006	sna_shm_watch_flush(sna, 1);
1007#ifdef DEBUG_MEMORY
1008	sna->debug_memory.cpu_bo_allocs++;
1009	sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo);
1010#endif
1011
1012	/* Be wary as we cannot cache SHM Pixmap in our freed cache */
1013	priv->header = false;
1014	priv->cpu = true;
1015	priv->shm = true;
1016	priv->stride = pitch;
1017	priv->ptr = MAKE_STATIC_PTR(addr);
1018	sna_damage_all(&priv->cpu_damage, pixmap);
1019
1020	pixmap->devKind = pitch;
1021	pixmap->devPrivate.ptr = addr;
1022
1023	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
1024	     __FUNCTION__,
1025	     pixmap->drawable.serialNumber,
1026	     pixmap->drawable.width,
1027	     pixmap->drawable.height,
1028	     pixmap->usage_hint));
1029	return pixmap;
1030}
1031
1032PixmapPtr
1033sna_pixmap_create_unattached(ScreenPtr screen,
1034			     int width, int height, int depth)
1035{
1036	return create_pixmap(to_sna_from_screen(screen),
1037			     screen, width, height, depth,
1038			     -1);
1039}
1040
1041static PixmapPtr
1042sna_pixmap_create_scratch(ScreenPtr screen,
1043			  int width, int height, int depth,
1044			  uint32_t tiling)
1045{
1046	struct sna *sna = to_sna_from_screen(screen);
1047	struct sna_pixmap *priv;
1048	PixmapPtr pixmap;
1049	int bpp;
1050
1051	DBG(("%s(%d, %d, %d, tiling=%d)\n", __FUNCTION__,
1052	     width, height, depth, tiling));
1053
1054	bpp = bits_per_pixel(depth);
1055	if (tiling == I915_TILING_Y &&
1056	    (sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0)
1057		tiling = I915_TILING_X;
1058
1059	if (tiling == I915_TILING_Y &&
1060	    (width > sna->render.max_3d_size ||
1061	     height > sna->render.max_3d_size))
1062		tiling = I915_TILING_X;
1063
1064	tiling = kgem_choose_tiling(&sna->kgem, tiling, width, height, bpp);
1065
1066	/* you promise never to access this via the cpu... */
1067	pixmap = create_pixmap_hdr(sna, screen, width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH, &priv);
1068	if (pixmap == NullPixmap)
1069		return NullPixmap;
1070
1071	priv->stride = PixmapBytePad(width, depth);
1072
1073	priv->gpu_bo = kgem_create_2d(&sna->kgem,
1074				      width, height, bpp, tiling,
1075				      CREATE_TEMPORARY);
1076	if (priv->gpu_bo == NULL) {
1077		free(priv);
1078		FreePixmap(pixmap);
1079		return NullPixmap;
1080	}
1081
1082	sna_damage_all(&priv->gpu_damage, pixmap);
1083
1084	assert(to_sna_from_pixmap(pixmap) == sna);
1085	assert(pixmap->drawable.pScreen == screen);
1086	assert(pixmap->refcnt == 1);
1087
1088	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
1089	     __FUNCTION__,
1090	     pixmap->drawable.serialNumber,
1091	     pixmap->drawable.width,
1092	     pixmap->drawable.height,
1093	     pixmap->usage_hint));
1094	return pixmap;
1095}
1096
1097static unsigned small_copy(const RegionRec *region)
1098{
1099	if ((region->extents.x2 - region->extents.x1)*(region->extents.y2 - region->extents.y1) < 1024) {
1100		DBG(("%s: region:%dx%d\n", __FUNCTION__,
1101		     (region->extents.x2 - region->extents.x1),
1102		     (region->extents.y2 - region->extents.y1)));
1103		return COPY_SMALL;
1104	}
1105
1106	return 0;
1107}
1108
1109#ifdef CREATE_PIXMAP_USAGE_SHARED
1110static Bool
1111sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle)
1112{
1113	struct sna *sna = to_sna_from_pixmap(pixmap);
1114	struct sna_pixmap *priv;
1115	int fd;
1116
1117	DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
1118
1119	priv = sna_pixmap_move_to_gpu(pixmap,
1120				      MOVE_READ | MOVE_WRITE | __MOVE_DRI | __MOVE_PRIME | __MOVE_FORCE);
1121	if (priv == NULL)
1122		return FALSE;
1123
1124	assert(!priv->shm);
1125	assert(priv->gpu_bo);
1126	assert(priv->stride);
1127
1128	/* XXX negotiate format and stride restrictions */
1129	if (priv->gpu_bo->tiling != I915_TILING_NONE ||
1130	    priv->gpu_bo->pitch & 255) {
1131		struct kgem_bo *bo;
1132		BoxRec box;
1133
1134		DBG(("%s: removing tiling %d, and aligning pitch %d for %dx%d pixmap=%ld\n",
1135		     __FUNCTION__, priv->gpu_bo->tiling, priv->gpu_bo->pitch,
1136		     pixmap->drawable.width, pixmap->drawable.height,
1137		     pixmap->drawable.serialNumber));
1138
1139		if (priv->pinned) {
1140			DBG(("%s: can't convert pinned %x bo\n", __FUNCTION__,
1141			     priv->pinned));
1142			return FALSE;
1143		}
1144
1145		assert_pixmap_damage(pixmap);
1146
1147		bo = kgem_create_2d(&sna->kgem,
1148				    pixmap->drawable.width,
1149				    pixmap->drawable.height,
1150				    pixmap->drawable.bitsPerPixel,
1151				    I915_TILING_NONE,
1152				    CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT);
1153		if (bo == NULL) {
1154			DBG(("%s: allocation failed\n", __FUNCTION__));
1155			return FALSE;
1156		}
1157
1158		box.x1 = box.y1 = 0;
1159		box.x2 = pixmap->drawable.width;
1160		box.y2 = pixmap->drawable.height;
1161
1162		assert(!wedged(sna)); /* XXX */
1163		if (!sna->render.copy_boxes(sna, GXcopy,
1164					    &pixmap->drawable, priv->gpu_bo, 0, 0,
1165					    &pixmap->drawable, bo, 0, 0,
1166					    &box, 1, 0)) {
1167			DBG(("%s: copy failed\n", __FUNCTION__));
1168			kgem_bo_destroy(&sna->kgem, bo);
1169			return FALSE;
1170		}
1171
1172		sna_pixmap_unmap(pixmap, priv);
1173		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1174		priv->gpu_bo = bo;
1175	}
1176	assert(priv->gpu_bo->tiling == I915_TILING_NONE);
1177	assert((priv->gpu_bo->pitch & 255) == 0);
1178
1179	/* And export the bo->pitch via pixmap->devKind */
1180	if (!priv->mapped) {
1181		void *ptr;
1182
1183		ptr = kgem_bo_map__async(&sna->kgem, priv->gpu_bo);
1184		if (ptr == NULL)
1185			return FALSE;
1186
1187		pixmap->devPrivate.ptr = ptr;
1188		pixmap->devKind = priv->gpu_bo->pitch;
1189		priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
1190	}
1191	assert_pixmap_map(pixmap, priv);
1192
1193	fd = kgem_bo_export_to_prime(&sna->kgem, priv->gpu_bo);
1194	if (fd == -1)
1195		return FALSE;
1196
1197	priv->pinned |= PIN_PRIME;
1198
1199	*fd_handle = (void *)(intptr_t)fd;
1200	return TRUE;
1201}
1202
1203static Bool
1204sna_set_shared_pixmap_backing(PixmapPtr pixmap, void *fd_handle)
1205{
1206	struct sna *sna = to_sna_from_pixmap(pixmap);
1207	struct sna_pixmap *priv;
1208	struct kgem_bo *bo;
1209
1210	DBG(("%s: pixmap=%ld, size=%dx%d, depth=%d/%d, stride=%d\n",
1211	     __FUNCTION__, pixmap->drawable.serialNumber,
1212	     pixmap->drawable.width, pixmap->drawable.height,
1213	     pixmap->drawable.depth, pixmap->drawable.bitsPerPixel,
1214	     pixmap->devKind));
1215
1216	priv = sna_pixmap(pixmap);
1217	if (priv == NULL)
1218		return FALSE;
1219
1220	if (priv->pinned & ~PIN_PRIME)
1221		return FALSE;
1222
1223	assert(!priv->flush);
1224
1225	if (priv->gpu_bo) {
1226		priv->clear = false;
1227		sna_damage_destroy(&priv->gpu_damage);
1228		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1229		priv->gpu_bo = NULL;
1230		priv->pinned = 0;
1231	}
1232
1233	assert(!priv->pinned);
1234
1235	assert(priv->cpu_bo == NULL);
1236	assert(priv->cpu_damage == NULL);
1237
1238	assert(priv->gpu_bo == NULL);
1239	assert(priv->gpu_damage == NULL);
1240
1241	bo = kgem_create_for_prime(&sna->kgem,
1242				   (intptr_t)fd_handle,
1243				   pixmap->devKind * pixmap->drawable.height);
1244	if (bo == NULL)
1245		return FALSE;
1246
1247	sna_damage_all(&priv->gpu_damage, pixmap);
1248
1249	bo->pitch = pixmap->devKind;
1250	priv->stride = pixmap->devKind;
1251
1252	assert(!priv->mapped);
1253	priv->gpu_bo = bo;
1254	priv->pinned |= PIN_PRIME;
1255
1256	close((intptr_t)fd_handle);
1257	return TRUE;
1258}
1259
1260static PixmapPtr
1261sna_create_pixmap_shared(struct sna *sna, ScreenPtr screen,
1262			 int width, int height, int depth)
1263{
1264	PixmapPtr pixmap;
1265	struct sna_pixmap *priv;
1266
1267	DBG(("%s: width=%d, height=%d, depth=%d\n",
1268	     __FUNCTION__, width, height, depth));
1269
1270	/* Create a stub to be attached later */
1271	pixmap = create_pixmap_hdr(sna, screen,
1272				   width, height, depth, 0,
1273				   &priv);
1274	if (pixmap == NullPixmap)
1275		return NullPixmap;
1276
1277	assert(!priv->mapped);
1278	priv->stride = 0;
1279	priv->create = 0;
1280
1281	if (width|height) {
1282		priv->gpu_bo = kgem_create_2d(&sna->kgem,
1283					      width, height,
1284					      pixmap->drawable.bitsPerPixel,
1285					      I915_TILING_NONE,
1286					      CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT);
1287		if (priv->gpu_bo == NULL) {
1288			free(priv);
1289			FreePixmap(pixmap);
1290			return NullPixmap;
1291		}
1292
1293		/* minimal interface for sharing is linear, 256 byte pitch */
1294		assert(priv->gpu_bo->tiling == I915_TILING_NONE);
1295		assert((priv->gpu_bo->pitch & 255) == 0);
1296
1297		pixmap->devPrivate.ptr =
1298			kgem_bo_map__async(&sna->kgem, priv->gpu_bo);
1299		if (pixmap->devPrivate.ptr == NULL) {
1300			kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1301			free(priv);
1302			FreePixmap(pixmap);
1303			return FALSE;
1304		}
1305
1306		pixmap->devKind = priv->gpu_bo->pitch;
1307
1308		priv->stride = priv->gpu_bo->pitch;
1309		priv->mapped = pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
1310		assert_pixmap_map(pixmap, priv);
1311
1312		sna_damage_all(&priv->gpu_damage, pixmap);
1313	}
1314
1315	return pixmap;
1316}
1317#endif
1318
1319static PixmapPtr sna_create_pixmap(ScreenPtr screen,
1320				   int width, int height, int depth,
1321				   unsigned int usage)
1322{
1323	struct sna *sna = to_sna_from_screen(screen);
1324	PixmapPtr pixmap;
1325	struct sna_pixmap *priv;
1326	unsigned flags;
1327	int pad;
1328	void *ptr;
1329
1330	DBG(("%s(%d, %d, %d, usage=%x)\n", __FUNCTION__,
1331	     width, height, depth, usage));
1332
1333#ifdef CREATE_PIXMAP_USAGE_SHARED
1334	if (usage == CREATE_PIXMAP_USAGE_SHARED)
1335		return sna_create_pixmap_shared(sna, screen,
1336						width, height, depth);
1337#endif
1338
1339	if ((width|height) == 0) {
1340		usage = -1;
1341		goto fallback;
1342	}
1343	assert(width && height);
1344
1345	flags = kgem_can_create_2d(&sna->kgem, width, height, depth);
1346	if (flags == 0) {
1347		DBG(("%s: can not use GPU, just creating shadow\n",
1348		     __FUNCTION__));
1349		goto fallback;
1350	}
1351
1352	if (unlikely((sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0))
1353		flags &= ~KGEM_CAN_CREATE_GPU;
1354	if (wedged(sna) && usage != SNA_CREATE_FB)
1355		flags &= ~KGEM_CAN_CREATE_GTT;
1356
1357	DBG(("%s: usage=%d, flags=%x\n", __FUNCTION__, usage, flags));
1358	switch (usage) {
1359	case CREATE_PIXMAP_USAGE_SCRATCH:
1360		if (flags & KGEM_CAN_CREATE_GPU)
1361			return sna_pixmap_create_scratch(screen,
1362							 width, height, depth,
1363							 I915_TILING_X);
1364		else
1365			goto fallback;
1366
1367	case SNA_CREATE_SCRATCH:
1368		if (flags & (KGEM_CAN_CREATE_CPU | KGEM_CAN_CREATE_GPU))
1369			return sna_pixmap_create_scratch(screen,
1370							 width, height, depth,
1371							 I915_TILING_Y);
1372		else
1373			return NullPixmap;
1374	}
1375
1376	if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE)
1377		flags &= ~KGEM_CAN_CREATE_GPU;
1378	if (usage == CREATE_PIXMAP_USAGE_BACKING_PIXMAP)
1379		usage = 0;
1380
1381	pad = PixmapBytePad(width, depth);
1382	if (pad * height < 4096) {
1383		DBG(("%s: small buffer [%d], attaching to shadow pixmap\n",
1384		     __FUNCTION__, pad * height));
1385		pixmap = create_pixmap(sna, screen,
1386				       width, height, depth, usage);
1387		if (pixmap == NullPixmap)
1388			return NullPixmap;
1389
1390		ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr);
1391		pad = pixmap->devKind;
1392		flags &= ~(KGEM_CAN_CREATE_GPU | KGEM_CAN_CREATE_CPU);
1393
1394		priv = sna_pixmap_attach(pixmap);
1395		if (priv == NULL) {
1396			free(pixmap);
1397			goto fallback;
1398		}
1399	} else {
1400		DBG(("%s: creating GPU pixmap %dx%d, stride=%d, flags=%x\n",
1401		     __FUNCTION__, width, height, pad, flags));
1402
1403		pixmap = create_pixmap_hdr(sna, screen, width, height, depth, usage, &priv);
1404		if (pixmap == NullPixmap)
1405			return NullPixmap;
1406
1407		ptr = NULL;
1408	}
1409
1410	priv->stride = pad;
1411	priv->create = flags;
1412	priv->ptr = ptr;
1413
1414	assert(to_sna_from_pixmap(pixmap) == sna);
1415	assert(pixmap->drawable.pScreen == screen);
1416	assert(pixmap->refcnt == 1);
1417
1418	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
1419	     __FUNCTION__,
1420	     pixmap->drawable.serialNumber,
1421	     pixmap->drawable.width,
1422	     pixmap->drawable.height,
1423	     pixmap->usage_hint));
1424	return pixmap;
1425
1426fallback:
1427	return create_pixmap(sna, screen, width, height, depth, usage);
1428}
1429
1430void sna_add_flush_pixmap(struct sna *sna,
1431			  struct sna_pixmap *priv,
1432			  struct kgem_bo *bo)
1433{
1434	DBG(("%s: marking pixmap=%ld for flushing\n",
1435	     __FUNCTION__, priv->pixmap->drawable.serialNumber));
1436	assert(bo);
1437	assert(bo->flush);
1438	assert(priv->gpu_damage == NULL || priv->gpu_bo);
1439	list_move(&priv->flush_list, &sna->flush_pixmaps);
1440
1441	if (bo->exec == NULL && sna->kgem.nbatch && kgem_is_idle(&sna->kgem)) {
1442		DBG(("%s: new flush bo, flushing before\n", __FUNCTION__));
1443		_kgem_submit(&sna->kgem);
1444	}
1445}
1446
1447static void __sna_free_pixmap(struct sna *sna,
1448			      PixmapPtr pixmap,
1449			      struct sna_pixmap *priv)
1450{
1451	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber));
1452	list_del(&priv->flush_list);
1453
1454	assert(priv->gpu_damage == NULL);
1455	assert(priv->cpu_damage == NULL);
1456
1457	__sna_pixmap_free_cpu(sna, priv);
1458
1459	if (priv->flush)
1460		sna_watch_flush(sna, -1);
1461
1462#if !NDEBUG
1463	pixmap->devKind = 0xdeadbeef;
1464#endif
1465	if (priv->header) {
1466		assert(pixmap->drawable.pScreen == to_screen_from_sna(sna));
1467		assert(!priv->shm);
1468		pixmap->devPrivate.ptr = sna->freed_pixmap;
1469		sna->freed_pixmap = pixmap;
1470#if DEBUG_MEMORY
1471		sna->debug_memory.pixmap_cached++;
1472#endif
1473	} else {
1474		free(priv);
1475		FreePixmap(pixmap);
1476	}
1477}
1478
1479static Bool sna_destroy_pixmap(PixmapPtr pixmap)
1480{
1481	struct sna *sna;
1482	struct sna_pixmap *priv;
1483
1484	assert(pixmap->refcnt > 0);
1485	if (--pixmap->refcnt)
1486		return TRUE;
1487
1488#if DEBUG_MEMORY
1489	to_sna_from_pixmap(pixmap)->debug_memory.pixmap_allocs--;
1490#endif
1491
1492	priv = sna_pixmap(pixmap);
1493	DBG(("%s: pixmap=%ld, attached?=%d\n",
1494	     __FUNCTION__, pixmap->drawable.serialNumber, priv != NULL));
1495	if (priv == NULL) {
1496		FreePixmap(pixmap);
1497		return TRUE;
1498	}
1499
1500	assert_pixmap_damage(pixmap);
1501	sna = to_sna_from_pixmap(pixmap);
1502
1503	sna_damage_destroy(&priv->gpu_damage);
1504	sna_damage_destroy(&priv->cpu_damage);
1505
1506	list_del(&priv->cow_list);
1507	if (priv->cow) {
1508		struct sna_cow *cow = COW(priv->cow);
1509		DBG(("%s: pixmap=%ld discarding cow, refcnt=%d\n",
1510		     __FUNCTION__, pixmap->drawable.serialNumber, cow->refcnt));
1511		assert(cow->refcnt);
1512		if (!--cow->refcnt)
1513			free(cow);
1514		priv->cow = NULL;
1515	} else
1516		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
1517
1518	if (priv->move_to_gpu)
1519		(void)priv->move_to_gpu(sna, priv, 0);
1520
1521	/* Always release the gpu bo back to the lower levels of caching */
1522	if (priv->gpu_bo) {
1523		sna_pixmap_unmap(pixmap, priv);
1524		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1525		priv->gpu_bo = NULL;
1526	}
1527
1528	if (priv->shm && kgem_bo_is_busy(priv->cpu_bo)) {
1529		DBG(("%s: deferring release of active SHM pixmap=%ld\n",
1530		     __FUNCTION__, pixmap->drawable.serialNumber));
1531		add_shm_flush(sna, priv);
1532		kgem_bo_submit(&sna->kgem, priv->cpu_bo); /* XXX ShmDetach */
1533	} else
1534		__sna_free_pixmap(sna, pixmap, priv);
1535	return TRUE;
1536}
1537
1538void sna_pixmap_destroy(PixmapPtr pixmap)
1539{
1540	assert(pixmap->refcnt == 1);
1541	assert(sna_pixmap(pixmap) == NULL || sna_pixmap(pixmap)->header == true);
1542
1543	sna_destroy_pixmap(pixmap);
1544}
1545
1546static inline bool has_coherent_map(struct sna *sna,
1547				    struct kgem_bo *bo,
1548				    unsigned flags)
1549{
1550	assert(bo);
1551
1552	if (kgem_bo_mapped(&sna->kgem, bo))
1553		return true;
1554
1555	if (bo->tiling == I915_TILING_Y)
1556		return false;
1557
1558	return kgem_bo_can_map__cpu(&sna->kgem, bo, flags & MOVE_WRITE);
1559}
1560
1561static inline bool has_coherent_ptr(struct sna *sna, struct sna_pixmap *priv, unsigned flags)
1562{
1563	if (priv == NULL)
1564		return true;
1565
1566	if (flags & MOVE_ASYNC_HINT) {
1567		/* Not referencing the pointer itself, so do not care */
1568		return true;
1569	}
1570
1571	if (!priv->mapped) {
1572		if (!priv->cpu_bo)
1573			return true;
1574
1575		assert(!priv->cpu_bo->needs_flush || (flags & MOVE_WRITE) == 0);
1576		assert(priv->pixmap->devKind == priv->cpu_bo->pitch);
1577		return priv->pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu);
1578	}
1579
1580	assert(!priv->move_to_gpu || (flags & MOVE_WRITE) == 0);
1581
1582	assert_pixmap_map(priv->pixmap, priv);
1583	assert(priv->pixmap->devKind == priv->gpu_bo->pitch);
1584
1585	if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu)) {
1586		assert(priv->mapped == MAPPED_CPU);
1587
1588		if (priv->gpu_bo->tiling != I915_TILING_NONE)
1589			return false;
1590
1591		return flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE);
1592	}
1593
1594	if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__gtt)) {
1595		assert(priv->mapped == MAPPED_GTT);
1596
1597		if (priv->gpu_bo->tiling == I915_TILING_Y && sna->kgem.gen == 0x21)
1598			return false;
1599
1600		return true;
1601	}
1602
1603	if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__wc)) {
1604		assert(priv->mapped == MAPPED_GTT);
1605		return true;
1606	}
1607
1608	return false;
1609}
1610
1611static inline bool pixmap_inplace(struct sna *sna,
1612				  PixmapPtr pixmap,
1613				  struct sna_pixmap *priv,
1614				  unsigned flags)
1615{
1616	if (FORCE_INPLACE)
1617		return FORCE_INPLACE > 0;
1618
1619	if (wedged(sna) && !priv->pinned) {
1620		DBG(("%s: no, wedged and unpinned; pull pixmap back to CPU\n", __FUNCTION__));
1621		return false;
1622	}
1623
1624	if (priv->move_to_gpu && flags & MOVE_WRITE)
1625		return false;
1626
1627	if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) {
1628		if (priv->clear) {
1629			DBG(("%s: no, clear GPU bo is busy\n", __FUNCTION__));
1630			return false;
1631		}
1632
1633		if (flags & MOVE_ASYNC_HINT) {
1634			DBG(("%s: no, async hint and GPU bo is busy\n", __FUNCTION__));
1635			return false;
1636		}
1637
1638		if ((flags & (MOVE_WRITE | MOVE_READ)) == (MOVE_WRITE | MOVE_READ)) {
1639			DBG(("%s: no, GPU bo is busy\n", __FUNCTION__));
1640			return false;
1641		}
1642
1643		if ((flags & MOVE_READ) == 0) {
1644			DBG(("%s: %s, GPU bo is busy, but not reading\n", __FUNCTION__, priv->pinned ? "no" : "yes"));
1645			return !priv->pinned;
1646		}
1647	}
1648
1649	if (priv->mapped) {
1650		DBG(("%s: %s, already mapped\n", __FUNCTION__, has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no"));
1651		return has_coherent_map(sna, priv->gpu_bo, flags);
1652	}
1653
1654	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) {
1655		DBG(("%s: yes, has CPU bo and is active on CPU\n", __FUNCTION__));
1656		return true;
1657	}
1658
1659	if (priv->cpu_bo && priv->cpu) {
1660		DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__));
1661		return false;
1662	}
1663
1664	if (flags & MOVE_READ &&
1665	    (priv->cpu || priv->cpu_damage || priv->gpu_damage == NULL)) {
1666		DBG(("%s:, no, reading and has CPU damage\n", __FUNCTION__));
1667		return false;
1668	}
1669
1670	return (priv->stride * pixmap->drawable.height >> 12) >
1671		sna->kgem.half_cpu_cache_pages;
1672}
1673
1674static bool sna_pixmap_alloc_gpu(struct sna *sna,
1675				 PixmapPtr pixmap,
1676				 struct sna_pixmap *priv,
1677				 unsigned flags)
1678{
1679	uint32_t tiling;
1680
1681	/* Use tiling by default, but disable per user request */
1682	if (pixmap->usage_hint == SNA_CREATE_FB && (sna->flags & SNA_LINEAR_FB) == 0) {
1683		flags |= CREATE_SCANOUT;
1684		tiling = kgem_choose_tiling(&sna->kgem,
1685					    -DEFAULT_SCANOUT_TILING,
1686					    pixmap->drawable.width,
1687					    pixmap->drawable.height,
1688					    pixmap->drawable.bitsPerPixel);
1689	} else
1690		tiling = sna_pixmap_default_tiling(sna, pixmap);
1691
1692	DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
1693
1694	priv->gpu_bo = kgem_create_2d(&sna->kgem,
1695				      pixmap->drawable.width,
1696				      pixmap->drawable.height,
1697				      pixmap->drawable.bitsPerPixel,
1698				      tiling, flags);
1699	return priv->gpu_bo != NULL;
1700}
1701
1702static bool
1703sna_pixmap_create_mappable_gpu(PixmapPtr pixmap,
1704			       bool can_replace)
1705{
1706	struct sna *sna = to_sna_from_pixmap(pixmap);
1707	struct sna_pixmap *priv = sna_pixmap(pixmap);
1708
1709	if (wedged(sna))
1710		goto out;
1711
1712	if ((priv->create & KGEM_CAN_CREATE_GTT) == 0)
1713		goto out;
1714
1715	assert_pixmap_damage(pixmap);
1716
1717	if (can_replace && priv->gpu_bo &&
1718	    (!kgem_bo_can_map(&sna->kgem, priv->gpu_bo) ||
1719	     __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) {
1720		if (priv->pinned)
1721			return false;
1722
1723		DBG(("%s: discard busy GPU bo\n", __FUNCTION__));
1724		sna_pixmap_free_gpu(sna, priv);
1725	}
1726
1727	if (priv->gpu_bo == NULL) {
1728		assert_pixmap_damage(pixmap);
1729		assert(priv->gpu_damage == NULL);
1730		sna_pixmap_alloc_gpu(sna, pixmap, priv, CREATE_GTT_MAP | CREATE_INACTIVE);
1731	}
1732
1733out:
1734	if (priv->gpu_bo == NULL)
1735		return false;
1736
1737	return (kgem_bo_can_map(&sna->kgem, priv->gpu_bo) &&
1738		!kgem_bo_is_busy(priv->gpu_bo));
1739}
1740
1741static inline bool gpu_bo_download(struct sna *sna,
1742				   struct sna_pixmap *priv,
1743				   int n, const BoxRec *box,
1744				   bool idle)
1745{
1746	char *src;
1747
1748	if (!USE_INPLACE)
1749		return false;
1750
1751	switch (priv->gpu_bo->tiling) {
1752	case I915_TILING_Y:
1753		return false;
1754	case I915_TILING_X:
1755		if (!sna->kgem.memcpy_from_tiled_x)
1756			return false;
1757	default:
1758		break;
1759	}
1760
1761	if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC))
1762		return false;
1763
1764	if (idle) {
1765		if (__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
1766			return false;
1767
1768		if (priv->cpu_bo && __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo))
1769			return false;
1770	}
1771
1772	src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
1773	if (src == NULL)
1774		return false;
1775
1776	kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC);
1777
1778	if (priv->cpu_bo)
1779		kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
1780	assert(has_coherent_ptr(sna, priv, MOVE_WRITE));
1781
1782	if (sigtrap_get())
1783		return false;
1784
1785	if (priv->gpu_bo->tiling) {
1786		int bpp = priv->pixmap->drawable.bitsPerPixel;
1787		void *dst = priv->pixmap->devPrivate.ptr;
1788		int dst_pitch = priv->pixmap->devKind;
1789
1790		DBG(("%s: download through a tiled CPU map\n", __FUNCTION__));
1791		do {
1792			DBG(("%s: box (%d, %d), (%d, %d)\n",
1793			     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
1794			memcpy_from_tiled_x(&sna->kgem, src, dst, bpp,
1795					    priv->gpu_bo->pitch, dst_pitch,
1796					    box->x1, box->y1,
1797					    box->x1, box->y1,
1798					    box->x2 - box->x1, box->y2 - box->y1);
1799			box++;
1800		} while (--n);
1801	} else {
1802		int bpp = priv->pixmap->drawable.bitsPerPixel;
1803		void *dst = priv->pixmap->devPrivate.ptr;
1804		int dst_pitch = priv->pixmap->devKind;
1805
1806		DBG(("%s: download through a linear CPU map\n", __FUNCTION__));
1807		do {
1808			DBG(("%s: box (%d, %d), (%d, %d)\n",
1809			     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
1810			memcpy_blt(src, dst, bpp,
1811				   priv->gpu_bo->pitch, dst_pitch,
1812				   box->x1, box->y1,
1813				   box->x1, box->y1,
1814				   box->x2 - box->x1, box->y2 - box->y1);
1815			box++;
1816		} while (--n);
1817	}
1818
1819	sigtrap_put();
1820	return true;
1821}
1822
1823static inline bool cpu_bo_download(struct sna *sna,
1824				   struct sna_pixmap *priv,
1825				   int n, const BoxRec *box)
1826{
1827	if (DBG_NO_CPU_DOWNLOAD)
1828		return false;
1829
1830	if (wedged(sna))
1831		return false;
1832
1833	if (priv->cpu_bo == NULL || !sna->kgem.can_blt_cpu)
1834		return false;
1835
1836	if (!kgem_bo_is_busy(priv->gpu_bo) && !kgem_bo_is_busy(priv->cpu_bo)) {
1837		/* Is it worth detiling? */
1838		assert(box[0].y1 < box[n-1].y2);
1839		if (kgem_bo_can_map(&sna->kgem, priv->gpu_bo) &&
1840		    (box[n-1].y2 - box[0].y1 - 1) * priv->gpu_bo->pitch < 4096) {
1841			DBG(("%s: no, tiny transfer (height=%d, pitch=%d) expect to read inplace\n",
1842			     __FUNCTION__, box[n-1].y2-box[0].y1, priv->gpu_bo->pitch));
1843			return false;
1844		}
1845	}
1846
1847	DBG(("%s: using GPU write to CPU bo for download from GPU\n", __FUNCTION__));
1848	return sna->render.copy_boxes(sna, GXcopy,
1849				      &priv->pixmap->drawable, priv->gpu_bo, 0, 0,
1850				      &priv->pixmap->drawable, priv->cpu_bo, 0, 0,
1851				      box, n, COPY_LAST);
1852}
1853
1854static void download_boxes(struct sna *sna,
1855			   struct sna_pixmap *priv,
1856			   int n, const BoxRec *box)
1857{
1858	bool ok;
1859
1860	DBG(("%s: nbox=%d\n", __FUNCTION__, n));
1861
1862	ok = gpu_bo_download(sna, priv, n, box, true);
1863	if (!ok)
1864		ok = cpu_bo_download(sna, priv, n, box);
1865	if (!ok)
1866		ok = gpu_bo_download(sna, priv, n, box, false);
1867	if (!ok) {
1868		if (priv->cpu_bo)
1869			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
1870		assert(priv->mapped == MAPPED_NONE);
1871		assert(has_coherent_ptr(sna, priv, MOVE_WRITE));
1872		sna_read_boxes(sna, priv->pixmap, priv->gpu_bo, box, n);
1873	}
1874}
1875
1876static inline bool use_cpu_bo_for_upload(struct sna *sna,
1877					 struct sna_pixmap *priv,
1878					 unsigned flags)
1879{
1880	if (DBG_NO_CPU_UPLOAD)
1881		return false;
1882
1883	if (wedged(sna))
1884		return false;
1885
1886	if (priv->cpu_bo == NULL)
1887		return false;
1888
1889	DBG(("%s? flags=%x, gpu busy?=%d, cpu busy?=%d\n", __FUNCTION__,
1890	     flags,
1891	     kgem_bo_is_busy(priv->gpu_bo),
1892	     kgem_bo_is_busy(priv->cpu_bo)));
1893
1894	if (!priv->cpu)
1895		return true;
1896
1897	if (flags & (MOVE_WRITE | MOVE_ASYNC_HINT))
1898		return true;
1899
1900	if (priv->gpu_bo->tiling)
1901		return true;
1902
1903	return kgem_bo_is_busy(priv->gpu_bo) || kgem_bo_is_busy(priv->cpu_bo);
1904}
1905
1906bool
1907sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags)
1908{
1909	struct sna_cow *cow = COW(priv->cow);
1910
1911	DBG(("%s: pixmap=%ld, handle=%d [refcnt=%d], cow refcnt=%d, flags=%x\n",
1912	     __FUNCTION__,
1913	     priv->pixmap->drawable.serialNumber,
1914	     priv->gpu_bo->handle,
1915	     priv->gpu_bo->refcnt,
1916	     cow->refcnt,
1917	     flags));
1918
1919	assert(priv->gpu_bo == cow->bo);
1920	assert(cow->refcnt);
1921
1922	if (flags && /* flags == 0 => force decouple */
1923	    (flags & MOVE_WRITE) == 0 &&
1924	    (((flags & __MOVE_FORCE) == 0) || IS_COW_OWNER(priv->cow)))
1925		return true;
1926
1927	if (!IS_COW_OWNER(priv->cow))
1928		list_del(&priv->cow_list);
1929
1930	if (!--cow->refcnt) {
1931		DBG(("%s: freeing cow\n", __FUNCTION__));
1932		assert(list_is_empty(&cow->list));
1933		free(cow);
1934	} else if (IS_COW_OWNER(priv->cow) && priv->pinned) {
1935		PixmapPtr pixmap = priv->pixmap;
1936		struct kgem_bo *bo;
1937		BoxRec box;
1938
1939		DBG(("%s: copying the Holy cow\n", __FUNCTION__));
1940
1941		box.x1 = box.y1 = 0;
1942		box.x2 = pixmap->drawable.width;
1943		box.y2 = pixmap->drawable.height;
1944
1945		bo = kgem_create_2d(&sna->kgem,
1946				    box.x2, box.y2,
1947				    pixmap->drawable.bitsPerPixel,
1948				    sna_pixmap_default_tiling(sna, pixmap),
1949				    0);
1950		if (bo == NULL) {
1951			cow->refcnt++;
1952			DBG(("%s: allocation failed\n", __FUNCTION__));
1953			return false;
1954		}
1955
1956		if (!sna->render.copy_boxes(sna, GXcopy,
1957					    &pixmap->drawable, priv->gpu_bo, 0, 0,
1958					    &pixmap->drawable, bo, 0, 0,
1959					    &box, 1, 0)) {
1960			DBG(("%s: copy failed\n", __FUNCTION__));
1961			kgem_bo_destroy(&sna->kgem, bo);
1962			cow->refcnt++;
1963			return false;
1964		}
1965
1966		assert(!list_is_empty(&cow->list));
1967		while (!list_is_empty(&cow->list)) {
1968			struct sna_pixmap *clone;
1969
1970			clone = list_first_entry(&cow->list,
1971						 struct sna_pixmap, cow_list);
1972			list_del(&clone->cow_list);
1973
1974			assert(clone->gpu_bo == cow->bo);
1975			sna_pixmap_unmap(clone->pixmap, clone);
1976			kgem_bo_destroy(&sna->kgem, clone->gpu_bo);
1977			clone->gpu_bo = kgem_bo_reference(bo);
1978		}
1979		cow->bo = bo;
1980		kgem_bo_destroy(&sna->kgem, bo);
1981	} else {
1982		struct kgem_bo *bo = NULL;
1983
1984		if (flags & MOVE_READ) {
1985			PixmapPtr pixmap = priv->pixmap;
1986			unsigned create, tiling;
1987			BoxRec box;
1988
1989			DBG(("%s: copying cow\n", __FUNCTION__));
1990
1991			box.x1 = box.y1 = 0;
1992			box.x2 = pixmap->drawable.width;
1993			box.y2 = pixmap->drawable.height;
1994
1995			if (flags & __MOVE_PRIME) {
1996				create = CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT;
1997				tiling = I915_TILING_NONE;
1998			} else {
1999				create = 0;
2000				tiling = sna_pixmap_default_tiling(sna, pixmap);
2001			}
2002
2003			bo = kgem_create_2d(&sna->kgem,
2004					    box.x2, box.y2,
2005					    pixmap->drawable.bitsPerPixel,
2006					    tiling, create);
2007			if (bo == NULL) {
2008				cow->refcnt++;
2009				DBG(("%s: allocation failed\n", __FUNCTION__));
2010				return false;
2011			}
2012
2013			if (!sna->render.copy_boxes(sna, GXcopy,
2014						    &pixmap->drawable, priv->gpu_bo, 0, 0,
2015						    &pixmap->drawable, bo, 0, 0,
2016						    &box, 1, 0)) {
2017				DBG(("%s: copy failed\n", __FUNCTION__));
2018				kgem_bo_destroy(&sna->kgem, bo);
2019				cow->refcnt++;
2020				return false;
2021			}
2022		}
2023
2024		assert(priv->gpu_bo);
2025		sna_pixmap_unmap(priv->pixmap, priv);
2026		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
2027		priv->gpu_bo = bo;
2028	}
2029
2030	priv->cow = NULL;
2031	return true;
2032}
2033
2034static bool
2035sna_pixmap_make_cow(struct sna *sna,
2036		    struct sna_pixmap *src_priv,
2037		    struct sna_pixmap *dst_priv)
2038{
2039	struct sna_cow *cow;
2040
2041	assert(src_priv->gpu_bo);
2042
2043	if (!USE_COW)
2044		return false;
2045
2046	if (src_priv->gpu_bo->proxy)
2047		return false;
2048
2049	DBG(("%s: make cow src=%ld, dst=%ld, handle=%d (already cow? src=%d, dst=%d)\n",
2050	     __FUNCTION__,
2051	     src_priv->pixmap->drawable.serialNumber,
2052	     dst_priv->pixmap->drawable.serialNumber,
2053	     src_priv->gpu_bo->handle,
2054	     src_priv->cow ? IS_COW_OWNER(src_priv->cow) ? 1 : -1 : 0,
2055	     dst_priv->cow ? IS_COW_OWNER(dst_priv->cow) ? 1 : -1 : 0));
2056
2057	if (dst_priv->pinned) {
2058		DBG(("%s: can't cow, dst_pinned=%x\n",
2059		     __FUNCTION__, dst_priv->pinned));
2060		return false;
2061	}
2062
2063	assert(dst_priv->move_to_gpu == NULL);
2064	assert(!dst_priv->flush);
2065	assert(list_is_empty(&dst_priv->cow_list));
2066
2067	cow = COW(src_priv->cow);
2068	if (cow == NULL) {
2069		cow = malloc(sizeof(*cow));
2070		if (cow == NULL)
2071			return false;
2072
2073		list_init(&cow->list);
2074
2075		cow->bo = src_priv->gpu_bo;
2076		cow->refcnt = 1;
2077
2078		DBG(("%s: moo! attaching source cow to pixmap=%ld, handle=%d\n",
2079		     __FUNCTION__,
2080		     src_priv->pixmap->drawable.serialNumber,
2081		     cow->bo->handle));
2082
2083		src_priv->cow = MAKE_COW_OWNER(cow);
2084		if (src_priv->flush & FLUSH_WRITE) {
2085			assert(!src_priv->shm);
2086			sna_add_flush_pixmap(sna, src_priv, src_priv->gpu_bo);
2087		}
2088	}
2089
2090	if (cow == COW(dst_priv->cow)) {
2091		assert(dst_priv->gpu_bo == cow->bo);
2092		return true;
2093	}
2094
2095	if (dst_priv->cow)
2096		sna_pixmap_undo_cow(sna, dst_priv, 0);
2097
2098	if (dst_priv->gpu_bo) {
2099		sna_pixmap_unmap(dst_priv->pixmap, dst_priv);
2100		kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo);
2101	}
2102	assert(!dst_priv->mapped);
2103	dst_priv->gpu_bo = kgem_bo_reference(cow->bo);
2104	dst_priv->cow = cow;
2105	list_add(&dst_priv->cow_list, &cow->list);
2106	cow->refcnt++;
2107
2108	DBG(("%s: moo! attaching clone to pixmap=%ld (source=%ld, handle=%d)\n",
2109	     __FUNCTION__,
2110	     dst_priv->pixmap->drawable.serialNumber,
2111	     src_priv->pixmap->drawable.serialNumber,
2112	     cow->bo->handle));
2113
2114	return true;
2115}
2116
2117static inline bool operate_inplace(struct sna_pixmap *priv, unsigned flags)
2118{
2119	if (!USE_INPLACE)
2120		return false;
2121
2122	if ((flags & MOVE_INPLACE_HINT) == 0) {
2123		DBG(("%s: no, inplace operation not suitable\n", __FUNCTION__));
2124		return false;
2125	}
2126
2127	assert((flags & MOVE_ASYNC_HINT) == 0 || (priv->create & KGEM_CAN_CREATE_LARGE));
2128
2129	if (priv->move_to_gpu && flags & MOVE_WRITE) {
2130		DBG(("%s: no, has pending move-to-gpu\n", __FUNCTION__));
2131		return false;
2132	}
2133
2134	if (priv->cow && flags & MOVE_WRITE) {
2135		DBG(("%s: no, has COW\n", __FUNCTION__));
2136		return false;
2137	}
2138
2139	if ((priv->create & KGEM_CAN_CREATE_GTT) == 0) {
2140		DBG(("%s: no, not accessible via GTT\n", __FUNCTION__));
2141		return false;
2142	}
2143
2144	if ((priv->gpu_damage == NULL || priv->cpu_damage) && flags & MOVE_READ) {
2145		DBG(("%s: no, has CPU damage and requires readback\n", __FUNCTION__));
2146		return false;
2147	}
2148
2149	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) {
2150		DBG(("%s: yes, CPU is busy\n", __FUNCTION__));
2151		return true;
2152	}
2153
2154	if (priv->create & KGEM_CAN_CREATE_LARGE) {
2155		DBG(("%s: large object, has GPU? %d\n",
2156		     __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0));
2157		return priv->gpu_bo != NULL;
2158	}
2159
2160	if (flags & MOVE_WRITE && priv->gpu_bo&&kgem_bo_is_busy(priv->gpu_bo)) {
2161		DBG(("%s: no, GPU is busy, so stage write\n", __FUNCTION__));
2162		return false;
2163	}
2164
2165	return true;
2166}
2167
2168bool
2169_sna_pixmap_move_to_cpu(PixmapPtr pixmap, unsigned int flags)
2170{
2171	struct sna *sna = to_sna_from_pixmap(pixmap);
2172	struct sna_pixmap *priv;
2173
2174	DBG(("%s(pixmap=%ld, %dx%d, flags=%x)\n", __FUNCTION__,
2175	     pixmap->drawable.serialNumber,
2176	     pixmap->drawable.width,
2177	     pixmap->drawable.height,
2178	     flags));
2179
2180	assert(flags & (MOVE_READ | MOVE_WRITE));
2181	assert_pixmap_damage(pixmap);
2182
2183	priv = sna_pixmap(pixmap);
2184	if (priv == NULL) {
2185		DBG(("%s: not attached\n", __FUNCTION__));
2186		return true;
2187	}
2188
2189	DBG(("%s: gpu_bo=%d, gpu_damage=%p, cpu_damage=%p, is-clear?=%d\n",
2190	     __FUNCTION__,
2191	     priv->gpu_bo ? priv->gpu_bo->handle : 0,
2192	     priv->gpu_damage, priv->cpu_damage, priv->clear));
2193
2194	assert(priv->gpu_damage == NULL || priv->gpu_bo);
2195
2196	if ((flags & MOVE_READ) == 0 && UNDO) {
2197		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
2198		if (priv->move_to_gpu)
2199			sna_pixmap_discard_shadow_damage(priv, NULL);
2200	}
2201
2202	if (kgem_bo_discard_cache(priv->gpu_bo, flags & MOVE_WRITE)) {
2203		assert(DAMAGE_IS_ALL(priv->cpu_damage));
2204		if (DAMAGE_IS_ALL(priv->gpu_damage)) {
2205			DBG(("%s: using magical upload buffer\n", __FUNCTION__));
2206			goto skip;
2207		}
2208
2209		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
2210		assert(priv->gpu_damage == NULL);
2211		assert(!priv->pinned);
2212		assert(!priv->mapped);
2213		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
2214		priv->gpu_bo = NULL;
2215	}
2216
2217	if (DAMAGE_IS_ALL(priv->cpu_damage)) {
2218		DBG(("%s: CPU all-damaged\n", __FUNCTION__));
2219		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage));
2220		assert(priv->gpu_damage == NULL || (flags & MOVE_WRITE) == 0);
2221		goto done;
2222	}
2223
2224	if (USE_INPLACE && (flags & MOVE_READ) == 0 && !(priv->cow || priv->move_to_gpu)) {
2225		assert(flags & MOVE_WRITE);
2226		DBG(("%s: no readback, discarding gpu damage [%d], pending clear[%d]\n",
2227		     __FUNCTION__, priv->gpu_damage != NULL, priv->clear));
2228
2229		if ((priv->gpu_bo || priv->create & KGEM_CAN_CREATE_GPU) &&
2230		    pixmap_inplace(sna, pixmap, priv, flags) &&
2231		    sna_pixmap_create_mappable_gpu(pixmap, true)) {
2232			void *ptr;
2233
2234			DBG(("%s: write inplace\n", __FUNCTION__));
2235			assert(!priv->shm);
2236			assert(priv->cow == NULL);
2237			assert(priv->move_to_gpu == NULL);
2238			assert(priv->gpu_bo->exec == NULL);
2239			assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL);
2240
2241			ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo);
2242			if (ptr == NULL)
2243				goto skip_inplace_map;
2244
2245			pixmap->devPrivate.ptr = ptr;
2246			pixmap->devKind = priv->gpu_bo->pitch;
2247			priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
2248			assert(has_coherent_ptr(sna, priv, flags));
2249
2250			assert(priv->gpu_bo->proxy == NULL);
2251			sna_damage_all(&priv->gpu_damage, pixmap);
2252			sna_damage_destroy(&priv->cpu_damage);
2253			priv->clear = false;
2254			list_del(&priv->flush_list);
2255
2256			assert(!priv->shm);
2257			assert(priv->cpu_bo == NULL || !priv->cpu_bo->flush);
2258			sna_pixmap_free_cpu(sna, priv, priv->cpu);
2259			priv->cpu &= priv->mapped == MAPPED_CPU;
2260
2261			assert_pixmap_damage(pixmap);
2262			return true;
2263		}
2264
2265skip_inplace_map:
2266		sna_damage_destroy(&priv->gpu_damage);
2267		priv->clear = false;
2268		if ((flags & MOVE_ASYNC_HINT) == 0 &&
2269		    priv->cpu_bo && !priv->cpu_bo->flush &&
2270		    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2271			DBG(("%s: discarding busy CPU bo\n", __FUNCTION__));
2272			assert(!priv->shm);
2273			assert(priv->gpu_bo == NULL || priv->gpu_damage == NULL);
2274
2275			sna_damage_destroy(&priv->cpu_damage);
2276			sna_pixmap_free_cpu(sna, priv, false);
2277
2278			assert(priv->mapped == MAPPED_NONE);
2279			if (!sna_pixmap_alloc_cpu(sna, pixmap, priv, 0))
2280				return false;
2281			assert(priv->mapped == MAPPED_NONE);
2282			assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2283
2284			goto mark_damage;
2285		}
2286	}
2287
2288	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2289
2290	if (operate_inplace(priv, flags) &&
2291	    pixmap_inplace(sna, pixmap, priv, flags) &&
2292	    sna_pixmap_create_mappable_gpu(pixmap, (flags & MOVE_READ) == 0)) {
2293		void *ptr;
2294
2295		DBG(("%s: try to operate inplace (GTT)\n", __FUNCTION__));
2296		assert(priv->gpu_bo);
2297		assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
2298		assert(!priv->move_to_gpu);
2299		assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2300		assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL);
2301		/* XXX only sync for writes? */
2302		kgem_bo_submit(&sna->kgem, priv->gpu_bo);
2303		assert(priv->gpu_bo->exec == NULL);
2304
2305		ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo);
2306		if (ptr != NULL) {
2307			pixmap->devPrivate.ptr = ptr;
2308			pixmap->devKind = priv->gpu_bo->pitch;
2309			priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
2310			assert(has_coherent_ptr(sna, priv, flags));
2311
2312			if (flags & MOVE_WRITE) {
2313				assert(priv->gpu_bo->proxy == NULL);
2314				sna_damage_all(&priv->gpu_damage, pixmap);
2315				sna_damage_destroy(&priv->cpu_damage);
2316				sna_pixmap_free_cpu(sna, priv, priv->cpu);
2317				list_del(&priv->flush_list);
2318				priv->clear = false;
2319			}
2320			priv->cpu &= priv->mapped == MAPPED_CPU;
2321
2322			assert_pixmap_damage(pixmap);
2323			DBG(("%s: operate inplace (GTT)\n", __FUNCTION__));
2324			return true;
2325		}
2326	}
2327
2328	sna_pixmap_unmap(pixmap, priv);
2329
2330	if (USE_INPLACE &&
2331	    (flags & MOVE_WRITE ? (void *)priv->gpu_bo : (void *)priv->gpu_damage) && priv->cpu_damage == NULL &&
2332	    priv->gpu_bo->tiling == I915_TILING_NONE &&
2333	    (flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE)) &&
2334	    (!priv->clear || !kgem_bo_is_busy(priv->gpu_bo)) &&
2335	    ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 ||
2336	     (!priv->cow && !priv->move_to_gpu && !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)))) {
2337		void *ptr;
2338
2339		DBG(("%s: try to operate inplace (CPU)\n", __FUNCTION__));
2340		assert(priv->gpu_bo);
2341		assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
2342		assert(priv->move_to_gpu == NULL || (flags & MOVE_WRITE) == 0);
2343		assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2344
2345		assert(!priv->mapped);
2346		assert(priv->gpu_bo->tiling == I915_TILING_NONE);
2347
2348		ptr = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
2349		if (ptr != NULL) {
2350			pixmap->devPrivate.ptr = ptr;
2351			pixmap->devKind = priv->gpu_bo->pitch;
2352			priv->mapped = MAPPED_CPU;
2353			assert(has_coherent_ptr(sna, priv, flags));
2354
2355			if (flags & MOVE_WRITE) {
2356				assert(priv->gpu_bo->proxy == NULL);
2357				sna_damage_all(&priv->gpu_damage, pixmap);
2358				sna_damage_destroy(&priv->cpu_damage);
2359				sna_pixmap_free_cpu(sna, priv, priv->cpu);
2360				list_del(&priv->flush_list);
2361				priv->clear = false;
2362				priv->cpu = true;
2363			}
2364
2365			assert(pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu));
2366			kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo,
2367					       FORCE_FULL_SYNC || flags & MOVE_WRITE);
2368			assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo));
2369			assert_pixmap_damage(pixmap);
2370			assert(has_coherent_ptr(sna, priv, flags));
2371			DBG(("%s: operate inplace (CPU)\n", __FUNCTION__));
2372			return true;
2373		}
2374	}
2375
2376	assert(priv->mapped == MAPPED_NONE);
2377	if (((flags & MOVE_READ) == 0 || priv->clear) &&
2378	    priv->cpu_bo && !priv->cpu_bo->flush &&
2379	    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2380		assert(!priv->shm);
2381		sna_pixmap_free_cpu(sna, priv, false);
2382	}
2383
2384	assert(priv->mapped == MAPPED_NONE);
2385	if (pixmap->devPrivate.ptr == NULL &&
2386	    !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags))
2387		return false;
2388	assert(priv->mapped == MAPPED_NONE);
2389	assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2390
2391	if (flags & MOVE_READ) {
2392		if (priv->clear) {
2393			DBG(("%s: applying clear [%08x] size=%dx%d, stride=%d (total=%d)\n",
2394			     __FUNCTION__, priv->clear_color, pixmap->drawable.width, pixmap->drawable.height,
2395			     pixmap->devKind, pixmap->devKind * pixmap->drawable.height));
2396
2397			if (priv->cpu_bo) {
2398				kgem_bo_undo(&sna->kgem, priv->cpu_bo);
2399				if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) &&
2400				    sna->kgem.can_blt_cpu &&
2401				    sna->render.fill_one(sna,
2402							  pixmap, priv->cpu_bo, priv->clear_color,
2403							  0, 0,
2404							  pixmap->drawable.width,
2405							  pixmap->drawable.height,
2406							  GXcopy))
2407					goto clear_done;
2408
2409				DBG(("%s: syncing CPU bo\n", __FUNCTION__));
2410				kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
2411				assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
2412			}
2413
2414			if (sigtrap_get() == 0) {
2415				assert(pixmap->devKind);
2416				sigtrap_assert_active();
2417				if (priv->clear_color == 0 ||
2418				    pixmap->drawable.bitsPerPixel == 8 ||
2419				    priv->clear_color == (1 << pixmap->drawable.depth) - 1) {
2420					memset(pixmap->devPrivate.ptr, priv->clear_color,
2421					       (size_t)pixmap->devKind * pixmap->drawable.height);
2422				} else {
2423					pixman_fill(pixmap->devPrivate.ptr,
2424						    pixmap->devKind/sizeof(uint32_t),
2425						    pixmap->drawable.bitsPerPixel,
2426						    0, 0,
2427						    pixmap->drawable.width,
2428						    pixmap->drawable.height,
2429						    priv->clear_color);
2430				}
2431				sigtrap_put();
2432			} else
2433				return false;
2434
2435clear_done:
2436			sna_damage_all(&priv->cpu_damage, pixmap);
2437			sna_pixmap_free_gpu(sna, priv);
2438			assert(priv->gpu_damage == NULL);
2439			assert(priv->clear == false);
2440		}
2441
2442		if (priv->gpu_damage) {
2443			const BoxRec *box;
2444			int n;
2445
2446			DBG(("%s: flushing GPU damage\n", __FUNCTION__));
2447			assert(priv->gpu_bo);
2448
2449			n = sna_damage_get_boxes(priv->gpu_damage, &box);
2450			if (n) {
2451				if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ)) {
2452					DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
2453					return false;
2454				}
2455
2456				download_boxes(sna, priv, n, box);
2457			}
2458
2459			__sna_damage_destroy(DAMAGE_PTR(priv->gpu_damage));
2460			priv->gpu_damage = NULL;
2461		}
2462	}
2463
2464	if (flags & MOVE_WRITE || priv->create & KGEM_CAN_CREATE_LARGE) {
2465mark_damage:
2466		DBG(("%s: marking as damaged\n", __FUNCTION__));
2467		sna_damage_all(&priv->cpu_damage, pixmap);
2468		sna_pixmap_free_gpu(sna, priv);
2469		assert(priv->gpu_damage == NULL);
2470		assert(priv->clear == false);
2471
2472		if (priv->flush) {
2473			assert(!priv->shm);
2474			sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
2475		}
2476	}
2477
2478done:
2479	if (flags & MOVE_WRITE) {
2480		assert(DAMAGE_IS_ALL(priv->cpu_damage));
2481		assert(priv->gpu_damage == NULL);
2482		assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
2483		if (priv->cow)
2484			sna_pixmap_undo_cow(sna, priv, 0);
2485		if (priv->gpu_bo && priv->gpu_bo->rq == NULL) {
2486			DBG(("%s: discarding idle GPU bo\n", __FUNCTION__));
2487			sna_pixmap_free_gpu(sna, priv);
2488		}
2489		if (priv->flush) {
2490			assert(!priv->shm);
2491			sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
2492		}
2493		priv->source_count = SOURCE_BIAS;
2494	}
2495
2496	if (priv->cpu_bo) {
2497		if ((flags & MOVE_ASYNC_HINT) == 0) {
2498			DBG(("%s: syncing CPU bo\n", __FUNCTION__));
2499			assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
2500			kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo,
2501					       FORCE_FULL_SYNC || flags & MOVE_WRITE);
2502			assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo));
2503		}
2504	}
2505skip:
2506	priv->cpu |= (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE;
2507	assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2508	assert(pixmap->devKind);
2509	assert_pixmap_damage(pixmap);
2510	assert(has_coherent_ptr(sna, sna_pixmap(pixmap), flags));
2511	return true;
2512}
2513
2514static bool
2515region_overlaps_damage(const RegionRec *region,
2516		       struct sna_damage *damage,
2517		       int dx, int dy)
2518{
2519	const BoxRec *re, *de;
2520
2521	DBG(("%s?\n", __FUNCTION__));
2522
2523	if (damage == NULL)
2524		return false;
2525
2526	if (DAMAGE_IS_ALL(damage))
2527		return true;
2528
2529	re = &region->extents;
2530	de = &DAMAGE_PTR(damage)->extents;
2531	DBG(("%s: region (%d, %d), (%d, %d), damage (%d, %d), (%d, %d)\n",
2532	     __FUNCTION__,
2533	     re->x1, re->y1, re->x2, re->y2,
2534	     de->x1, de->y1, de->x2, de->y2));
2535
2536	return (re->x1 + dx < de->x2 && re->x2 + dx > de->x1 &&
2537		re->y1 + dy < de->y2 && re->y2 + dy > de->y1);
2538}
2539
2540static inline bool region_inplace(struct sna *sna,
2541				  PixmapPtr pixmap,
2542				  RegionPtr region,
2543				  struct sna_pixmap *priv,
2544				  unsigned flags)
2545{
2546	assert_pixmap_damage(pixmap);
2547
2548	if (FORCE_INPLACE)
2549		return FORCE_INPLACE > 0;
2550
2551	if (wedged(sna) && !priv->pinned)
2552		return false;
2553
2554	if (priv->gpu_damage &&
2555	    (priv->clear || (flags & MOVE_READ) == 0) &&
2556	    kgem_bo_is_busy(priv->gpu_bo))
2557		return false;
2558
2559	if (flags & MOVE_READ &&
2560	    (priv->cpu ||
2561	     priv->gpu_damage == NULL ||
2562	     region_overlaps_damage(region, priv->cpu_damage, 0, 0))) {
2563		DBG(("%s: no, uncovered CPU damage pending\n", __FUNCTION__));
2564		return false;
2565	}
2566
2567	if (priv->mapped) {
2568		DBG(("%s: %s, already mapped, continuing\n", __FUNCTION__,
2569		     has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no"));
2570		return has_coherent_map(sna, priv->gpu_bo, flags);
2571	}
2572
2573	if (priv->flush) {
2574		DBG(("%s: yes, exported via dri, will flush\n", __FUNCTION__));
2575		return true;
2576	}
2577
2578	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
2579		DBG(("%s: yes, already wholly damaged on the GPU\n", __FUNCTION__));
2580		assert(priv->gpu_bo);
2581		return true;
2582	}
2583
2584	if (priv->cpu_bo && priv->cpu) {
2585		DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__));
2586		return false;
2587	}
2588
2589	DBG(("%s: (%dx%d), inplace? %d\n",
2590	     __FUNCTION__,
2591	     region->extents.x2 - region->extents.x1,
2592	     region->extents.y2 - region->extents.y1,
2593	     ((int)(region->extents.x2 - region->extents.x1) *
2594	      (int)(region->extents.y2 - region->extents.y1) *
2595	      pixmap->drawable.bitsPerPixel >> 12)
2596	     >= sna->kgem.half_cpu_cache_pages));
2597	return ((int)(region->extents.x2 - region->extents.x1) *
2598		(int)(region->extents.y2 - region->extents.y1) *
2599		pixmap->drawable.bitsPerPixel >> 12)
2600		>= sna->kgem.half_cpu_cache_pages;
2601}
2602
2603static bool cpu_clear_boxes(struct sna *sna,
2604			    PixmapPtr pixmap,
2605			    struct sna_pixmap *priv,
2606			    const BoxRec *box, int n)
2607{
2608	struct sna_fill_op fill;
2609
2610	if (!sna->kgem.can_blt_cpu)
2611		return false;
2612
2613	if (!sna_fill_init_blt(&fill, sna,
2614			       pixmap, priv->cpu_bo,
2615			       GXcopy, priv->clear_color,
2616			       FILL_BOXES)) {
2617		DBG(("%s: unsupported fill\n",
2618		     __FUNCTION__));
2619		return false;
2620	}
2621
2622	fill.boxes(sna, &fill, box, n);
2623	fill.done(sna, &fill);
2624	return true;
2625}
2626
2627bool
2628sna_drawable_move_region_to_cpu(DrawablePtr drawable,
2629				RegionPtr region,
2630				unsigned flags)
2631{
2632	PixmapPtr pixmap = get_drawable_pixmap(drawable);
2633	struct sna *sna = to_sna_from_pixmap(pixmap);
2634	struct sna_pixmap *priv;
2635	int16_t dx, dy;
2636
2637	DBG(("%s(pixmap=%ld (%dx%d), [(%d, %d), (%d, %d)], flags=%x)\n",
2638	     __FUNCTION__, pixmap->drawable.serialNumber,
2639	     pixmap->drawable.width, pixmap->drawable.height,
2640	     RegionExtents(region)->x1, RegionExtents(region)->y1,
2641	     RegionExtents(region)->x2, RegionExtents(region)->y2,
2642	     flags));
2643
2644	assert_pixmap_damage(pixmap);
2645	if (flags & MOVE_WRITE) {
2646		assert_drawable_contains_box(drawable, &region->extents);
2647	}
2648	assert(flags & (MOVE_WRITE | MOVE_READ));
2649
2650	if (box_empty(&region->extents))
2651		return true;
2652
2653	if (MIGRATE_ALL || DBG_NO_PARTIAL_MOVE_TO_CPU) {
2654		if (!region_subsumes_pixmap(region, pixmap))
2655			flags |= MOVE_READ;
2656		return _sna_pixmap_move_to_cpu(pixmap, flags);
2657	}
2658
2659	priv = sna_pixmap(pixmap);
2660	if (priv == NULL) {
2661		DBG(("%s: not attached to pixmap %ld (depth %d)\n",
2662		     __FUNCTION__, pixmap->drawable.serialNumber, pixmap->drawable.depth));
2663		return true;
2664	}
2665
2666	assert(priv->gpu_damage == NULL || priv->gpu_bo);
2667
2668	if (kgem_bo_discard_cache(priv->gpu_bo, flags & MOVE_WRITE)) {
2669		assert(DAMAGE_IS_ALL(priv->cpu_damage));
2670		if (DAMAGE_IS_ALL(priv->gpu_damage)) {
2671			DBG(("%s: using magical upload buffer\n", __FUNCTION__));
2672			goto skip;
2673		}
2674
2675		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
2676		assert(priv->gpu_damage == NULL);
2677		assert(!priv->pinned);
2678		assert(!priv->mapped);
2679		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
2680		priv->gpu_bo = NULL;
2681	}
2682
2683	if (sna_damage_is_all(&priv->cpu_damage,
2684			      pixmap->drawable.width,
2685			      pixmap->drawable.height)) {
2686		bool discard_gpu = priv->cpu;
2687
2688		DBG(("%s: pixmap=%ld all damaged on CPU\n",
2689		     __FUNCTION__, pixmap->drawable.serialNumber));
2690		assert(!priv->clear);
2691
2692		sna_damage_destroy(&priv->gpu_damage);
2693
2694		if ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 &&
2695		    priv->cpu_bo && !priv->cpu_bo->flush &&
2696		    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2697			DBG(("%s: active CPU bo replacing\n", __FUNCTION__));
2698			assert(!priv->shm);
2699			assert(!IS_STATIC_PTR(priv->ptr));
2700
2701			if (!region_subsumes_pixmap(region, pixmap)) {
2702				DBG(("%s: partial replacement\n", __FUNCTION__));
2703				if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
2704					RegionTranslate(region, dx, dy);
2705
2706				if (sna->kgem.has_llc && !priv->pinned &&
2707				    sna_pixmap_default_tiling(sna, pixmap) == I915_TILING_NONE) {
2708#ifdef DEBUG_MEMORY
2709					sna->debug_memory.cpu_bo_allocs--;
2710					sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
2711#endif
2712					DBG(("%s: promoting CPU bo to GPU bo\n", __FUNCTION__));
2713					if (priv->gpu_bo)
2714						sna_pixmap_free_gpu(sna, priv);
2715					priv->gpu_bo = priv->cpu_bo;
2716					priv->cpu_bo = NULL;
2717					priv->ptr = NULL;
2718					pixmap->devPrivate.ptr = NULL;
2719
2720					priv->gpu_damage = priv->cpu_damage;
2721					priv->cpu_damage = NULL;
2722
2723					sna_damage_subtract(&priv->gpu_damage, region);
2724					discard_gpu = false;
2725				} else {
2726					DBG(("%s: pushing surrounding damage to GPU bo\n", __FUNCTION__));
2727					sna_damage_subtract(&priv->cpu_damage, region);
2728					assert(priv->cpu_damage);
2729					if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) {
2730						sna_pixmap_free_cpu(sna, priv, false);
2731						if (priv->flush)
2732							sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
2733
2734						assert(priv->cpu_damage == NULL);
2735						sna_damage_all(&priv->gpu_damage, pixmap);
2736						sna_damage_subtract(&priv->gpu_damage, region);
2737						discard_gpu = false;
2738					}
2739				}
2740				sna_damage_add_to_pixmap(&priv->cpu_damage, region, pixmap);
2741				if (priv->flush) {
2742					assert(!priv->shm);
2743					sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
2744				}
2745
2746				if (dx | dy)
2747					RegionTranslate(region, -dx, -dy);
2748			} else
2749				sna_pixmap_free_cpu(sna, priv, false);
2750		}
2751
2752		if (flags & MOVE_WRITE && discard_gpu)
2753			sna_pixmap_free_gpu(sna, priv);
2754
2755		sna_pixmap_unmap(pixmap, priv);
2756		assert(priv->mapped == MAPPED_NONE);
2757		if (pixmap->devPrivate.ptr == NULL &&
2758		    !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags))
2759			return false;
2760		assert(priv->mapped == MAPPED_NONE);
2761		assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2762
2763		goto out;
2764	}
2765
2766	if (USE_INPLACE &&
2767	    (priv->create & KGEM_CAN_CREATE_LARGE ||
2768	     ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 &&
2769	      (priv->flush ||
2770	       (flags & MOVE_WHOLE_HINT && whole_pixmap_inplace(pixmap)) ||
2771	       box_inplace(pixmap, &region->extents))))) {
2772		DBG(("%s: marking for inplace hint (%d, %d)\n",
2773		     __FUNCTION__, priv->flush, box_inplace(pixmap, &region->extents)));
2774		flags |= MOVE_INPLACE_HINT;
2775	}
2776
2777	if (region_subsumes_pixmap(region, pixmap)) {
2778		DBG(("%s: region (%d, %d), (%d, %d) + (%d, %d) subsumes pixmap (%dx%d)\n",
2779		       __FUNCTION__,
2780		       region->extents.x1,
2781		       region->extents.y1,
2782		       region->extents.x2,
2783		       region->extents.y2,
2784		       get_drawable_dx(drawable), get_drawable_dy(drawable),
2785		       pixmap->drawable.width,
2786		       pixmap->drawable.height));
2787		return _sna_pixmap_move_to_cpu(pixmap, flags);
2788	}
2789
2790	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2791
2792	if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
2793		DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy));
2794		RegionTranslate(region, dx, dy);
2795	}
2796
2797	if (priv->move_to_gpu) {
2798		DBG(("%s: applying move-to-gpu override\n", __FUNCTION__));
2799		if ((flags & MOVE_READ) == 0)
2800			sna_pixmap_discard_shadow_damage(priv, region);
2801		if (!priv->move_to_gpu(sna, priv, MOVE_READ)) {
2802			DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
2803			return NULL;
2804		}
2805	}
2806
2807	if (operate_inplace(priv, flags) &&
2808	    region_inplace(sna, pixmap, region, priv, flags) &&
2809	    sna_pixmap_create_mappable_gpu(pixmap, false)) {
2810		void *ptr;
2811
2812		DBG(("%s: try to operate inplace\n", __FUNCTION__));
2813		assert(priv->gpu_bo);
2814		assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
2815		assert(priv->move_to_gpu == NULL || (flags & MOVE_WRITE) == 0);
2816		assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2817
2818		/* XXX only sync for writes? */
2819		kgem_bo_submit(&sna->kgem, priv->gpu_bo);
2820		assert(priv->gpu_bo->exec == NULL);
2821
2822		ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo);
2823		if (ptr != NULL) {
2824			pixmap->devPrivate.ptr = ptr;
2825			pixmap->devKind = priv->gpu_bo->pitch;
2826			priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
2827			assert(has_coherent_ptr(sna, priv, flags));
2828
2829			if (flags & MOVE_WRITE) {
2830				if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
2831					assert(!priv->clear);
2832					sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap);
2833					if (sna_damage_is_all(&priv->gpu_damage,
2834							      pixmap->drawable.width,
2835							      pixmap->drawable.height)) {
2836						DBG(("%s: replaced entire pixmap, destroying CPU shadow\n",
2837						     __FUNCTION__));
2838						sna_damage_destroy(&priv->cpu_damage);
2839						list_del(&priv->flush_list);
2840					} else
2841						sna_damage_subtract(&priv->cpu_damage,
2842								    region);
2843				}
2844				priv->clear = false;
2845			}
2846			priv->cpu &= priv->mapped == MAPPED_CPU;
2847			assert_pixmap_damage(pixmap);
2848			if (dx | dy)
2849				RegionTranslate(region, -dx, -dy);
2850			DBG(("%s: operate inplace\n", __FUNCTION__));
2851			return true;
2852		}
2853	}
2854
2855	if (priv->clear && flags & MOVE_WRITE) {
2856		DBG(("%s: pending clear, moving whole pixmap for partial write\n", __FUNCTION__));
2857demote_to_cpu:
2858		if (dx | dy)
2859			RegionTranslate(region, -dx, -dy);
2860		return _sna_pixmap_move_to_cpu(pixmap, flags | MOVE_READ);
2861	}
2862
2863	if (flags & MOVE_WHOLE_HINT) {
2864		DBG(("%s: region (%d, %d), (%d, %d) marked with WHOLE hint, pixmap %dx%d\n",
2865		       __FUNCTION__,
2866		       region->extents.x1,
2867		       region->extents.y1,
2868		       region->extents.x2,
2869		       region->extents.y2,
2870		       pixmap->drawable.width,
2871		       pixmap->drawable.height));
2872move_to_cpu:
2873		if ((flags & MOVE_READ) == 0)
2874			sna_damage_subtract(&priv->gpu_damage, region);
2875		goto demote_to_cpu;
2876	}
2877
2878	sna_pixmap_unmap(pixmap, priv);
2879
2880	if (USE_INPLACE &&
2881	    priv->gpu_damage &&
2882	    priv->gpu_bo->tiling == I915_TILING_NONE &&
2883	    ((priv->cow == NULL && priv->move_to_gpu == NULL) || (flags & MOVE_WRITE) == 0) &&
2884	    (DAMAGE_IS_ALL(priv->gpu_damage) ||
2885	     sna_damage_contains_box__no_reduce(priv->gpu_damage,
2886						&region->extents)) &&
2887	    kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE) &&
2888	    ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 ||
2889	     !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) {
2890		void *ptr;
2891
2892		DBG(("%s: try to operate inplace (CPU), read? %d, write? %d\n",
2893		     __FUNCTION__, !!(flags & MOVE_READ), !!(flags & MOVE_WRITE)));
2894		assert(priv->gpu_bo);
2895		assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2896		assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
2897		assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
2898
2899		ptr = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
2900		if (ptr != NULL) {
2901			pixmap->devPrivate.ptr = ptr;
2902			pixmap->devKind = priv->gpu_bo->pitch;
2903			priv->mapped = MAPPED_CPU;
2904			assert(has_coherent_ptr(sna, priv, flags));
2905
2906			if (flags & MOVE_WRITE) {
2907				if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
2908					assert(!priv->clear);
2909					sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap);
2910					if (sna_damage_is_all(&priv->gpu_damage,
2911							      pixmap->drawable.width,
2912							      pixmap->drawable.height)) {
2913						DBG(("%s: replaced entire pixmap, destroying CPU shadow\n",
2914						     __FUNCTION__));
2915						sna_damage_destroy(&priv->cpu_damage);
2916						list_del(&priv->flush_list);
2917					} else
2918						sna_damage_subtract(&priv->cpu_damage,
2919								    region);
2920				}
2921				priv->clear = false;
2922			}
2923			assert_pixmap_damage(pixmap);
2924
2925			kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo,
2926					       FORCE_FULL_SYNC || flags & MOVE_WRITE);
2927			priv->cpu = true;
2928
2929			assert_pixmap_map(pixmap, priv);
2930			assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo));
2931			if (dx | dy)
2932				RegionTranslate(region, -dx, -dy);
2933			DBG(("%s: operate inplace (CPU)\n", __FUNCTION__));
2934			return true;
2935		}
2936	}
2937
2938	if ((priv->clear || (flags & MOVE_READ) == 0) &&
2939	    priv->cpu_bo && !priv->cpu_bo->flush &&
2940	    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2941		sna_damage_subtract(&priv->cpu_damage, region);
2942		if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) {
2943			assert(priv->gpu_bo);
2944			sna_damage_all(&priv->gpu_damage, pixmap);
2945			sna_pixmap_free_cpu(sna, priv, false);
2946		}
2947	}
2948
2949	assert(priv->mapped == MAPPED_NONE);
2950	if (pixmap->devPrivate.ptr == NULL &&
2951	    !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags)) {
2952		DBG(("%s: CPU bo allocation failed, trying full move-to-cpu\n", __FUNCTION__));
2953		goto move_to_cpu;
2954	}
2955	assert(priv->mapped == MAPPED_NONE);
2956	assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2957
2958	if (priv->gpu_bo == NULL) {
2959		assert(priv->gpu_damage == NULL);
2960		goto done;
2961	}
2962
2963	assert(priv->gpu_bo->proxy == NULL);
2964
2965	if ((flags & MOVE_READ) == 0) {
2966		assert(flags & MOVE_WRITE);
2967		sna_damage_subtract(&priv->gpu_damage, region);
2968		priv->clear = false;
2969		goto done;
2970	}
2971
2972	if (priv->clear) {
2973		int n = region_num_rects(region);
2974		const BoxRec *box = region_rects(region);
2975
2976		assert(DAMAGE_IS_ALL(priv->gpu_damage));
2977		assert(priv->cpu_damage == NULL);
2978
2979		DBG(("%s: pending clear, doing partial fill\n", __FUNCTION__));
2980		if (priv->cpu_bo) {
2981			if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) &&
2982			    cpu_clear_boxes(sna, pixmap, priv, box, n))
2983				goto clear_done;
2984
2985			DBG(("%s: syncing CPU bo\n", __FUNCTION__));
2986			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
2987			assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
2988		}
2989
2990		if (sigtrap_get() == 0) {
2991			assert(pixmap->devKind);
2992			sigtrap_assert_active();
2993			do {
2994				pixman_fill(pixmap->devPrivate.ptr,
2995					    pixmap->devKind/sizeof(uint32_t),
2996					    pixmap->drawable.bitsPerPixel,
2997					    box->x1, box->y1,
2998					    box->x2 - box->x1,
2999					    box->y2 - box->y1,
3000					    priv->clear_color);
3001				box++;
3002			} while (--n);
3003			sigtrap_put();
3004		} else
3005			return false;
3006
3007clear_done:
3008		if (flags & MOVE_WRITE ||
3009		    region->extents.x2 - region->extents.x1 > 1 ||
3010		    region->extents.y2 - region->extents.y1 > 1) {
3011			sna_damage_subtract(&priv->gpu_damage, region);
3012			priv->clear = false;
3013		}
3014		goto done;
3015	}
3016
3017	if (priv->gpu_damage &&
3018	    (DAMAGE_IS_ALL(priv->gpu_damage) ||
3019	     sna_damage_overlaps_box(priv->gpu_damage, &region->extents))) {
3020		DBG(("%s: region (%dx%d) overlaps gpu damage\n",
3021		     __FUNCTION__,
3022		     region->extents.x2 - region->extents.x1,
3023		     region->extents.y2 - region->extents.y1));
3024		assert(priv->gpu_bo);
3025
3026		if (priv->cpu_damage == NULL) {
3027			if ((flags & MOVE_WRITE) == 0 &&
3028			    region->extents.x2 - region->extents.x1 == 1 &&
3029			    region->extents.y2 - region->extents.y1 == 1) {
3030				/*  Often associated with synchronisation, KISS */
3031				DBG(("%s: single pixel read\n", __FUNCTION__));
3032				sna_read_boxes(sna, pixmap, priv->gpu_bo,
3033					       &region->extents, 1);
3034				goto done;
3035			}
3036		} else {
3037			if (DAMAGE_IS_ALL(priv->cpu_damage) ||
3038			    sna_damage_contains_box__no_reduce(priv->cpu_damage,
3039							       &region->extents)) {
3040				assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_OUT);
3041				assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_IN);
3042
3043				DBG(("%s: region already in CPU damage\n",
3044				     __FUNCTION__));
3045				goto already_damaged;
3046			}
3047		}
3048
3049		if (sna_damage_contains_box(&priv->gpu_damage,
3050					    &region->extents) != PIXMAN_REGION_OUT) {
3051			RegionRec want, *r = region;
3052
3053			DBG(("%s: region (%dx%d) intersects gpu damage\n",
3054			     __FUNCTION__,
3055			     region->extents.x2 - region->extents.x1,
3056			     region->extents.y2 - region->extents.y1));
3057
3058			if ((flags & MOVE_WRITE) == 0 &&
3059			    region->extents.x2 - region->extents.x1 == 1 &&
3060			    region->extents.y2 - region->extents.y1 == 1) {
3061				sna_read_boxes(sna, pixmap, priv->gpu_bo,
3062					       &region->extents, 1);
3063				goto done;
3064			}
3065
3066			/* Expand the region to move 32x32 pixel blocks at a
3067			 * time, as we assume that we will continue writing
3068			 * afterwards and so aim to coallesce subsequent
3069			 * reads.
3070			 */
3071			if (flags & MOVE_WRITE) {
3072				int n = region_num_rects(region), i;
3073				const BoxRec *boxes = region_rects(region);
3074				BoxPtr blocks;
3075
3076				blocks = NULL;
3077				if (priv->cpu_damage == NULL)
3078					blocks = malloc(sizeof(BoxRec) * n);
3079				if (blocks) {
3080					for (i = 0; i < n; i++) {
3081						blocks[i].x1 = boxes[i].x1 & ~31;
3082						if (blocks[i].x1 < 0)
3083							blocks[i].x1 = 0;
3084
3085						blocks[i].x2 = (boxes[i].x2 + 31) & ~31;
3086						if (blocks[i].x2 > pixmap->drawable.width)
3087							blocks[i].x2 = pixmap->drawable.width;
3088
3089						blocks[i].y1 = boxes[i].y1 & ~31;
3090						if (blocks[i].y1 < 0)
3091							blocks[i].y1 = 0;
3092
3093						blocks[i].y2 = (boxes[i].y2 + 31) & ~31;
3094						if (blocks[i].y2 > pixmap->drawable.height)
3095							blocks[i].y2 = pixmap->drawable.height;
3096					}
3097					if (pixman_region_init_rects(&want, blocks, i))
3098						r = &want;
3099					free(blocks);
3100				}
3101			}
3102
3103			if (region_subsumes_damage(r, priv->gpu_damage)) {
3104				const BoxRec *box;
3105				int n;
3106
3107				DBG(("%s: region wholly contains damage\n",
3108				     __FUNCTION__));
3109
3110				n = sna_damage_get_boxes(priv->gpu_damage, &box);
3111				if (n)
3112					download_boxes(sna, priv, n, box);
3113
3114				sna_damage_destroy(&priv->gpu_damage);
3115			} else if (DAMAGE_IS_ALL(priv->gpu_damage) ||
3116				   sna_damage_contains_box__no_reduce(priv->gpu_damage,
3117								      &r->extents)) {
3118
3119				DBG(("%s: region wholly inside damage\n",
3120				     __FUNCTION__));
3121
3122				assert(sna_damage_contains_box(&priv->gpu_damage, &r->extents) == PIXMAN_REGION_IN);
3123				assert(sna_damage_contains_box(&priv->cpu_damage, &r->extents) == PIXMAN_REGION_OUT);
3124
3125				download_boxes(sna, priv,
3126					       region_num_rects(r),
3127					       region_rects(r));
3128				sna_damage_subtract(&priv->gpu_damage, r);
3129			} else {
3130				RegionRec need;
3131
3132				pixman_region_init(&need);
3133				if (sna_damage_intersect(priv->gpu_damage, r, &need)) {
3134					DBG(("%s: region intersects damage\n",
3135					     __FUNCTION__));
3136
3137					download_boxes(sna, priv,
3138						       region_num_rects(&need),
3139						       region_rects(&need));
3140					sna_damage_subtract(&priv->gpu_damage, r);
3141					RegionUninit(&need);
3142				}
3143			}
3144			if (r == &want)
3145				pixman_region_fini(&want);
3146		}
3147	}
3148
3149done:
3150	if ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE) {
3151		DBG(("%s: applying cpu damage\n", __FUNCTION__));
3152		assert(!DAMAGE_IS_ALL(priv->cpu_damage));
3153		assert_pixmap_contains_box(pixmap, RegionExtents(region));
3154		sna_damage_add_to_pixmap(&priv->cpu_damage, region, pixmap);
3155		sna_damage_reduce_all(&priv->cpu_damage, pixmap);
3156		if (DAMAGE_IS_ALL(priv->cpu_damage)) {
3157			DBG(("%s: replaced entire pixmap\n", __FUNCTION__));
3158			sna_pixmap_free_gpu(sna, priv);
3159		}
3160		if (priv->flush) {
3161			assert(!priv->shm);
3162			sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
3163		}
3164	}
3165
3166already_damaged:
3167	if (dx | dy)
3168		RegionTranslate(region, -dx, -dy);
3169
3170out:
3171	if (flags & MOVE_WRITE) {
3172		assert(!DAMAGE_IS_ALL(priv->gpu_damage));
3173		priv->source_count = SOURCE_BIAS;
3174		assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
3175		assert(priv->gpu_bo || priv->gpu_damage == NULL);
3176		assert(!priv->flush || !list_is_empty(&priv->flush_list));
3177		assert(!priv->clear);
3178	}
3179	if ((flags & MOVE_ASYNC_HINT) == 0 && priv->cpu_bo) {
3180		DBG(("%s: syncing cpu bo\n", __FUNCTION__));
3181		assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
3182		kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo,
3183				       FORCE_FULL_SYNC || flags & MOVE_WRITE);
3184		assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo));
3185	}
3186skip:
3187	priv->cpu |= (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE;
3188	assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
3189	assert(pixmap->devKind);
3190	assert_pixmap_damage(pixmap);
3191	assert(has_coherent_ptr(sna, priv, flags));
3192	return true;
3193}
3194
3195bool
3196sna_drawable_move_to_cpu(DrawablePtr drawable, unsigned flags)
3197{
3198	RegionRec region;
3199	PixmapPtr pixmap;
3200	int16_t dx, dy;
3201
3202	if (drawable->type == DRAWABLE_PIXMAP)
3203		return sna_pixmap_move_to_cpu((PixmapPtr)drawable, flags);
3204
3205	pixmap = get_window_pixmap((WindowPtr)drawable);
3206	get_drawable_deltas(drawable, pixmap, &dx, &dy);
3207
3208	DBG(("%s: (%d, %d)x(%d, %d) + (%d, %d), flags=%x\n",
3209	     __FUNCTION__,
3210	     drawable->x, drawable->y,
3211	     drawable->width, drawable->height,
3212	     dx, dy, flags));
3213
3214	region.extents.x1 = drawable->x + dx;
3215	region.extents.y1 = drawable->y + dy;
3216	region.extents.x2 = region.extents.x1 + drawable->width;
3217	region.extents.y2 = region.extents.y1 + drawable->height;
3218	region.data = NULL;
3219
3220	if (region.extents.x1 < 0)
3221		region.extents.x1 = 0;
3222	if (region.extents.y1 < 0)
3223		region.extents.y1 = 0;
3224	if (region.extents.x2 > pixmap->drawable.width)
3225		region.extents.x2 = pixmap->drawable.width;
3226	if (region.extents.y2 > pixmap->drawable.height)
3227		region.extents.y2 = pixmap->drawable.height;
3228
3229	if (box_empty(&region.extents))
3230		return true;
3231
3232	return sna_drawable_move_region_to_cpu(&pixmap->drawable, &region, flags);
3233}
3234
3235pure static bool alu_overwrites(uint8_t alu)
3236{
3237	switch (alu) {
3238	case GXclear:
3239	case GXcopy:
3240	case GXcopyInverted:
3241	case GXset:
3242		return true;
3243	default:
3244		return false;
3245	}
3246}
3247
3248inline static bool drawable_gc_inplace_hint(DrawablePtr draw, GCPtr gc)
3249{
3250	if (!alu_overwrites(gc->alu))
3251		return false;
3252
3253	if (!PM_IS_SOLID(draw, gc->planemask))
3254		return false;
3255
3256	if (gc->fillStyle == FillStippled)
3257		return false;
3258
3259	return true;
3260}
3261
3262inline static unsigned
3263drawable_gc_flags(DrawablePtr draw, GCPtr gc, bool partial)
3264{
3265	assert(sna_gc(gc)->changes == 0);
3266
3267	if (gc->fillStyle == FillStippled) {
3268		DBG(("%s: read due to fill %d\n",
3269		     __FUNCTION__, gc->fillStyle));
3270		return MOVE_READ | MOVE_WRITE;
3271	}
3272
3273	if (fb_gc(gc)->and | fb_gc(gc)->bgand) {
3274		DBG(("%s: read due to rrop %d:%x\n",
3275		     __FUNCTION__, gc->alu, (unsigned)fb_gc(gc)->and));
3276		return MOVE_READ | MOVE_WRITE;
3277	}
3278
3279	DBG(("%s: try operating on drawable inplace [hint? %d]\n",
3280	     __FUNCTION__, drawable_gc_inplace_hint(draw, gc)));
3281
3282	return (partial ? MOVE_READ : 0) | MOVE_WRITE | MOVE_INPLACE_HINT;
3283}
3284
3285static inline struct sna_pixmap *
3286sna_pixmap_mark_active(struct sna *sna, struct sna_pixmap *priv)
3287{
3288	assert(priv->gpu_bo);
3289	DBG(("%s: pixmap=%ld, handle=%u\n", __FUNCTION__,
3290	     priv->pixmap->drawable.serialNumber,
3291	     priv->gpu_bo->handle));
3292	return priv;
3293}
3294
3295inline static struct sna_pixmap *
3296__sna_pixmap_for_gpu(struct sna *sna, PixmapPtr pixmap, unsigned flags)
3297{
3298	struct sna_pixmap *priv;
3299
3300	assert(flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE));
3301	if ((flags & __MOVE_FORCE) == 0 && wedged(sna))
3302		return NULL;
3303
3304	priv = sna_pixmap(pixmap);
3305	if (priv == NULL) {
3306		DBG(("%s: not attached\n", __FUNCTION__));
3307		if ((flags & (__MOVE_DRI | __MOVE_SCANOUT)) == 0)
3308			return NULL;
3309
3310		if (pixmap->usage_hint == -1) {
3311			DBG(("%s: not promoting SHM Pixmap for DRI\n", __FUNCTION__));
3312			return NULL;
3313		}
3314
3315		DBG(("%s: forcing the creation on the GPU\n", __FUNCTION__));
3316
3317		priv = sna_pixmap_attach(pixmap);
3318		if (priv == NULL)
3319			return NULL;
3320
3321		sna_damage_all(&priv->cpu_damage, pixmap);
3322
3323		assert(priv->gpu_bo == NULL);
3324		assert(priv->gpu_damage == NULL);
3325	}
3326
3327	return priv;
3328}
3329
3330inline static void sna_pixmap_unclean(struct sna *sna,
3331				      struct sna_pixmap *priv,
3332				      unsigned flags)
3333{
3334	struct drm_i915_gem_busy busy;
3335
3336	assert(DAMAGE_IS_ALL(priv->gpu_damage));
3337	assert(priv->gpu_bo);
3338	assert(priv->gpu_bo->proxy == NULL);
3339	assert_pixmap_map(priv->pixmap, priv);
3340
3341	sna_damage_destroy(&priv->cpu_damage);
3342	list_del(&priv->flush_list);
3343
3344	if (flags & (__MOVE_DRI | __MOVE_SCANOUT))
3345		return;
3346
3347	if (!priv->flush || priv->gpu_bo->exec)
3348		return;
3349
3350	busy.handle = priv->gpu_bo->handle;
3351	busy.busy = 0;
3352	ioctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
3353
3354	DBG(("%s(pixmap=%ld): cleaning foreign bo handle=%u, busy=%x [ring=%d]\n",
3355	     __FUNCTION__,
3356	     priv->pixmap->drawable.serialNumber,
3357	     busy.handle, busy.busy, !!(busy.busy & (0xfffe << 16))));
3358
3359	if (busy.busy) {
3360		unsigned mode = KGEM_RENDER;
3361		if (busy.busy & (0xfffe << 16))
3362			mode = KGEM_BLT;
3363		kgem_bo_mark_busy(&sna->kgem, priv->gpu_bo, mode);
3364	} else
3365		__kgem_bo_clear_busy(priv->gpu_bo);
3366}
3367
3368struct sna_pixmap *
3369sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int flags)
3370{
3371	struct sna *sna = to_sna_from_pixmap(pixmap);
3372	struct sna_pixmap *priv;
3373	RegionRec i, r;
3374
3375	DBG(("%s: pixmap=%ld box=(%d, %d), (%d, %d), flags=%x\n",
3376	     __FUNCTION__, pixmap->drawable.serialNumber,
3377	     box->x1, box->y1, box->x2, box->y2, flags));
3378
3379	priv = __sna_pixmap_for_gpu(sna, pixmap, flags);
3380	if (priv == NULL)
3381		return NULL;
3382
3383	assert(box->x2 > box->x1 && box->y2 > box->y1);
3384	assert_pixmap_damage(pixmap);
3385	assert_pixmap_contains_box(pixmap, box);
3386	assert(priv->gpu_damage == NULL || priv->gpu_bo);
3387
3388	if ((flags & MOVE_READ) == 0)
3389		sna_damage_subtract_box(&priv->cpu_damage, box);
3390
3391	if (priv->move_to_gpu) {
3392		unsigned int hint;
3393
3394		DBG(("%s: applying move-to-gpu override\n", __FUNCTION__));
3395		hint = flags | MOVE_READ;
3396		if ((flags & MOVE_READ) == 0) {
3397			RegionRec region;
3398
3399			region.extents = *box;
3400			region.data = NULL;
3401			sna_pixmap_discard_shadow_damage(priv, &region);
3402			if (region_subsumes_pixmap(&region, pixmap))
3403				hint &= ~MOVE_READ;
3404		} else {
3405			if (priv->cpu_damage)
3406				hint |= MOVE_WRITE;
3407		}
3408		if (!priv->move_to_gpu(sna, priv, hint)) {
3409			DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
3410			return NULL;
3411		}
3412	}
3413
3414	if (priv->cow) {
3415		unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE);
3416
3417		assert(cow);
3418
3419		if ((flags & MOVE_READ) == 0) {
3420			if (priv->gpu_damage) {
3421				r.extents = *box;
3422				r.data = NULL;
3423				if (!region_subsumes_damage(&r, priv->gpu_damage))
3424					cow |= MOVE_READ | __MOVE_FORCE;
3425			}
3426		} else {
3427			if (priv->cpu_damage) {
3428				r.extents = *box;
3429				r.data = NULL;
3430				if (region_overlaps_damage(&r, priv->cpu_damage, 0, 0))
3431					cow |= MOVE_WRITE;
3432			}
3433		}
3434
3435		if (!sna_pixmap_undo_cow(sna, priv, cow))
3436			return NULL;
3437
3438		if (priv->gpu_bo == NULL)
3439			sna_damage_destroy(&priv->gpu_damage);
3440	}
3441
3442	if (sna_damage_is_all(&priv->gpu_damage,
3443			      pixmap->drawable.width,
3444			      pixmap->drawable.height)) {
3445		DBG(("%s: already all-damaged\n", __FUNCTION__));
3446		sna_pixmap_unclean(sna, priv, flags);
3447		goto done;
3448	}
3449
3450	if (kgem_bo_discard_cache(priv->gpu_bo, flags & (MOVE_WRITE | __MOVE_FORCE))) {
3451		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
3452		assert(DAMAGE_IS_ALL(priv->cpu_damage));
3453		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */
3454		assert(!priv->pinned);
3455		assert(!priv->mapped);
3456		sna_damage_destroy(&priv->gpu_damage);
3457		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
3458		priv->gpu_bo = NULL;
3459	}
3460
3461	sna_damage_reduce(&priv->cpu_damage);
3462	assert_pixmap_damage(pixmap);
3463
3464	if (priv->cpu_damage == NULL) {
3465		list_del(&priv->flush_list);
3466		return sna_pixmap_move_to_gpu(pixmap, MOVE_READ | flags);
3467	}
3468
3469	if (priv->gpu_bo == NULL) {
3470		assert(priv->gpu_damage == NULL);
3471
3472		if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU)
3473			sna_pixmap_alloc_gpu(sna, pixmap, priv, CREATE_INACTIVE);
3474
3475		if (priv->gpu_bo == NULL)
3476			return NULL;
3477
3478		DBG(("%s: created gpu bo\n", __FUNCTION__));
3479	}
3480
3481	if (priv->gpu_bo->proxy) {
3482		DBG(("%s: reusing cached upload\n", __FUNCTION__));
3483		assert((flags & MOVE_WRITE) == 0);
3484		assert(priv->gpu_damage == NULL);
3485		return priv;
3486	}
3487
3488	add_shm_flush(sna, priv);
3489
3490	assert(priv->cpu_damage);
3491	region_set(&r, box);
3492	if (MIGRATE_ALL || region_subsumes_damage(&r, priv->cpu_damage)) {
3493		bool ok = false;
3494		int n;
3495
3496		n = sna_damage_get_boxes(priv->cpu_damage, &box);
3497		assert(n);
3498		if (use_cpu_bo_for_upload(sna, priv, 0)) {
3499			DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__));
3500			ok = sna->render.copy_boxes(sna, GXcopy,
3501						    &pixmap->drawable, priv->cpu_bo, 0, 0,
3502						    &pixmap->drawable, priv->gpu_bo, 0, 0,
3503						    box, n, 0);
3504		}
3505		if (!ok) {
3506			sna_pixmap_unmap(pixmap, priv);
3507			if (pixmap->devPrivate.ptr == NULL)
3508				return NULL;
3509
3510			assert(pixmap->devKind);
3511			if (n == 1 && !priv->pinned &&
3512			    box->x1 <= 0 && box->y1 <= 0 &&
3513			    box->x2 >= pixmap->drawable.width &&
3514			    box->y2 >= pixmap->drawable.height) {
3515				ok = sna_replace(sna, pixmap,
3516						 pixmap->devPrivate.ptr,
3517						 pixmap->devKind);
3518			} else {
3519				ok = sna_write_boxes(sna, pixmap,
3520						     priv->gpu_bo, 0, 0,
3521						     pixmap->devPrivate.ptr,
3522						     pixmap->devKind,
3523						     0, 0,
3524						     box, n);
3525			}
3526			if (!ok)
3527				return NULL;
3528		}
3529
3530		sna_damage_destroy(&priv->cpu_damage);
3531	} else if (DAMAGE_IS_ALL(priv->cpu_damage) ||
3532		   sna_damage_contains_box__no_reduce(priv->cpu_damage, box)) {
3533		bool ok = false;
3534
3535		assert(sna_damage_contains_box(&priv->gpu_damage, box) == PIXMAN_REGION_OUT);
3536		assert(sna_damage_contains_box(&priv->cpu_damage, box) == PIXMAN_REGION_IN);
3537
3538		if (use_cpu_bo_for_upload(sna, priv, 0)) {
3539			DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__));
3540			ok = sna->render.copy_boxes(sna, GXcopy,
3541						    &pixmap->drawable, priv->cpu_bo, 0, 0,
3542						    &pixmap->drawable, priv->gpu_bo, 0, 0,
3543						    box, 1, 0);
3544		}
3545		if (!ok) {
3546			sna_pixmap_unmap(pixmap, priv);
3547			if (pixmap->devPrivate.ptr != NULL) {
3548				assert(pixmap->devKind);
3549				ok = sna_write_boxes(sna, pixmap,
3550						priv->gpu_bo, 0, 0,
3551						pixmap->devPrivate.ptr,
3552						pixmap->devKind,
3553						0, 0,
3554						box, 1);
3555			}
3556		}
3557		if (!ok)
3558			return NULL;
3559
3560		sna_damage_subtract(&priv->cpu_damage, &r);
3561	} else if (sna_damage_intersect(priv->cpu_damage, &r, &i)) {
3562		int n = region_num_rects(&i);
3563		bool ok;
3564
3565		box = region_rects(&i);
3566		ok = false;
3567		if (use_cpu_bo_for_upload(sna, priv, 0)) {
3568			DBG(("%s: using CPU bo for upload to GPU, %d boxes\n", __FUNCTION__, n));
3569			ok = sna->render.copy_boxes(sna, GXcopy,
3570						    &pixmap->drawable, priv->cpu_bo, 0, 0,
3571						    &pixmap->drawable, priv->gpu_bo, 0, 0,
3572						    box, n, 0);
3573		}
3574		if (!ok) {
3575			sna_pixmap_unmap(pixmap, priv);
3576			if (pixmap->devPrivate.ptr != NULL) {
3577				assert(pixmap->devKind);
3578				ok = sna_write_boxes(sna, pixmap,
3579						priv->gpu_bo, 0, 0,
3580						pixmap->devPrivate.ptr,
3581						pixmap->devKind,
3582						0, 0,
3583						box, n);
3584			}
3585		}
3586		if (!ok)
3587			return NULL;
3588
3589		sna_damage_subtract(&priv->cpu_damage, &r);
3590		RegionUninit(&i);
3591	}
3592
3593done:
3594	if (priv->cpu_damage == NULL && priv->flush)
3595		list_del(&priv->flush_list);
3596	if (flags & MOVE_WRITE) {
3597		priv->clear = false;
3598		if (!DAMAGE_IS_ALL(priv->gpu_damage) &&
3599		    priv->cpu_damage == NULL &&
3600		    (box_covers_pixmap(pixmap, &r.extents) ||
3601		     box_inplace(pixmap, &r.extents))) {
3602			DBG(("%s: large operation on undamaged, discarding CPU shadow\n",
3603			     __FUNCTION__));
3604			assert(priv->gpu_bo);
3605			assert(priv->gpu_bo->proxy == NULL);
3606			if (sna_pixmap_free_cpu(sna, priv, priv->cpu)) {
3607				DBG(("%s: large operation on undamaged, promoting to full GPU\n",
3608				     __FUNCTION__));
3609				sna_damage_all(&priv->gpu_damage, pixmap);
3610			}
3611		}
3612		if (DAMAGE_IS_ALL(priv->gpu_damage)) {
3613			sna_pixmap_free_cpu(sna, priv, priv->cpu);
3614			sna_damage_destroy(&priv->cpu_damage);
3615			list_del(&priv->flush_list);
3616		}
3617		priv->cpu = false;
3618	}
3619
3620	assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0);
3621	return sna_pixmap_mark_active(sna, priv);
3622}
3623
3624struct kgem_bo *
3625sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box,
3626		    struct sna_damage ***damage)
3627{
3628	PixmapPtr pixmap = get_drawable_pixmap(drawable);
3629	struct sna_pixmap *priv = sna_pixmap(pixmap);
3630	struct sna *sna;
3631	RegionRec region;
3632	int16_t dx, dy;
3633	int ret;
3634
3635	DBG(("%s pixmap=%ld, box=((%d, %d), (%d, %d)), flags=%x...\n",
3636	     __FUNCTION__,
3637	     pixmap->drawable.serialNumber,
3638	     box->x1, box->y1, box->x2, box->y2,
3639	     flags));
3640
3641	assert(box->x2 > box->x1 && box->y2 > box->y1);
3642	assert(pixmap->refcnt);
3643	assert_pixmap_damage(pixmap);
3644	assert_drawable_contains_box(drawable, box);
3645
3646	if (priv == NULL) {
3647		DBG(("%s: not attached\n", __FUNCTION__));
3648		return NULL;
3649	}
3650
3651	if (priv->cow) {
3652		unsigned cow = MOVE_WRITE | MOVE_READ | __MOVE_FORCE;
3653		assert(cow);
3654
3655		if (flags & IGNORE_DAMAGE) {
3656			if (priv->gpu_damage) {
3657				region.extents = *box;
3658				if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3659					region.extents.x1 += dx;
3660					region.extents.x2 += dx;
3661					region.extents.y1 += dy;
3662					region.extents.y2 += dy;
3663				}
3664				region.data = NULL;
3665				if (region_subsumes_damage(&region,
3666							   priv->gpu_damage))
3667					cow &= ~MOVE_READ;
3668			} else
3669				cow &= ~MOVE_READ;
3670		}
3671
3672		if (!sna_pixmap_undo_cow(to_sna_from_pixmap(pixmap), priv, cow))
3673			return NULL;
3674
3675		if (priv->gpu_bo == NULL)
3676			sna_damage_destroy(&priv->gpu_damage);
3677	}
3678
3679	if (kgem_bo_discard_cache(priv->gpu_bo, true)) {
3680		DBG(("%s: cached upload proxy, discard and revert to GPU\n", __FUNCTION__));
3681		assert(DAMAGE_IS_ALL(priv->cpu_damage));
3682		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */
3683		assert(!priv->pinned);
3684		assert(!priv->mapped);
3685		sna_damage_destroy(&priv->gpu_damage);
3686		kgem_bo_destroy(&to_sna_from_pixmap(pixmap)->kgem,
3687				priv->gpu_bo);
3688		priv->gpu_bo = NULL;
3689		goto use_cpu_bo;
3690	}
3691
3692	if (priv->flush) {
3693		DBG(("%s: exported target, set PREFER_GPU\n", __FUNCTION__));
3694		flags |= PREFER_GPU;
3695	}
3696	if (priv->shm) {
3697		DBG(("%s: shm target, discard PREFER_GPU\n", __FUNCTION__));
3698		flags &= ~PREFER_GPU;
3699	}
3700	if (priv->pinned) {
3701		DBG(("%s: pinned, never REPLACES\n", __FUNCTION__));
3702		flags &= ~REPLACES;
3703	}
3704	if (priv->cpu && (flags & (FORCE_GPU | IGNORE_DAMAGE)) == 0) {
3705		DBG(("%s: last on cpu and needs damage, discard PREFER_GPU\n", __FUNCTION__));
3706		flags &= ~PREFER_GPU;
3707	}
3708
3709	if ((flags & (PREFER_GPU | IGNORE_DAMAGE)) == IGNORE_DAMAGE) {
3710		if (priv->gpu_bo && (box_covers_pixmap(pixmap, box) || box_inplace(pixmap, box))) {
3711			DBG(("%s: not reading damage and large, set PREFER_GPU\n", __FUNCTION__));
3712			flags |= PREFER_GPU;
3713		}
3714	}
3715
3716	DBG(("%s: flush=%d, shm=%d, cpu=%d => flags=%x\n",
3717	     __FUNCTION__, priv->flush, priv->shm, priv->cpu, flags));
3718
3719	if ((flags & PREFER_GPU) == 0 &&
3720	    (flags & (REPLACES | IGNORE_DAMAGE) || !priv->gpu_damage || !kgem_bo_is_busy(priv->gpu_bo))) {
3721		DBG(("%s: try cpu as GPU bo is idle\n", __FUNCTION__));
3722		goto use_cpu_bo;
3723	}
3724
3725	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
3726		DBG(("%s: use GPU fast path (all-damaged)\n", __FUNCTION__));
3727		assert(priv->cpu_damage == NULL);
3728		assert(priv->gpu_bo);
3729		assert(priv->gpu_bo->proxy == NULL);
3730		goto use_gpu_bo;
3731	}
3732
3733	if (DAMAGE_IS_ALL(priv->cpu_damage)) {
3734		assert(priv->gpu_damage == NULL);
3735		if ((flags & FORCE_GPU) == 0 || priv->cpu_bo) {
3736			DBG(("%s: use CPU fast path (all-damaged), and not forced-gpu\n",
3737			     __FUNCTION__));
3738			goto use_cpu_bo;
3739		}
3740	}
3741
3742	DBG(("%s: gpu? %d, damaged? %d; cpu? %d, damaged? %d\n", __FUNCTION__,
3743	     priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->gpu_damage != NULL,
3744	     priv->cpu_bo ? priv->cpu_bo->handle : 0, priv->cpu_damage != NULL));
3745	if (priv->gpu_bo == NULL) {
3746		unsigned int move;
3747
3748		if ((flags & FORCE_GPU) == 0 &&
3749		    (priv->create & KGEM_CAN_CREATE_GPU) == 0) {
3750			DBG(("%s: untiled, will not force allocation\n",
3751			     __FUNCTION__));
3752			goto use_cpu_bo;
3753		}
3754
3755		if ((flags & IGNORE_DAMAGE) == 0) {
3756			if (priv->cpu_bo) {
3757				if (to_sna_from_pixmap(pixmap)->kgem.can_blt_cpu) {
3758					if (kgem_bo_is_busy(priv->cpu_bo)) {
3759						DBG(("%s: already using CPU bo, will not force allocation\n",
3760						     __FUNCTION__));
3761						goto use_cpu_bo;
3762					}
3763
3764					if ((flags & RENDER_GPU) == 0) {
3765						DBG(("%s: prefer cpu", __FUNCTION__));
3766						goto use_cpu_bo;
3767					}
3768				} else {
3769					if (kgem_bo_is_busy(priv->cpu_bo)) {
3770						DBG(("%s: CPU bo active, must force allocation\n",
3771						     __FUNCTION__));
3772						goto create_gpu_bo;
3773					}
3774				}
3775			}
3776
3777			if ((flags & FORCE_GPU) == 0 && priv->cpu_damage) {
3778				if ((flags & PREFER_GPU) == 0) {
3779					DBG(("%s: already damaged and prefer cpu",
3780					     __FUNCTION__));
3781					goto use_cpu_bo;
3782				}
3783
3784				if (!box_inplace(pixmap, box)) {
3785					DBG(("%s: damaged with a small operation, will not force allocation\n",
3786					     __FUNCTION__));
3787					goto use_cpu_bo;
3788				}
3789			}
3790		} else if (priv->cpu_damage) {
3791			region.extents = *box;
3792			if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3793				region.extents.x1 += dx;
3794				region.extents.x2 += dx;
3795				region.extents.y1 += dy;
3796				region.extents.y2 += dy;
3797			}
3798			region.data = NULL;
3799
3800			sna_damage_subtract(&priv->cpu_damage, &region);
3801			if (priv->cpu_damage == NULL) {
3802				list_del(&priv->flush_list);
3803				priv->cpu = false;
3804			}
3805		}
3806
3807create_gpu_bo:
3808		move = MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT;
3809		if (flags & FORCE_GPU)
3810			move |= __MOVE_FORCE;
3811		if (!sna_pixmap_move_to_gpu(pixmap, move))
3812			goto use_cpu_bo;
3813
3814		DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__));
3815		goto done;
3816	}
3817
3818
3819	region.extents = *box;
3820	if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3821		region.extents.x1 += dx;
3822		region.extents.x2 += dx;
3823		region.extents.y1 += dy;
3824		region.extents.y2 += dy;
3825	}
3826	region.data = NULL;
3827
3828	DBG(("%s extents (%d, %d), (%d, %d)\n", __FUNCTION__,
3829	     region.extents.x1, region.extents.y1,
3830	     region.extents.x2, region.extents.y2));
3831
3832	if (priv->gpu_damage) {
3833		assert(priv->gpu_bo);
3834		if (!priv->cpu_damage || flags & IGNORE_DAMAGE) {
3835			if (flags & REPLACES || box_covers_pixmap(pixmap, &region.extents)) {
3836				unsigned int move;
3837
3838				if (flags & IGNORE_DAMAGE)
3839					move = MOVE_WRITE;
3840				else
3841					move = MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT;
3842
3843				if (sna_pixmap_move_to_gpu(pixmap, move)) {
3844					sna_damage_all(&priv->gpu_damage,
3845						       pixmap);
3846					goto use_gpu_bo;
3847				}
3848			}
3849
3850			if (DAMAGE_IS_ALL(priv->gpu_damage) ||
3851			    sna_damage_contains_box__no_reduce(priv->gpu_damage,
3852							       &region.extents)) {
3853				DBG(("%s: region wholly contained within GPU damage\n",
3854				     __FUNCTION__));
3855				assert(sna_damage_contains_box(&priv->gpu_damage, &region.extents) == PIXMAN_REGION_IN);
3856				assert(sna_damage_contains_box(&priv->cpu_damage, &region.extents) == PIXMAN_REGION_OUT);
3857				goto use_gpu_bo;
3858			} else {
3859				DBG(("%s: partial GPU damage with no CPU damage, continuing to use GPU\n",
3860				     __FUNCTION__));
3861				goto move_to_gpu;
3862			}
3863		}
3864
3865		ret = sna_damage_contains_box(&priv->gpu_damage, &region.extents);
3866		if (ret == PIXMAN_REGION_IN) {
3867			DBG(("%s: region wholly contained within GPU damage\n",
3868			     __FUNCTION__));
3869			goto use_gpu_bo;
3870		}
3871
3872		if (ret != PIXMAN_REGION_OUT) {
3873			DBG(("%s: region partially contained within GPU damage\n",
3874			     __FUNCTION__));
3875			goto move_to_gpu;
3876		}
3877	}
3878
3879	if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_damage) {
3880		ret = sna_damage_contains_box(&priv->cpu_damage, &region.extents);
3881		if (ret == PIXMAN_REGION_IN) {
3882			DBG(("%s: region wholly contained within CPU damage\n",
3883			     __FUNCTION__));
3884			goto use_cpu_bo;
3885		}
3886
3887		if (box_inplace(pixmap, box)) {
3888			DBG(("%s: forcing inplace\n", __FUNCTION__));
3889			goto move_to_gpu;
3890		}
3891
3892		if (ret != PIXMAN_REGION_OUT) {
3893			DBG(("%s: region partially contained within CPU damage\n",
3894			     __FUNCTION__));
3895			goto use_cpu_bo;
3896		}
3897	}
3898
3899move_to_gpu:
3900	if (!sna_pixmap_move_area_to_gpu(pixmap, &region.extents,
3901					 flags & IGNORE_DAMAGE ? MOVE_WRITE : MOVE_READ | MOVE_WRITE)) {
3902		DBG(("%s: failed to move-to-gpu, fallback\n", __FUNCTION__));
3903		assert(priv->gpu_bo == NULL);
3904		goto use_cpu_bo;
3905	}
3906
3907done:
3908	assert(priv->move_to_gpu == NULL);
3909	assert(priv->gpu_bo != NULL);
3910	assert(priv->gpu_bo->refcnt);
3911	if (sna_damage_is_all(&priv->gpu_damage,
3912			      pixmap->drawable.width,
3913			      pixmap->drawable.height)) {
3914		sna_damage_destroy(&priv->cpu_damage);
3915		list_del(&priv->flush_list);
3916		*damage = NULL;
3917	} else
3918		*damage = &priv->gpu_damage;
3919
3920	DBG(("%s: using GPU bo with damage? %d\n",
3921	     __FUNCTION__, *damage != NULL));
3922	assert(*damage == NULL || !DAMAGE_IS_ALL(*damage));
3923	assert(priv->gpu_bo->proxy == NULL);
3924	assert(priv->clear == false);
3925	assert(priv->cpu == false);
3926	assert(!priv->shm);
3927	return priv->gpu_bo;
3928
3929use_gpu_bo:
3930	if (priv->move_to_gpu) {
3931		unsigned hint = MOVE_READ | MOVE_WRITE;
3932
3933		sna = to_sna_from_pixmap(pixmap);
3934
3935		DBG(("%s: applying move-to-gpu override\n", __FUNCTION__));
3936		if (flags & IGNORE_DAMAGE) {
3937			region.extents = *box;
3938			region.data = NULL;
3939			if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3940				region.extents.x1 += dx;
3941				region.extents.x2 += dx;
3942				region.extents.y1 += dy;
3943				region.extents.y2 += dy;
3944			}
3945			sna_pixmap_discard_shadow_damage(priv, &region);
3946			if (region_subsumes_pixmap(&region, pixmap)) {
3947				DBG(("%s: discarding move-to-gpu READ for subsumed pixmap\n", __FUNCTION__));
3948				hint = MOVE_WRITE;
3949			}
3950		}
3951
3952		if (!priv->move_to_gpu(sna, priv, hint)) {
3953			DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
3954			goto use_cpu_bo;
3955		}
3956	}
3957
3958	if (priv->shm) {
3959		assert(!priv->flush);
3960		list_move(&priv->flush_list, &sna->flush_pixmaps);
3961	}
3962
3963	DBG(("%s: using whole GPU bo\n", __FUNCTION__));
3964	assert(priv->gpu_bo != NULL);
3965	assert(priv->gpu_bo->refcnt);
3966	assert(priv->gpu_bo->proxy == NULL);
3967	assert(priv->gpu_damage);
3968	priv->cpu = false;
3969	priv->clear = false;
3970	*damage = NULL;
3971	return priv->gpu_bo;
3972
3973use_cpu_bo:
3974	if (!USE_CPU_BO || priv->cpu_bo == NULL) {
3975		if ((flags & FORCE_GPU) == 0) {
3976			DBG(("%s: no CPU bo, and GPU not forced\n", __FUNCTION__));
3977			return NULL;
3978		}
3979
3980		flags &= ~FORCE_GPU;
3981
3982		region.extents = *box;
3983		if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3984			region.extents.x1 += dx;
3985			region.extents.x2 += dx;
3986			region.extents.y1 += dy;
3987			region.extents.y2 += dy;
3988		}
3989		region.data = NULL;
3990
3991		if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, &region,
3992						     (flags & IGNORE_DAMAGE ? 0 : MOVE_READ) | MOVE_WRITE | MOVE_ASYNC_HINT) ||
3993		    priv->cpu_bo == NULL) {
3994			DBG(("%s: did not create CPU bo\n", __FUNCTION__));
3995cpu_fail:
3996			if (priv->gpu_bo)
3997				goto move_to_gpu;
3998
3999			return NULL;
4000		}
4001	}
4002
4003	assert(priv->cpu_bo->refcnt);
4004
4005	sna = to_sna_from_pixmap(pixmap);
4006	if ((flags & FORCE_GPU) == 0 &&
4007	    !__kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
4008		DBG(("%s: has CPU bo, but is idle and acceleration not forced\n",
4009		     __FUNCTION__));
4010		return NULL;
4011	}
4012
4013	region.extents = *box;
4014	if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
4015		region.extents.x1 += dx;
4016		region.extents.x2 += dx;
4017		region.extents.y1 += dy;
4018		region.extents.y2 += dy;
4019	}
4020	region.data = NULL;
4021
4022	if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) {
4023		DBG(("%s: both CPU and GPU are busy, prefer to use the GPU\n",
4024		     __FUNCTION__));
4025		goto move_to_gpu;
4026	}
4027
4028	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
4029
4030	if (flags & RENDER_GPU) {
4031		flags &= ~RENDER_GPU;
4032
4033		if ((flags & IGNORE_DAMAGE) == 0 && priv->gpu_damage) {
4034			DBG(("%s: prefer to use GPU bo for rendering whilst reading from GPU damage\n", __FUNCTION__));
4035
4036prefer_gpu_bo:
4037			if (priv->gpu_bo == NULL) {
4038				if ((flags & FORCE_GPU) == 0) {
4039					DBG(("%s: untiled, will not force allocation\n",
4040					     __FUNCTION__));
4041					return NULL;
4042				}
4043
4044				if (flags & IGNORE_DAMAGE) {
4045					sna_damage_subtract(&priv->cpu_damage, &region);
4046					if (priv->cpu_damage == NULL) {
4047						list_del(&priv->flush_list);
4048						priv->cpu = false;
4049					}
4050				}
4051
4052				if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE))
4053					return NULL;
4054
4055				sna_damage_all(&priv->gpu_damage, pixmap);
4056
4057				DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__));
4058				goto done;
4059			}
4060			goto move_to_gpu;
4061		}
4062
4063		if (!priv->shm) {
4064			if ((priv->cpu_damage == NULL || flags & IGNORE_DAMAGE)) {
4065				if (priv->gpu_bo && priv->gpu_bo->tiling) {
4066					DBG(("%s: prefer to use GPU bo for rendering large pixmaps\n", __FUNCTION__));
4067					goto prefer_gpu_bo;
4068				}
4069
4070				if (priv->cpu_bo->pitch >= 4096) {
4071					DBG(("%s: prefer to use GPU bo for rendering wide pixmaps\n", __FUNCTION__));
4072					goto prefer_gpu_bo;
4073				}
4074			}
4075
4076			if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_bo->snoop) {
4077				DBG(("%s: prefer to use GPU bo for reading from snooped target bo\n", __FUNCTION__));
4078				goto prefer_gpu_bo;
4079			}
4080
4081			if (!sna->kgem.can_blt_cpu) {
4082				DBG(("%s: can't render to CPU bo, try to use GPU bo\n", __FUNCTION__));
4083				goto prefer_gpu_bo;
4084			}
4085		}
4086	}
4087
4088	if (!sna->kgem.can_blt_cpu)
4089		goto cpu_fail;
4090
4091	if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, &region,
4092					     (flags & IGNORE_DAMAGE ? 0 : MOVE_READ) | MOVE_WRITE | MOVE_ASYNC_HINT)) {
4093		DBG(("%s: failed to move-to-cpu, fallback\n", __FUNCTION__));
4094		goto cpu_fail;
4095	}
4096
4097	if (priv->shm) {
4098		add_shm_flush(sna, priv);
4099		/* As we may have flushed and retired,, recheck for busy bo */
4100		if ((flags & FORCE_GPU) == 0 && !kgem_bo_is_busy(priv->cpu_bo))
4101			return NULL;
4102	}
4103	if (priv->flush) {
4104		assert(!priv->shm);
4105		sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
4106	}
4107
4108	if (sna_damage_is_all(&priv->cpu_damage,
4109			      pixmap->drawable.width,
4110			      pixmap->drawable.height)) {
4111		sna_damage_destroy(&priv->gpu_damage);
4112		*damage = NULL;
4113	} else {
4114		assert(!DAMAGE_IS_ALL(priv->cpu_damage));
4115		if (priv->cpu_damage &&
4116		    sna_damage_contains_box__no_reduce(priv->cpu_damage,
4117						       &region.extents)) {
4118			assert(sna_damage_contains_box(&priv->gpu_damage, &region.extents) == PIXMAN_REGION_OUT);
4119			assert(sna_damage_contains_box(&priv->cpu_damage, &region.extents) == PIXMAN_REGION_IN);
4120			*damage = NULL;
4121		} else
4122			*damage = &priv->cpu_damage;
4123	}
4124
4125	DBG(("%s: using CPU bo with damage? %d\n",
4126	     __FUNCTION__, *damage != NULL));
4127	assert(damage == NULL || !DAMAGE_IS_ALL(*damage));
4128	assert(priv->clear == false);
4129	priv->cpu = false;
4130	return priv->cpu_bo;
4131}
4132
4133PixmapPtr
4134sna_pixmap_create_upload(ScreenPtr screen,
4135			 int width, int height, int depth,
4136			 unsigned flags)
4137{
4138	struct sna *sna = to_sna_from_screen(screen);
4139	PixmapPtr pixmap;
4140	struct sna_pixmap *priv;
4141	void *ptr;
4142
4143	DBG(("%s(%d, %d, %d, flags=%x)\n", __FUNCTION__,
4144	     width, height, depth, flags));
4145	assert(width);
4146	assert(height);
4147
4148	if (depth < 8)
4149		return create_pixmap(sna, screen, width, height, depth,
4150				     CREATE_PIXMAP_USAGE_SCRATCH);
4151
4152	pixmap = create_pixmap_hdr(sna, screen,
4153				   width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH,
4154				   &priv);
4155	if (!pixmap)
4156		return NullPixmap;
4157
4158	priv->gpu_bo = kgem_create_buffer_2d(&sna->kgem,
4159					     width, height,
4160					     pixmap->drawable.bitsPerPixel,
4161					     flags, &ptr);
4162	if (!priv->gpu_bo) {
4163		free(priv);
4164		FreePixmap(pixmap);
4165		return NullPixmap;
4166	}
4167
4168	/* Marking both the shadow and the GPU bo is a little dubious,
4169	 * but will work so long as we always check before doing the
4170	 * transfer.
4171	 */
4172	sna_damage_all(&priv->gpu_damage, pixmap);
4173	sna_damage_all(&priv->cpu_damage, pixmap);
4174
4175	pixmap->devKind = priv->gpu_bo->pitch;
4176	pixmap->devPrivate.ptr = ptr;
4177	priv->ptr = MAKE_STATIC_PTR(ptr);
4178	priv->stride = priv->gpu_bo->pitch;
4179	priv->create = 0;
4180
4181	pixmap->usage_hint = 0;
4182	if (!kgem_buffer_is_inplace(priv->gpu_bo))
4183		pixmap->usage_hint = 1;
4184
4185	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
4186	     __FUNCTION__,
4187	     pixmap->drawable.serialNumber,
4188	     pixmap->drawable.width,
4189	     pixmap->drawable.height,
4190	     pixmap->usage_hint));
4191	return pixmap;
4192}
4193
4194static bool can_convert_to_gpu(struct sna_pixmap *priv, unsigned flags)
4195{
4196	assert(priv->gpu_bo == NULL);
4197
4198	if (priv->cpu_bo == NULL)
4199		return false;
4200
4201	if (priv->shm)
4202		return false;
4203
4204	/* Linear scanout have a restriction that their pitch must be
4205	 * 64 byte aligned. Force the creation of a proper GPU bo if
4206	 * this CPU bo is not suitable for scanout.
4207	 */
4208	if (priv->pixmap->usage_hint == SNA_CREATE_FB || flags & __MOVE_SCANOUT)
4209		if (priv->cpu_bo->pitch & 63)
4210			return false;
4211
4212	if (flags & __MOVE_PRIME)
4213		if (priv->cpu_bo->pitch & 255)
4214			return false;
4215
4216	return true;
4217}
4218
4219struct sna_pixmap *
4220sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
4221{
4222	struct sna *sna = to_sna_from_pixmap(pixmap);
4223	struct sna_pixmap *priv;
4224	const BoxRec *box;
4225	int n;
4226
4227	DBG(("%s(pixmap=%ld, usage=%d), flags=%x\n",
4228	     __FUNCTION__,
4229	     pixmap->drawable.serialNumber,
4230	     pixmap->usage_hint,
4231	     flags));
4232
4233	priv = __sna_pixmap_for_gpu(sna, pixmap, flags);
4234	if (priv == NULL)
4235		return NULL;
4236
4237	assert_pixmap_damage(pixmap);
4238
4239	if (priv->move_to_gpu &&
4240	    !priv->move_to_gpu(sna, priv, flags | ((priv->cpu_damage && (flags & MOVE_READ)) ? MOVE_WRITE : 0))) {
4241		DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
4242		return NULL;
4243	}
4244
4245	if ((flags & MOVE_READ) == 0 && UNDO)
4246		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
4247
4248	if (priv->cow) {
4249		unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE);
4250		assert(cow);
4251		if (flags & MOVE_READ && priv->cpu_damage)
4252			cow |= MOVE_WRITE;
4253		if (!sna_pixmap_undo_cow(sna, priv, cow))
4254			return NULL;
4255
4256		if (priv->gpu_bo == NULL)
4257			sna_damage_destroy(&priv->gpu_damage);
4258	}
4259
4260	if (sna_damage_is_all(&priv->gpu_damage,
4261			      pixmap->drawable.width,
4262			      pixmap->drawable.height)) {
4263		DBG(("%s: already all-damaged\n", __FUNCTION__));
4264		sna_pixmap_unclean(sna, priv, flags);
4265		goto active;
4266	}
4267
4268	if ((flags & MOVE_READ) == 0)
4269		sna_damage_destroy(&priv->cpu_damage);
4270
4271	sna_damage_reduce(&priv->cpu_damage);
4272	assert_pixmap_damage(pixmap);
4273	DBG(("%s: CPU damage? %d\n", __FUNCTION__, priv->cpu_damage != NULL));
4274	if (priv->gpu_bo == NULL ||
4275	    kgem_bo_discard_cache(priv->gpu_bo, flags & (MOVE_WRITE | __MOVE_FORCE))) {
4276		struct kgem_bo *proxy;
4277
4278		proxy = priv->gpu_bo;
4279		priv->gpu_bo = NULL;
4280
4281		DBG(("%s: creating GPU bo (%dx%d@%d), create=%x\n",
4282		     __FUNCTION__,
4283		     pixmap->drawable.width,
4284		     pixmap->drawable.height,
4285		     pixmap->drawable.bitsPerPixel,
4286		     priv->create));
4287		assert(!priv->mapped);
4288		assert(list_is_empty(&priv->flush_list));
4289
4290		if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU) {
4291			bool is_linear;
4292
4293			assert(pixmap->drawable.width > 0);
4294			assert(pixmap->drawable.height > 0);
4295			assert(pixmap->drawable.bitsPerPixel >= 8);
4296
4297			if (flags & __MOVE_PRIME) {
4298				assert((flags & __MOVE_TILED) == 0);
4299				is_linear = true;
4300			} else {
4301				is_linear = sna_pixmap_default_tiling(sna, pixmap) == I915_TILING_NONE;
4302				if (is_linear && flags & __MOVE_TILED) {
4303					DBG(("%s: not creating linear GPU bo\n",
4304					     __FUNCTION__));
4305					return NULL;
4306				}
4307			}
4308
4309			if (is_linear &&
4310			    can_convert_to_gpu(priv, flags) &&
4311			    kgem_bo_convert_to_gpu(&sna->kgem, priv->cpu_bo, flags)) {
4312				assert(!priv->mapped);
4313				assert(!IS_STATIC_PTR(priv->ptr));
4314#ifdef DEBUG_MEMORY
4315				sna->debug_memory.cpu_bo_allocs--;
4316				sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
4317#endif
4318				priv->gpu_bo = priv->cpu_bo;
4319				priv->cpu_bo = NULL;
4320				priv->ptr = NULL;
4321				pixmap->devPrivate.ptr = NULL;
4322				sna_damage_all(&priv->gpu_damage, pixmap);
4323				sna_damage_destroy(&priv->cpu_damage);
4324			} else {
4325				unsigned create = 0;
4326				if (flags & MOVE_INPLACE_HINT || (priv->cpu_damage && priv->cpu_bo == NULL))
4327					create = CREATE_GTT_MAP | CREATE_INACTIVE;
4328				if (flags & __MOVE_PRIME)
4329					create |= CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT;
4330
4331				sna_pixmap_alloc_gpu(sna, pixmap, priv, create);
4332			}
4333		}
4334
4335		if (priv->gpu_bo == NULL) {
4336			DBG(("%s: not creating GPU bo\n", __FUNCTION__));
4337			assert(priv->gpu_damage == NULL);
4338			priv->gpu_bo = proxy;
4339			if (proxy)
4340				sna_damage_all(&priv->cpu_damage, pixmap);
4341			return NULL;
4342		}
4343
4344		if (proxy) {
4345			DBG(("%s: promoting upload proxy handle=%d to GPU\n", __FUNCTION__, proxy->handle));
4346
4347			if (priv->cpu_damage &&
4348			    sna->render.copy_boxes(sna, GXcopy,
4349						   &pixmap->drawable, proxy, 0, 0,
4350						   &pixmap->drawable, priv->gpu_bo, 0, 0,
4351						   region_rects(DAMAGE_REGION(priv->cpu_damage)),
4352						   region_num_rects(DAMAGE_REGION(priv->cpu_damage)),
4353						   0))
4354				sna_damage_destroy(&priv->cpu_damage);
4355
4356			kgem_bo_destroy(&sna->kgem, proxy);
4357		}
4358
4359		if (flags & MOVE_WRITE && priv->cpu_damage == NULL) {
4360			/* Presume that we will only ever write to the GPU
4361			 * bo. Readbacks are expensive but fairly constant
4362			 * in cost for all sizes i.e. it is the act of
4363			 * synchronisation that takes the most time. This is
4364			 * mitigated by avoiding fallbacks in the first place.
4365			 */
4366			assert(priv->gpu_bo);
4367			assert(priv->gpu_bo->proxy == NULL);
4368			sna_damage_all(&priv->gpu_damage, pixmap);
4369			DBG(("%s: marking as all-damaged for GPU\n",
4370			     __FUNCTION__));
4371			goto active;
4372		}
4373	}
4374
4375	if (priv->gpu_bo->proxy) {
4376		DBG(("%s: reusing cached upload\n", __FUNCTION__));
4377		assert((flags & MOVE_WRITE) == 0);
4378		assert(priv->gpu_damage == NULL);
4379		return priv;
4380	}
4381
4382	if (priv->cpu_damage == NULL)
4383		goto done;
4384
4385	if (DAMAGE_IS_ALL(priv->cpu_damage) && priv->cpu_bo &&
4386	    !priv->pinned && !priv->shm &&
4387	    priv->gpu_bo->tiling == I915_TILING_NONE &&
4388	    kgem_bo_convert_to_gpu(&sna->kgem, priv->cpu_bo, flags)) {
4389		assert(!priv->mapped);
4390		assert(!IS_STATIC_PTR(priv->ptr));
4391#ifdef DEBUG_MEMORY
4392		sna->debug_memory.cpu_bo_allocs--;
4393		sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
4394#endif
4395		sna_pixmap_free_gpu(sna, priv);
4396		priv->gpu_bo = priv->cpu_bo;
4397		priv->cpu_bo = NULL;
4398		priv->ptr = NULL;
4399		pixmap->devPrivate.ptr = NULL;
4400		sna_damage_all(&priv->gpu_damage, pixmap);
4401		sna_damage_destroy(&priv->cpu_damage);
4402		goto done;
4403	}
4404
4405	add_shm_flush(sna, priv);
4406
4407	n = sna_damage_get_boxes(priv->cpu_damage, &box);
4408	assert(n);
4409	if (n) {
4410		bool ok;
4411
4412		assert_pixmap_contains_damage(pixmap, priv->cpu_damage);
4413		DBG(("%s: uploading %d damage boxes\n", __FUNCTION__, n));
4414
4415		ok = false;
4416		if (use_cpu_bo_for_upload(sna, priv, flags)) {
4417			DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__));
4418			ok = sna->render.copy_boxes(sna, GXcopy,
4419						    &pixmap->drawable, priv->cpu_bo, 0, 0,
4420						    &pixmap->drawable, priv->gpu_bo, 0, 0,
4421						    box, n, 0);
4422		}
4423		if (!ok) {
4424			sna_pixmap_unmap(pixmap, priv);
4425			if (pixmap->devPrivate.ptr == NULL)
4426				return NULL;
4427
4428			assert(pixmap->devKind);
4429			if (n == 1 && !priv->pinned &&
4430			    (box->x2 - box->x1) >= pixmap->drawable.width &&
4431			    (box->y2 - box->y1) >= pixmap->drawable.height) {
4432				ok = sna_replace(sna, pixmap,
4433						 pixmap->devPrivate.ptr,
4434						 pixmap->devKind);
4435			} else {
4436				ok = sna_write_boxes(sna, pixmap,
4437						     priv->gpu_bo, 0, 0,
4438						     pixmap->devPrivate.ptr,
4439						     pixmap->devKind,
4440						     0, 0,
4441						     box, n);
4442			}
4443			if (!ok)
4444				return NULL;
4445		}
4446	}
4447
4448	__sna_damage_destroy(DAMAGE_PTR(priv->cpu_damage));
4449	priv->cpu_damage = NULL;
4450
4451	/* For large bo, try to keep only a single copy around */
4452	if (priv->create & KGEM_CAN_CREATE_LARGE || flags & MOVE_SOURCE_HINT) {
4453		DBG(("%s: disposing of system copy for large/source\n",
4454		     __FUNCTION__));
4455		assert(!priv->shm);
4456		assert(priv->gpu_bo);
4457		assert(priv->gpu_bo->proxy == NULL);
4458		sna_damage_all(&priv->gpu_damage, pixmap);
4459		sna_pixmap_free_cpu(sna, priv,
4460				    (priv->create & KGEM_CAN_CREATE_LARGE) ? false : priv->cpu);
4461	}
4462done:
4463	list_del(&priv->flush_list);
4464
4465	sna_damage_reduce_all(&priv->gpu_damage, pixmap);
4466	if (DAMAGE_IS_ALL(priv->gpu_damage))
4467		sna_pixmap_free_cpu(sna, priv, priv->cpu);
4468
4469active:
4470	if (flags & MOVE_WRITE) {
4471		priv->clear = false;
4472		priv->cpu = false;
4473	}
4474	assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0);
4475	return sna_pixmap_mark_active(sna, priv);
4476}
4477
4478static bool must_check sna_validate_pixmap(DrawablePtr draw, PixmapPtr pixmap)
4479{
4480	DBG(("%s: target bpp=%d, source bpp=%d\n",
4481	     __FUNCTION__, draw->bitsPerPixel, pixmap->drawable.bitsPerPixel));
4482
4483	if (draw->bitsPerPixel == pixmap->drawable.bitsPerPixel &&
4484	    FbEvenTile(pixmap->drawable.width *
4485		       pixmap->drawable.bitsPerPixel)) {
4486		DBG(("%s: flushing pixmap\n", __FUNCTION__));
4487		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
4488			return false;
4489
4490		fbPadPixmap(pixmap);
4491	}
4492
4493	return true;
4494}
4495
4496static bool must_check sna_gc_move_to_cpu(GCPtr gc,
4497					  DrawablePtr drawable,
4498					  RegionPtr region)
4499{
4500	struct sna_gc *sgc = sna_gc(gc);
4501	long changes = sgc->changes;
4502
4503	DBG(("%s(%p) changes=%lx\n", __FUNCTION__, gc, changes));
4504	assert(drawable);
4505	assert(region);
4506
4507	assert(gc->ops == (GCOps *)&sna_gc_ops);
4508	gc->ops = (GCOps *)&sna_gc_ops__cpu;
4509
4510	assert(gc->funcs);
4511	sgc->old_funcs = gc->funcs;
4512	gc->funcs = (GCFuncs *)&sna_gc_funcs__cpu;
4513
4514	assert(gc->pCompositeClip);
4515	sgc->priv = gc->pCompositeClip;
4516	gc->pCompositeClip = region;
4517
4518#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0)
4519	if (gc->clientClipType == CT_PIXMAP) {
4520		PixmapPtr clip = gc->clientClip;
4521		gc->clientClip = region_from_bitmap(gc->pScreen, clip);
4522		gc->pScreen->DestroyPixmap(clip);
4523		gc->clientClipType = gc->clientClip ? CT_REGION : CT_NONE;
4524		changes |= GCClipMask;
4525	} else
4526		changes &= ~GCClipMask;
4527#else
4528	changes &= ~GCClipMask;
4529#endif
4530
4531	if (changes || drawable->serialNumber != (sgc->serial & DRAWABLE_SERIAL_BITS)) {
4532		long tmp = gc->serialNumber;
4533		gc->serialNumber = sgc->serial;
4534
4535		if (fb_gc(gc)->bpp != drawable->bitsPerPixel) {
4536			changes |= GCStipple | GCForeground | GCBackground | GCPlaneMask;
4537			fb_gc(gc)->bpp = drawable->bitsPerPixel;
4538		}
4539
4540		if (changes & GCTile && !gc->tileIsPixel) {
4541			DBG(("%s: flushing tile pixmap\n", __FUNCTION__));
4542			if (!sna_validate_pixmap(drawable, gc->tile.pixmap))
4543				return false;
4544		}
4545
4546		if (changes & GCStipple && gc->stipple) {
4547			DBG(("%s: flushing stipple pixmap\n", __FUNCTION__));
4548			if (!sna_validate_pixmap(drawable, gc->stipple))
4549				return false;
4550		}
4551
4552		fbValidateGC(gc, changes, drawable);
4553		gc->serialNumber = tmp;
4554	}
4555	sgc->changes = 0;
4556
4557	switch (gc->fillStyle) {
4558	case FillTiled:
4559		DBG(("%s: moving tile to cpu\n", __FUNCTION__));
4560		return sna_drawable_move_to_cpu(&gc->tile.pixmap->drawable, MOVE_READ);
4561	case FillStippled:
4562	case FillOpaqueStippled:
4563		DBG(("%s: moving stipple to cpu\n", __FUNCTION__));
4564		return sna_drawable_move_to_cpu(&gc->stipple->drawable, MOVE_READ);
4565	default:
4566		return true;
4567	}
4568}
4569
4570static void sna_gc_move_to_gpu(GCPtr gc)
4571{
4572	DBG(("%s(%p)\n", __FUNCTION__, gc));
4573
4574	assert(gc->ops == (GCOps *)&sna_gc_ops__cpu);
4575	assert(gc->funcs == (GCFuncs *)&sna_gc_funcs__cpu);
4576
4577	gc->ops = (GCOps *)&sna_gc_ops;
4578	gc->funcs = (GCFuncs *)sna_gc(gc)->old_funcs;
4579	assert(gc->funcs);
4580	gc->pCompositeClip = sna_gc(gc)->priv;
4581	assert(gc->pCompositeClip);
4582}
4583
4584static inline bool clip_box(BoxPtr box, GCPtr gc)
4585{
4586	const BoxRec *clip;
4587	bool clipped;
4588
4589	assert(gc->pCompositeClip);
4590	clip = &gc->pCompositeClip->extents;
4591
4592	clipped = !region_is_singular(gc->pCompositeClip);
4593	if (box->x1 < clip->x1)
4594		box->x1 = clip->x1, clipped = true;
4595	if (box->x2 > clip->x2)
4596		box->x2 = clip->x2, clipped = true;
4597
4598	if (box->y1 < clip->y1)
4599		box->y1 = clip->y1, clipped = true;
4600	if (box->y2 > clip->y2)
4601		box->y2 = clip->y2, clipped = true;
4602
4603	return clipped;
4604}
4605
4606static inline void translate_box(BoxPtr box, DrawablePtr d)
4607{
4608	box->x1 += d->x;
4609	box->x2 += d->x;
4610
4611	box->y1 += d->y;
4612	box->y2 += d->y;
4613}
4614
4615static inline bool trim_and_translate_box(BoxPtr box, DrawablePtr d, GCPtr gc)
4616{
4617	translate_box(box, d);
4618	return clip_box(box, gc);
4619}
4620
4621static inline bool box32_clip(Box32Rec *box, GCPtr gc)
4622{
4623	bool clipped = !region_is_singular(gc->pCompositeClip);
4624	const BoxRec *clip = &gc->pCompositeClip->extents;
4625
4626	if (box->x1 < clip->x1)
4627		box->x1 = clip->x1, clipped = true;
4628	if (box->x2 > clip->x2)
4629		box->x2 = clip->x2, clipped = true;
4630
4631	if (box->y1 < clip->y1)
4632		box->y1 = clip->y1, clipped = true;
4633	if (box->y2 > clip->y2)
4634		box->y2 = clip->y2, clipped = true;
4635
4636	return clipped;
4637}
4638
4639static inline void box32_translate(Box32Rec *box, DrawablePtr d)
4640{
4641	box->x1 += d->x;
4642	box->x2 += d->x;
4643
4644	box->y1 += d->y;
4645	box->y2 += d->y;
4646}
4647
4648static inline bool box32_trim_and_translate(Box32Rec *box, DrawablePtr d, GCPtr gc)
4649{
4650	box32_translate(box, d);
4651	return box32_clip(box, gc);
4652}
4653
4654static inline void box_add_xy(BoxPtr box, int16_t x, int16_t y)
4655{
4656	if (box->x1 > x)
4657		box->x1 = x;
4658	else if (box->x2 < x)
4659		box->x2 = x;
4660
4661	if (box->y1 > y)
4662		box->y1 = y;
4663	else if (box->y2 < y)
4664		box->y2 = y;
4665}
4666
4667static inline void box_add_pt(BoxPtr box, const DDXPointRec *pt)
4668{
4669	box_add_xy(box, pt->x, pt->y);
4670}
4671
4672static inline bool box32_to_box16(const Box32Rec *b32, BoxRec *b16)
4673{
4674	b16->x1 = b32->x1;
4675	b16->y1 = b32->y1;
4676	b16->x2 = b32->x2;
4677	b16->y2 = b32->y2;
4678
4679	return b16->x2 > b16->x1 && b16->y2 > b16->y1;
4680}
4681
4682static inline void box32_add_rect(Box32Rec *box, const xRectangle *r)
4683{
4684	int32_t v;
4685
4686	v = r->x;
4687	if (box->x1 > v)
4688		box->x1 = v;
4689	v += r->width;
4690	if (box->x2 < v)
4691		box->x2 = v;
4692
4693	v = r->y;
4694	if (box->y1 > v)
4695		box->y1 = v;
4696	v += r->height;
4697	if (box->y2 < v)
4698		box->y2 = v;
4699}
4700
4701static bool
4702can_create_upload_tiled_x(struct sna *sna,
4703			  PixmapPtr pixmap,
4704			  struct sna_pixmap *priv,
4705			  bool replaces)
4706{
4707	if (priv->shm || (priv->cpu && !replaces))
4708		return false;
4709
4710	if ((priv->create & KGEM_CAN_CREATE_GPU) == 0)
4711		return false;
4712
4713	if (sna->kgem.has_llc)
4714		return true;
4715
4716	if (!sna->kgem.has_wc_mmap && sna_pixmap_default_tiling(sna, pixmap))
4717		return false;
4718
4719	return true;
4720}
4721
4722static bool
4723create_upload_tiled_x(struct sna *sna,
4724		      PixmapPtr pixmap,
4725		      struct sna_pixmap *priv,
4726		      bool replaces)
4727{
4728	unsigned create;
4729
4730	if (!can_create_upload_tiled_x(sna, pixmap, priv, replaces))
4731		return false;
4732
4733	assert(priv->gpu_bo == NULL);
4734	assert(priv->gpu_damage == NULL);
4735
4736	if (sna->kgem.has_llc)
4737		create = CREATE_CPU_MAP | CREATE_INACTIVE;
4738	else if (sna->kgem.has_wc_mmap)
4739		create = CREATE_GTT_MAP | CREATE_INACTIVE;
4740	else
4741		create = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_CACHED;
4742
4743	return sna_pixmap_alloc_gpu(sna, pixmap, priv, create);
4744}
4745
4746static bool can_upload__tiled_x(struct kgem *kgem, struct kgem_bo *bo)
4747{
4748	return kgem_bo_can_map__cpu(kgem, bo, true) || kgem->has_wc_mmap;
4749}
4750
4751static bool
4752try_upload__tiled_x(PixmapPtr pixmap, RegionRec *region,
4753		    int x, int y, int w, int  h, char *bits, int stride)
4754{
4755	struct sna *sna = to_sna_from_pixmap(pixmap);
4756	struct sna_pixmap *priv = sna_pixmap(pixmap);
4757	const BoxRec *box;
4758	uint8_t *dst;
4759	int n;
4760
4761	if (!can_upload__tiled_x(&sna->kgem, priv->gpu_bo)) {
4762		DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__));
4763		return false;
4764	}
4765
4766	if (!sna_pixmap_move_area_to_gpu(pixmap, &region->extents,
4767					 MOVE_WRITE | (region->data ? MOVE_READ : 0)))
4768		return false;
4769
4770	if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 &&
4771	    __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
4772		return false;
4773
4774	if (kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true)) {
4775		dst = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
4776		if (dst == NULL)
4777			return false;
4778
4779		kgem_bo_sync__cpu(&sna->kgem, priv->gpu_bo);
4780	} else {
4781		dst = kgem_bo_map__wc(&sna->kgem, priv->gpu_bo);
4782		if (dst == NULL)
4783			return false;
4784
4785		kgem_bo_sync__gtt(&sna->kgem, priv->gpu_bo);
4786	}
4787
4788	box = region_rects(region);
4789	n = region_num_rects(region);
4790
4791	DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n));
4792
4793	if (sigtrap_get())
4794		return false;
4795
4796	if (priv->gpu_bo->tiling) {
4797		do {
4798			DBG(("%s: copy tiled box (%d, %d)->(%d, %d)x(%d, %d)\n",
4799			     __FUNCTION__,
4800			     box->x1 - x, box->y1 - y,
4801			     box->x1, box->y1,
4802			     box->x2 - box->x1, box->y2 - box->y1));
4803
4804			assert(box->x2 > box->x1);
4805			assert(box->y2 > box->y1);
4806
4807			assert(box->x1 >= 0);
4808			assert(box->y1 >= 0);
4809			assert(box->x2 <= pixmap->drawable.width);
4810			assert(box->y2 <= pixmap->drawable.height);
4811
4812			assert(box->x1 - x >= 0);
4813			assert(box->y1 - y >= 0);
4814			assert(box->x2 - x <= w);
4815			assert(box->y2 - y <= h);
4816
4817			memcpy_to_tiled_x(&sna->kgem, bits, dst,
4818					  pixmap->drawable.bitsPerPixel,
4819					  stride, priv->gpu_bo->pitch,
4820					  box->x1 - x, box->y1 - y,
4821					  box->x1, box->y1,
4822					  box->x2 - box->x1, box->y2 - box->y1);
4823			box++;
4824		} while (--n);
4825	} else {
4826		do {
4827			DBG(("%s: copy lined box (%d, %d)->(%d, %d)x(%d, %d)\n",
4828			     __FUNCTION__,
4829			     box->x1 - x, box->y1 - y,
4830			     box->x1, box->y1,
4831			     box->x2 - box->x1, box->y2 - box->y1));
4832
4833			assert(box->x2 > box->x1);
4834			assert(box->y2 > box->y1);
4835
4836			assert(box->x1 >= 0);
4837			assert(box->y1 >= 0);
4838			assert(box->x2 <= pixmap->drawable.width);
4839			assert(box->y2 <= pixmap->drawable.height);
4840
4841			assert(box->x1 - x >= 0);
4842			assert(box->y1 - y >= 0);
4843			assert(box->x2 - x <= w);
4844			assert(box->y2 - y <= h);
4845
4846			memcpy_blt(bits, dst,
4847				   pixmap->drawable.bitsPerPixel,
4848				   stride, priv->gpu_bo->pitch,
4849				   box->x1 - x, box->y1 - y,
4850				   box->x1, box->y1,
4851				   box->x2 - box->x1, box->y2 - box->y1);
4852			box++;
4853		} while (--n);
4854
4855		if (!priv->shm) {
4856			pixmap->devPrivate.ptr = dst;
4857			pixmap->devKind = priv->gpu_bo->pitch;
4858			if (dst == MAP(priv->gpu_bo->map__cpu)) {
4859				priv->mapped = MAPPED_CPU;
4860				priv->cpu = true;
4861			} else
4862				priv->mapped = MAPPED_GTT;
4863			assert_pixmap_map(pixmap, priv);
4864		}
4865	}
4866
4867	sigtrap_put();
4868	return true;
4869}
4870
4871static bool
4872try_upload__inplace(PixmapPtr pixmap, RegionRec *region,
4873		    int x, int y, int w, int  h, char *bits, int stride)
4874{
4875	struct sna *sna = to_sna_from_pixmap(pixmap);
4876	struct sna_pixmap *priv = sna_pixmap(pixmap);
4877	bool ignore_cpu = false;
4878	bool replaces;
4879	const BoxRec *box;
4880	uint8_t *dst;
4881	int n;
4882
4883	if (!USE_INPLACE)
4884		return false;
4885
4886	assert(priv);
4887
4888	if (priv->shm && priv->gpu_damage == NULL)
4889		return false;
4890
4891	replaces = region_subsumes_pixmap(region, pixmap);
4892
4893	DBG(("%s: bo? %d, can map? %d, replaces? %d\n", __FUNCTION__,
4894	     priv->gpu_bo != NULL,
4895	     priv->gpu_bo ? kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true) : 0,
4896	     replaces));
4897
4898	if (kgem_bo_discard_cache(priv->gpu_bo, true)) {
4899		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
4900		assert(DAMAGE_IS_ALL(priv->cpu_damage));
4901		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */
4902		assert(!priv->pinned);
4903		assert(!priv->mapped);
4904		sna_damage_destroy(&priv->gpu_damage);
4905		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
4906		priv->gpu_bo = NULL;
4907	}
4908
4909	if (priv->gpu_bo && replaces) {
4910		if (UNDO) kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
4911		if (can_create_upload_tiled_x(sna, pixmap, priv, true) &&
4912		    (priv->cow ||
4913		     __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo) ||
4914		     !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))) {
4915			DBG(("%s: discarding unusable target bo (busy? %d, mappable? %d)\n", __FUNCTION__,
4916			     kgem_bo_is_busy(priv->gpu_bo),
4917			     kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true)));
4918			sna_pixmap_free_gpu(sna, priv);
4919			ignore_cpu = true;
4920		}
4921	}
4922	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
4923
4924	if (priv->cow ||
4925	    (priv->move_to_gpu && !sna_pixmap_discard_shadow_damage(priv, replaces ? NULL : region))) {
4926		DBG(("%s: no, has pending COW? %d or move-to-gpu? %d\n",
4927		     __FUNCTION__, priv->cow != NULL, priv->move_to_gpu != NULL));
4928		return false;
4929	}
4930
4931	if (priv->gpu_damage &&
4932	    region_subsumes_damage(region, priv->gpu_damage)) {
4933		if (UNDO) kgem_bo_undo(&sna->kgem, priv->gpu_bo);
4934		if (can_create_upload_tiled_x(sna, pixmap, priv, priv->cpu_damage == NULL) &&
4935		    (__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo) ||
4936		     !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))) {
4937			DBG(("%s: discarding unusable partial target bo (busy? %d, mappable? %d)\n", __FUNCTION__,
4938			     kgem_bo_is_busy(priv->gpu_bo),
4939			     kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true)));
4940			sna_pixmap_free_gpu(sna, priv);
4941			ignore_cpu = priv->cpu_damage == NULL;
4942			if (priv->ptr)
4943				sna_damage_all(&priv->cpu_damage, pixmap);
4944		}
4945	}
4946
4947	if (priv->gpu_bo == NULL &&
4948	    !create_upload_tiled_x(sna, pixmap, priv, ignore_cpu))
4949		return false;
4950
4951	DBG(("%s: tiling=%d\n", __FUNCTION__, priv->gpu_bo->tiling));
4952	switch (priv->gpu_bo->tiling) {
4953	case I915_TILING_Y:
4954		break;
4955	case I915_TILING_X:
4956		if (!sna->kgem.memcpy_to_tiled_x)
4957			break;
4958	default:
4959		if (try_upload__tiled_x(pixmap, region, x, y, w, h, bits, stride))
4960			goto done;
4961		break;
4962	}
4963
4964	if (priv->gpu_damage == NULL && !box_inplace(pixmap, &region->extents)) {
4965		DBG(("%s: no, too small to bother with using the GTT\n", __FUNCTION__));
4966		return false;
4967	}
4968
4969	if (!kgem_bo_can_map(&sna->kgem, priv->gpu_bo)) {
4970		DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__));
4971		return false;
4972	}
4973
4974	if (!sna_pixmap_move_area_to_gpu(pixmap, &region->extents,
4975					 MOVE_WRITE | (region->data ? MOVE_READ : 0)))
4976		return false;
4977
4978	if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 &&
4979	    __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
4980		return false;
4981
4982	dst = kgem_bo_map(&sna->kgem, priv->gpu_bo);
4983	if (dst == NULL)
4984		return false;
4985
4986	pixmap->devPrivate.ptr = dst;
4987	pixmap->devKind = priv->gpu_bo->pitch;
4988	priv->mapped = dst == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
4989	priv->cpu &= priv->mapped == MAPPED_CPU;
4990	assert(has_coherent_ptr(sna, priv, MOVE_WRITE));
4991
4992	box = region_rects(region);
4993	n = region_num_rects(region);
4994
4995	DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n));
4996
4997	if (sigtrap_get())
4998		return false;
4999
5000	do {
5001		DBG(("%s: copy lined box (%d, %d)->(%d, %d)x(%d, %d)\n",
5002		     __FUNCTION__,
5003		     box->x1 - x, box->y1 - y,
5004		     box->x1, box->y1,
5005		     box->x2 - box->x1, box->y2 - box->y1));
5006
5007		assert(box->x2 > box->x1);
5008		assert(box->y2 > box->y1);
5009
5010		assert(box->x1 >= 0);
5011		assert(box->y1 >= 0);
5012		assert(box->x2 <= pixmap->drawable.width);
5013		assert(box->y2 <= pixmap->drawable.height);
5014
5015		assert(box->x1 - x >= 0);
5016		assert(box->y1 - y >= 0);
5017		assert(box->x2 - x <= w);
5018		assert(box->y2 - y <= h);
5019
5020		memcpy_blt(bits, dst,
5021			   pixmap->drawable.bitsPerPixel,
5022			   stride, priv->gpu_bo->pitch,
5023			   box->x1 - x, box->y1 - y,
5024			   box->x1, box->y1,
5025			   box->x2 - box->x1, box->y2 - box->y1);
5026		box++;
5027	} while (--n);
5028
5029	sigtrap_put();
5030
5031done:
5032	if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
5033		if (replaces) {
5034			sna_damage_all(&priv->gpu_damage, pixmap);
5035		} else {
5036			sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap);
5037			sna_damage_reduce_all(&priv->gpu_damage, pixmap);
5038		}
5039		if (DAMAGE_IS_ALL(priv->gpu_damage))
5040			sna_damage_destroy(&priv->cpu_damage);
5041		else
5042			sna_damage_subtract(&priv->cpu_damage, region);
5043
5044		if (priv->cpu_damage == NULL) {
5045			list_del(&priv->flush_list);
5046			sna_damage_all(&priv->gpu_damage, pixmap);
5047		}
5048
5049		add_shm_flush(sna, priv);
5050	}
5051
5052	assert(!priv->clear);
5053	return true;
5054}
5055
5056static bool
5057try_upload__blt(PixmapPtr pixmap, RegionRec *region,
5058		int x, int y, int w, int  h, char *bits, int stride)
5059{
5060	struct sna *sna = to_sna_from_pixmap(pixmap);
5061	struct sna_pixmap *priv;
5062	struct kgem_bo *src_bo;
5063	bool ok;
5064
5065	if (!sna->kgem.has_userptr || !USE_USERPTR_UPLOADS)
5066		return false;
5067
5068	priv = sna_pixmap(pixmap);
5069	assert(priv);
5070	assert(priv->gpu_bo);
5071	assert(priv->gpu_bo->proxy == NULL);
5072
5073	if (priv->cpu_damage &&
5074	    (DAMAGE_IS_ALL(priv->cpu_damage) ||
5075	     sna_damage_contains_box__no_reduce(priv->cpu_damage,
5076						&region->extents)) &&
5077	    !box_inplace(pixmap, &region->extents)) {
5078		DBG(("%s: no, damage on CPU and too small\n", __FUNCTION__));
5079		return false;
5080	}
5081
5082	src_bo = kgem_create_map(&sna->kgem, bits, stride * h, true);
5083	if (src_bo == NULL)
5084		return false;
5085
5086	src_bo->pitch = stride;
5087	kgem_bo_mark_unreusable(src_bo);
5088
5089	if (!sna_pixmap_move_area_to_gpu(pixmap, &region->extents,
5090					 MOVE_WRITE | MOVE_ASYNC_HINT | (region->data ? MOVE_READ : 0))) {
5091		kgem_bo_destroy(&sna->kgem, src_bo);
5092		return false;
5093	}
5094
5095	DBG(("%s: upload(%d, %d, %d, %d) x %d through a temporary map\n",
5096	     __FUNCTION__, x, y, w, h, region_num_rects(region)));
5097
5098	if (sigtrap_get() == 0) {
5099		ok = sna->render.copy_boxes(sna, GXcopy,
5100					    &pixmap->drawable, src_bo, -x, -y,
5101					    &pixmap->drawable, priv->gpu_bo, 0, 0,
5102					    region_rects(region),
5103					    region_num_rects(region),
5104					    COPY_LAST);
5105		sigtrap_put();
5106	} else
5107		ok = false;
5108
5109	kgem_bo_sync__cpu(&sna->kgem, src_bo);
5110	assert(src_bo->rq == NULL);
5111	kgem_bo_destroy(&sna->kgem, src_bo);
5112
5113	if (!ok) {
5114		DBG(("%s: copy failed!\n", __FUNCTION__));
5115		return false;
5116	}
5117
5118	if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
5119		assert(!priv->clear);
5120		if (region_subsumes_drawable(region, &pixmap->drawable)) {
5121			sna_damage_all(&priv->gpu_damage, pixmap);
5122		} else {
5123			sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap);
5124			sna_damage_reduce_all(&priv->gpu_damage, pixmap);
5125		}
5126		if (DAMAGE_IS_ALL(priv->gpu_damage))
5127			sna_damage_destroy(&priv->cpu_damage);
5128		else
5129			sna_damage_subtract(&priv->cpu_damage, region);
5130		if (priv->cpu_damage == NULL) {
5131			list_del(&priv->flush_list);
5132			if (sna_pixmap_free_cpu(sna, priv, priv->cpu))
5133				sna_damage_all(&priv->gpu_damage, pixmap);
5134		}
5135	}
5136	priv->cpu = false;
5137	priv->clear = false;
5138
5139	return true;
5140}
5141
5142static bool ignore_cpu_damage(struct sna *sna, struct sna_pixmap *priv, const RegionRec *region)
5143{
5144	if (region_subsumes_pixmap(region, priv->pixmap))
5145		return true;
5146
5147	if (priv->cpu_damage != NULL) {
5148		if (DAMAGE_IS_ALL(priv->cpu_damage))
5149			return false;
5150
5151		if (!box_inplace(priv->pixmap, &region->extents))
5152			return false;
5153
5154		if (sna_damage_contains_box__no_reduce(priv->cpu_damage, &region->extents))
5155			return false;
5156	}
5157
5158	return priv->gpu_bo == NULL || !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo);
5159
5160}
5161
5162static bool
5163try_upload__fast(PixmapPtr pixmap, RegionRec *region,
5164		 int x, int y, int w, int  h, char *bits, int stride)
5165{
5166	struct sna *sna = to_sna_from_pixmap(pixmap);
5167	struct sna_pixmap *priv;
5168
5169	if (wedged(sna))
5170		return false;
5171
5172	priv = sna_pixmap(pixmap);
5173	if (priv == NULL)
5174		return false;
5175
5176	if (ignore_cpu_damage(sna, priv, region)) {
5177		DBG(("%s: ignore existing cpu damage (if any)\n", __FUNCTION__));
5178		if (try_upload__inplace(pixmap, region, x, y, w, h, bits, stride))
5179			return true;
5180	}
5181
5182	if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL || priv->cpu) {
5183		DBG(("%s: no, no gpu damage\n", __FUNCTION__));
5184		return false;
5185	}
5186
5187	assert(priv->gpu_bo);
5188	assert(priv->gpu_bo->proxy == NULL);
5189
5190	if (try_upload__blt(pixmap, region, x, y, w, h, bits, stride))
5191		return true;
5192
5193	if (try_upload__inplace(pixmap, region, x, y, w, h, bits, stride))
5194		return true;
5195
5196	return false;
5197}
5198
5199static bool
5200sna_put_zpixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
5201		    int x, int y, int w, int  h, char *bits, int stride)
5202{
5203	PixmapPtr pixmap = get_drawable_pixmap(drawable);
5204	unsigned int hint;
5205	const BoxRec *box;
5206	int16_t dx, dy;
5207	int n;
5208
5209	assert_pixmap_contains_box(pixmap, RegionExtents(region));
5210
5211	if (gc->alu != GXcopy)
5212		return false;
5213
5214	if (drawable->depth < 8)
5215		return false;
5216
5217	get_drawable_deltas(drawable, pixmap, &dx, &dy);
5218	x += dx + drawable->x;
5219	y += dy + drawable->y;
5220	assert(region->extents.x1 >= x);
5221	assert(region->extents.y1 >= y);
5222	assert(region->extents.x2 <= x + w);
5223	assert(region->extents.y2 <= y + h);
5224
5225	if (try_upload__fast(pixmap, region, x, y, w, h, bits, stride))
5226		return true;
5227
5228	hint = MOVE_WRITE;
5229	if (region_is_unclipped(region, pixmap->drawable.width, h) &&
5230	    (h+1)*stride > 65536) {
5231		DBG(("%s: segmented, unclipped large upload (%d bytes), marking WHOLE_HINT\n",
5232		     __FUNCTION__, h*stride));
5233		hint |= MOVE_WHOLE_HINT;
5234	}
5235
5236	if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, region, hint))
5237		return false;
5238
5239	if (sigtrap_get())
5240		return false;
5241
5242	/* Region is pre-clipped and translated into pixmap space */
5243	box = region_rects(region);
5244	n = region_num_rects(region);
5245	DBG(("%s: upload(%d, %d, %d, %d) x %d boxes\n", __FUNCTION__, x, y, w, h, n));
5246	do {
5247		DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n",
5248		     __FUNCTION__,
5249		     box->x1 - x, box->y1 - y,
5250		     box->x1, box->y1,
5251		     box->x2 - box->x1, box->y2 - box->y1));
5252
5253		assert(box->x2 > box->x1);
5254		assert(box->y2 > box->y1);
5255
5256		assert(box->x1 >= 0);
5257		assert(box->y1 >= 0);
5258		assert(box->x2 <= pixmap->drawable.width);
5259		assert(box->y2 <= pixmap->drawable.height);
5260
5261		assert(box->x1 - x >= 0);
5262		assert(box->y1 - y >= 0);
5263		assert(box->x2 - x <= w);
5264		assert(box->y2 - y <= h);
5265
5266		assert(has_coherent_ptr(to_sna_from_pixmap(pixmap), sna_pixmap(pixmap), MOVE_WRITE));
5267		assert(pixmap->devKind);
5268		memcpy_blt(bits, pixmap->devPrivate.ptr,
5269			   pixmap->drawable.bitsPerPixel,
5270			   stride, pixmap->devKind,
5271			   box->x1 - x, box->y1 - y,
5272			   box->x1, box->y1,
5273			   box->x2 - box->x1, box->y2 - box->y1);
5274		box++;
5275	} while (--n);
5276
5277	sigtrap_put();
5278	assert_pixmap_damage(pixmap);
5279	return true;
5280}
5281
5282static inline uint8_t byte_reverse(uint8_t b)
5283{
5284	return ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
5285}
5286
5287static inline uint8_t blt_depth(int depth)
5288{
5289	switch (depth) {
5290	case 8: return 0;
5291	case 15: return 0x2;
5292	case 16: return 0x1;
5293	default: return 0x3;
5294	}
5295}
5296
5297inline static void blt_done(struct sna *sna)
5298{
5299	sna->blt_state.fill_bo = 0;
5300	if (sna->kgem.nbatch && __kgem_ring_empty(&sna->kgem)) {
5301		DBG(("%s: flushing BLT operation on empty ring\n",
5302		     __FUNCTION__));
5303		_kgem_submit(&sna->kgem);
5304	}
5305}
5306
5307static bool
5308sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
5309		     int x, int y, int w, int  h, char *bits)
5310{
5311	PixmapPtr pixmap = get_drawable_pixmap(drawable);
5312	struct sna *sna = to_sna_from_pixmap(pixmap);
5313	struct sna_damage **damage;
5314	struct kgem_bo *bo;
5315	const BoxRec *box;
5316	int16_t dx, dy;
5317	int n;
5318	uint8_t rop = copy_ROP[gc->alu];
5319
5320	bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU,
5321				 &region->extents, &damage);
5322	if (bo == NULL)
5323		return false;
5324
5325	if (bo->tiling == I915_TILING_Y) {
5326		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
5327		assert(bo == __sna_pixmap_get_bo(pixmap));
5328		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
5329		if (bo == NULL) {
5330			DBG(("%s: fallback -- unable to change tiling\n",
5331			     __FUNCTION__));
5332			return false;
5333		}
5334	}
5335
5336	if (!kgem_bo_can_blt(&sna->kgem, bo))
5337		return false;
5338
5339	assert_pixmap_contains_box(pixmap, RegionExtents(region));
5340	if (damage)
5341		sna_damage_add_to_pixmap(damage, region, pixmap);
5342	assert_pixmap_damage(pixmap);
5343
5344	DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h));
5345
5346	get_drawable_deltas(drawable, pixmap, &dx, &dy);
5347	x += dx + drawable->x;
5348	y += dy + drawable->y;
5349
5350	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
5351	assert(kgem_bo_can_blt(&sna->kgem, bo));
5352	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
5353
5354	/* Region is pre-clipped and translated into pixmap space */
5355	box = region_rects(region);
5356	n = region_num_rects(region);
5357	do {
5358		int bx1 = (box->x1 - x) & ~7;
5359		int bx2 = (box->x2 - x + 7) & ~7;
5360		int bw = (bx2 - bx1)/8;
5361		int bh = box->y2 - box->y1;
5362		int bstride = ALIGN(bw, 2);
5363		struct kgem_bo *upload;
5364		void *ptr;
5365
5366		if (!kgem_check_batch(&sna->kgem, 10) ||
5367		    !kgem_check_bo_fenced(&sna->kgem, bo) ||
5368		    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
5369			kgem_submit(&sna->kgem);
5370			if (!kgem_check_bo_fenced(&sna->kgem, bo))
5371				return false;
5372			_kgem_set_mode(&sna->kgem, KGEM_BLT);
5373		}
5374		kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
5375
5376		upload = kgem_create_buffer(&sna->kgem,
5377					    bstride*bh,
5378					    KGEM_BUFFER_WRITE_INPLACE,
5379					    &ptr);
5380		if (!upload)
5381			break;
5382
5383
5384		if (sigtrap_get() == 0) {
5385			int src_stride = BitmapBytePad(w);
5386			uint8_t *dst = ptr;
5387			uint8_t *src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8;
5388			uint32_t *b;
5389
5390			bstride -= bw;
5391			src_stride -= bw;
5392
5393			do {
5394				int i = bw;
5395				assert(src >= (uint8_t *)bits);
5396				do {
5397					*dst++ = byte_reverse(*src++);
5398				} while (--i);
5399				assert(src <= (uint8_t *)bits + BitmapBytePad(w) * h);
5400				assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload));
5401				dst += bstride;
5402				src += src_stride;
5403			} while (--bh);
5404
5405			assert(sna->kgem.mode == KGEM_BLT);
5406			if (sna->kgem.gen >= 0100) {
5407				b = sna->kgem.batch + sna->kgem.nbatch;
5408				b[0] = XY_MONO_SRC_COPY | 3 << 20 | 8;
5409				b[0] |= ((box->x1 - x) & 7) << 17;
5410				b[1] = bo->pitch;
5411				if (bo->tiling) {
5412					b[0] |= BLT_DST_TILED;
5413					b[1] >>= 2;
5414				}
5415				b[1] |= blt_depth(drawable->depth) << 24;
5416				b[1] |= rop << 16;
5417				b[2] = box->y1 << 16 | box->x1;
5418				b[3] = box->y2 << 16 | box->x2;
5419				*(uint64_t *)(b+4) =
5420					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
5421							I915_GEM_DOMAIN_RENDER << 16 |
5422							I915_GEM_DOMAIN_RENDER |
5423							KGEM_RELOC_FENCED,
5424							0);
5425				*(uint64_t *)(b+6) =
5426					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
5427							I915_GEM_DOMAIN_RENDER << 16 |
5428							KGEM_RELOC_FENCED,
5429							0);
5430				b[8] = gc->bgPixel;
5431				b[9] = gc->fgPixel;
5432
5433				sna->kgem.nbatch += 10;
5434			} else {
5435				b = sna->kgem.batch + sna->kgem.nbatch;
5436				b[0] = XY_MONO_SRC_COPY | 3 << 20 | 6;
5437				b[0] |= ((box->x1 - x) & 7) << 17;
5438				b[1] = bo->pitch;
5439				if (sna->kgem.gen >= 040 && bo->tiling) {
5440					b[0] |= BLT_DST_TILED;
5441					b[1] >>= 2;
5442				}
5443				b[1] |= blt_depth(drawable->depth) << 24;
5444				b[1] |= rop << 16;
5445				b[2] = box->y1 << 16 | box->x1;
5446				b[3] = box->y2 << 16 | box->x2;
5447				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
5448						I915_GEM_DOMAIN_RENDER << 16 |
5449						I915_GEM_DOMAIN_RENDER |
5450						KGEM_RELOC_FENCED,
5451						0);
5452				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
5453						I915_GEM_DOMAIN_RENDER << 16 |
5454						KGEM_RELOC_FENCED,
5455						0);
5456				b[6] = gc->bgPixel;
5457				b[7] = gc->fgPixel;
5458
5459				sna->kgem.nbatch += 8;
5460			}
5461			sigtrap_put();
5462		}
5463		kgem_bo_destroy(&sna->kgem, upload);
5464
5465		box++;
5466	} while (--n);
5467
5468	blt_done(sna);
5469	return true;
5470}
5471
5472static bool
5473sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
5474		     int x, int y, int w, int  h, int left,char *bits)
5475{
5476	PixmapPtr pixmap = get_drawable_pixmap(drawable);
5477	struct sna *sna = to_sna_from_pixmap(pixmap);
5478	struct sna_damage **damage;
5479	struct kgem_bo *bo;
5480	int16_t dx, dy;
5481	unsigned i, skip;
5482
5483	if (gc->alu != GXcopy)
5484		return false;
5485
5486	bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU,
5487				 &region->extents, &damage);
5488	if (bo == NULL)
5489		return false;
5490
5491	if (bo->tiling == I915_TILING_Y) {
5492		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
5493		assert(bo == __sna_pixmap_get_bo(pixmap));
5494		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
5495		if (bo == NULL) {
5496			DBG(("%s: fallback -- unable to change tiling\n",
5497			     __FUNCTION__));
5498			return false;
5499		}
5500	}
5501
5502	if (!kgem_bo_can_blt(&sna->kgem, bo))
5503		return false;
5504
5505	assert_pixmap_contains_box(pixmap, RegionExtents(region));
5506	if (damage)
5507		sna_damage_add_to_pixmap(damage, region, pixmap);
5508	assert_pixmap_damage(pixmap);
5509
5510	DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h));
5511
5512	get_drawable_deltas(drawable, pixmap, &dx, &dy);
5513	x += dx + drawable->x;
5514	y += dy + drawable->y;
5515
5516	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
5517	assert(kgem_bo_can_blt(&sna->kgem, bo));
5518	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
5519
5520	skip = h * BitmapBytePad(w + left);
5521	for (i = 1 << (gc->depth-1); i; i >>= 1, bits += skip) {
5522		const BoxRec *box = region_rects(region);
5523		int n = region_num_rects(region);
5524
5525		if ((gc->planemask & i) == 0)
5526			continue;
5527
5528		/* Region is pre-clipped and translated into pixmap space */
5529		do {
5530			int bx1 = (box->x1 - x) & ~7;
5531			int bx2 = (box->x2 - x + 7) & ~7;
5532			int bw = (bx2 - bx1)/8;
5533			int bh = box->y2 - box->y1;
5534			int bstride = ALIGN(bw, 2);
5535			struct kgem_bo *upload;
5536			void *ptr;
5537
5538			if (!kgem_check_batch(&sna->kgem, 14) ||
5539			    !kgem_check_bo_fenced(&sna->kgem, bo) ||
5540			    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
5541				kgem_submit(&sna->kgem);
5542				if (!kgem_check_bo_fenced(&sna->kgem, bo))
5543					return false;
5544				_kgem_set_mode(&sna->kgem, KGEM_BLT);
5545			}
5546			kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
5547
5548			upload = kgem_create_buffer(&sna->kgem,
5549						    bstride*bh,
5550						    KGEM_BUFFER_WRITE_INPLACE,
5551						    &ptr);
5552			if (!upload)
5553				break;
5554
5555			if (sigtrap_get() == 0) {
5556				int src_stride = BitmapBytePad(w);
5557				uint8_t *src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8;
5558				uint8_t *dst = ptr;
5559				uint32_t *b;
5560
5561				bstride -= bw;
5562				src_stride -= bw;
5563				do {
5564					int j = bw;
5565					assert(src >= (uint8_t *)bits);
5566					do {
5567						*dst++ = byte_reverse(*src++);
5568					} while (--j);
5569					assert(src <= (uint8_t *)bits + BitmapBytePad(w) * h);
5570					assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload));
5571					dst += bstride;
5572					src += src_stride;
5573				} while (--bh);
5574
5575				assert(sna->kgem.mode == KGEM_BLT);
5576				if (sna->kgem.gen >= 0100) {
5577					assert(sna->kgem.mode == KGEM_BLT);
5578					b = sna->kgem.batch + sna->kgem.nbatch;
5579					b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20 | 12;
5580					b[0] |= ((box->x1 - x) & 7) << 17;
5581					b[1] = bo->pitch;
5582					if (bo->tiling) {
5583						b[0] |= BLT_DST_TILED;
5584						b[1] >>= 2;
5585					}
5586					b[1] |= 1 << 31; /* solid pattern */
5587					b[1] |= blt_depth(drawable->depth) << 24;
5588					b[1] |= 0xce << 16; /* S or (D and !P) */
5589					b[2] = box->y1 << 16 | box->x1;
5590					b[3] = box->y2 << 16 | box->x2;
5591					*(uint64_t *)(b+4) =
5592						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
5593								I915_GEM_DOMAIN_RENDER << 16 |
5594								I915_GEM_DOMAIN_RENDER |
5595								KGEM_RELOC_FENCED,
5596								0);
5597					*(uint64_t *)(b+6) =
5598						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
5599								I915_GEM_DOMAIN_RENDER << 16 |
5600								KGEM_RELOC_FENCED,
5601								0);
5602					b[8] = 0;
5603					b[9] = i;
5604					b[10] = i;
5605					b[11] = i;
5606					b[12] = -1;
5607					b[13] = -1;
5608					sna->kgem.nbatch += 14;
5609				} else {
5610					b = sna->kgem.batch + sna->kgem.nbatch;
5611					b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20 | 10;
5612					b[0] |= ((box->x1 - x) & 7) << 17;
5613					b[1] = bo->pitch;
5614					if (sna->kgem.gen >= 040 && bo->tiling) {
5615						b[0] |= BLT_DST_TILED;
5616						b[1] >>= 2;
5617					}
5618					b[1] |= 1 << 31; /* solid pattern */
5619					b[1] |= blt_depth(drawable->depth) << 24;
5620					b[1] |= 0xce << 16; /* S or (D and !P) */
5621					b[2] = box->y1 << 16 | box->x1;
5622					b[3] = box->y2 << 16 | box->x2;
5623					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
5624							I915_GEM_DOMAIN_RENDER << 16 |
5625							I915_GEM_DOMAIN_RENDER |
5626							KGEM_RELOC_FENCED,
5627							0);
5628					b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
5629							I915_GEM_DOMAIN_RENDER << 16 |
5630							KGEM_RELOC_FENCED,
5631							0);
5632					b[6] = 0;
5633					b[7] = i;
5634					b[8] = i;
5635					b[9] = i;
5636					b[10] = -1;
5637					b[11] = -1;
5638					sna->kgem.nbatch += 12;
5639				}
5640				sigtrap_put();
5641			}
5642			kgem_bo_destroy(&sna->kgem, upload);
5643
5644			box++;
5645		} while (--n);
5646	}
5647
5648	blt_done(sna);
5649	return true;
5650}
5651
5652static void
5653sna_put_image(DrawablePtr drawable, GCPtr gc, int depth,
5654	      int x, int y, int w, int h, int left, int format,
5655	      char *bits)
5656{
5657	PixmapPtr pixmap = get_drawable_pixmap(drawable);
5658	struct sna *sna = to_sna_from_pixmap(pixmap);
5659	struct sna_pixmap *priv = sna_pixmap(pixmap);
5660	RegionRec region;
5661	int16_t dx, dy;
5662
5663	DBG(("%s((%d, %d)x(%d, %d), depth=%d, format=%d)\n",
5664	     __FUNCTION__, x, y, w, h, depth, format));
5665
5666	if (w == 0 || h == 0)
5667		return;
5668
5669	region.extents.x1 = x + drawable->x;
5670	region.extents.y1 = y + drawable->y;
5671	region.extents.x2 = region.extents.x1 + w;
5672	region.extents.y2 = region.extents.y1 + h;
5673	region.data = NULL;
5674
5675	if (!region_is_singular(gc->pCompositeClip) ||
5676	    gc->pCompositeClip->extents.x1 > region.extents.x1 ||
5677	    gc->pCompositeClip->extents.y1 > region.extents.y1 ||
5678	    gc->pCompositeClip->extents.x2 < region.extents.x2 ||
5679	    gc->pCompositeClip->extents.y2 < region.extents.y2) {
5680		if (!RegionIntersect(&region, &region, gc->pCompositeClip) ||
5681		    box_empty(&region.extents))
5682			return;
5683	}
5684
5685	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
5686		RegionTranslate(&region, dx, dy);
5687
5688	if (priv == NULL) {
5689		DBG(("%s: fallback -- unattached(%d, %d, %d, %d)\n",
5690		     __FUNCTION__, x, y, w, h));
5691		goto fallback;
5692	}
5693
5694	if (FORCE_FALLBACK)
5695		goto fallback;
5696
5697	if (wedged(sna))
5698		goto fallback;
5699
5700	if (!ACCEL_PUT_IMAGE)
5701		goto fallback;
5702
5703	switch (format) {
5704	case ZPixmap:
5705		if (!PM_IS_SOLID(drawable, gc->planemask))
5706			goto fallback;
5707
5708		if (sna_put_zpixmap_blt(drawable, gc, &region,
5709					x, y, w, h,
5710					bits, PixmapBytePad(w, depth)))
5711			return;
5712		break;
5713
5714	case XYBitmap:
5715		if (!PM_IS_SOLID(drawable, gc->planemask))
5716			goto fallback;
5717
5718		if (sna_put_xybitmap_blt(drawable, gc, &region,
5719					 x, y, w, h,
5720					 bits))
5721			return;
5722		break;
5723
5724	case XYPixmap:
5725		if (sna_put_xypixmap_blt(drawable, gc, &region,
5726					 x, y, w, h, left,
5727					 bits))
5728			return;
5729		break;
5730
5731	default:
5732		return;
5733	}
5734
5735fallback:
5736	DBG(("%s: fallback\n", __FUNCTION__));
5737	RegionTranslate(&region, -dx, -dy);
5738
5739	if (!sna_gc_move_to_cpu(gc, drawable, &region))
5740		goto out;
5741	if (!sna_drawable_move_region_to_cpu(drawable, &region,
5742					      format == XYPixmap ?
5743					      MOVE_READ | MOVE_WRITE :
5744					      drawable_gc_flags(drawable, gc, false)))
5745		goto out;
5746
5747	if (sigtrap_get() == 0) {
5748		DBG(("%s: fbPutImage(%d, %d, %d, %d)\n",
5749		     __FUNCTION__, x, y, w, h));
5750		fbPutImage(drawable, gc, depth, x, y, w, h, left, format, bits);
5751		FALLBACK_FLUSH(drawable);
5752		sigtrap_put();
5753	}
5754out:
5755	sna_gc_move_to_gpu(gc);
5756	RegionUninit(&region);
5757}
5758
5759static bool
5760source_contains_region(struct sna_damage *damage,
5761		       const RegionRec *region, int16_t dx, int16_t dy)
5762{
5763	BoxRec box;
5764
5765	if (DAMAGE_IS_ALL(damage))
5766		return true;
5767
5768	if (damage == NULL)
5769		return false;
5770
5771	box = region->extents;
5772	box.x1 += dx;
5773	box.x2 += dx;
5774	box.y1 += dy;
5775	box.y2 += dy;
5776	return sna_damage_contains_box__no_reduce(damage, &box);
5777}
5778
5779static bool
5780move_to_gpu(PixmapPtr pixmap, struct sna_pixmap *priv,
5781	    RegionRec *region, int16_t dx, int16_t dy,
5782	    uint8_t alu, bool dst_is_gpu)
5783{
5784	int w = region->extents.x2 - region->extents.x1;
5785	int h = region->extents.y2 - region->extents.y1;
5786	int count;
5787
5788	assert_pixmap_map(pixmap, priv);
5789	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
5790		assert(priv->gpu_bo);
5791		return true;
5792	}
5793
5794	if (dst_is_gpu && priv->cpu_bo && priv->cpu_damage) {
5795		DBG(("%s: can use CPU bo? cpu_damage=%d, gpu_damage=%d, cpu hint=%d\n",
5796		     __FUNCTION__,
5797		     priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0,
5798		     priv->gpu_damage ? DAMAGE_IS_ALL(priv->gpu_damage) ? -1 : 1 : 0,
5799		     priv->cpu));
5800		if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL)
5801			return false;
5802
5803		if (priv->cpu &&
5804		    source_contains_region(priv->cpu_damage, region, dx, dy))
5805			return false;
5806	}
5807
5808	if (priv->gpu_bo) {
5809		DBG(("%s: has gpu bo (cpu damage?=%d, cpu=%d, gpu tiling=%d)\n",
5810		     __FUNCTION__,
5811		     priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0,
5812		     priv->cpu, priv->gpu_bo->tiling));
5813
5814		if (priv->cpu_damage == NULL)
5815			return true;
5816
5817		if (alu != GXcopy)
5818			return true;
5819
5820		if (!priv->cpu)
5821			return true;
5822
5823		if (priv->gpu_bo->tiling)
5824			return true;
5825
5826		RegionTranslate(region, dx, dy);
5827		count = region_subsumes_damage(region, priv->cpu_damage);
5828		RegionTranslate(region, -dx, -dy);
5829		if (count)
5830			return true;
5831	} else {
5832		if ((priv->create & KGEM_CAN_CREATE_GPU) == 0)
5833			return false;
5834		if (priv->shm)
5835			return false;
5836	}
5837
5838	count = priv->source_count++;
5839	if (priv->cpu_bo) {
5840		if (priv->cpu_bo->flush && count > SOURCE_BIAS)
5841			return true;
5842
5843		if (sna_pixmap_default_tiling(to_sna_from_pixmap(pixmap), pixmap) == I915_TILING_NONE)
5844			return false;
5845
5846		if (priv->cpu)
5847			return false;
5848
5849		return count > SOURCE_BIAS;
5850	} else {
5851		if (w == pixmap->drawable.width && h == pixmap->drawable.height)
5852			return count > SOURCE_BIAS;
5853
5854		return count * w*h >= (SOURCE_BIAS+2) * (int)pixmap->drawable.width * pixmap->drawable.height;
5855	}
5856}
5857
5858static const BoxRec *
5859reorder_boxes(const BoxRec *box, int n, int dx, int dy)
5860{
5861	const BoxRec *next, *base;
5862	BoxRec *new;
5863
5864	DBG(("%s x %d dx=%d, dy=%d\n", __FUNCTION__, n, dx, dy));
5865
5866	if (dy <= 0 && dx <= 0) {
5867		BoxRec *tmp;
5868
5869		new = malloc(sizeof(BoxRec) * n);
5870		if (new == NULL)
5871			return NULL;
5872
5873		tmp = new;
5874		next = box + n;
5875		do {
5876			*tmp++ = *--next;
5877		} while (next != box);
5878	} else if (dy < 0) {
5879		new = malloc(sizeof(BoxRec) * n);
5880		if (new == NULL)
5881			return NULL;
5882
5883		base = next = box + n - 1;
5884		while (base >= box) {
5885			const BoxRec *tmp;
5886
5887			while (next >= box && base->y1 == next->y1)
5888				next--;
5889			tmp = next + 1;
5890			while (tmp <= base)
5891				*new++ = *tmp++;
5892			base = next;
5893		}
5894		new -= n;
5895	} else {
5896		new = malloc(sizeof(BoxRec) * n);
5897		if (!new)
5898			return NULL;
5899
5900		base = next = box;
5901		while (base < box + n) {
5902			const BoxRec *tmp;
5903
5904			while (next < box + n && next->y1 == base->y1)
5905				next++;
5906			tmp = next;
5907			while (tmp != base)
5908				*new++ = *--tmp;
5909			base = next;
5910		}
5911		new -= n;
5912	}
5913
5914	return new;
5915}
5916
5917static void
5918sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
5919		    RegionPtr region,int dx, int dy,
5920		    Pixel bitplane, void *closure)
5921{
5922	PixmapPtr pixmap = get_drawable_pixmap(src);
5923	struct sna *sna = to_sna_from_pixmap(pixmap);
5924	struct sna_pixmap *priv = sna_pixmap(pixmap);
5925	const BoxRec *box = region_rects(region);
5926	int n = region_num_rects(region);
5927	int alu = gc ? gc->alu : GXcopy;
5928	int16_t tx, ty, sx, sy;
5929
5930	assert(pixmap == get_drawable_pixmap(dst));
5931
5932	assert(region_num_rects(region));
5933	if (((dx | dy) == 0 && alu == GXcopy))
5934		return;
5935
5936	if (n > 1 && (dx | dy) < 0) {
5937		box = reorder_boxes(box, n, dx, dy);
5938		if (box == NULL)
5939			return;
5940	}
5941
5942	DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d, pix.size=%dx%d)\n",
5943	     __FUNCTION__, n,
5944	     region->extents.x1, region->extents.y1,
5945	     region->extents.x2, region->extents.y2,
5946	     dx, dy, alu,
5947	     pixmap->drawable.width, pixmap->drawable.height));
5948
5949	get_drawable_deltas(dst, pixmap, &tx, &ty);
5950	get_drawable_deltas(src, pixmap, &sx, &sy);
5951	sx += dx;
5952	sy += dy;
5953
5954	if (priv == NULL || DAMAGE_IS_ALL(priv->cpu_damage)) {
5955		DBG(("%s: unattached, or all damaged on CPU\n", __FUNCTION__));
5956		goto fallback;
5957	}
5958
5959	if (priv->gpu_damage || (priv->cpu_damage == NULL && priv->gpu_bo)) {
5960		assert(priv->gpu_bo);
5961
5962		if (alu == GXcopy && priv->clear)
5963			goto free_boxes;
5964
5965		assert(priv->gpu_bo->proxy == NULL);
5966		if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT)) {
5967			DBG(("%s: fallback - not a pure copy and failed to move dst to GPU\n",
5968			     __FUNCTION__));
5969			goto fallback;
5970		}
5971		assert(priv->cpu_damage == NULL);
5972
5973		if (!sna->render.copy_boxes(sna, alu,
5974					    &pixmap->drawable, priv->gpu_bo, sx, sy,
5975					    &pixmap->drawable, priv->gpu_bo, tx, ty,
5976					    box, n, small_copy(region))) {
5977			DBG(("%s: fallback - accelerated copy boxes failed\n",
5978			     __FUNCTION__));
5979			goto fallback;
5980		}
5981
5982		if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
5983			assert(!priv->clear);
5984			if (sna_pixmap_free_cpu(sna, priv, false)) {
5985				sna_damage_all(&priv->gpu_damage, pixmap);
5986			} else {
5987				RegionTranslate(region, tx, ty);
5988				sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap);
5989			}
5990		}
5991		assert_pixmap_damage(pixmap);
5992	} else {
5993fallback:
5994		DBG(("%s: fallback\n", __FUNCTION__));
5995		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE))
5996			goto free_boxes;
5997
5998		if (alu == GXcopy && pixmap->drawable.bitsPerPixel >= 8) {
5999			assert(pixmap->devKind);
6000			if (sigtrap_get() == 0) {
6001				FbBits *dst_bits, *src_bits;
6002				int stride = pixmap->devKind;
6003				int bpp = pixmap->drawable.bitsPerPixel;
6004				int i;
6005
6006				dst_bits = (FbBits *)
6007					((char *)pixmap->devPrivate.ptr +
6008					 ty * stride + tx * bpp / 8);
6009				src_bits = (FbBits *)
6010					((char *)pixmap->devPrivate.ptr +
6011					 sy * stride + sx * bpp / 8);
6012
6013				for (i = 0; i < n; i++)
6014					memmove_box(src_bits, dst_bits,
6015						    bpp, stride, box+i,
6016						    dx, dy);
6017				sigtrap_put();
6018			}
6019		} else {
6020			if (gc && !sna_gc_move_to_cpu(gc, dst, region))
6021				goto out;
6022
6023			if (sigtrap_get() == 0) {
6024				miCopyRegion(src, dst, gc,
6025					     region, dx, dy,
6026					     fbCopyNtoN, 0, NULL);
6027				sigtrap_put();
6028			}
6029
6030			if (gc)
6031out:
6032				sna_gc_move_to_gpu(gc);
6033		}
6034	}
6035
6036free_boxes:
6037	if (box != region_rects(region))
6038		free((void *)box);
6039}
6040
6041static inline bool
6042sna_pixmap_is_gpu(PixmapPtr pixmap)
6043{
6044	struct sna_pixmap *priv = sna_pixmap(pixmap);
6045
6046	if (priv == NULL || priv->clear)
6047		return false;
6048
6049	if (DAMAGE_IS_ALL(priv->gpu_damage) ||
6050	    (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo) && !priv->gpu_bo->proxy))
6051		return true;
6052
6053	return priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo);
6054}
6055
6056static int
6057copy_prefer_gpu(struct sna *sna,
6058		struct sna_pixmap *dst_priv,
6059		struct sna_pixmap *src_priv,
6060		RegionRec *region,
6061		int16_t dx, int16_t dy)
6062{
6063	assert(dst_priv);
6064
6065	if (wedged(sna) && !dst_priv->pinned)
6066		return 0;
6067
6068	if (src_priv == NULL) {
6069		DBG(("%s: source unattached, use cpu\n", __FUNCTION__));
6070		return 0;
6071	}
6072
6073	if (src_priv->clear) {
6074		DBG(("%s: source is clear, don't force use of GPU\n", __FUNCTION__));
6075		return 0;
6076	}
6077
6078	if (src_priv->gpu_damage &&
6079	    !source_contains_region(src_priv->cpu_damage, region, dx, dy)) {
6080		DBG(("%s: source has gpu damage, force gpu? %d\n",
6081		     __FUNCTION__, src_priv->cpu_damage == NULL));
6082		assert(src_priv->gpu_bo);
6083		return src_priv->cpu_damage ? PREFER_GPU : PREFER_GPU | FORCE_GPU;
6084	}
6085
6086	if (src_priv->cpu_bo && kgem_bo_is_busy(src_priv->cpu_bo)) {
6087		DBG(("%s: source has busy CPU bo, force gpu\n", __FUNCTION__));
6088		return PREFER_GPU | FORCE_GPU;
6089	}
6090
6091	if (source_contains_region(src_priv->cpu_damage, region, dx, dy))
6092		return src_priv->cpu_bo && kgem_is_idle(&sna->kgem);
6093
6094	DBG(("%s: source has GPU bo? %d\n",
6095	     __FUNCTION__, src_priv->gpu_bo != NULL));
6096	return src_priv->gpu_bo != NULL;
6097}
6098
6099static bool use_shm_bo(struct sna *sna,
6100		       struct kgem_bo *bo,
6101		       struct sna_pixmap *priv,
6102		       int alu, bool replaces)
6103{
6104	if (priv == NULL || priv->cpu_bo == NULL) {
6105		DBG(("%s: no, not attached\n", __FUNCTION__));
6106		return false;
6107	}
6108
6109	if (!priv->shm && !priv->cpu) {
6110		DBG(("%s: yes, ordinary CPU bo\n", __FUNCTION__));
6111		return true;
6112	}
6113
6114	if (alu != GXcopy) {
6115		DBG(("%s: yes, complex alu=%d\n", __FUNCTION__, alu));
6116		return true;
6117	}
6118
6119	if (!replaces && __kgem_bo_is_busy(&sna->kgem, bo)) {
6120		DBG(("%s: yes, dst is busy\n", __FUNCTION__));
6121		return true;
6122	}
6123
6124	if (priv->cpu_bo->needs_flush &&
6125	    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
6126		DBG(("%s: yes, src is busy\n", __FUNCTION__));
6127		return true;
6128	}
6129
6130	return false;
6131}
6132
6133static bool
6134sna_damage_contains_box__no_reduce__offset(struct sna_damage *damage,
6135					   const BoxRec *extents,
6136					   int16_t dx, int16_t dy)
6137{
6138	BoxRec _extents;
6139
6140	if (dx | dy) {
6141		_extents.x1 = extents->x1 + dx;
6142		_extents.x2 = extents->x2 + dx;
6143		_extents.y1 = extents->y1 + dy;
6144		_extents.y2 = extents->y2 + dy;
6145		extents = &_extents;
6146	}
6147
6148	return sna_damage_contains_box__no_reduce(damage, extents);
6149}
6150
6151static bool
6152sna_copy_boxes__inplace(struct sna *sna, RegionPtr region, int alu,
6153			PixmapPtr src_pixmap, struct sna_pixmap *src_priv,
6154			int dx, int dy,
6155			PixmapPtr dst_pixmap, struct sna_pixmap *dst_priv,
6156			bool replaces)
6157{
6158	const BoxRec *box;
6159	char *ptr;
6160	int n;
6161
6162	assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel);
6163
6164	if (alu != GXcopy) {
6165		DBG(("%s - no, complex alu [%d]\n", __FUNCTION__, alu));
6166		return false;
6167	}
6168
6169	if (!USE_INPLACE) {
6170		DBG(("%s - no, compile time disabled\n", __FUNCTION__));
6171		return false;
6172	}
6173
6174	if (dst_priv == src_priv) {
6175		DBG(("%s - no, dst == src\n", __FUNCTION__));
6176		return false;
6177	}
6178
6179	if (src_priv == NULL || src_priv->gpu_bo == NULL) {
6180		if (dst_priv && dst_priv->gpu_bo)
6181			goto upload_inplace;
6182
6183		DBG(("%s - no, no src or dst GPU bo\n", __FUNCTION__));
6184		return false;
6185	}
6186
6187	switch (src_priv->gpu_bo->tiling) {
6188	case I915_TILING_Y:
6189		DBG(("%s - no, bad src tiling [Y]\n", __FUNCTION__));
6190		return false;
6191	case I915_TILING_X:
6192		if (!sna->kgem.memcpy_from_tiled_x) {
6193			DBG(("%s - no, bad src tiling [X]\n", __FUNCTION__));
6194			return false;
6195		}
6196	default:
6197		break;
6198	}
6199
6200	if (src_priv->move_to_gpu && !src_priv->move_to_gpu(sna, src_priv, MOVE_READ)) {
6201		DBG(("%s - no, pending src move-to-gpu failed\n", __FUNCTION__));
6202		return false;
6203	}
6204
6205	if (!kgem_bo_can_map__cpu(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC)) {
6206		DBG(("%s - no, cannot map src for reads into the CPU\n", __FUNCTION__));
6207		return false;
6208	}
6209
6210	if (src_priv->gpu_damage == NULL ||
6211	    !(DAMAGE_IS_ALL(src_priv->gpu_damage) ||
6212	      sna_damage_contains_box__no_reduce__offset(src_priv->gpu_damage,
6213							 &region->extents,
6214							 dx, dy))) {
6215		DBG(("%s - no, src is not damaged on the GPU\n", __FUNCTION__));
6216		return false;
6217	}
6218
6219	assert(sna_damage_contains_box__offset(&src_priv->gpu_damage, &region->extents, dx, dy) == PIXMAN_REGION_IN);
6220	assert(sna_damage_contains_box__offset(&src_priv->cpu_damage, &region->extents, dx, dy) == PIXMAN_REGION_OUT);
6221
6222	ptr = kgem_bo_map__cpu(&sna->kgem, src_priv->gpu_bo);
6223	if (ptr == NULL) {
6224		DBG(("%s - no, map failed\n", __FUNCTION__));
6225		return false;
6226	}
6227
6228	if (dst_priv &&
6229	    !sna_drawable_move_region_to_cpu(&dst_pixmap->drawable,
6230					     region, MOVE_WRITE | MOVE_INPLACE_HINT)) {
6231		DBG(("%s - no, dst sync failed\n", __FUNCTION__));
6232		return false;
6233	}
6234
6235	kgem_bo_sync__cpu_full(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC);
6236
6237	if (sigtrap_get())
6238		return false;
6239
6240	box = region_rects(region);
6241	n = region_num_rects(region);
6242	if (src_priv->gpu_bo->tiling) {
6243		DBG(("%s: copy from a tiled CPU map\n", __FUNCTION__));
6244		assert(dst_pixmap->devKind);
6245		do {
6246			memcpy_from_tiled_x(&sna->kgem, ptr, dst_pixmap->devPrivate.ptr,
6247					    src_pixmap->drawable.bitsPerPixel,
6248					    src_priv->gpu_bo->pitch,
6249					    dst_pixmap->devKind,
6250					    box->x1 + dx, box->y1 + dy,
6251					    box->x1, box->y1,
6252					    box->x2 - box->x1, box->y2 - box->y1);
6253			box++;
6254		} while (--n);
6255	} else {
6256		DBG(("%s: copy from a linear CPU map\n", __FUNCTION__));
6257		assert(dst_pixmap->devKind);
6258		do {
6259			memcpy_blt(ptr, dst_pixmap->devPrivate.ptr,
6260				   src_pixmap->drawable.bitsPerPixel,
6261				   src_priv->gpu_bo->pitch,
6262				   dst_pixmap->devKind,
6263				   box->x1 + dx, box->y1 + dy,
6264				   box->x1, box->y1,
6265				   box->x2 - box->x1, box->y2 - box->y1);
6266			box++;
6267		} while (--n);
6268
6269		if (!src_priv->shm) {
6270			assert(ptr == MAP(src_priv->gpu_bo->map__cpu));
6271			src_pixmap->devPrivate.ptr = ptr;
6272			src_pixmap->devKind = src_priv->gpu_bo->pitch;
6273			src_priv->mapped = MAPPED_CPU;
6274			assert_pixmap_map(src_pixmap, src_priv);
6275			src_priv->cpu = true;
6276		}
6277	}
6278
6279	sigtrap_put();
6280
6281	return true;
6282
6283upload_inplace:
6284	switch (dst_priv->gpu_bo->tiling) {
6285	case I915_TILING_Y:
6286		DBG(("%s - no, bad dst tiling [Y]\n", __FUNCTION__));
6287		return false;
6288	case I915_TILING_X:
6289		if (!sna->kgem.memcpy_to_tiled_x) {
6290			DBG(("%s - no, bad dst tiling [X]\n", __FUNCTION__));
6291			return false;
6292		}
6293	default:
6294		break;
6295	}
6296
6297	if (dst_priv->move_to_gpu) {
6298		DBG(("%s - no, pending dst move-to-gpu\n", __FUNCTION__));
6299		return false;
6300	}
6301
6302	if (!can_upload__tiled_x(&sna->kgem, dst_priv->gpu_bo) ||
6303	    __kgem_bo_is_busy(&sna->kgem, dst_priv->gpu_bo)) {
6304		if (replaces && !dst_priv->pinned) {
6305			unsigned create;
6306			struct kgem_bo *bo;
6307
6308			create = CREATE_CPU_MAP | CREATE_INACTIVE;
6309			if (dst_priv->gpu_bo->scanout)
6310				create |= CREATE_SCANOUT;
6311
6312			bo = kgem_create_2d(&sna->kgem,
6313					    dst_pixmap->drawable.width,
6314					    dst_pixmap->drawable.height,
6315					    dst_pixmap->drawable.bitsPerPixel,
6316					    dst_priv->gpu_bo->tiling,
6317					    create);
6318			if (bo == NULL)
6319				return false;
6320
6321			sna_pixmap_unmap(dst_pixmap, dst_priv);
6322			kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo);
6323			dst_priv->gpu_bo = bo;
6324		} else {
6325			DBG(("%s - no, dst is busy\n", __FUNCTION__));
6326			return false;
6327		}
6328
6329		if (!can_upload__tiled_x(&sna->kgem, dst_priv->gpu_bo)) {
6330			DBG(("%s - no, cannot map dst for reads into the CPU\n", __FUNCTION__));
6331			return false;
6332		}
6333	}
6334
6335	if (src_priv &&
6336	    !sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
6337					     region, MOVE_READ)) {
6338		DBG(("%s - no, src sync failed\n", __FUNCTION__));
6339		return false;
6340	}
6341
6342	if (kgem_bo_can_map__cpu(&sna->kgem, dst_priv->gpu_bo, true)) {
6343		ptr = kgem_bo_map__cpu(&sna->kgem, dst_priv->gpu_bo);
6344		if (ptr == NULL) {
6345			DBG(("%s - no, map failed\n", __FUNCTION__));
6346			return false;
6347		}
6348
6349		kgem_bo_sync__cpu(&sna->kgem, dst_priv->gpu_bo);
6350	} else {
6351		ptr = kgem_bo_map__wc(&sna->kgem, dst_priv->gpu_bo);
6352		if (ptr == NULL) {
6353			DBG(("%s - no, map failed\n", __FUNCTION__));
6354			return false;
6355		}
6356
6357		kgem_bo_sync__gtt(&sna->kgem, dst_priv->gpu_bo);
6358	}
6359
6360	if (!DAMAGE_IS_ALL(dst_priv->gpu_damage)) {
6361		assert(!dst_priv->clear);
6362		sna_damage_add_to_pixmap(&dst_priv->gpu_damage, region, dst_pixmap);
6363		if (sna_damage_is_all(&dst_priv->gpu_damage,
6364				      dst_pixmap->drawable.width,
6365				      dst_pixmap->drawable.height)) {
6366			DBG(("%s: replaced entire pixmap, destroying CPU shadow\n",
6367			     __FUNCTION__));
6368			sna_damage_destroy(&dst_priv->cpu_damage);
6369			list_del(&dst_priv->flush_list);
6370		} else
6371			sna_damage_subtract(&dst_priv->cpu_damage,
6372					    region);
6373	}
6374	dst_priv->clear = false;
6375
6376	assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
6377
6378	if (sigtrap_get())
6379		return false;
6380
6381	box = region_rects(region);
6382	n = region_num_rects(region);
6383	if (dst_priv->gpu_bo->tiling) {
6384		DBG(("%s: copy to a tiled CPU map\n", __FUNCTION__));
6385		assert(dst_priv->gpu_bo->tiling == I915_TILING_X);
6386		assert(src_pixmap->devKind);
6387		do {
6388			memcpy_to_tiled_x(&sna->kgem, src_pixmap->devPrivate.ptr, ptr,
6389					  src_pixmap->drawable.bitsPerPixel,
6390					  src_pixmap->devKind,
6391					  dst_priv->gpu_bo->pitch,
6392					  box->x1 + dx, box->y1 + dy,
6393					  box->x1, box->y1,
6394					  box->x2 - box->x1, box->y2 - box->y1);
6395			box++;
6396		} while (--n);
6397	} else {
6398		DBG(("%s: copy to a linear CPU map\n", __FUNCTION__));
6399		assert(src_pixmap->devKind);
6400		do {
6401			memcpy_blt(src_pixmap->devPrivate.ptr, ptr,
6402				   src_pixmap->drawable.bitsPerPixel,
6403				   src_pixmap->devKind,
6404				   dst_priv->gpu_bo->pitch,
6405				   box->x1 + dx, box->y1 + dy,
6406				   box->x1, box->y1,
6407				   box->x2 - box->x1, box->y2 - box->y1);
6408			box++;
6409		} while (--n);
6410
6411		if (!dst_priv->shm) {
6412			dst_pixmap->devPrivate.ptr = ptr;
6413			dst_pixmap->devKind = dst_priv->gpu_bo->pitch;
6414			if (ptr == MAP(dst_priv->gpu_bo->map__cpu)) {
6415				dst_priv->mapped = MAPPED_CPU;
6416				dst_priv->cpu = true;
6417			} else
6418				dst_priv->mapped = MAPPED_GTT;
6419			assert_pixmap_map(dst_pixmap, dst_priv);
6420		}
6421	}
6422
6423	sigtrap_put();
6424
6425	return true;
6426}
6427
6428static void discard_cpu_damage(struct sna *sna, struct sna_pixmap *priv)
6429{
6430	if (priv->cpu_damage == NULL && !priv->shm)
6431		return;
6432
6433	DBG(("%s: discarding existing CPU damage\n", __FUNCTION__));
6434
6435	if (kgem_bo_discard_cache(priv->gpu_bo, true)) {
6436		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
6437		assert(DAMAGE_IS_ALL(priv->cpu_damage));
6438		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */
6439		assert(!priv->pinned);
6440		assert(!priv->mapped);
6441		sna_damage_destroy(&priv->gpu_damage);
6442		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
6443		priv->gpu_bo = NULL;
6444	}
6445
6446	sna_damage_destroy(&priv->cpu_damage);
6447	list_del(&priv->flush_list);
6448
6449	if (priv->gpu_bo && sna_pixmap_free_cpu(sna, priv, priv->cpu))
6450		sna_damage_all(&priv->gpu_damage, priv->pixmap);
6451	priv->cpu = false;
6452}
6453
6454static void
6455sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
6456	       RegionPtr region, int dx, int dy,
6457	       Pixel bitplane, void *closure)
6458{
6459	PixmapPtr src_pixmap = get_drawable_pixmap(src);
6460	struct sna_pixmap *src_priv = sna_pixmap(src_pixmap);
6461	PixmapPtr dst_pixmap = get_drawable_pixmap(dst);
6462	struct sna_pixmap *dst_priv = sna_pixmap(dst_pixmap);
6463	struct sna *sna = to_sna_from_pixmap(src_pixmap);
6464	struct sna_damage **damage;
6465	struct kgem_bo *bo;
6466	int16_t src_dx, src_dy;
6467	int16_t dst_dx, dst_dy;
6468	const BoxRec *box = region_rects(region);
6469	int n = region_num_rects(region);
6470	int alu = gc->alu;
6471	int stride, bpp;
6472	char *bits;
6473	bool replaces;
6474
6475	assert(region_num_rects(region));
6476
6477	if (src_priv &&
6478	    src_priv->gpu_bo == NULL &&
6479	    src_priv->cpu_bo == NULL &&
6480	    src_priv->ptr == NULL) {
6481		/* Rare but still happens, nothing to copy */
6482		DBG(("%s: src pixmap=%ld is empty\n",
6483		     __FUNCTION__, src_pixmap->drawable.serialNumber));
6484		return;
6485	}
6486
6487	if (src_pixmap == dst_pixmap)
6488		return sna_self_copy_boxes(src, dst, gc,
6489					   region, dx, dy,
6490					   bitplane, closure);
6491
6492	DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src pixmap=%ld+(%d, %d), dst pixmap=%ld+(%d, %d), alu=%d, src.size=%dx%d, dst.size=%dx%d)\n",
6493	     __FUNCTION__, n,
6494	     box[0].x1, box[0].y1, box[0].x2, box[0].y2,
6495	     src_pixmap->drawable.serialNumber, dx, dy,
6496	     dst_pixmap->drawable.serialNumber, get_drawable_dx(dst), get_drawable_dy(dst),
6497	     alu,
6498	     src_pixmap->drawable.width, src_pixmap->drawable.height,
6499	     dst_pixmap->drawable.width, dst_pixmap->drawable.height));
6500
6501	assert_pixmap_damage(dst_pixmap);
6502	assert_pixmap_damage(src_pixmap);
6503
6504	bpp = dst_pixmap->drawable.bitsPerPixel;
6505
6506	if (get_drawable_deltas(dst, dst_pixmap, &dst_dx, &dst_dy))
6507		RegionTranslate(region, dst_dx, dst_dy);
6508	get_drawable_deltas(src, src_pixmap, &src_dx, &src_dy);
6509	src_dx += dx - dst_dx;
6510	src_dy += dy - dst_dy;
6511
6512	assert_pixmap_contains_box(dst_pixmap, RegionExtents(region));
6513	assert_pixmap_contains_box_with_offset(src_pixmap,
6514					       RegionExtents(region),
6515					       src_dx, src_dy);
6516
6517	replaces = n == 1 &&
6518		alu_overwrites(alu) &&
6519		box->x1 <= 0 &&
6520		box->y1 <= 0 &&
6521		box->x2 >= dst_pixmap->drawable.width &&
6522		box->y2 >= dst_pixmap->drawable.height;
6523
6524	DBG(("%s: dst=(priv=%p, gpu_bo=%d, cpu_bo=%d), src=(priv=%p, gpu_bo=%d, cpu_bo=%d), replaces=%d\n",
6525	     __FUNCTION__,
6526	     dst_priv,
6527	     dst_priv && dst_priv->gpu_bo ? dst_priv->gpu_bo->handle : 0,
6528	     dst_priv && dst_priv->cpu_bo ? dst_priv->cpu_bo->handle : 0,
6529	     src_priv,
6530	     src_priv && src_priv->gpu_bo ? src_priv->gpu_bo->handle : 0,
6531	     src_priv && src_priv->cpu_bo ? src_priv->cpu_bo->handle : 0,
6532	     replaces));
6533
6534	if (dst_priv == NULL) {
6535		DBG(("%s: unattached dst failed, fallback\n", __FUNCTION__));
6536		goto fallback;
6537	}
6538
6539	if (alu == GXcopy &&
6540	    src_priv && src_priv->cow &&
6541	    COW(src_priv->cow) == COW(dst_priv->cow)) {
6542		if ((dx | dy) == 0) {
6543			DBG(("%s: ignoring cow for no op\n",
6544			     __FUNCTION__));
6545			return;
6546		} else if (IS_COW_OWNER(dst_priv->cow)) {
6547			/* XXX hack for firefox -- subsequent uses of src will be corrupt! */
6548			DBG(("%s: ignoring cow reference for cousin copy\n",
6549			     __FUNCTION__));
6550			assert(src_priv->cpu_damage == NULL);
6551			assert(dst_priv->move_to_gpu == NULL);
6552			bo = dst_priv->gpu_bo;
6553			damage = NULL;
6554		} else
6555			goto discard_cow;
6556	} else {
6557		unsigned hint;
6558discard_cow:
6559		hint = copy_prefer_gpu(sna, dst_priv, src_priv, region, src_dx, src_dy);
6560		if (replaces) {
6561			discard_cpu_damage(sna, dst_priv);
6562			hint |= REPLACES | IGNORE_DAMAGE;
6563		} else if (alu_overwrites(alu)) {
6564			if (region->data == NULL)
6565				hint |= IGNORE_DAMAGE;
6566			if (dst_priv->cpu_damage &&
6567			    region_subsumes_damage(region,
6568						   dst_priv->cpu_damage))
6569				discard_cpu_damage(sna, dst_priv);
6570		}
6571		bo = sna_drawable_use_bo(&dst_pixmap->drawable, hint,
6572					 &region->extents, &damage);
6573	}
6574	if (bo) {
6575		if (alu == GXset || alu == GXclear || (src_priv && src_priv->clear)) {
6576			uint32_t color;
6577
6578			if (alu == GXset)
6579				color = (1 << dst_pixmap->drawable.depth) - 1;
6580			else if (alu == GXclear)
6581				color = 0;
6582			else
6583				color = src_priv->clear_color;
6584			DBG(("%s: applying src clear [%08x] to dst\n",
6585			     __FUNCTION__, src_priv->clear_color));
6586
6587			if (n == 1) {
6588				if (replaces && UNDO)
6589					kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
6590
6591				if (!sna->render.fill_one(sna,
6592							  dst_pixmap, bo, color,
6593							  box->x1, box->y1,
6594							  box->x2, box->y2,
6595							  alu)) {
6596					DBG(("%s: unsupported fill\n",
6597					     __FUNCTION__));
6598					goto fallback;
6599				}
6600
6601				if (replaces && bo == dst_priv->gpu_bo) {
6602					DBG(("%s: marking dst handle=%d as all clear [%08x]\n",
6603					     __FUNCTION__,
6604					     dst_priv->gpu_bo->handle,
6605					     src_priv->clear_color));
6606					dst_priv->clear = true;
6607					dst_priv->clear_color = color;
6608					sna_damage_all(&dst_priv->gpu_damage, dst_pixmap);
6609					sna_damage_destroy(&dst_priv->cpu_damage);
6610					list_del(&dst_priv->flush_list);
6611					return;
6612				}
6613			} else {
6614				struct sna_fill_op fill;
6615
6616				if (!sna_fill_init_blt(&fill, sna,
6617						       dst_pixmap, bo,
6618						       alu, color,
6619						       FILL_BOXES)) {
6620					DBG(("%s: unsupported fill\n",
6621					     __FUNCTION__));
6622					goto fallback;
6623				}
6624
6625				fill.boxes(sna, &fill, box, n);
6626				fill.done(sna, &fill);
6627			}
6628
6629			if (damage)
6630				sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6631			return;
6632		}
6633
6634		if (src_priv &&
6635		    move_to_gpu(src_pixmap, src_priv, region, src_dx, src_dy, alu, bo == dst_priv->gpu_bo) &&
6636		    sna_pixmap_move_to_gpu(src_pixmap, MOVE_READ | MOVE_ASYNC_HINT)) {
6637			DBG(("%s: move whole src_pixmap to GPU and copy\n",
6638			     __FUNCTION__));
6639			if (replaces && UNDO)
6640				kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
6641
6642			if (replaces &&
6643			    src_pixmap->drawable.width == dst_pixmap->drawable.width &&
6644			    src_pixmap->drawable.height == dst_pixmap->drawable.height) {
6645				assert(src_pixmap->drawable.depth == dst_pixmap->drawable.depth);
6646				assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel);
6647				if (sna_pixmap_make_cow(sna, src_priv, dst_priv)) {
6648					assert(dst_priv->gpu_bo == src_priv->gpu_bo);
6649					sna_damage_all(&dst_priv->gpu_damage, dst_pixmap);
6650					sna_damage_destroy(&dst_priv->cpu_damage);
6651					list_del(&dst_priv->flush_list);
6652					add_shm_flush(sna, dst_priv);
6653					return;
6654				}
6655			}
6656			if (!sna->render.copy_boxes(sna, alu,
6657						    &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy,
6658						    &dst_pixmap->drawable, bo, 0, 0,
6659						    box, n, small_copy(region))) {
6660				DBG(("%s: fallback - accelerated copy boxes failed\n",
6661				     __FUNCTION__));
6662				goto fallback;
6663			}
6664
6665			if (damage)
6666				sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6667			return;
6668		}
6669
6670		if (src_priv &&
6671		    region_overlaps_damage(region, src_priv->gpu_damage,
6672					   src_dx, src_dy)) {
6673			BoxRec area;
6674
6675			DBG(("%s: region overlaps GPU damage, upload and copy\n",
6676			     __FUNCTION__));
6677
6678			area = region->extents;
6679			area.x1 += src_dx;
6680			area.x2 += src_dx;
6681			area.y1 += src_dy;
6682			area.y2 += src_dy;
6683
6684			if (!sna_pixmap_move_area_to_gpu(src_pixmap, &area,
6685							 MOVE_READ | MOVE_ASYNC_HINT)) {
6686				DBG(("%s: move-to-gpu(src) failed, fallback\n", __FUNCTION__));
6687				goto fallback;
6688			}
6689
6690			if (replaces && UNDO)
6691				kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
6692
6693			if (!sna->render.copy_boxes(sna, alu,
6694						    &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy,
6695						    &dst_pixmap->drawable, bo, 0, 0,
6696						    box, n, small_copy(region))) {
6697				DBG(("%s: fallback - accelerated copy boxes failed\n",
6698				     __FUNCTION__));
6699				goto fallback;
6700			}
6701
6702			if (damage)
6703				sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6704			return;
6705		}
6706
6707		if (bo != dst_priv->gpu_bo)
6708			goto fallback;
6709
6710		if (use_shm_bo(sna, bo, src_priv, alu, replaces && !dst_priv->pinned)) {
6711			bool ret;
6712
6713			DBG(("%s: region overlaps CPU damage, copy from CPU bo (shm? %d)\n",
6714			     __FUNCTION__, src_priv->shm));
6715
6716			assert(bo != dst_priv->cpu_bo);
6717
6718			RegionTranslate(region, src_dx, src_dy);
6719			ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
6720							      region,
6721							      MOVE_READ | MOVE_ASYNC_HINT);
6722			RegionTranslate(region, -src_dx, -src_dy);
6723			if (!ret) {
6724				DBG(("%s: move-to-cpu(src) failed, fallback\n", __FUNCTION__));
6725				goto fallback;
6726			}
6727
6728			if (replaces && UNDO)
6729				kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
6730
6731			add_shm_flush(sna, src_priv);
6732
6733			if (!sna->render.copy_boxes(sna, alu,
6734						    &src_pixmap->drawable, src_priv->cpu_bo, src_dx, src_dy,
6735						    &dst_pixmap->drawable, bo, 0, 0,
6736						    box, n, small_copy(region) | (src_priv->shm ? COPY_LAST : 0))) {
6737				DBG(("%s: fallback - accelerated copy boxes failed\n",
6738				     __FUNCTION__));
6739				goto fallback;
6740			}
6741
6742			if (damage)
6743				sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6744			return;
6745		}
6746
6747		if (src_priv) {
6748			bool ret;
6749
6750			RegionTranslate(region, src_dx, src_dy);
6751			ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
6752							      region, MOVE_READ);
6753			RegionTranslate(region, -src_dx, -src_dy);
6754			if (!ret) {
6755				DBG(("%s: move-to-cpu(src) failed, fallback\n", __FUNCTION__));
6756				goto fallback;
6757			}
6758
6759			assert(!src_priv->mapped);
6760			if (src_pixmap->devPrivate.ptr == NULL)
6761				/* uninitialised!*/
6762				return;
6763		}
6764
6765		if (USE_USERPTR_UPLOADS &&
6766		    sna->kgem.has_userptr &&
6767		    (alu != GXcopy ||
6768		     (box_inplace(src_pixmap, &region->extents) &&
6769		      __kgem_bo_is_busy(&sna->kgem, bo)))) {
6770			struct kgem_bo *src_bo;
6771			bool ok = false;
6772
6773			DBG(("%s: upload through a temporary map\n",
6774			     __FUNCTION__));
6775
6776			assert(src_pixmap->devKind);
6777			src_bo = kgem_create_map(&sna->kgem,
6778						 src_pixmap->devPrivate.ptr,
6779						 src_pixmap->devKind * src_pixmap->drawable.height,
6780						 true);
6781			if (src_bo) {
6782				src_bo->pitch = src_pixmap->devKind;
6783				kgem_bo_mark_unreusable(src_bo);
6784
6785				ok = sna->render.copy_boxes(sna, alu,
6786							    &src_pixmap->drawable, src_bo, src_dx, src_dy,
6787							    &dst_pixmap->drawable, bo, 0, 0,
6788							    box, n, small_copy(region) |  COPY_LAST);
6789				kgem_bo_sync__cpu(&sna->kgem, src_bo);
6790				assert(src_bo->rq == NULL);
6791				kgem_bo_destroy(&sna->kgem, src_bo);
6792			}
6793
6794			if (ok) {
6795				if (damage)
6796					sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6797				return;
6798			}
6799		}
6800
6801		if (alu != GXcopy) {
6802			PixmapPtr tmp;
6803			struct kgem_bo *src_bo;
6804			int i;
6805
6806			assert(src_pixmap->drawable.depth != 1);
6807
6808			DBG(("%s: creating temporary source upload for non-copy alu [%d]\n",
6809			     __FUNCTION__, alu));
6810
6811			tmp = sna_pixmap_create_upload(src->pScreen,
6812						       region->extents.x2 - region->extents.x1,
6813						       region->extents.y2 - region->extents.y1,
6814						       src->depth,
6815						       KGEM_BUFFER_WRITE_INPLACE);
6816			if (tmp == NullPixmap)
6817				return;
6818
6819			src_bo = __sna_pixmap_get_bo(tmp);
6820			assert(src_bo != NULL);
6821
6822			dx = -region->extents.x1;
6823			dy = -region->extents.y1;
6824			for (i = 0; i < n; i++) {
6825				assert(box[i].x1 + src_dx >= 0);
6826				assert(box[i].y1 + src_dy >= 0);
6827				assert(box[i].x2 + src_dx <= src_pixmap->drawable.width);
6828				assert(box[i].y2 + src_dy <= src_pixmap->drawable.height);
6829
6830				assert(box[i].x1 + dx >= 0);
6831				assert(box[i].y1 + dy >= 0);
6832				assert(box[i].x2 + dx <= tmp->drawable.width);
6833				assert(box[i].y2 + dy <= tmp->drawable.height);
6834
6835				assert(has_coherent_ptr(sna, sna_pixmap(src_pixmap), MOVE_READ));
6836				assert(has_coherent_ptr(sna, sna_pixmap(tmp), MOVE_WRITE));
6837				assert(src_pixmap->devKind);
6838				assert(tmp->devKind);
6839				memcpy_blt(src_pixmap->devPrivate.ptr,
6840					   tmp->devPrivate.ptr,
6841					   src_pixmap->drawable.bitsPerPixel,
6842					   src_pixmap->devKind,
6843					   tmp->devKind,
6844					   box[i].x1 + src_dx,
6845					   box[i].y1 + src_dy,
6846					   box[i].x1 + dx,
6847					   box[i].y1 + dy,
6848					   box[i].x2 - box[i].x1,
6849					   box[i].y2 - box[i].y1);
6850			}
6851
6852			if (n == 1 &&
6853			    tmp->drawable.width == src_pixmap->drawable.width &&
6854			    tmp->drawable.height == src_pixmap->drawable.height) {
6855				DBG(("%s: caching upload for src bo\n",
6856				     __FUNCTION__));
6857				assert(src_priv->gpu_damage == NULL);
6858				assert(src_priv->gpu_bo == NULL);
6859				kgem_proxy_bo_attach(src_bo, &src_priv->gpu_bo);
6860			}
6861
6862			if (!sna->render.copy_boxes(sna, alu,
6863						    &tmp->drawable, src_bo, dx, dy,
6864						    &dst_pixmap->drawable, bo, 0, 0,
6865						    box, n, 0)) {
6866				DBG(("%s: fallback - accelerated copy boxes failed\n",
6867				     __FUNCTION__));
6868				tmp->drawable.pScreen->DestroyPixmap(tmp);
6869				goto fallback;
6870			}
6871			tmp->drawable.pScreen->DestroyPixmap(tmp);
6872
6873			if (damage)
6874				sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6875			return;
6876		} else {
6877			DBG(("%s: dst is on the GPU, src is on the CPU, uploading into dst\n",
6878			     __FUNCTION__));
6879
6880			assert(src_pixmap->devKind);
6881			if (!dst_priv->pinned && replaces) {
6882				stride = src_pixmap->devKind;
6883				bits = src_pixmap->devPrivate.ptr;
6884				bits += (src_dy + box->y1) * stride + (src_dx + box->x1) * bpp / 8;
6885
6886				if (!sna_replace(sna, dst_pixmap, bits, stride)) {
6887					DBG(("%s: replace failed, fallback\n", __FUNCTION__));
6888					goto fallback;
6889				}
6890			} else {
6891				assert(!DAMAGE_IS_ALL(dst_priv->cpu_damage));
6892				if (!sna_write_boxes(sna, dst_pixmap,
6893						     dst_priv->gpu_bo, 0, 0,
6894						     src_pixmap->devPrivate.ptr,
6895						     src_pixmap->devKind,
6896						     src_dx, src_dy,
6897						     box, n)) {
6898					DBG(("%s: write failed, fallback\n", __FUNCTION__));
6899					goto fallback;
6900				}
6901			}
6902
6903			assert(dst_priv->clear == false);
6904			dst_priv->cpu = false;
6905			if (damage) {
6906				assert(!dst_priv->clear);
6907				assert(dst_priv->gpu_bo);
6908				assert(dst_priv->gpu_bo->proxy == NULL);
6909				assert(*damage == dst_priv->gpu_damage);
6910				if (replaces) {
6911					sna_damage_destroy(&dst_priv->cpu_damage);
6912					sna_damage_all(&dst_priv->gpu_damage, dst_pixmap);
6913					list_del(&dst_priv->flush_list);
6914				} else
6915					sna_damage_add(&dst_priv->gpu_damage,
6916						       region);
6917				assert_pixmap_damage(dst_pixmap);
6918			}
6919		}
6920
6921		return;
6922	}
6923
6924fallback:
6925	if (alu == GXcopy && src_priv && src_priv->clear) {
6926		DBG(("%s: copying clear [%08x]\n",
6927		     __FUNCTION__, src_priv->clear_color));
6928
6929		if (dst_priv) {
6930			if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable,
6931							     region,
6932							     MOVE_WRITE | MOVE_INPLACE_HINT))
6933				return;
6934		}
6935
6936		if (sigtrap_get() == 0) {
6937			assert(dst_pixmap->devPrivate.ptr);
6938			assert(dst_pixmap->devKind);
6939			sigtrap_assert_active();
6940			do {
6941				pixman_fill(dst_pixmap->devPrivate.ptr,
6942					    dst_pixmap->devKind/sizeof(uint32_t),
6943					    dst_pixmap->drawable.bitsPerPixel,
6944					    box->x1, box->y1,
6945					    box->x2 - box->x1,
6946					    box->y2 - box->y1,
6947					    src_priv->clear_color);
6948				box++;
6949			} while (--n);
6950			sigtrap_put();
6951		}
6952	} else if (!sna_copy_boxes__inplace(sna, region, alu,
6953					    src_pixmap, src_priv,
6954					    src_dx, src_dy,
6955					    dst_pixmap, dst_priv,
6956					    replaces)) {
6957		FbBits *dst_bits, *src_bits;
6958		int dst_stride, src_stride;
6959
6960		DBG(("%s: fallback -- src=(%d, %d), dst=(%d, %d)\n",
6961		     __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy));
6962		if (src_priv) {
6963			unsigned mode;
6964
6965			RegionTranslate(region, src_dx, src_dy);
6966
6967			assert_pixmap_contains_box(src_pixmap,
6968						   RegionExtents(region));
6969
6970			mode = MOVE_READ;
6971			if (!sna->kgem.can_blt_cpu ||
6972			    (src_priv->cpu_bo == NULL &&
6973			     (src_priv->create & KGEM_CAN_CREATE_CPU) == 0))
6974				mode |= MOVE_INPLACE_HINT;
6975
6976			if (!sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
6977							     region, mode))
6978				return;
6979
6980			RegionTranslate(region, -src_dx, -src_dy);
6981		}
6982		assert(src_priv == sna_pixmap(src_pixmap));
6983
6984		if (dst_priv) {
6985			unsigned mode;
6986
6987			if (alu_overwrites(alu))
6988				mode = MOVE_WRITE | MOVE_INPLACE_HINT;
6989			else
6990				mode = MOVE_WRITE | MOVE_READ;
6991			if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable,
6992							     region, mode))
6993				return;
6994		}
6995		assert(dst_priv == sna_pixmap(dst_pixmap));
6996
6997		assert(dst_pixmap->devKind);
6998		assert(src_pixmap->devKind);
6999		dst_stride = dst_pixmap->devKind;
7000		src_stride = src_pixmap->devKind;
7001
7002		if (alu == GXcopy && bpp >= 8) {
7003			dst_bits = (FbBits *)dst_pixmap->devPrivate.ptr;
7004			src_bits = (FbBits *)
7005				((char *)src_pixmap->devPrivate.ptr +
7006				 src_dy * src_stride + src_dx * bpp / 8);
7007
7008			if (sigtrap_get() == 0) {
7009				do {
7010					DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n",
7011					     __FUNCTION__,
7012					     box->x1, box->y1,
7013					     box->x2 - box->x1,
7014					     box->y2 - box->y1,
7015					     src_dx, src_dy,
7016					     src_stride, dst_stride));
7017
7018					assert(box->x1 >= 0);
7019					assert(box->y1 >= 0);
7020					assert(box->x2 <= dst_pixmap->drawable.width);
7021					assert(box->y2 <= dst_pixmap->drawable.height);
7022
7023					assert(box->x1 + src_dx >= 0);
7024					assert(box->y1 + src_dy >= 0);
7025					assert(box->x2 + src_dx <= src_pixmap->drawable.width);
7026					assert(box->y2 + src_dy <= src_pixmap->drawable.height);
7027					assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
7028					assert(has_coherent_ptr(sna, dst_priv, MOVE_WRITE));
7029					assert(src_stride);
7030					assert(dst_stride);
7031					memcpy_blt(src_bits, dst_bits, bpp,
7032						   src_stride, dst_stride,
7033						   box->x1, box->y1,
7034						   box->x1, box->y1,
7035						   box->x2 - box->x1,
7036						   box->y2 - box->y1);
7037					box++;
7038				} while (--n);
7039				sigtrap_put();
7040			}
7041		} else {
7042			DBG(("%s: fallback -- miCopyRegion\n", __FUNCTION__));
7043
7044			RegionTranslate(region, -dst_dx, -dst_dy);
7045
7046			if (sna_gc_move_to_cpu(gc, dst, region) &&
7047			    sigtrap_get() == 0) {
7048				miCopyRegion(src, dst, gc,
7049					     region, dx, dy,
7050					     fbCopyNtoN, 0, NULL);
7051				sigtrap_put();
7052			}
7053
7054			sna_gc_move_to_gpu(gc);
7055		}
7056	}
7057}
7058
7059typedef void (*sna_copy_func)(DrawablePtr src, DrawablePtr dst, GCPtr gc,
7060			      RegionPtr region, int dx, int dy,
7061			      Pixel bitPlane, void *closure);
7062
7063static inline bool box_equal(const BoxRec *a, const BoxRec *b)
7064{
7065	return *(const uint64_t *)a == *(const uint64_t *)b;
7066}
7067
7068static inline bool has_clip(GCPtr gc)
7069{
7070#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0)
7071	return gc->clientClipType != CT_NONE;
7072#else
7073	return gc->clientClip != NULL;
7074#endif
7075}
7076
7077static RegionPtr
7078sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc,
7079	    int sx, int sy,
7080	    int width, int height,
7081	    int dx, int dy,
7082	    sna_copy_func copy, Pixel bitPlane, void *closure)
7083{
7084	RegionPtr clip;
7085	RegionRec region;
7086	BoxRec src_extents;
7087	bool expose;
7088
7089	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n",
7090	     __FUNCTION__, sx, sy, dx, dy, width, height));
7091
7092	/* Short cut for unmapped windows */
7093	if (dst->type == DRAWABLE_WINDOW && !((WindowPtr)dst)->realized) {
7094		DBG(("%s: unmapped/unrealized dst (pixmap=%ld)\n",
7095		     __FUNCTION__, get_window_pixmap((WindowPtr)dst)));
7096		return NULL;
7097	}
7098
7099	SourceValidate(src, sx, sy, width, height, gc->subWindowMode);
7100
7101	sx += src->x;
7102	sy += src->y;
7103
7104	dx += dst->x;
7105	dy += dst->y;
7106
7107	DBG(("%s: after drawable: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n",
7108	     __FUNCTION__, sx, sy, dx, dy, width, height));
7109
7110	region.extents.x1 = dx;
7111	region.extents.y1 = dy;
7112	region.extents.x2 = bound(dx, width);
7113	region.extents.y2 = bound(dy, height);
7114	region.data = NULL;
7115
7116	DBG(("%s: dst extents (%d, %d), (%d, %d), dst clip extents (%d, %d), (%d, %d), dst size=%dx%d\n", __FUNCTION__,
7117	     region.extents.x1, region.extents.y1,
7118	     region.extents.x2, region.extents.y2,
7119	     gc->pCompositeClip->extents.x1, gc->pCompositeClip->extents.y1,
7120	     gc->pCompositeClip->extents.x2, gc->pCompositeClip->extents.y2,
7121	     dst->width, dst->height));
7122
7123	if (!box_intersect(&region.extents, &gc->pCompositeClip->extents)) {
7124		DBG(("%s: dst clipped out\n", __FUNCTION__));
7125		return NULL;
7126	}
7127
7128	DBG(("%s: clipped dst extents (%d, %d), (%d, %d)\n", __FUNCTION__,
7129	     region.extents.x1, region.extents.y1,
7130	     region.extents.x2, region.extents.y2));
7131	assert_drawable_contains_box(dst, &region.extents);
7132
7133	region.extents.x1 = clamp(region.extents.x1, sx - dx);
7134	region.extents.x2 = clamp(region.extents.x2, sx - dx);
7135	region.extents.y1 = clamp(region.extents.y1, sy - dy);
7136	region.extents.y2 = clamp(region.extents.y2, sy - dy);
7137
7138	src_extents = region.extents;
7139	expose = true;
7140
7141	DBG(("%s: unclipped src extents (%d, %d), (%d, %d)\n", __FUNCTION__,
7142	     region.extents.x1, region.extents.y1,
7143	     region.extents.x2, region.extents.y2));
7144
7145	if (region.extents.x1 < src->x)
7146		region.extents.x1 = src->x;
7147	if (region.extents.y1 < src->y)
7148		region.extents.y1 = src->y;
7149	if (region.extents.x2 > src->x + (int) src->width)
7150		region.extents.x2 = src->x + (int) src->width;
7151	if (region.extents.y2 > src->y + (int) src->height)
7152		region.extents.y2 = src->y + (int) src->height;
7153
7154	DBG(("%s: clipped src extents (%d, %d), (%d, %d)\n", __FUNCTION__,
7155	     region.extents.x1, region.extents.y1,
7156	     region.extents.x2, region.extents.y2));
7157	if (box_empty(&region.extents)) {
7158		DBG(("%s: src clipped out\n", __FUNCTION__));
7159		return NULL;
7160	}
7161
7162	/* Compute source clip region */
7163	if (src->type == DRAWABLE_PIXMAP) {
7164		if (src == dst && !has_clip(gc)) {
7165			DBG(("%s: pixmap -- using gc clip\n", __FUNCTION__));
7166			clip = gc->pCompositeClip;
7167		} else {
7168			DBG(("%s: pixmap -- no source clipping\n", __FUNCTION__));
7169			expose = false;
7170			clip = NULL;
7171		}
7172	} else {
7173		WindowPtr w = (WindowPtr)src;
7174		if (gc->subWindowMode == IncludeInferiors) {
7175			DBG(("%s: window -- include inferiors\n", __FUNCTION__));
7176
7177			if (w->winSize.data)
7178				RegionIntersect(&region, &region, &w->winSize);
7179			else
7180				box_intersect(&region.extents, &w->winSize.extents);
7181			clip = &w->borderClip;
7182		} else {
7183			DBG(("%s: window -- clip by children\n", __FUNCTION__));
7184			clip = &w->clipList;
7185		}
7186	}
7187	if (clip != NULL) {
7188		if (clip->data == NULL) {
7189			box_intersect(&region.extents, &clip->extents);
7190			if (box_equal(&src_extents, &region.extents))
7191				expose = false;
7192		} else
7193			RegionIntersect(&region, &region, clip);
7194	}
7195	DBG(("%s: src extents (%d, %d), (%d, %d) x %d\n", __FUNCTION__,
7196	     region.extents.x1, region.extents.y1,
7197	     region.extents.x2, region.extents.y2,
7198	     region_num_rects(&region)));
7199
7200	RegionTranslate(&region, dx-sx, dy-sy);
7201	if (gc->pCompositeClip->data)
7202		RegionIntersect(&region, &region, gc->pCompositeClip);
7203	DBG(("%s: copy region (%d, %d), (%d, %d) x %d + (%d, %d)\n",
7204	     __FUNCTION__,
7205	     region.extents.x1, region.extents.y1,
7206	     region.extents.x2, region.extents.y2,
7207	     region_num_rects(&region),
7208	     sx-dx, sy-dy));
7209
7210	if (!box_empty(&region.extents))
7211		copy(src, dst, gc, &region, sx-dx, sy-dy, bitPlane, closure);
7212	assert(gc->pCompositeClip != &region);
7213	RegionUninit(&region);
7214
7215	/* Pixmap sources generate a NoExposed (we return NULL to do this) */
7216	clip = NULL;
7217	if (expose && gc->fExpose)
7218		clip = miHandleExposures(src, dst, gc,
7219					 sx - src->x, sy - src->y,
7220					 width, height,
7221					 dx - dst->x, dy - dst->y,
7222					 (unsigned long) bitPlane);
7223	return clip;
7224}
7225
7226static void
7227sna_fallback_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
7228			RegionPtr region, int dx, int dy,
7229			Pixel bitplane, void *closure)
7230{
7231	DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d\n",
7232	     __FUNCTION__, region_num_rects(region),
7233	     region->extents.x1, region->extents.y1,
7234	     region->extents.x2, region->extents.y2,
7235	     dx, dy, gc->alu));
7236
7237	if (!sna_gc_move_to_cpu(gc, dst, region))
7238		goto out;
7239
7240	RegionTranslate(region, dx, dy);
7241	if (!sna_drawable_move_region_to_cpu(src, region, MOVE_READ))
7242		goto out;
7243	RegionTranslate(region, -dx, -dy);
7244
7245	if (src == dst ||
7246	    get_drawable_pixmap(src) == get_drawable_pixmap(dst)) {
7247		DBG(("%s: self-copy\n", __FUNCTION__));
7248		if (!sna_drawable_move_to_cpu(dst, MOVE_WRITE | MOVE_READ))
7249			goto out;
7250	} else {
7251		if (!sna_drawable_move_region_to_cpu(dst, region,
7252						     drawable_gc_flags(dst, gc, false)))
7253			goto out;
7254	}
7255
7256	if (sigtrap_get() == 0) {
7257		miCopyRegion(src, dst, gc,
7258			     region, dx, dy,
7259			     fbCopyNtoN, 0, NULL);
7260		FALLBACK_FLUSH(dst);
7261		sigtrap_put();
7262	}
7263out:
7264	sna_gc_move_to_gpu(gc);
7265}
7266
7267static RegionPtr
7268sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
7269	      int src_x, int src_y,
7270	      int width, int height,
7271	      int dst_x, int dst_y)
7272{
7273	struct sna *sna = to_sna_from_drawable(dst);
7274	sna_copy_func copy;
7275
7276	if (gc->planemask == 0)
7277		return NULL;
7278
7279	if (sna->ignore_copy_area)
7280		return NULL;
7281
7282	DBG(("%s: src=pixmap=%ld:(%d, %d)x(%d, %d)+(%d, %d) -> dst=pixmap=%ld:(%d, %d)+(%d, %d); alu=%d, pm=%lx, depth=%d\n",
7283	     __FUNCTION__,
7284	     get_drawable_pixmap(src)->drawable.serialNumber,
7285	     src_x, src_y, width, height, src->x, src->y,
7286	     get_drawable_pixmap(dst)->drawable.serialNumber,
7287	     dst_x, dst_y, dst->x, dst->y,
7288	     gc->alu, gc->planemask, gc->depth));
7289
7290	if (FORCE_FALLBACK || !ACCEL_COPY_AREA || wedged(sna) ||
7291	    !PM_IS_SOLID(dst, gc->planemask) || gc->depth < 8) {
7292		DBG(("%s: fallback copy\n", __FUNCTION__));
7293		copy = sna_fallback_copy_boxes;
7294	} else if (src == dst) {
7295		DBG(("%s: self copy\n", __FUNCTION__));
7296		copy = sna_self_copy_boxes;
7297	} else {
7298		DBG(("%s: normal copy\n", __FUNCTION__));
7299		copy = sna_copy_boxes;
7300	}
7301
7302	return sna_do_copy(src, dst, gc,
7303			   src_x, src_y,
7304			   width, height,
7305			   dst_x, dst_y,
7306			   copy, 0, NULL);
7307}
7308
7309const BoxRec *
7310__find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y)
7311{
7312	assert(end - begin > 1);
7313	do {
7314		const BoxRec *mid = begin + (end - begin) / 2;
7315		if (mid->y2 > y)
7316			end = mid;
7317		else
7318			begin = mid;
7319	} while (end > begin + 1);
7320	if (begin->y2 > y)
7321		return begin;
7322	else
7323		return end;
7324}
7325
7326struct sna_fill_spans {
7327	struct sna *sna;
7328	PixmapPtr pixmap;
7329	RegionRec region;
7330	unsigned flags;
7331	uint32_t phase;
7332	struct kgem_bo *bo;
7333	struct sna_damage **damage;
7334	int16_t dx, dy;
7335	void *op;
7336};
7337
7338static void
7339sna_poly_point__cpu(DrawablePtr drawable, GCPtr gc,
7340		    int mode, int n, DDXPointPtr pt)
7341{
7342	fbPolyPoint(drawable, gc, mode, n, pt, -1);
7343}
7344
7345static void
7346sna_poly_point__fill(DrawablePtr drawable, GCPtr gc,
7347		     int mode, int n, DDXPointPtr pt)
7348{
7349	struct sna_fill_spans *data = sna_gc(gc)->priv;
7350	struct sna_fill_op *op = data->op;
7351	BoxRec box[512];
7352	DDXPointRec last;
7353
7354	DBG(("%s: count=%d\n", __FUNCTION__, n));
7355	if (n == 0)
7356		return;
7357
7358	last.x = drawable->x + data->dx;
7359	last.y = drawable->y + data->dy;
7360	if (op->points && mode != CoordModePrevious) {
7361		op->points(data->sna, op, last.x, last.y, pt, n);
7362	} else do {
7363		BoxRec *b = box;
7364		unsigned nbox = n;
7365		if (nbox > ARRAY_SIZE(box))
7366			nbox = ARRAY_SIZE(box);
7367		n -= nbox;
7368		do {
7369			*(DDXPointRec *)b = *pt++;
7370
7371			b->x1 += last.x;
7372			b->y1 += last.y;
7373			if (mode == CoordModePrevious)
7374				last = *(DDXPointRec *)b;
7375
7376			b->x2 = b->x1 + 1;
7377			b->y2 = b->y1 + 1;
7378			b++;
7379		} while (--nbox);
7380		op->boxes(data->sna, op, box, b - box);
7381	} while (n);
7382}
7383
7384static void
7385sna_poly_point__gpu(DrawablePtr drawable, GCPtr gc,
7386		     int mode, int n, DDXPointPtr pt)
7387{
7388	struct sna_fill_spans *data = sna_gc(gc)->priv;
7389	struct sna_fill_op fill;
7390	BoxRec box[512];
7391	DDXPointRec last;
7392
7393	if (!sna_fill_init_blt(&fill,
7394			       data->sna, data->pixmap,
7395			       data->bo, gc->alu, gc->fgPixel,
7396			       FILL_POINTS))
7397		return;
7398
7399	DBG(("%s: count=%d\n", __FUNCTION__, n));
7400
7401	last.x = drawable->x;
7402	last.y = drawable->y;
7403	while (n) {
7404		BoxRec *b = box;
7405		unsigned nbox = n;
7406		if (nbox > ARRAY_SIZE(box))
7407			nbox = ARRAY_SIZE(box);
7408		n -= nbox;
7409		do {
7410			*(DDXPointRec *)b = *pt++;
7411
7412			b->x1 += last.x;
7413			b->y1 += last.y;
7414			if (mode == CoordModePrevious)
7415				last = *(DDXPointRec *)b;
7416
7417			if (RegionContainsPoint(&data->region,
7418						b->x1, b->y1, NULL)) {
7419				b->x1 += data->dx;
7420				b->y1 += data->dy;
7421				b->x2 = b->x1 + 1;
7422				b->y2 = b->y1 + 1;
7423				b++;
7424			}
7425		} while (--nbox);
7426		if (b != box)
7427			fill.boxes(data->sna, &fill, box, b - box);
7428	}
7429	fill.done(data->sna, &fill);
7430}
7431
7432static void
7433sna_poly_point__fill_clip_extents(DrawablePtr drawable, GCPtr gc,
7434				  int mode, int n, DDXPointPtr pt)
7435{
7436	struct sna_fill_spans *data = sna_gc(gc)->priv;
7437	struct sna_fill_op *op = data->op;
7438	const BoxRec *extents = &data->region.extents;
7439	BoxRec box[512], *b = box;
7440	const BoxRec *const last_box = b + ARRAY_SIZE(box);
7441	DDXPointRec last;
7442
7443	DBG(("%s: count=%d\n", __FUNCTION__, n));
7444
7445	last.x = drawable->x + data->dx;
7446	last.y = drawable->y + data->dy;
7447	while (n--) {
7448		*(DDXPointRec *)b = *pt++;
7449
7450		b->x1 += last.x;
7451		b->y1 += last.y;
7452		if (mode == CoordModePrevious)
7453			last = *(DDXPointRec *)b;
7454
7455		if (b->x1 >= extents->x1 && b->x1 < extents->x2 &&
7456		    b->y1 >= extents->y1 && b->y1 < extents->y2) {
7457			b->x2 = b->x1 + 1;
7458			b->y2 = b->y1 + 1;
7459			if (++b == last_box) {
7460				op->boxes(data->sna, op, box, last_box - box);
7461				b = box;
7462			}
7463		}
7464	}
7465	if (b != box)
7466		op->boxes(data->sna, op, box, b - box);
7467}
7468
7469static void
7470sna_poly_point__fill_clip_boxes(DrawablePtr drawable, GCPtr gc,
7471				int mode, int n, DDXPointPtr pt)
7472{
7473	struct sna_fill_spans *data = sna_gc(gc)->priv;
7474	struct sna_fill_op *op = data->op;
7475	RegionRec *clip = &data->region;
7476	BoxRec box[512], *b = box;
7477	const BoxRec *const last_box = b + ARRAY_SIZE(box);
7478	DDXPointRec last;
7479
7480	DBG(("%s: count=%d\n", __FUNCTION__, n));
7481
7482	last.x = drawable->x + data->dx;
7483	last.y = drawable->y + data->dy;
7484	while (n--) {
7485		*(DDXPointRec *)b = *pt++;
7486
7487		b->x1 += last.x;
7488		b->y1 += last.y;
7489		if (mode == CoordModePrevious)
7490			last = *(DDXPointRec *)b;
7491
7492		if (RegionContainsPoint(clip, b->x1, b->y1, NULL)) {
7493			b->x2 = b->x1 + 1;
7494			b->y2 = b->y1 + 1;
7495			if (++b == last_box) {
7496				op->boxes(data->sna, op, box, last_box - box);
7497				b = box;
7498			}
7499		}
7500	}
7501	if (b != box)
7502		op->boxes(data->sna, op, box, b - box);
7503}
7504
7505static void
7506sna_poly_point__dash(DrawablePtr drawable, GCPtr gc,
7507		     int mode, int n, DDXPointPtr pt)
7508{
7509	struct sna_fill_spans *data = sna_gc(gc)->priv;
7510	if (data->phase == gc->fgPixel)
7511		sna_poly_point__fill(drawable, gc, mode, n, pt);
7512}
7513
7514static void
7515sna_poly_point__dash_clip_extents(DrawablePtr drawable, GCPtr gc,
7516				  int mode, int n, DDXPointPtr pt)
7517{
7518	struct sna_fill_spans *data = sna_gc(gc)->priv;
7519	if (data->phase == gc->fgPixel)
7520		sna_poly_point__fill_clip_extents(drawable, gc, mode, n, pt);
7521}
7522
7523static void
7524sna_poly_point__dash_clip_boxes(DrawablePtr drawable, GCPtr gc,
7525				  int mode, int n, DDXPointPtr pt)
7526{
7527	struct sna_fill_spans *data = sna_gc(gc)->priv;
7528	if (data->phase == gc->fgPixel)
7529		sna_poly_point__fill_clip_boxes(drawable, gc, mode, n, pt);
7530}
7531
7532static void
7533sna_fill_spans__fill(DrawablePtr drawable,
7534		     GCPtr gc, int n,
7535		     DDXPointPtr pt, int *width, int sorted)
7536{
7537	struct sna_fill_spans *data = sna_gc(gc)->priv;
7538	struct sna_fill_op *op = data->op;
7539	BoxRec box[512];
7540
7541	DBG(("%s: alu=%d, fg=%08lx, count=%d\n",
7542	     __FUNCTION__, gc->alu, gc->fgPixel, n));
7543
7544	while (n) {
7545		BoxRec *b = box;
7546		int nbox = n;
7547		if (nbox > ARRAY_SIZE(box))
7548			nbox = ARRAY_SIZE(box);
7549		n -= nbox;
7550		do {
7551			*(DDXPointRec *)b = *pt++;
7552			b->x2 = b->x1 + (int)*width++;
7553			b->y2 = b->y1 + 1;
7554			DBG(("%s: (%d, %d), (%d, %d)\n",
7555			     __FUNCTION__, b->x1, b->y1, b->x2, b->y2));
7556			assert(b->x1 >= drawable->x);
7557			assert(b->x2 <= drawable->x + drawable->width);
7558			assert(b->y1 >= drawable->y);
7559			assert(b->y2 <= drawable->y + drawable->height);
7560			if (b->x2 > b->x1) {
7561				if (b != box &&
7562				    b->y1 == b[-1].y2 &&
7563				    b->x1 == b[-1].x1 &&
7564				    b->x2 == b[-1].x2)
7565					b[-1].y2 = b->y2;
7566				else
7567					b++;
7568			}
7569		} while (--nbox);
7570		if (b != box)
7571			op->boxes(data->sna, op, box, b - box);
7572	}
7573}
7574
7575static void
7576sna_fill_spans__dash(DrawablePtr drawable,
7577		     GCPtr gc, int n,
7578		     DDXPointPtr pt, int *width, int sorted)
7579{
7580	struct sna_fill_spans *data = sna_gc(gc)->priv;
7581	if (data->phase == gc->fgPixel)
7582		sna_fill_spans__fill(drawable, gc, n, pt, width, sorted);
7583}
7584
7585static void
7586sna_fill_spans__fill_offset(DrawablePtr drawable,
7587			    GCPtr gc, int n,
7588			    DDXPointPtr pt, int *width, int sorted)
7589{
7590	struct sna_fill_spans *data = sna_gc(gc)->priv;
7591	struct sna_fill_op *op = data->op;
7592	BoxRec box[512];
7593
7594	DBG(("%s: alu=%d, fg=%08lx\n", __FUNCTION__, gc->alu, gc->fgPixel));
7595
7596	while (n) {
7597		BoxRec *b = box;
7598		int nbox = n;
7599		if (nbox > ARRAY_SIZE(box))
7600			nbox = ARRAY_SIZE(box);
7601		n -= nbox;
7602		do {
7603			*(DDXPointRec *)b = *pt++;
7604			b->x1 += data->dx;
7605			b->y1 += data->dy;
7606			b->x2 = b->x1 + (int)*width++;
7607			b->y2 = b->y1 + 1;
7608			if (b->x2 > b->x1)
7609				b++;
7610		} while (--nbox);
7611		if (b != box)
7612			op->boxes(data->sna, op, box, b - box);
7613	}
7614}
7615
7616static void
7617sna_fill_spans__dash_offset(DrawablePtr drawable,
7618			    GCPtr gc, int n,
7619			    DDXPointPtr pt, int *width, int sorted)
7620{
7621	struct sna_fill_spans *data = sna_gc(gc)->priv;
7622	if (data->phase == gc->fgPixel)
7623		sna_fill_spans__fill_offset(drawable, gc, n, pt, width, sorted);
7624}
7625
7626static void
7627sna_fill_spans__fill_clip_extents(DrawablePtr drawable,
7628				  GCPtr gc, int n,
7629				  DDXPointPtr pt, int *width, int sorted)
7630{
7631	struct sna_fill_spans *data = sna_gc(gc)->priv;
7632	struct sna_fill_op *op = data->op;
7633	const BoxRec *extents = &data->region.extents;
7634	BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box);
7635
7636	DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n",
7637	     __FUNCTION__, gc->alu, gc->fgPixel, n,
7638	     extents->x1, extents->y1,
7639	     extents->x2, extents->y2));
7640
7641	while (n--) {
7642		DBG(("%s: [%d] pt=(%d, %d), width=%d\n",
7643		     __FUNCTION__, n, pt->x, pt->y, *width));
7644		*(DDXPointRec *)b = *pt++;
7645		b->x2 = b->x1 + (int)*width++;
7646		b->y2 = b->y1 + 1;
7647		if (box_intersect(b, extents)) {
7648			DBG(("%s: [%d] clipped=(%d, %d), (%d, %d)\n",
7649			     __FUNCTION__, n, b->x1, b->y1, b->x2, b->y2));
7650			if (data->dx|data->dy) {
7651				b->x1 += data->dx; b->x2 += data->dx;
7652				b->y1 += data->dy; b->y2 += data->dy;
7653			}
7654			if (b != box &&
7655			    b->y1 == b[-1].y2 &&
7656			    b->x1 == b[-1].x1 &&
7657			    b->x2 == b[-1].x2) {
7658				b[-1].y2 = b->y2;
7659			} else if (++b == last_box) {
7660				op->boxes(data->sna, op, box, last_box - box);
7661				b = box;
7662			}
7663		}
7664	}
7665	if (b != box)
7666		op->boxes(data->sna, op, box, b - box);
7667}
7668
7669static void
7670sna_fill_spans__dash_clip_extents(DrawablePtr drawable,
7671				  GCPtr gc, int n,
7672				  DDXPointPtr pt, int *width, int sorted)
7673{
7674	struct sna_fill_spans *data = sna_gc(gc)->priv;
7675	if (data->phase == gc->fgPixel)
7676		sna_fill_spans__fill_clip_extents(drawable, gc, n, pt, width, sorted);
7677}
7678
7679static void
7680sna_fill_spans__fill_clip_boxes(DrawablePtr drawable,
7681				GCPtr gc, int n,
7682				DDXPointPtr pt, int *width, int sorted)
7683{
7684	struct sna_fill_spans *data = sna_gc(gc)->priv;
7685	struct sna_fill_op *op = data->op;
7686	BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box);
7687	const BoxRec * const clip_start = RegionBoxptr(&data->region);
7688	const BoxRec * const clip_end = clip_start + data->region.data->numRects;
7689
7690	DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n",
7691	     __FUNCTION__, gc->alu, gc->fgPixel, n,
7692	     data->region.extents.x1, data->region.extents.y1,
7693	     data->region.extents.x2, data->region.extents.y2));
7694
7695	while (n--) {
7696		int16_t X1 = pt->x;
7697		int16_t y = pt->y;
7698		int16_t X2 = X1 + (int)*width;
7699		const BoxRec *c;
7700
7701		pt++;
7702		width++;
7703
7704		if (y < data->region.extents.y1 || data->region.extents.y2 <= y)
7705			continue;
7706
7707		if (X1 < data->region.extents.x1)
7708			X1 = data->region.extents.x1;
7709
7710		if (X2 > data->region.extents.x2)
7711			X2 = data->region.extents.x2;
7712
7713		if (X1 >= X2)
7714			continue;
7715
7716		c = find_clip_box_for_y(clip_start, clip_end, y);
7717		while (c != clip_end) {
7718			if (y + 1 <= c->y1 || X2 <= c->x1)
7719				break;
7720
7721			if (X1 >= c->x2) {
7722				c++;
7723				continue;
7724			}
7725
7726			b->x1 = c->x1;
7727			b->x2 = c->x2;
7728			c++;
7729
7730			if (b->x1 < X1)
7731				b->x1 = X1;
7732			if (b->x2 > X2)
7733				b->x2 = X2;
7734			if (b->x2 <= b->x1)
7735				continue;
7736
7737			b->x1 += data->dx;
7738			b->x2 += data->dx;
7739			b->y1 = y + data->dy;
7740			b->y2 = b->y1 + 1;
7741			if (++b == last_box) {
7742				op->boxes(data->sna, op, box, last_box - box);
7743				b = box;
7744			}
7745		}
7746	}
7747	if (b != box)
7748		op->boxes(data->sna, op, box, b - box);
7749}
7750
7751static void
7752sna_fill_spans__dash_clip_boxes(DrawablePtr drawable,
7753				GCPtr gc, int n,
7754				DDXPointPtr pt, int *width, int sorted)
7755{
7756	struct sna_fill_spans *data = sna_gc(gc)->priv;
7757	if (data->phase == gc->fgPixel)
7758		sna_fill_spans__fill_clip_boxes(drawable, gc, n, pt, width, sorted);
7759}
7760
7761static bool
7762sna_fill_spans_blt(DrawablePtr drawable,
7763		   struct kgem_bo *bo, struct sna_damage **damage,
7764		   GCPtr gc, uint32_t pixel,
7765		   int n, DDXPointPtr pt, int *width, int sorted,
7766		   const BoxRec *extents, unsigned clipped)
7767{
7768	PixmapPtr pixmap = get_drawable_pixmap(drawable);
7769	struct sna *sna = to_sna_from_pixmap(pixmap);
7770	int16_t dx, dy;
7771	struct sna_fill_op fill;
7772	BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box);
7773	static void * const jump[] = {
7774		&&no_damage,
7775		&&damage,
7776		&&no_damage_clipped,
7777		&&damage_clipped,
7778	};
7779	unsigned v;
7780
7781	DBG(("%s: alu=%d, fg=%08lx, damge=%p, clipped?=%d\n",
7782	     __FUNCTION__, gc->alu, gc->fgPixel, damage, clipped));
7783
7784	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_SPANS))
7785		return false;
7786
7787	get_drawable_deltas(drawable, pixmap, &dx, &dy);
7788
7789	v = (damage != NULL) | clipped;
7790	goto *jump[v];
7791
7792no_damage:
7793	if (dx|dy) {
7794		do {
7795			int nbox = n;
7796			if (nbox > last_box - box)
7797				nbox = last_box - box;
7798			n -= nbox;
7799			do {
7800				*(DDXPointRec *)b = *pt++;
7801				b->x1 += dx;
7802				b->y1 += dy;
7803				b->x2 = b->x1 + (int)*width++;
7804				b->y2 = b->y1 + 1;
7805				b++;
7806			} while (--nbox);
7807			fill.boxes(sna, &fill, box, b - box);
7808			b = box;
7809		} while (n);
7810	} else {
7811		do {
7812			int nbox = n;
7813			if (nbox > last_box - box)
7814				nbox = last_box - box;
7815			n -= nbox;
7816			do {
7817				*(DDXPointRec *)b = *pt++;
7818				b->x2 = b->x1 + (int)*width++;
7819				b->y2 = b->y1 + 1;
7820				b++;
7821			} while (--nbox);
7822			fill.boxes(sna, &fill, box, b - box);
7823			b = box;
7824		} while (n);
7825	}
7826	goto done;
7827
7828damage:
7829	do {
7830		*(DDXPointRec *)b = *pt++;
7831		b->x1 += dx;
7832		b->y1 += dy;
7833		b->x2 = b->x1 + (int)*width++;
7834		b->y2 = b->y1 + 1;
7835
7836		if (++b == last_box) {
7837			assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0);
7838			fill.boxes(sna, &fill, box, last_box - box);
7839			sna_damage_add_boxes(damage, box, last_box - box, 0, 0);
7840			b = box;
7841		}
7842	} while (--n);
7843	if (b != box) {
7844		assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
7845		fill.boxes(sna, &fill, box, b - box);
7846		sna_damage_add_boxes(damage, box, b - box, 0, 0);
7847	}
7848	goto done;
7849
7850no_damage_clipped:
7851	{
7852		RegionRec clip;
7853
7854		region_set(&clip, extents);
7855		if (!region_maybe_clip(&clip, gc->pCompositeClip))
7856			return true;
7857
7858		assert(dx + clip.extents.x1 >= 0);
7859		assert(dy + clip.extents.y1 >= 0);
7860		assert(dx + clip.extents.x2 <= pixmap->drawable.width);
7861		assert(dy + clip.extents.y2 <= pixmap->drawable.height);
7862
7863		DBG(("%s: clip %d x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n",
7864		     __FUNCTION__,
7865		     region_num_rects(&clip),
7866		     clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2,
7867		     n, pt->x, pt->y));
7868
7869		if (clip.data == NULL) {
7870			do {
7871				*(DDXPointRec *)b = *pt++;
7872				b->x2 = b->x1 + (int)*width++;
7873				b->y2 = b->y1 + 1;
7874
7875				if (box_intersect(b, &clip.extents)) {
7876					if (dx|dy) {
7877						b->x1 += dx; b->x2 += dx;
7878						b->y1 += dy; b->y2 += dy;
7879					}
7880					if (++b == last_box) {
7881						fill.boxes(sna, &fill, box, last_box - box);
7882						b = box;
7883					}
7884				}
7885			} while (--n);
7886		} else {
7887			const BoxRec * const clip_start = RegionBoxptr(&clip);
7888			const BoxRec * const clip_end = clip_start + clip.data->numRects;
7889			do {
7890				int16_t X1 = pt->x;
7891				int16_t y = pt->y;
7892				int16_t X2 = X1 + (int)*width;
7893				const BoxRec *c;
7894
7895				pt++;
7896				width++;
7897
7898				if (y < extents->y1 || extents->y2 <= y)
7899					continue;
7900
7901				if (X1 < extents->x1)
7902					X1 = extents->x1;
7903
7904				if (X2 > extents->x2)
7905					X2 = extents->x2;
7906
7907				if (X1 >= X2)
7908					continue;
7909
7910				c = find_clip_box_for_y(clip_start,
7911							clip_end,
7912							y);
7913				while (c != clip_end) {
7914					if (y + 1 <= c->y1 || X2 <= c->x1)
7915						break;
7916
7917					if (X1 >= c->x2) {
7918						c++;
7919						continue;
7920					}
7921
7922					b->x1 = c->x1;
7923					b->x2 = c->x2;
7924					c++;
7925
7926					if (b->x1 < X1)
7927						b->x1 = X1;
7928					if (b->x2 > X2)
7929						b->x2 = X2;
7930					if (b->x2 <= b->x1)
7931						continue;
7932
7933					b->x1 += dx;
7934					b->x2 += dx;
7935					b->y1 = y + dy;
7936					b->y2 = b->y1 + 1;
7937					if (++b == last_box) {
7938						fill.boxes(sna, &fill, box, last_box - box);
7939						b = box;
7940					}
7941				}
7942			} while (--n);
7943			RegionUninit(&clip);
7944		}
7945		if (b != box)
7946			fill.boxes(sna, &fill, box, b - box);
7947		goto done;
7948	}
7949
7950damage_clipped:
7951	{
7952		RegionRec clip;
7953
7954		region_set(&clip, extents);
7955		if (!region_maybe_clip(&clip, gc->pCompositeClip))
7956			return true;
7957
7958		assert(dx + clip.extents.x1 >= 0);
7959		assert(dy + clip.extents.y1 >= 0);
7960		assert(dx + clip.extents.x2 <= pixmap->drawable.width);
7961		assert(dy + clip.extents.y2 <= pixmap->drawable.height);
7962
7963		DBG(("%s: clip %d x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n",
7964		     __FUNCTION__,
7965		     region_num_rects(&clip),
7966		     clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2,
7967		     n, pt->x, pt->y));
7968
7969		if (clip.data == NULL) {
7970			do {
7971				*(DDXPointRec *)b = *pt++;
7972				b->x2 = b->x1 + (int)*width++;
7973				b->y2 = b->y1 + 1;
7974
7975				if (box_intersect(b, &clip.extents)) {
7976					b->x1 += dx;
7977					b->x2 += dx;
7978					b->y1 += dy;
7979					b->y2 += dy;
7980					if (++b == last_box) {
7981						assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
7982						fill.boxes(sna, &fill, box, last_box - box);
7983						sna_damage_add_boxes(damage, box, b - box, 0, 0);
7984						b = box;
7985					}
7986				}
7987			} while (--n);
7988		} else {
7989			const BoxRec * const clip_start = RegionBoxptr(&clip);
7990			const BoxRec * const clip_end = clip_start + clip.data->numRects;
7991			do {
7992				int16_t X1 = pt->x;
7993				int16_t y = pt->y;
7994				int16_t X2 = X1 + (int)*width;
7995				const BoxRec *c;
7996
7997				pt++;
7998				width++;
7999
8000				if (y < extents->y1 || extents->y2 <= y)
8001					continue;
8002
8003				if (X1 < extents->x1)
8004					X1 = extents->x1;
8005
8006				if (X2 > extents->x2)
8007					X2 = extents->x2;
8008
8009				if (X1 >= X2)
8010					continue;
8011
8012				c = find_clip_box_for_y(clip_start,
8013							clip_end,
8014							y);
8015				while (c != clip_end) {
8016					if (y + 1 <= c->y1 || X2 <= c->x1)
8017						break;
8018
8019					if (X1 >= c->x2) {
8020						c++;
8021						continue;
8022					}
8023
8024					b->x1 = c->x1;
8025					b->x2 = c->x2;
8026					c++;
8027
8028					if (b->x1 < X1)
8029						b->x1 = X1;
8030					if (b->x2 > X2)
8031						b->x2 = X2;
8032					if (b->x2 <= b->x1)
8033						continue;
8034
8035					b->x1 += dx;
8036					b->x2 += dx;
8037					b->y1 = y + dy;
8038					b->y2 = b->y1 + 1;
8039					if (++b == last_box) {
8040						assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0);
8041						fill.boxes(sna, &fill, box, last_box - box);
8042						sna_damage_add_boxes(damage, box, last_box - box, 0, 0);
8043						b = box;
8044					}
8045				}
8046			} while (--n);
8047			RegionUninit(&clip);
8048		}
8049		if (b != box) {
8050			assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
8051			fill.boxes(sna, &fill, box, b - box);
8052			sna_damage_add_boxes(damage, box, b - box, 0, 0);
8053		}
8054		goto done;
8055	}
8056
8057done:
8058	fill.done(sna, &fill);
8059	assert_pixmap_damage(pixmap);
8060	return true;
8061}
8062
8063static bool
8064sna_poly_fill_rect_tiled_blt(DrawablePtr drawable,
8065			     struct kgem_bo *bo,
8066			     struct sna_damage **damage,
8067			     GCPtr gc, int n, xRectangle *rect,
8068			     const BoxRec *extents, unsigned clipped);
8069
8070static bool
8071sna_poly_fill_rect_stippled_blt(DrawablePtr drawable,
8072				struct kgem_bo *bo,
8073				struct sna_damage **damage,
8074				GCPtr gc, int n, xRectangle *rect,
8075				const BoxRec *extents, unsigned clipped);
8076
8077static inline bool
8078gc_is_solid(GCPtr gc, uint32_t *color)
8079{
8080	assert(FbFullMask(gc->depth) == (FbFullMask(gc->depth) & gc->planemask));
8081
8082	if (gc->alu == GXclear) {
8083		*color = 0;
8084		return true;
8085	}
8086	if (gc->alu == GXset) {
8087		*color = (1 << gc->depth) - 1;
8088		return true;
8089	}
8090
8091	if (gc->fillStyle == FillSolid ||
8092	    (gc->fillStyle == FillTiled && gc->tileIsPixel) ||
8093	    (gc->fillStyle == FillOpaqueStippled && gc->bgPixel == gc->fgPixel)) {
8094		*color = gc->fillStyle == FillTiled ? gc->tile.pixel : gc->fgPixel;
8095		return true;
8096	}
8097
8098	return false;
8099}
8100
8101static void
8102sna_fill_spans__gpu(DrawablePtr drawable, GCPtr gc, int n,
8103		    DDXPointPtr pt, int *width, int sorted)
8104{
8105	struct sna_fill_spans *data = sna_gc(gc)->priv;
8106	uint32_t color;
8107
8108	DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n",
8109	     __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted));
8110
8111	assert(PM_IS_SOLID(drawable, gc->planemask));
8112	if (n == 0)
8113		return;
8114
8115	/* The mi routines do not attempt to keep the spans it generates
8116	 * within the clip, so we must run them through the clipper.
8117	 */
8118
8119	if (gc_is_solid(gc, &color)) {
8120		sna_fill_spans_blt(drawable,
8121				   data->bo, NULL,
8122				   gc, color, n, pt, width, sorted,
8123				   &data->region.extents, 2);
8124	} else {
8125		/* Try converting these to a set of rectangles instead */
8126		xRectangle *rect;
8127		int i;
8128
8129		DBG(("%s: converting to rectagnles\n", __FUNCTION__));
8130
8131		rect = malloc (n * sizeof (xRectangle));
8132		if (rect == NULL)
8133			return;
8134
8135		for (i = 0; i < n; i++) {
8136			rect[i].x = pt[i].x - drawable->x;
8137			rect[i].width = width[i];
8138			rect[i].y = pt[i].y - drawable->y;
8139			rect[i].height = 1;
8140		}
8141
8142		if (gc->fillStyle == FillTiled) {
8143			(void)sna_poly_fill_rect_tiled_blt(drawable,
8144							   data->bo, NULL,
8145							   gc, n, rect,
8146							   &data->region.extents, 2);
8147		} else {
8148			(void)sna_poly_fill_rect_stippled_blt(drawable,
8149							      data->bo, NULL,
8150							      gc, n, rect,
8151							      &data->region.extents, 2);
8152		}
8153		free (rect);
8154	}
8155}
8156
8157static unsigned
8158sna_spans_extents(DrawablePtr drawable, GCPtr gc,
8159		  int n, DDXPointPtr pt, int *width,
8160		  BoxPtr out)
8161{
8162	BoxRec box;
8163	bool clipped = false;
8164
8165	if (n == 0)
8166		return 0;
8167
8168	box.x1 = pt->x;
8169	box.x2 = box.x1 + *width;
8170	box.y2 = box.y1 = pt->y;
8171
8172	while (--n) {
8173		pt++;
8174		width++;
8175		if (box.x1 > pt->x)
8176			box.x1 = pt->x;
8177		if (box.x2 < pt->x + *width)
8178			box.x2 = pt->x + *width;
8179
8180		if (box.y1 > pt->y)
8181			box.y1 = pt->y;
8182		else if (box.y2 < pt->y)
8183			box.y2 = pt->y;
8184	}
8185	box.y2++;
8186
8187	if (gc)
8188		clipped = clip_box(&box, gc);
8189	if (box_empty(&box))
8190		return 0;
8191
8192	*out = box;
8193	return 1 | clipped << 1;
8194}
8195
8196static void
8197sna_fill_spans(DrawablePtr drawable, GCPtr gc, int n,
8198	       DDXPointPtr pt, int *width, int sorted)
8199{
8200	PixmapPtr pixmap = get_drawable_pixmap(drawable);
8201	struct sna *sna = to_sna_from_pixmap(pixmap);
8202	struct sna_damage **damage;
8203	struct kgem_bo *bo;
8204	RegionRec region;
8205	unsigned flags;
8206	uint32_t color;
8207
8208	DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n",
8209	     __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted));
8210
8211	flags = sna_spans_extents(drawable, gc, n, pt, width, &region.extents);
8212	if (flags == 0)
8213		return;
8214
8215	DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__,
8216	     region.extents.x1, region.extents.y1,
8217	     region.extents.x2, region.extents.y2));
8218
8219	if (FORCE_FALLBACK)
8220		goto fallback;
8221
8222	if (!ACCEL_FILL_SPANS)
8223		goto fallback;
8224
8225	if (wedged(sna)) {
8226		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
8227		goto fallback;
8228	}
8229
8230	DBG(("%s: fillStyle=%x [%d], mask=%lx [%d]\n", __FUNCTION__,
8231	     gc->fillStyle, gc->fillStyle == FillSolid,
8232	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask)));
8233	if (!PM_IS_SOLID(drawable, gc->planemask))
8234		goto fallback;
8235
8236	bo = sna_drawable_use_bo(drawable, PREFER_GPU,
8237				 &region.extents, &damage);
8238	if (bo) {
8239		if (gc_is_solid(gc, &color)) {
8240			DBG(("%s: trying solid fill [alu=%d, pixel=%08lx] blt paths\n",
8241			     __FUNCTION__, gc->alu, gc->fgPixel));
8242
8243			sna_fill_spans_blt(drawable,
8244					   bo, damage,
8245					   gc, color, n, pt, width, sorted,
8246					   &region.extents, flags & IS_CLIPPED);
8247		} else {
8248			/* Try converting these to a set of rectangles instead */
8249			xRectangle *rect;
8250			int i;
8251
8252			DBG(("%s: converting to rectagnles\n", __FUNCTION__));
8253
8254			rect = malloc (n * sizeof (xRectangle));
8255			if (rect == NULL)
8256				return;
8257
8258			for (i = 0; i < n; i++) {
8259				rect[i].x = pt[i].x - drawable->x;
8260				rect[i].width = width[i];
8261				rect[i].y = pt[i].y - drawable->y;
8262				rect[i].height = 1;
8263			}
8264
8265			if (gc->fillStyle == FillTiled) {
8266				i = sna_poly_fill_rect_tiled_blt(drawable,
8267								 bo, damage,
8268								 gc, n, rect,
8269								 &region.extents, flags & IS_CLIPPED);
8270			} else {
8271				i = sna_poly_fill_rect_stippled_blt(drawable,
8272								    bo, damage,
8273								    gc, n, rect,
8274								    &region.extents, flags & IS_CLIPPED);
8275			}
8276			free (rect);
8277
8278			if (i)
8279				return;
8280		}
8281	}
8282
8283fallback:
8284	DBG(("%s: fallback\n", __FUNCTION__));
8285	region.data = NULL;
8286	if (!region_maybe_clip(&region, gc->pCompositeClip))
8287		return;
8288
8289	if (!sna_gc_move_to_cpu(gc, drawable, &region))
8290		goto out;
8291	if (!sna_drawable_move_region_to_cpu(drawable, &region,
8292					     drawable_gc_flags(drawable, gc, n > 1)))
8293		goto out;
8294
8295	if (sigtrap_get() == 0) {
8296		DBG(("%s: fbFillSpans\n", __FUNCTION__));
8297		fbFillSpans(drawable, gc, n, pt, width, sorted);
8298		FALLBACK_FLUSH(drawable);
8299		sigtrap_put();
8300	}
8301out:
8302	sna_gc_move_to_gpu(gc);
8303	RegionUninit(&region);
8304}
8305
8306static void
8307sna_set_spans(DrawablePtr drawable, GCPtr gc, char *src,
8308	      DDXPointPtr pt, int *width, int n, int sorted)
8309{
8310	RegionRec region;
8311
8312	if (sna_spans_extents(drawable, gc, n, pt, width, &region.extents) == 0)
8313		return;
8314
8315	DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__,
8316	     region.extents.x1, region.extents.y1,
8317	     region.extents.x2, region.extents.y2));
8318
8319	if (FORCE_FALLBACK)
8320		goto fallback;
8321
8322	if (!ACCEL_SET_SPANS)
8323		goto fallback;
8324
8325fallback:
8326	region.data = NULL;
8327	if (!region_maybe_clip(&region, gc->pCompositeClip))
8328		return;
8329
8330	if (!sna_gc_move_to_cpu(gc, drawable, &region))
8331		goto out;
8332	if (!sna_drawable_move_region_to_cpu(drawable, &region,
8333					     drawable_gc_flags(drawable, gc, n > 1)))
8334		goto out;
8335
8336	if (sigtrap_get() == 0) {
8337		DBG(("%s: fbSetSpans\n", __FUNCTION__));
8338		fbSetSpans(drawable, gc, src, pt, width, n, sorted);
8339		FALLBACK_FLUSH(drawable);
8340		sigtrap_put();
8341	}
8342out:
8343	sna_gc_move_to_gpu(gc);
8344	RegionUninit(&region);
8345}
8346
8347struct sna_copy_plane {
8348	struct sna_damage **damage;
8349	struct kgem_bo *bo;
8350};
8351
8352static void
8353sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
8354		    RegionRec *region, int sx, int sy,
8355		    Pixel bitplane, void *closure)
8356{
8357	PixmapPtr pixmap = get_drawable_pixmap(drawable);
8358	struct sna *sna = to_sna_from_pixmap(pixmap);
8359	struct sna_copy_plane *arg = closure;
8360	PixmapPtr bitmap = (PixmapPtr)_bitmap;
8361	uint32_t br00, br13;
8362	int16_t dx, dy;
8363	const BoxRec *box;
8364	int n;
8365
8366	DBG(("%s: plane=%x (%d,%d),(%d,%d)xld\n",
8367	     __FUNCTION__, (unsigned)bitplane,
8368	     region->extents.x1, region->extents.y1,
8369	     region->extents.x2, region->extents.y2,
8370	     region_num_rects(region)));
8371
8372	box = region_rects(region);
8373	n = region_num_rects(region);
8374	assert(n);
8375
8376	get_drawable_deltas(drawable, pixmap, &dx, &dy);
8377	assert_pixmap_contains_boxes(pixmap, box, n, dx, dy);
8378
8379	br00 = 3 << 20;
8380	br13 = arg->bo->pitch;
8381	if (sna->kgem.gen >= 040 && arg->bo->tiling) {
8382		br00 |= BLT_DST_TILED;
8383		br13 >>= 2;
8384	}
8385	br13 |= blt_depth(drawable->depth) << 24;
8386	br13 |= copy_ROP[gc->alu] << 16;
8387	DBG(("%s: target-depth=%d, alu=%d, bg=%08x, fg=%08x\n",
8388	     __FUNCTION__, drawable->depth, gc->alu, gc->bgPixel, gc->fgPixel));
8389
8390	kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo);
8391	assert(kgem_bo_can_blt(&sna->kgem, arg->bo));
8392	do {
8393		int bx1 = (box->x1 + sx) & ~7;
8394		int bx2 = (box->x2 + sx + 7) & ~7;
8395		int bw = (bx2 - bx1)/8;
8396		int bh = box->y2 - box->y1;
8397		int bstride = ALIGN(bw, 2);
8398		int src_stride;
8399		uint8_t *dst, *src;
8400		uint32_t *b;
8401
8402		DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n",
8403		     __FUNCTION__,
8404		     box->x1, box->y1,
8405		     box->x2, box->y2,
8406		     sx, sy, bx1, bx2));
8407
8408		src_stride = bstride*bh;
8409		assert(src_stride > 0);
8410		if (src_stride <= 128) {
8411			src_stride = ALIGN(src_stride, 8) / 4;
8412			assert(src_stride <= 32);
8413			if (!kgem_check_batch(&sna->kgem, 8+src_stride) ||
8414			    !kgem_check_bo_fenced(&sna->kgem, arg->bo) ||
8415			    !kgem_check_reloc(&sna->kgem, 1)) {
8416				kgem_submit(&sna->kgem);
8417				if (!kgem_check_bo_fenced(&sna->kgem, arg->bo))
8418					return; /* XXX fallback? */
8419				_kgem_set_mode(&sna->kgem, KGEM_BLT);
8420			}
8421			kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo);
8422
8423			assert(sna->kgem.mode == KGEM_BLT);
8424			if (sna->kgem.gen >= 0100) {
8425				b = sna->kgem.batch + sna->kgem.nbatch;
8426				b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00;
8427				b[0] |= ((box->x1 + sx) & 7) << 17;
8428				b[1] = br13;
8429				b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8430				b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8431				*(uint64_t *)(b+4) =
8432					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8433							 I915_GEM_DOMAIN_RENDER << 16 |
8434							 I915_GEM_DOMAIN_RENDER |
8435							 KGEM_RELOC_FENCED,
8436							 0);
8437				b[6] = gc->bgPixel;
8438				b[7] = gc->fgPixel;
8439
8440				dst = (uint8_t *)&b[8];
8441				sna->kgem.nbatch += 8 + src_stride;
8442			} else {
8443				b = sna->kgem.batch + sna->kgem.nbatch;
8444				b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
8445				b[0] |= ((box->x1 + sx) & 7) << 17;
8446				b[1] = br13;
8447				b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8448				b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8449				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8450						      I915_GEM_DOMAIN_RENDER << 16 |
8451						      I915_GEM_DOMAIN_RENDER |
8452						      KGEM_RELOC_FENCED,
8453						      0);
8454				b[5] = gc->bgPixel;
8455				b[6] = gc->fgPixel;
8456
8457				dst = (uint8_t *)&b[7];
8458				sna->kgem.nbatch += 7 + src_stride;
8459			}
8460
8461			assert(bitmap->devKind);
8462			src_stride = bitmap->devKind;
8463			src = bitmap->devPrivate.ptr;
8464			src += (box->y1 + sy) * src_stride + bx1/8;
8465			src_stride -= bstride;
8466			do {
8467				int i = bstride;
8468				assert(src >= (uint8_t *)bitmap->devPrivate.ptr);
8469				do {
8470					*dst++ = byte_reverse(*src++);
8471					*dst++ = byte_reverse(*src++);
8472					i -= 2;
8473				} while (i);
8474				assert(src <= (uint8_t *)bitmap->devPrivate.ptr + bitmap->devKind * bitmap->drawable.height);
8475				src += src_stride;
8476			} while (--bh);
8477		} else {
8478			struct kgem_bo *upload;
8479			void *ptr;
8480
8481			if (!kgem_check_batch(&sna->kgem, 10) ||
8482			    !kgem_check_bo_fenced(&sna->kgem, arg->bo) ||
8483			    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
8484				kgem_submit(&sna->kgem);
8485				if (!kgem_check_bo_fenced(&sna->kgem, arg->bo))
8486					return; /* XXX fallback? */
8487				_kgem_set_mode(&sna->kgem, KGEM_BLT);
8488			}
8489			kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo);
8490
8491			upload = kgem_create_buffer(&sna->kgem,
8492						    bstride*bh,
8493						    KGEM_BUFFER_WRITE_INPLACE,
8494						    &ptr);
8495			if (!upload)
8496				break;
8497
8498			if (sigtrap_get() == 0) {
8499				assert(sna->kgem.mode == KGEM_BLT);
8500				b = sna->kgem.batch + sna->kgem.nbatch;
8501				if (sna->kgem.gen >= 0100) {
8502					b[0] = XY_MONO_SRC_COPY | br00 | 8;
8503					b[0] |= ((box->x1 + sx) & 7) << 17;
8504					b[1] = br13;
8505					b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8506					b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8507					*(uint64_t *)(b+4) =
8508						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8509								I915_GEM_DOMAIN_RENDER << 16 |
8510								I915_GEM_DOMAIN_RENDER |
8511								KGEM_RELOC_FENCED,
8512								0);
8513					*(uint64_t *)(b+6) =
8514						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
8515								I915_GEM_DOMAIN_RENDER << 16 |
8516								KGEM_RELOC_FENCED,
8517								0);
8518					b[8] = gc->bgPixel;
8519					b[9] = gc->fgPixel;
8520
8521					sna->kgem.nbatch += 10;
8522				} else {
8523					b[0] = XY_MONO_SRC_COPY | br00 | 6;
8524					b[0] |= ((box->x1 + sx) & 7) << 17;
8525					b[1] = br13;
8526					b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8527					b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8528					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8529							I915_GEM_DOMAIN_RENDER << 16 |
8530							I915_GEM_DOMAIN_RENDER |
8531							KGEM_RELOC_FENCED,
8532							0);
8533					b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
8534							I915_GEM_DOMAIN_RENDER << 16 |
8535							KGEM_RELOC_FENCED,
8536							0);
8537					b[6] = gc->bgPixel;
8538					b[7] = gc->fgPixel;
8539
8540					sna->kgem.nbatch += 8;
8541				}
8542
8543				dst = ptr;
8544				assert(bitmap->devKind);
8545				src_stride = bitmap->devKind;
8546				src = bitmap->devPrivate.ptr;
8547				src += (box->y1 + sy) * src_stride + bx1/8;
8548				src_stride -= bstride;
8549				do {
8550					int i = bstride;
8551					assert(src >= (uint8_t *)bitmap->devPrivate.ptr);
8552					do {
8553						*dst++ = byte_reverse(*src++);
8554						*dst++ = byte_reverse(*src++);
8555						i -= 2;
8556					} while (i);
8557					assert(src <= (uint8_t *)bitmap->devPrivate.ptr + bitmap->devKind * bitmap->drawable.height);
8558					assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload));
8559					src += src_stride;
8560				} while (--bh);
8561
8562				sigtrap_put();
8563			}
8564
8565			kgem_bo_destroy(&sna->kgem, upload);
8566		}
8567
8568		box++;
8569	} while (--n);
8570
8571	if (arg->damage) {
8572		RegionTranslate(region, dx, dy);
8573		sna_damage_add_to_pixmap(arg->damage, region, pixmap);
8574	}
8575	assert_pixmap_damage(pixmap);
8576	blt_done(sna);
8577}
8578
8579static void
8580sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc,
8581		   RegionPtr region, int sx, int sy,
8582		   Pixel bitplane, void *closure)
8583{
8584	PixmapPtr dst_pixmap = get_drawable_pixmap(drawable);
8585	PixmapPtr src_pixmap = get_drawable_pixmap(source);
8586	struct sna *sna = to_sna_from_pixmap(dst_pixmap);
8587	struct sna_copy_plane *arg = closure;
8588	int16_t dx, dy;
8589	int bit = ffs(bitplane) - 1;
8590	uint32_t br00, br13;
8591	const BoxRec *box = region_rects(region);
8592	int n = region_num_rects(region);
8593
8594	DBG(("%s: plane=%x [%d] x%d\n", __FUNCTION__,
8595	     (unsigned)bitplane, bit, n));
8596
8597	if (n == 0)
8598		return;
8599
8600	if (get_drawable_deltas(source, src_pixmap, &dx, &dy))
8601		sx += dx, sy += dy;
8602
8603	get_drawable_deltas(drawable, dst_pixmap, &dx, &dy);
8604	assert_pixmap_contains_boxes(dst_pixmap, box, n, dx, dy);
8605
8606	br00 = XY_MONO_SRC_COPY | 3 << 20;
8607	br13 = arg->bo->pitch;
8608	if (sna->kgem.gen >= 040 && arg->bo->tiling) {
8609		br00 |= BLT_DST_TILED;
8610		br13 >>= 2;
8611	}
8612	br13 |= blt_depth(drawable->depth) << 24;
8613	br13 |= copy_ROP[gc->alu] << 16;
8614
8615	kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo);
8616	assert(kgem_bo_can_blt(&sna->kgem, arg->bo));
8617	do {
8618		int bx1 = (box->x1 + sx) & ~7;
8619		int bx2 = (box->x2 + sx + 7) & ~7;
8620		int bw = (bx2 - bx1)/8;
8621		int bh = box->y2 - box->y1;
8622		int bstride = ALIGN(bw, 2);
8623		struct kgem_bo *upload;
8624		void *ptr;
8625
8626		DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n",
8627		     __FUNCTION__,
8628		     box->x1, box->y1,
8629		     box->x2, box->y2,
8630		     sx, sy, bx1, bx2));
8631
8632		if (!kgem_check_batch(&sna->kgem, 10) ||
8633		    !kgem_check_bo_fenced(&sna->kgem, arg->bo) ||
8634		    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
8635			kgem_submit(&sna->kgem);
8636			if (!kgem_check_bo_fenced(&sna->kgem, arg->bo))
8637				return; /* XXX fallback? */
8638			_kgem_set_mode(&sna->kgem, KGEM_BLT);
8639		}
8640		kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo);
8641
8642		upload = kgem_create_buffer(&sna->kgem,
8643					    bstride*bh,
8644					    KGEM_BUFFER_WRITE_INPLACE,
8645					    &ptr);
8646		if (!upload)
8647			break;
8648
8649		if (sigtrap_get() == 0) {
8650			uint32_t *b;
8651
8652			assert(src_pixmap->devKind);
8653			switch (source->bitsPerPixel) {
8654			case 32:
8655				{
8656					uint32_t *src = src_pixmap->devPrivate.ptr;
8657					int src_stride = src_pixmap->devKind/sizeof(uint32_t);
8658					uint8_t *dst = ptr;
8659
8660					src += (box->y1 + sy) * src_stride;
8661					src += bx1;
8662
8663					src_stride -= bw * 8;
8664					bstride -= bw;
8665
8666					do {
8667						int i = bw;
8668						do {
8669							uint8_t v = 0;
8670
8671							v |= ((*src++ >> bit) & 1) << 7;
8672							v |= ((*src++ >> bit) & 1) << 6;
8673							v |= ((*src++ >> bit) & 1) << 5;
8674							v |= ((*src++ >> bit) & 1) << 4;
8675							v |= ((*src++ >> bit) & 1) << 3;
8676							v |= ((*src++ >> bit) & 1) << 2;
8677							v |= ((*src++ >> bit) & 1) << 1;
8678							v |= ((*src++ >> bit) & 1) << 0;
8679
8680							*dst++ = v;
8681						} while (--i);
8682						dst += bstride;
8683						src += src_stride;
8684					} while (--bh);
8685					break;
8686				}
8687			case 16:
8688				{
8689					uint16_t *src = src_pixmap->devPrivate.ptr;
8690					int src_stride = src_pixmap->devKind/sizeof(uint16_t);
8691					uint8_t *dst = ptr;
8692
8693					src += (box->y1 + sy) * src_stride;
8694					src += bx1;
8695
8696					src_stride -= bw * 8;
8697					bstride -= bw;
8698
8699					do {
8700						int i = bw;
8701						do {
8702							uint8_t v = 0;
8703
8704							v |= ((*src++ >> bit) & 1) << 7;
8705							v |= ((*src++ >> bit) & 1) << 6;
8706							v |= ((*src++ >> bit) & 1) << 5;
8707							v |= ((*src++ >> bit) & 1) << 4;
8708							v |= ((*src++ >> bit) & 1) << 3;
8709							v |= ((*src++ >> bit) & 1) << 2;
8710							v |= ((*src++ >> bit) & 1) << 1;
8711							v |= ((*src++ >> bit) & 1) << 0;
8712
8713							*dst++ = v;
8714						} while (--i);
8715						dst += bstride;
8716						src += src_stride;
8717					} while (--bh);
8718					break;
8719				}
8720			default:
8721				assert(0);
8722			case 8:
8723				{
8724					uint8_t *src = src_pixmap->devPrivate.ptr;
8725					int src_stride = src_pixmap->devKind/sizeof(uint8_t);
8726					uint8_t *dst = ptr;
8727
8728					src += (box->y1 + sy) * src_stride;
8729					src += bx1;
8730
8731					src_stride -= bw * 8;
8732					bstride -= bw;
8733
8734					do {
8735						int i = bw;
8736						do {
8737							uint8_t v = 0;
8738
8739							v |= ((*src++ >> bit) & 1) << 7;
8740							v |= ((*src++ >> bit) & 1) << 6;
8741							v |= ((*src++ >> bit) & 1) << 5;
8742							v |= ((*src++ >> bit) & 1) << 4;
8743							v |= ((*src++ >> bit) & 1) << 3;
8744							v |= ((*src++ >> bit) & 1) << 2;
8745							v |= ((*src++ >> bit) & 1) << 1;
8746							v |= ((*src++ >> bit) & 1) << 0;
8747
8748							*dst++ = v;
8749						} while (--i);
8750						dst += bstride;
8751						src += src_stride;
8752					} while (--bh);
8753					break;
8754				}
8755			}
8756
8757			kgem_bcs_set_tiling(&sna->kgem, upload, arg->bo);
8758
8759			assert(sna->kgem.mode == KGEM_BLT);
8760			b = sna->kgem.batch + sna->kgem.nbatch;
8761			if (sna->kgem.gen >= 0100) {
8762				b[0] = br00 | ((box->x1 + sx) & 7) << 17 | 8;
8763				b[1] = br13;
8764				b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8765				b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8766				*(uint64_t *)(b+4) =
8767					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8768							I915_GEM_DOMAIN_RENDER << 16 |
8769							I915_GEM_DOMAIN_RENDER |
8770							KGEM_RELOC_FENCED,
8771							0);
8772				*(uint64_t *)(b+6) =
8773					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
8774							I915_GEM_DOMAIN_RENDER << 16 |
8775							KGEM_RELOC_FENCED,
8776							0);
8777				b[8] = gc->bgPixel;
8778				b[9] = gc->fgPixel;
8779
8780				sna->kgem.nbatch += 10;
8781			} else {
8782				b[0] = br00 | ((box->x1 + sx) & 7) << 17 | 6;
8783				b[1] = br13;
8784				b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8785				b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8786				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8787						I915_GEM_DOMAIN_RENDER << 16 |
8788						I915_GEM_DOMAIN_RENDER |
8789						KGEM_RELOC_FENCED,
8790						0);
8791				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
8792						I915_GEM_DOMAIN_RENDER << 16 |
8793						KGEM_RELOC_FENCED,
8794						0);
8795				b[6] = gc->bgPixel;
8796				b[7] = gc->fgPixel;
8797
8798				sna->kgem.nbatch += 8;
8799			}
8800			sigtrap_put();
8801		}
8802		kgem_bo_destroy(&sna->kgem, upload);
8803
8804		box++;
8805	} while (--n);
8806
8807	if (arg->damage) {
8808		RegionTranslate(region, dx, dy);
8809		sna_damage_add_to_pixmap(arg->damage, region, dst_pixmap);
8810	}
8811	assert_pixmap_damage(dst_pixmap);
8812	blt_done(sna);
8813}
8814
8815static RegionPtr
8816sna_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc,
8817	       int src_x, int src_y,
8818	       int w, int h,
8819	       int dst_x, int dst_y,
8820	       unsigned long bit)
8821{
8822	PixmapPtr pixmap = get_drawable_pixmap(dst);
8823	struct sna *sna = to_sna_from_pixmap(pixmap);
8824	RegionRec region, *ret = NULL;
8825	struct sna_copy_plane arg;
8826
8827	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=%dx%d\n", __FUNCTION__,
8828	     src_x, src_y, dst_x, dst_y, w, h));
8829
8830	if (gc->planemask == 0)
8831		goto empty;
8832
8833	if (src->bitsPerPixel == 1 && (bit&1) == 0)
8834		goto empty;
8835
8836	region.extents.x1 = dst_x + dst->x;
8837	region.extents.y1 = dst_y + dst->y;
8838	region.extents.x2 = region.extents.x1 + w;
8839	region.extents.y2 = region.extents.y1 + h;
8840	region.data = NULL;
8841	RegionIntersect(&region, &region, gc->pCompositeClip);
8842
8843	DBG(("%s: dst extents (%d, %d), (%d, %d)\n",
8844	     __FUNCTION__,
8845	     region.extents.x1, region.extents.y1,
8846	     region.extents.x2, region.extents.y2));
8847
8848	{
8849		RegionRec clip;
8850
8851		clip.extents.x1 = src->x - (src->x + src_x) + (dst->x + dst_x);
8852		clip.extents.y1 = src->y - (src->y + src_y) + (dst->y + dst_y);
8853		clip.extents.x2 = clip.extents.x1 + src->width;
8854		clip.extents.y2 = clip.extents.y1 + src->height;
8855		clip.data = NULL;
8856
8857		DBG(("%s: src extents (%d, %d), (%d, %d)\n",
8858		     __FUNCTION__,
8859		     clip.extents.x1, clip.extents.y1,
8860		     clip.extents.x2, clip.extents.y2));
8861
8862		RegionIntersect(&region, &region, &clip);
8863	}
8864	DBG(("%s: dst^src extents (%d, %d), (%d, %d)\n",
8865	     __FUNCTION__,
8866	     region.extents.x1, region.extents.y1,
8867	     region.extents.x2, region.extents.y2));
8868	if (box_empty(&region.extents))
8869		goto empty;
8870
8871	RegionTranslate(&region,
8872			src_x - dst_x - dst->x + src->x,
8873			src_y - dst_y - dst->y + src->y);
8874
8875	if (!sna_drawable_move_region_to_cpu(src, &region, MOVE_READ))
8876		goto out;
8877
8878	RegionTranslate(&region,
8879			-(src_x - dst_x - dst->x + src->x),
8880			-(src_y - dst_y - dst->y + src->y));
8881
8882	if (FORCE_FALLBACK)
8883		goto fallback;
8884
8885	if (!ACCEL_COPY_PLANE)
8886		goto fallback;
8887
8888	if (wedged(sna))
8889		goto fallback;
8890
8891	if (!PM_IS_SOLID(dst, gc->planemask))
8892		goto fallback;
8893
8894	arg.bo = sna_drawable_use_bo(dst, PREFER_GPU,
8895				     &region.extents, &arg.damage);
8896	if (arg.bo) {
8897		if (arg.bo->tiling == I915_TILING_Y) {
8898			assert(arg.bo == __sna_pixmap_get_bo(pixmap));
8899			arg.bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
8900			if (arg.bo == NULL) {
8901				DBG(("%s: fallback -- unable to change tiling\n",
8902				     __FUNCTION__));
8903				goto fallback;
8904			}
8905		}
8906
8907		if (!kgem_bo_can_blt(&sna->kgem, arg.bo))
8908			return false;
8909
8910		RegionUninit(&region);
8911		return sna_do_copy(src, dst, gc,
8912				   src_x, src_y,
8913				   w, h,
8914				   dst_x, dst_y,
8915				   src->depth == 1 ? sna_copy_bitmap_blt : sna_copy_plane_blt,
8916				   (Pixel)bit, &arg);
8917	}
8918
8919fallback:
8920	DBG(("%s: fallback\n", __FUNCTION__));
8921	if (!sna_gc_move_to_cpu(gc, dst, &region))
8922		goto out;
8923	if (!sna_drawable_move_region_to_cpu(dst, &region,
8924					     drawable_gc_flags(dst, gc, false)))
8925		goto out;
8926
8927	if (sigtrap_get() == 0) {
8928		DBG(("%s: fbCopyPlane(%d, %d, %d, %d, %d,%d) %x\n",
8929		     __FUNCTION__, src_x, src_y, w, h, dst_x, dst_y, (unsigned)bit));
8930		ret = miDoCopy(src, dst, gc,
8931			       src_x, src_y, w, h, dst_x, dst_y,
8932			       src->bitsPerPixel > 1 ? fbCopyNto1 : fbCopy1toN,
8933			       bit, 0);
8934		FALLBACK_FLUSH(dst);
8935		sigtrap_put();
8936	}
8937out:
8938	sna_gc_move_to_gpu(gc);
8939	RegionUninit(&region);
8940	return ret;
8941empty:
8942	return miHandleExposures(src, dst, gc,
8943				 src_x, src_y,
8944				 w, h,
8945				 dst_x, dst_y, bit);
8946}
8947
8948static bool
8949sna_poly_point_blt(DrawablePtr drawable,
8950		   struct kgem_bo *bo,
8951		   struct sna_damage **damage,
8952		   GCPtr gc, int mode, int n, DDXPointPtr pt,
8953		   bool clipped)
8954{
8955	PixmapPtr pixmap = get_drawable_pixmap(drawable);
8956	struct sna *sna = to_sna_from_pixmap(pixmap);
8957	BoxRec box[512], *b = box, * const last_box = box + ARRAY_SIZE(box);
8958	struct sna_fill_op fill;
8959	DDXPointRec last;
8960	int16_t dx, dy;
8961
8962	DBG(("%s: alu=%d, pixel=%08lx, clipped?=%d\n",
8963	     __FUNCTION__, gc->alu, gc->fgPixel, clipped));
8964
8965	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_POINTS))
8966		return false;
8967
8968	get_drawable_deltas(drawable, pixmap, &dx, &dy);
8969
8970	last.x = drawable->x;
8971	last.y = drawable->y;
8972
8973	if (!clipped) {
8974		last.x += dx;
8975		last.y += dy;
8976
8977		assert_pixmap_contains_points(pixmap, pt, n, last.x, last.y);
8978		sna_damage_add_points(damage, pt, n, last.x, last.y);
8979		if (fill.points && mode != CoordModePrevious) {
8980			fill.points(sna, &fill, last.x, last.y, pt, n);
8981		} else {
8982			do {
8983				unsigned nbox = n;
8984				if (nbox > ARRAY_SIZE(box))
8985					nbox = ARRAY_SIZE(box);
8986				n -= nbox;
8987				do {
8988					*(DDXPointRec *)b = *pt++;
8989
8990					b->x1 += last.x;
8991					b->y1 += last.y;
8992					if (mode == CoordModePrevious)
8993						last = *(DDXPointRec *)b;
8994
8995					b->x2 = b->x1 + 1;
8996					b->y2 = b->y1 + 1;
8997					b++;
8998				} while (--nbox);
8999				fill.boxes(sna, &fill, box, b - box);
9000				b = box;
9001			} while (n);
9002		}
9003	} else {
9004		RegionPtr clip = gc->pCompositeClip;
9005
9006		while (n--) {
9007			int x, y;
9008
9009			x = pt->x;
9010			y = pt->y;
9011			pt++;
9012			if (mode == CoordModePrevious) {
9013				x += last.x;
9014				y += last.y;
9015				last.x = x;
9016				last.y = y;
9017			} else {
9018				x += drawable->x;
9019				y += drawable->y;
9020			}
9021
9022			if (RegionContainsPoint(clip, x, y, NULL)) {
9023				b->x1 = x + dx;
9024				b->y1 = y + dy;
9025				b->x2 = b->x1 + 1;
9026				b->y2 = b->y1 + 1;
9027				if (++b == last_box){
9028					assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0);
9029					fill.boxes(sna, &fill, box, last_box - box);
9030					if (damage)
9031						sna_damage_add_boxes(damage, box, last_box-box, 0, 0);
9032					b = box;
9033				}
9034			}
9035		}
9036		if (b != box){
9037			assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
9038			fill.boxes(sna, &fill, box, b - box);
9039			if (damage)
9040				sna_damage_add_boxes(damage, box, b-box, 0, 0);
9041		}
9042	}
9043	fill.done(sna, &fill);
9044	assert_pixmap_damage(pixmap);
9045	return true;
9046}
9047
9048static unsigned
9049sna_poly_point_extents(DrawablePtr drawable, GCPtr gc,
9050		       int mode, int n, DDXPointPtr pt, BoxPtr out)
9051{
9052	BoxRec box;
9053	bool clipped;
9054
9055	if (n == 0)
9056		return 0;
9057
9058	box.x2 = box.x1 = pt->x;
9059	box.y2 = box.y1 = pt->y;
9060	if (mode == CoordModePrevious) {
9061		DDXPointRec last = *pt++;
9062		while (--n) {
9063			last.x += pt->x;
9064			last.y += pt->y;
9065			pt++;
9066			box_add_xy(&box, last.x, last.y);
9067		}
9068	} else {
9069		while (--n)
9070			box_add_pt(&box, ++pt);
9071	}
9072	box.x2++;
9073	box.y2++;
9074
9075	clipped = trim_and_translate_box(&box, drawable, gc);
9076	if (box_empty(&box))
9077		return 0;
9078
9079	*out = box;
9080	return 1 | clipped << 1;
9081}
9082
9083static void
9084sna_poly_point(DrawablePtr drawable, GCPtr gc,
9085	       int mode, int n, DDXPointPtr pt)
9086{
9087	PixmapPtr pixmap = get_drawable_pixmap(drawable);
9088	struct sna *sna = to_sna_from_pixmap(pixmap);
9089	RegionRec region;
9090	unsigned flags;
9091
9092	DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d)\n",
9093	     __FUNCTION__, mode, n, pt[0].x, pt[0].y));
9094
9095	flags = sna_poly_point_extents(drawable, gc, mode, n, pt, &region.extents);
9096	if (flags == 0)
9097		return;
9098
9099	DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
9100	     region.extents.x1, region.extents.y1,
9101	     region.extents.x2, region.extents.y2,
9102	     flags));
9103
9104	if (FORCE_FALLBACK)
9105		goto fallback;
9106
9107	if (!ACCEL_POLY_POINT)
9108		goto fallback;
9109
9110	if (wedged(sna)) {
9111		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
9112		goto fallback;
9113	}
9114
9115	if (PM_IS_SOLID(drawable, gc->planemask)) {
9116		struct sna_damage **damage;
9117		struct kgem_bo *bo;
9118
9119		DBG(("%s: trying solid fill [%08lx] blt paths\n",
9120		     __FUNCTION__, gc->fgPixel));
9121
9122		if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU,
9123					      &region.extents, &damage)) &&
9124		    sna_poly_point_blt(drawable, bo, damage,
9125				       gc, mode, n, pt, flags & IS_CLIPPED))
9126			return;
9127	}
9128
9129fallback:
9130	DBG(("%s: fallback\n", __FUNCTION__));
9131	region.data = NULL;
9132	if (!region_maybe_clip(&region, gc->pCompositeClip))
9133		return;
9134
9135	if (!sna_gc_move_to_cpu(gc, drawable, &region))
9136		goto out;
9137	if (!sna_drawable_move_region_to_cpu(drawable, &region,
9138					     MOVE_READ | MOVE_WRITE))
9139		goto out;
9140
9141	if (sigtrap_get() == 0) {
9142		DBG(("%s: fbPolyPoint\n", __FUNCTION__));
9143		fbPolyPoint(drawable, gc, mode, n, pt, flags);
9144		FALLBACK_FLUSH(drawable);
9145		sigtrap_put();
9146	}
9147out:
9148	sna_gc_move_to_gpu(gc);
9149	RegionUninit(&region);
9150}
9151
9152static bool
9153sna_poly_zero_line_blt(DrawablePtr drawable,
9154		       struct kgem_bo *bo,
9155		       struct sna_damage **damage,
9156		       GCPtr gc, int mode, const int _n, const DDXPointRec * const _pt,
9157		       const BoxRec *extents, unsigned clipped)
9158{
9159	static void * const _jump[] = {
9160		&&no_damage,
9161		&&damage,
9162
9163		&&no_damage_offset,
9164		&&damage_offset,
9165	};
9166
9167	PixmapPtr pixmap = get_drawable_pixmap(drawable);
9168	struct sna *sna = to_sna_from_pixmap(pixmap);
9169	int x2, y2, xstart, ystart, oc2;
9170	unsigned int bias = miGetZeroLineBias(drawable->pScreen);
9171	bool degenerate = true;
9172	struct sna_fill_op fill;
9173	RegionRec clip;
9174	BoxRec box[512], *b, * const last_box = box + ARRAY_SIZE(box);
9175	const BoxRec *last_extents;
9176	int16_t dx, dy;
9177	void *jump, *ret;
9178
9179	DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n",
9180	     __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage));
9181	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_SPANS))
9182		return false;
9183
9184	get_drawable_deltas(drawable, pixmap, &dx, &dy);
9185
9186	region_set(&clip, extents);
9187	if (clipped) {
9188		if (!region_maybe_clip(&clip, gc->pCompositeClip))
9189			return true;
9190	}
9191
9192	jump = _jump[(damage != NULL) | !!(dx|dy) << 1];
9193	DBG(("%s: [clipped=%x] extents=(%d, %d), (%d, %d), delta=(%d, %d), damage=%p\n",
9194	     __FUNCTION__, clipped,
9195	     clip.extents.x1, clip.extents.y1,
9196	     clip.extents.x2, clip.extents.y2,
9197	     dx, dy, damage));
9198
9199	extents = region_rects(&clip);
9200	last_extents = extents + region_num_rects(&clip);
9201
9202	b = box;
9203	do {
9204		int n = _n;
9205		const DDXPointRec *pt = _pt;
9206
9207		xstart = pt->x + drawable->x;
9208		ystart = pt->y + drawable->y;
9209
9210		x2 = xstart;
9211		y2 = ystart;
9212		oc2 = 0;
9213		OUTCODES(oc2, x2, y2, extents);
9214
9215		while (--n) {
9216			int16_t sdx, sdy;
9217			int adx, ady, length;
9218			int e, e1, e2, e3;
9219			int x1 = x2, x;
9220			int y1 = y2, y;
9221			int oc1 = oc2;
9222			int octant;
9223
9224			++pt;
9225
9226			x2 = pt->x;
9227			y2 = pt->y;
9228			if (mode == CoordModePrevious) {
9229				x2 += x1;
9230				y2 += y1;
9231			} else {
9232				x2 += drawable->x;
9233				y2 += drawable->y;
9234			}
9235			DBG(("%s: segment (%d, %d) to (%d, %d)\n",
9236			     __FUNCTION__, x1, y1, x2, y2));
9237			if (x2 == x1 && y2 == y1)
9238				continue;
9239
9240			degenerate = false;
9241
9242			oc2 = 0;
9243			OUTCODES(oc2, x2, y2, extents);
9244			if (oc1 & oc2)
9245				continue;
9246
9247			CalcLineDeltas(x1, y1, x2, y2,
9248				       adx, ady, sdx, sdy,
9249				       1, 1, octant);
9250
9251			DBG(("%s: adx=(%d, %d), sdx=(%d, %d), oc1=%x, oc2=%x\n",
9252			     __FUNCTION__, adx, ady, sdx, sdy, oc1, oc2));
9253			if (adx == 0 || ady == 0) {
9254				if (x1 <= x2) {
9255					b->x1 = x1;
9256					b->x2 = x2;
9257				} else {
9258					b->x1 = x2;
9259					b->x2 = x1;
9260				}
9261				if (y1 <= y2) {
9262					b->y1 = y1;
9263					b->y2 = y2;
9264				} else {
9265					b->y1 = y2;
9266					b->y2 = y1;
9267				}
9268				b->x2++;
9269				b->y2++;
9270				if (oc1 | oc2) {
9271					bool intersects;
9272
9273					intersects = box_intersect(b, extents);
9274					assert(intersects);
9275				}
9276				if (++b == last_box) {
9277					ret = &&rectangle_continue;
9278					goto *jump;
9279rectangle_continue:
9280					b = box;
9281				}
9282			} else if (adx >= ady) {
9283				int x2_clipped = x2, y2_clipped = y2;
9284				bool dirty;
9285
9286				/* X-major segment */
9287				e1 = ady << 1;
9288				e2 = e1 - (adx << 1);
9289				e  = e1 - adx;
9290				length = adx;
9291
9292				FIXUP_ERROR(e, octant, bias);
9293
9294				x = x1;
9295				y = y1;
9296
9297				if (oc1 | oc2) {
9298					int pt1_clipped, pt2_clipped;
9299
9300					if (miZeroClipLine(extents->x1, extents->y1,
9301							   extents->x2-1, extents->y2-1,
9302							   &x, &y, &x2_clipped, &y2_clipped,
9303							   adx, ady,
9304							   &pt1_clipped, &pt2_clipped,
9305							   octant, bias, oc1, oc2) == -1)
9306						continue;
9307
9308					length = abs(x2_clipped - x);
9309					if (length == 0)
9310						continue;
9311
9312					if (pt1_clipped) {
9313						int clipdx = abs(x - x1);
9314						int clipdy = abs(y - y1);
9315						e += clipdy * e2 + (clipdx - clipdy) * e1;
9316					}
9317				}
9318
9319				e3 = e2 - e1;
9320				e  = e - e1;
9321
9322				b->x1 = x;
9323				b->y1 = y;
9324				dirty = false;
9325				while (length--) {
9326					e += e1;
9327					dirty = true;
9328					if (e >= 0) {
9329						e += e3;
9330
9331						if (sdx < 0) {
9332							b->x2 = b->x1 + 1;
9333							b->x1 = x;
9334						} else
9335							b->x2 = x + 1;
9336						b->y2 = b->y1 + 1;
9337
9338						if (++b == last_box) {
9339							ret = &&X_continue;
9340							goto *jump;
9341X_continue:
9342							b = box;
9343						}
9344
9345						b->x1 = x + sdx;
9346						b->y1 = y += sdy;
9347						dirty = false;
9348					}
9349					x += sdx;
9350				}
9351				if (dirty) {
9352					x -= sdx;
9353					if (sdx < 0) {
9354						b->x2 = b->x1 + 1;
9355						b->x1 = x;
9356					} else
9357						b->x2 = x + 1;
9358					b->y2 = b->y1 + 1;
9359
9360					if (++b == last_box) {
9361						ret = &&X2_continue;
9362						goto *jump;
9363X2_continue:
9364						b = box;
9365					}
9366				}
9367			} else {
9368				int x2_clipped = x2, y2_clipped = y2;
9369				bool dirty;
9370
9371				/* Y-major segment */
9372				e1 = adx << 1;
9373				e2 = e1 - (ady << 1);
9374				e  = e1 - ady;
9375				length  = ady;
9376
9377				SetYMajorOctant(octant);
9378				FIXUP_ERROR(e, octant, bias);
9379
9380				x = x1;
9381				y = y1;
9382
9383				if (oc1 | oc2) {
9384					int pt1_clipped, pt2_clipped;
9385
9386					if (miZeroClipLine(extents->x1, extents->y1,
9387							   extents->x2-1, extents->y2-1,
9388							   &x, &y, &x2_clipped, &y2_clipped,
9389							   adx, ady,
9390							   &pt1_clipped, &pt2_clipped,
9391							   octant, bias, oc1, oc2) == -1)
9392						continue;
9393
9394					length = abs(y2_clipped - y);
9395					if (length == 0)
9396						continue;
9397
9398					if (pt1_clipped) {
9399						int clipdx = abs(x - x1);
9400						int clipdy = abs(y - y1);
9401						e += clipdx * e2 + (clipdy - clipdx) * e1;
9402					}
9403				}
9404
9405				e3 = e2 - e1;
9406				e  = e - e1;
9407
9408				b->x1 = x;
9409				b->y1 = y;
9410				dirty = false;
9411				while (length--) {
9412					e += e1;
9413					dirty = true;
9414					if (e >= 0) {
9415						e += e3;
9416
9417						if (sdy < 0) {
9418							b->y2 = b->y1 + 1;
9419							b->y1 = y;
9420						} else
9421							b->y2 = y + 1;
9422						b->x2 = x + 1;
9423
9424						if (++b == last_box) {
9425							ret = &&Y_continue;
9426							goto *jump;
9427Y_continue:
9428							b = box;
9429						}
9430
9431						b->x1 = x += sdx;
9432						b->y1 = y + sdy;
9433						dirty = false;
9434					}
9435					y += sdy;
9436				}
9437
9438				if (dirty) {
9439					y -= sdy;
9440					if (sdy < 0) {
9441						b->y2 = b->y1 + 1;
9442						b->y1 = y;
9443					} else
9444						b->y2 = y + 1;
9445					b->x2 = x + 1;
9446
9447					if (++b == last_box) {
9448						ret = &&Y2_continue;
9449						goto *jump;
9450Y2_continue:
9451						b = box;
9452					}
9453				}
9454			}
9455		}
9456
9457#if 0
9458		/* Only do the CapNotLast check on the last segment
9459		 * and only if the endpoint wasn't clipped.  And then, if the last
9460		 * point is the same as the first point, do not draw it, unless the
9461		 * line is degenerate
9462		 */
9463		if (!pt2_clipped &&
9464		    gc->capStyle != CapNotLast &&
9465		    !(xstart == x2 && ystart == y2 && !degenerate))
9466		{
9467			b->x2 = x2;
9468			b->y2 = y2;
9469			if (b->x2 < b->x1) {
9470				int16_t t = b->x1;
9471				b->x1 = b->x2;
9472				b->x2 = t;
9473			}
9474			if (b->y2 < b->y1) {
9475				int16_t t = b->y1;
9476				b->y1 = b->y2;
9477				b->y2 = t;
9478			}
9479			b->x2++;
9480			b->y2++;
9481			b++;
9482		}
9483#endif
9484	} while (++extents != last_extents);
9485
9486	if (b != box) {
9487		ret = &&done;
9488		goto *jump;
9489	}
9490
9491done:
9492	fill.done(sna, &fill);
9493	assert_pixmap_damage(pixmap);
9494	RegionUninit(&clip);
9495	return true;
9496
9497damage:
9498	assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
9499	sna_damage_add_boxes(damage, box, b-box, 0, 0);
9500no_damage:
9501	fill.boxes(sna, &fill, box, b-box);
9502	goto *ret;
9503
9504no_damage_offset:
9505	{
9506		BoxRec *bb = box;
9507		do {
9508			bb->x1 += dx;
9509			bb->x2 += dx;
9510			bb->y1 += dy;
9511			bb->y2 += dy;
9512		} while (++bb != b);
9513		assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
9514		fill.boxes(sna, &fill, box, b - box);
9515	}
9516	goto *ret;
9517
9518damage_offset:
9519	{
9520		BoxRec *bb = box;
9521		do {
9522			bb->x1 += dx;
9523			bb->x2 += dx;
9524			bb->y1 += dy;
9525			bb->y2 += dy;
9526		} while (++bb != b);
9527		assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
9528		fill.boxes(sna, &fill, box, b - box);
9529		sna_damage_add_boxes(damage, box, b - box, 0, 0);
9530	}
9531	goto *ret;
9532}
9533
9534static bool
9535sna_poly_line_blt(DrawablePtr drawable,
9536		  struct kgem_bo *bo,
9537		  struct sna_damage **damage,
9538		  GCPtr gc, uint32_t pixel,
9539		  int mode, int n, DDXPointPtr pt,
9540		  const BoxRec *extents, bool clipped)
9541{
9542	PixmapPtr pixmap = get_drawable_pixmap(drawable);
9543	struct sna *sna = to_sna_from_pixmap(pixmap);
9544	BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes);
9545	struct sna_fill_op fill;
9546	DDXPointRec last;
9547	int16_t dx, dy;
9548
9549	DBG(("%s: alu=%d, fg=%08x, clipped=%d\n", __FUNCTION__, gc->alu, (unsigned)pixel, clipped));
9550
9551	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_BOXES))
9552		return false;
9553
9554	get_drawable_deltas(drawable, pixmap, &dx, &dy);
9555
9556	if (!clipped) {
9557		dx += drawable->x;
9558		dy += drawable->y;
9559
9560		last.x = pt->x + dx;
9561		last.y = pt->y + dy;
9562		pt++;
9563
9564		while (--n) {
9565			DDXPointRec p;
9566
9567			p = *pt++;
9568			if (mode == CoordModePrevious) {
9569				p.x += last.x;
9570				p.y += last.y;
9571			} else {
9572				p.x += dx;
9573				p.y += dy;
9574			}
9575			DBG(("%s: line (%d, %d) -> (%d, %d)\n", __FUNCTION__, last.x, last.y, p.x, p.y));
9576
9577			if (last.x == p.x) {
9578				b->x1 = last.x;
9579				b->x2 = last.x + 1;
9580			} else if (last.x < p.x) {
9581				b->x1 = last.x;
9582				b->x2 = p.x;
9583			} else {
9584				b->x1 = p.x;
9585				b->x2 = last.x;
9586			}
9587
9588			if (last.y == p.y) {
9589				b->y1 = last.y;
9590				b->y2 = last.y + 1;
9591			} else if (last.y < p.y) {
9592				b->y1 = last.y;
9593				b->y2 = p.y;
9594			} else {
9595				b->y1 = p.y;
9596				b->y2 = last.y;
9597			}
9598			b->y2 += last.x == p.x && last.y != p.y;
9599			b->x2 += last.y == p.y && last.x != p.x;
9600			DBG(("%s: blt (%d, %d), (%d, %d)\n",
9601			     __FUNCTION__,
9602			     b->x1, b->y1, b->x2, b->y2));
9603
9604			if (++b == last_box) {
9605				assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0);
9606				fill.boxes(sna, &fill, boxes, last_box - boxes);
9607				if (damage)
9608					sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0);
9609				b = boxes;
9610			}
9611
9612			last = p;
9613		}
9614	} else {
9615		RegionRec clip;
9616
9617		region_set(&clip, extents);
9618		if (!region_maybe_clip(&clip, gc->pCompositeClip))
9619			return true;
9620
9621		last.x = pt->x + drawable->x;
9622		last.y = pt->y + drawable->y;
9623		pt++;
9624
9625		if (clip.data == NULL) {
9626			while (--n) {
9627				DDXPointRec p;
9628
9629				p = *pt++;
9630				if (mode == CoordModePrevious) {
9631					p.x += last.x;
9632					p.y += last.y;
9633				} else {
9634					p.x += drawable->x;
9635					p.y += drawable->y;
9636				}
9637				if (last.x == p.x) {
9638					b->x1 = last.x;
9639					b->x2 = last.x + 1;
9640				} else if (last.x < p.x) {
9641					b->x1 = last.x;
9642					b->x2 = p.x;
9643				} else {
9644					b->x1 = p.x;
9645					b->x2 = last.x;
9646				}
9647				if (last.y == p.y) {
9648					b->y1 = last.y;
9649					b->y2 = last.y + 1;
9650				} else if (last.y < p.y) {
9651					b->y1 = last.y;
9652					b->y2 = p.y;
9653				} else {
9654					b->y1 = p.y;
9655					b->y2 = last.y;
9656				}
9657				b->y2 += last.x == p.x && last.y != p.y;
9658				b->x2 += last.y == p.y && last.x != p.x;
9659				DBG(("%s: blt (%d, %d), (%d, %d)\n",
9660				     __FUNCTION__,
9661				     b->x1, b->y1, b->x2, b->y2));
9662				if (box_intersect(b, &clip.extents)) {
9663					b->x1 += dx;
9664					b->x2 += dx;
9665					b->y1 += dy;
9666					b->y2 += dy;
9667					if (++b == last_box) {
9668						assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0);
9669						fill.boxes(sna, &fill, boxes, last_box - boxes);
9670						if (damage)
9671							sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0);
9672						b = boxes;
9673					}
9674				}
9675
9676				last = p;
9677			}
9678		} else {
9679			const BoxRec * const clip_start = RegionBoxptr(&clip);
9680			const BoxRec * const clip_end = clip_start + clip.data->numRects;
9681			const BoxRec *c;
9682
9683			while (--n) {
9684				DDXPointRec p;
9685				BoxRec box;
9686
9687				p = *pt++;
9688				if (mode == CoordModePrevious) {
9689					p.x += last.x;
9690					p.y += last.y;
9691				} else {
9692					p.x += drawable->x;
9693					p.y += drawable->y;
9694				}
9695				if (last.x == p.x) {
9696					box.x1 = last.x;
9697					box.x2 = last.x + 1;
9698				} else if (last.x < p.x) {
9699					box.x1 = last.x;
9700					box.x2 = p.x;
9701				} else {
9702					box.x1 = p.x;
9703					box.x2 = last.x;
9704				}
9705				if (last.y == p.y) {
9706					box.y1 = last.y;
9707					box.y2 = last.y + 1;
9708				} else if (last.y < p.y) {
9709					box.y1 = last.y;
9710					box.y2 = p.y;
9711				} else {
9712					box.y1 = p.y;
9713					box.y2 = last.y;
9714				}
9715				b->y2 += last.x == p.x && last.y != p.y;
9716				b->x2 += last.y == p.y && last.x != p.x;
9717				DBG(("%s: blt (%d, %d), (%d, %d)\n",
9718				     __FUNCTION__,
9719				     box.x1, box.y1, box.x2, box.y2));
9720
9721				c = find_clip_box_for_y(clip_start,
9722							clip_end,
9723							box.y1);
9724				while (c != clip_end) {
9725					if (box.y2 <= c->y1)
9726						break;
9727
9728					*b = box;
9729					if (box_intersect(b, c++)) {
9730						b->x1 += dx;
9731						b->x2 += dx;
9732						b->y1 += dy;
9733						b->y2 += dy;
9734						if (++b == last_box) {
9735							assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0);
9736							fill.boxes(sna, &fill, boxes, last_box-boxes);
9737							if (damage)
9738								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
9739							b = boxes;
9740						}
9741					}
9742				}
9743
9744				last = p;
9745			}
9746		}
9747		RegionUninit(&clip);
9748	}
9749	if (b != boxes) {
9750		assert_pixmap_contains_boxes(pixmap, boxes, b-boxes, 0, 0);
9751		fill.boxes(sna, &fill, boxes, b - boxes);
9752		if (damage)
9753			sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0);
9754	}
9755	fill.done(sna, &fill);
9756	assert_pixmap_damage(pixmap);
9757	return true;
9758}
9759
9760static unsigned
9761sna_poly_line_extents(DrawablePtr drawable, GCPtr gc,
9762		      int mode, int n, DDXPointPtr pt,
9763		      BoxPtr out)
9764{
9765	BoxRec box;
9766	bool clip, blt = true;
9767
9768	if (n == 0)
9769		return 0;
9770
9771	box.x2 = box.x1 = pt->x;
9772	box.y2 = box.y1 = pt->y;
9773	if (mode == CoordModePrevious) {
9774		int x = box.x1;
9775		int y = box.y1;
9776		while (--n) {
9777			pt++;
9778			x += pt->x;
9779			y += pt->y;
9780			if (blt)
9781				blt &= pt->x == 0 || pt->y == 0;
9782			box_add_xy(&box, x, y);
9783		}
9784	} else {
9785		int x = box.x1;
9786		int y = box.y1;
9787		while (--n) {
9788			pt++;
9789			if (blt) {
9790				blt &= pt->x == x || pt->y == y;
9791				x = pt->x;
9792				y = pt->y;
9793			}
9794			box_add_pt(&box, pt);
9795		}
9796	}
9797	box.x2++;
9798	box.y2++;
9799
9800	if (gc->lineWidth) {
9801		int extra = gc->lineWidth >> 1;
9802		if (n > 1) {
9803			if (gc->joinStyle == JoinMiter)
9804				extra = 6 * gc->lineWidth;
9805			else if (gc->capStyle == CapProjecting)
9806				extra = gc->lineWidth;
9807		}
9808		if (extra) {
9809			box.x1 -= extra;
9810			box.x2 += extra;
9811			box.y1 -= extra;
9812			box.y2 += extra;
9813		}
9814	}
9815
9816	clip = trim_and_translate_box(&box, drawable, gc);
9817	if (box_empty(&box))
9818		return 0;
9819
9820	*out = box;
9821	return 1 | blt << 2 | clip << 1;
9822}
9823
9824inline static int
9825_use_line_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags)
9826{
9827	uint32_t ignored;
9828
9829	if (USE_SPANS)
9830		return USE_SPANS > 0;
9831
9832	if (flags & RECTILINEAR)
9833		return PREFER_GPU;
9834
9835	if (gc->lineStyle != LineSolid && gc->lineWidth == 0)
9836		return 0;
9837
9838	if (gc_is_solid(gc, &ignored))
9839		return PREFER_GPU;
9840
9841	return !drawable_gc_inplace_hint(drawable, gc);
9842}
9843
9844inline static int
9845use_line_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags)
9846{
9847	int ret = _use_line_spans(drawable, gc, extents, flags);
9848	DBG(("%s? %d\n", __FUNCTION__, ret));
9849	return ret;
9850}
9851
9852static void
9853sna_poly_line(DrawablePtr drawable, GCPtr gc,
9854	      int mode, int n, DDXPointPtr pt)
9855{
9856	struct sna_pixmap *priv;
9857	struct sna_fill_spans data;
9858	uint32_t color;
9859
9860	DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d), lineWidth=%d\n",
9861	     __FUNCTION__, mode, n, pt[0].x, pt[0].y, gc->lineWidth));
9862
9863	data.flags = sna_poly_line_extents(drawable, gc, mode, n, pt,
9864					   &data.region.extents);
9865	if (data.flags == 0)
9866		return;
9867
9868	DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
9869	     data.region.extents.x1, data.region.extents.y1,
9870	     data.region.extents.x2, data.region.extents.y2,
9871	     data.flags));
9872
9873	data.region.data = NULL;
9874
9875	if (FORCE_FALLBACK)
9876		goto fallback;
9877
9878	if (!ACCEL_POLY_LINE)
9879		goto fallback;
9880
9881	data.pixmap = get_drawable_pixmap(drawable);
9882	data.sna = to_sna_from_pixmap(data.pixmap);
9883	if (wedged(data.sna)) {
9884		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
9885		goto fallback;
9886	}
9887
9888	DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lx [%d], rectlinear=%d\n",
9889	     __FUNCTION__,
9890	     gc->fillStyle, gc->fillStyle == FillSolid,
9891	     gc->lineStyle, gc->lineStyle == LineSolid,
9892	     gc->lineWidth,
9893	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask),
9894	     data.flags & RECTILINEAR));
9895
9896	if (!PM_IS_SOLID(drawable, gc->planemask))
9897		goto fallback;
9898
9899	priv = sna_pixmap(data.pixmap);
9900	if (!priv) {
9901		DBG(("%s: not attached to pixmap %ld\n",
9902		     __FUNCTION__, data.pixmap->drawable.serialNumber));
9903		goto fallback;
9904	}
9905
9906	if (gc->lineStyle != LineSolid) {
9907		DBG(("%s: lineStyle, %d, is not solid\n",
9908		     __FUNCTION__, gc->lineStyle));
9909		goto spans_fallback;
9910	}
9911	if (!(gc->lineWidth == 0 ||
9912	      (gc->lineWidth == 1 && (n == 1 || gc->alu == GXcopy)))) {
9913		DBG(("%s: non-zero lineWidth %d\n",
9914		     __FUNCTION__, gc->lineWidth));
9915		goto spans_fallback;
9916	}
9917
9918	data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
9919				      &data.region.extents,
9920				      &data.damage);
9921	if (data.bo == NULL)
9922		goto fallback;
9923
9924	if (gc_is_solid(gc, &color)) {
9925		DBG(("%s: trying solid fill [%08x]\n",
9926		     __FUNCTION__, (unsigned)color));
9927		if (data.flags & RECTILINEAR) {
9928			if (sna_poly_line_blt(drawable,
9929					      data.bo, data.damage,
9930					      gc, color, mode, n, pt,
9931					      &data.region.extents,
9932					      data.flags & IS_CLIPPED))
9933				return;
9934		} else { /* !rectilinear */
9935			if (sna_poly_zero_line_blt(drawable,
9936						   data.bo, data.damage,
9937						   gc, mode, n, pt,
9938						   &data.region.extents,
9939						   data.flags & IS_CLIPPED))
9940				return;
9941
9942		}
9943	} else if (data.flags & RECTILINEAR) {
9944		/* Try converting these to a set of rectangles instead */
9945		DDXPointRec p1, p2;
9946		xRectangle *rect;
9947		int i;
9948
9949		DBG(("%s: converting to rectagnles\n", __FUNCTION__));
9950
9951		rect = malloc (n * sizeof (xRectangle));
9952		if (rect == NULL)
9953			return;
9954
9955		p1 = pt[0];
9956		for (i = 1; i < n; i++) {
9957			if (mode == CoordModePrevious) {
9958				p2.x = p1.x + pt[i].x;
9959				p2.y = p1.y + pt[i].y;
9960			} else
9961				p2 = pt[i];
9962			if (p1.x < p2.x) {
9963				rect[i].x = p1.x;
9964				rect[i].width = p2.x - p1.x + 1;
9965			} else if (p1.x > p2.x) {
9966				rect[i].x = p2.x;
9967				rect[i].width = p1.x - p2.x + 1;
9968			} else {
9969				rect[i].x = p1.x;
9970				rect[i].width = 1;
9971			}
9972			if (p1.y < p2.y) {
9973				rect[i].y = p1.y;
9974				rect[i].height = p2.y - p1.y + 1;
9975			} else if (p1.y > p2.y) {
9976				rect[i].y = p2.y;
9977				rect[i].height = p1.y - p2.y + 1;
9978			} else {
9979				rect[i].y = p1.y;
9980				rect[i].height = 1;
9981			}
9982
9983			/* don't paint last pixel */
9984			if (gc->capStyle == CapNotLast) {
9985				if (p1.x == p2.x)
9986					rect[i].height--;
9987				else
9988					rect[i].width--;
9989			}
9990			p1 = p2;
9991		}
9992
9993		if (gc->fillStyle == FillTiled) {
9994			i = sna_poly_fill_rect_tiled_blt(drawable,
9995							 data.bo, data.damage,
9996							 gc, n - 1, rect + 1,
9997							 &data.region.extents,
9998							 data.flags & IS_CLIPPED);
9999		} else {
10000			i = sna_poly_fill_rect_stippled_blt(drawable,
10001							    data.bo, data.damage,
10002							    gc, n - 1, rect + 1,
10003							    &data.region.extents,
10004							    data.flags & IS_CLIPPED);
10005		}
10006		free (rect);
10007
10008		if (i)
10009			return;
10010	}
10011
10012spans_fallback:
10013	if ((data.bo = sna_drawable_use_bo(drawable,
10014					   use_line_spans(drawable, gc, &data.region.extents, data.flags),
10015					   &data.region.extents, &data.damage))) {
10016		DBG(("%s: converting line into spans\n", __FUNCTION__));
10017		get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy);
10018		sna_gc(gc)->priv = &data;
10019
10020		if (gc->lineWidth == 0 && gc_is_solid(gc, &color)) {
10021			struct sna_fill_op fill;
10022
10023			if (gc->lineStyle == LineSolid) {
10024				if (!sna_fill_init_blt(&fill,
10025						       data.sna, data.pixmap,
10026						       data.bo, gc->alu, color,
10027						       FILL_POINTS | FILL_SPANS))
10028					goto fallback;
10029
10030				data.op = &fill;
10031
10032				if ((data.flags & IS_CLIPPED) == 0) {
10033					if (data.dx | data.dy)
10034						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
10035					else
10036						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
10037					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill;
10038				} else {
10039					if (!region_maybe_clip(&data.region,
10040							       gc->pCompositeClip))
10041						return;
10042
10043					if (region_is_singular(&data.region)) {
10044						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
10045						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents;
10046					} else {
10047						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
10048						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes;
10049					}
10050				}
10051				assert(gc->miTranslate);
10052
10053				gc->ops = &sna_gc_ops__tmp;
10054				DBG(("%s: miZeroLine (solid fill)\n", __FUNCTION__));
10055				miZeroLine(drawable, gc, mode, n, pt);
10056				fill.done(data.sna, &fill);
10057			} else {
10058				data.op = &fill;
10059
10060				if ((data.flags & IS_CLIPPED) == 0) {
10061					if (data.dx | data.dy)
10062						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_offset;
10063					else
10064						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash;
10065					sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash;
10066				} else {
10067					if (!region_maybe_clip(&data.region,
10068							       gc->pCompositeClip))
10069						return;
10070
10071					if (region_is_singular(&data.region)) {
10072						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_extents;
10073						sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_extents;
10074					} else {
10075						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_boxes;
10076						sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_boxes;
10077					}
10078				}
10079				assert(gc->miTranslate);
10080
10081				DBG(("%s: miZeroLine (solid dash, clipped? %d (complex? %d)), fg pass [%08x]\n",
10082				     __FUNCTION__,
10083				     !!(data.flags & IS_CLIPPED), data.flags & IS_CLIPPED && !region_is_singular(&data.region),
10084				     gc->fgPixel));
10085
10086				if (!sna_fill_init_blt(&fill,
10087						       data.sna, data.pixmap,
10088						       data.bo, gc->alu, color,
10089						       FILL_POINTS | FILL_SPANS))
10090					goto fallback;
10091
10092				gc->ops = &sna_gc_ops__tmp;
10093				data.phase = gc->fgPixel;
10094				miZeroDashLine(drawable, gc, mode, n, pt);
10095				fill.done(data.sna, &fill);
10096
10097				DBG(("%s: miZeroLine (solid dash, clipped? %d (complex? %d)), bg pass [%08x]\n",
10098				     __FUNCTION__,
10099				     !!(data.flags & IS_CLIPPED), data.flags & IS_CLIPPED && !region_is_singular(&data.region),
10100				     gc->bgPixel));
10101
10102				if (sna_fill_init_blt(&fill,
10103						      data.sna, data.pixmap,
10104						      data.bo, gc->alu,
10105						      gc->bgPixel,
10106						      FILL_POINTS | FILL_SPANS)) {
10107					data.phase = gc->bgPixel;
10108					miZeroDashLine(drawable, gc, mode, n, pt);
10109					fill.done(data.sna, &fill);
10110				}
10111			}
10112		} else {
10113			/* Note that the WideDash functions alternate
10114			 * between filling using fgPixel and bgPixel
10115			 * so we need to reset state between FillSpans and
10116			 * cannot use the fill fast paths.
10117			 */
10118			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
10119			sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu;
10120			sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu;
10121			gc->ops = &sna_gc_ops__tmp;
10122
10123			switch (gc->lineStyle) {
10124			default:
10125				assert(0);
10126			case LineSolid:
10127				if (gc->lineWidth == 0) {
10128					DBG(("%s: miZeroLine\n", __FUNCTION__));
10129					miZeroLine(drawable, gc, mode, n, pt);
10130				} else {
10131					DBG(("%s: miWideLine\n", __FUNCTION__));
10132					miWideLine(drawable, gc, mode, n, pt);
10133				}
10134				break;
10135			case LineOnOffDash:
10136			case LineDoubleDash:
10137				if (gc->lineWidth == 0) {
10138					DBG(("%s: miZeroDashLine\n", __FUNCTION__));
10139					miZeroDashLine(drawable, gc, mode, n, pt);
10140				} else {
10141					DBG(("%s: miWideDash\n", __FUNCTION__));
10142					miWideDash(drawable, gc, mode, n, pt);
10143				}
10144				break;
10145			}
10146		}
10147
10148		gc->ops = (GCOps *)&sna_gc_ops;
10149		if (data.damage) {
10150			if (data.dx | data.dy)
10151				pixman_region_translate(&data.region, data.dx, data.dy);
10152			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
10153			sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap);
10154			assert_pixmap_damage(data.pixmap);
10155		}
10156		RegionUninit(&data.region);
10157		return;
10158	}
10159
10160fallback:
10161	DBG(("%s: fallback\n", __FUNCTION__));
10162	if (!region_maybe_clip(&data.region, gc->pCompositeClip))
10163		return;
10164
10165	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
10166		goto out;
10167	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
10168					     drawable_gc_flags(drawable, gc,
10169							       !(data.flags & RECTILINEAR && n == 2))))
10170		goto out;
10171
10172	if (sigtrap_get() == 0) {
10173		DBG(("%s: fbPolyLine\n", __FUNCTION__));
10174		fbPolyLine(drawable, gc, mode, n, pt);
10175		FALLBACK_FLUSH(drawable);
10176		sigtrap_put();
10177	}
10178out:
10179	sna_gc_move_to_gpu(gc);
10180	RegionUninit(&data.region);
10181}
10182
10183static inline bool box_from_seg(BoxPtr b, const xSegment *seg, GCPtr gc)
10184{
10185	if (seg->x1 == seg->x2) {
10186		if (seg->y1 > seg->y2) {
10187			b->y2 = seg->y1 + 1;
10188			b->y1 = seg->y2 + 1;
10189			if (gc->capStyle != CapNotLast)
10190				b->y1--;
10191		} else {
10192			b->y1 = seg->y1;
10193			b->y2 = seg->y2;
10194			if (gc->capStyle != CapNotLast)
10195				b->y2++;
10196		}
10197		if (b->y1 >= b->y2)
10198			return false;
10199
10200		b->x1 = seg->x1;
10201		b->x2 = seg->x1 + 1;
10202	} else {
10203		if (seg->x1 > seg->x2) {
10204			b->x2 = seg->x1 + 1;
10205			b->x1 = seg->x2 + 1;
10206			if (gc->capStyle != CapNotLast)
10207				b->x1--;
10208		} else {
10209			b->x1 = seg->x1;
10210			b->x2 = seg->x2;
10211			if (gc->capStyle != CapNotLast)
10212				b->x2++;
10213		}
10214		if (b->x1 >= b->x2)
10215			return false;
10216
10217		b->y1 = seg->y1;
10218		b->y2 = seg->y1 + 1;
10219	}
10220
10221	DBG(("%s: seg=(%d,%d),(%d,%d); box=(%d,%d),(%d,%d)\n",
10222	     __FUNCTION__,
10223	     seg->x1, seg->y1, seg->x2, seg->y2,
10224	     b->x1, b->y1, b->x2, b->y2));
10225	return true;
10226}
10227
10228static bool
10229sna_poly_segment_blt(DrawablePtr drawable,
10230		     struct kgem_bo *bo,
10231		     struct sna_damage **damage,
10232		     GCPtr gc, uint32_t pixel,
10233		     int n, xSegment *seg,
10234		     const BoxRec *extents, unsigned clipped)
10235{
10236	PixmapPtr pixmap = get_drawable_pixmap(drawable);
10237	struct sna *sna = to_sna_from_pixmap(pixmap);
10238	BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes);
10239	struct sna_fill_op fill;
10240	int16_t dx, dy;
10241
10242	DBG(("%s: n=%d, alu=%d, fg=%08lx, clipped=%d\n",
10243	     __FUNCTION__, n, gc->alu, gc->fgPixel, clipped));
10244
10245	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_SPANS))
10246		return false;
10247
10248	get_drawable_deltas(drawable, pixmap, &dx, &dy);
10249
10250	if (!clipped) {
10251		dx += drawable->x;
10252		dy += drawable->y;
10253		if (dx|dy) {
10254			do {
10255				unsigned nbox = n;
10256				if (nbox > ARRAY_SIZE(boxes))
10257					nbox = ARRAY_SIZE(boxes);
10258				n -= nbox;
10259				do {
10260					if (box_from_seg(b, seg++, gc)) {
10261						assert(!box_empty(b));
10262						b->x1 += dx;
10263						b->x2 += dx;
10264						b->y1 += dy;
10265						b->y2 += dy;
10266						assert(!box_empty(b));
10267						b++;
10268					}
10269				} while (--nbox);
10270
10271				if (b != boxes) {
10272					fill.boxes(sna, &fill, boxes, b-boxes);
10273					if (damage)
10274						sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
10275					b = boxes;
10276				}
10277			} while (n);
10278		} else {
10279			do {
10280				unsigned nbox = n;
10281				if (nbox > ARRAY_SIZE(boxes))
10282					nbox = ARRAY_SIZE(boxes);
10283				n -= nbox;
10284				do {
10285					if (box_from_seg(b, seg++, gc)) {
10286						assert(!box_empty(b));
10287						b++;
10288					}
10289				} while (--nbox);
10290
10291				if (b != boxes) {
10292					fill.boxes(sna, &fill, boxes, b-boxes);
10293					if (damage)
10294						sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
10295					b = boxes;
10296				}
10297			} while (n);
10298		}
10299	} else {
10300		RegionRec clip;
10301
10302		region_set(&clip, extents);
10303		if (!region_maybe_clip(&clip, gc->pCompositeClip))
10304			goto done;
10305
10306		if (clip.data) {
10307			const BoxRec * const clip_start = RegionBoxptr(&clip);
10308			const BoxRec * const clip_end = clip_start + clip.data->numRects;
10309			const BoxRec *c;
10310			do {
10311				BoxRec box;
10312
10313				if (!box_from_seg(&box, seg++, gc))
10314					continue;
10315
10316				assert(!box_empty(&box));
10317				box.x1 += drawable->x;
10318				box.x2 += drawable->x;
10319				box.y1 += drawable->y;
10320				box.y2 += drawable->y;
10321				c = find_clip_box_for_y(clip_start,
10322							clip_end,
10323							box.y1);
10324				while (c != clip_end) {
10325					if (box.y2 <= c->y1)
10326						break;
10327
10328					*b = box;
10329					if (box_intersect(b, c++)) {
10330						b->x1 += dx;
10331						b->x2 += dx;
10332						b->y1 += dy;
10333						b->y2 += dy;
10334						assert(!box_empty(b));
10335						if (++b == last_box) {
10336							fill.boxes(sna, &fill, boxes, last_box-boxes);
10337							if (damage)
10338								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
10339							b = boxes;
10340						}
10341					}
10342				}
10343			} while (--n);
10344		} else {
10345			do {
10346				if (!box_from_seg(b, seg++, gc))
10347					continue;
10348
10349				assert(!box_empty(b));
10350				b->x1 += drawable->x;
10351				b->x2 += drawable->x;
10352				b->y1 += drawable->y;
10353				b->y2 += drawable->y;
10354				if (box_intersect(b, &clip.extents)) {
10355					b->x1 += dx;
10356					b->x2 += dx;
10357					b->y1 += dy;
10358					b->y2 += dy;
10359					assert(!box_empty(b));
10360					if (++b == last_box) {
10361						fill.boxes(sna, &fill, boxes, last_box-boxes);
10362						if (damage)
10363							sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
10364						b = boxes;
10365					}
10366				}
10367			} while (--n);
10368		}
10369		RegionUninit(&clip);
10370	}
10371	if (b != boxes) {
10372		fill.boxes(sna, &fill, boxes, b - boxes);
10373		if (damage)
10374			sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0);
10375	}
10376done:
10377	fill.done(sna, &fill);
10378	assert_pixmap_damage(pixmap);
10379	return true;
10380}
10381
10382static bool
10383sna_poly_zero_segment_blt(DrawablePtr drawable,
10384			  struct kgem_bo *bo,
10385			  struct sna_damage **damage,
10386			  GCPtr gc, const int _n, const xSegment *_s,
10387			  const BoxRec *extents, unsigned clipped)
10388{
10389	static void * const _jump[] = {
10390		&&no_damage,
10391		&&damage,
10392
10393		&&no_damage_offset,
10394		&&damage_offset,
10395	};
10396
10397	PixmapPtr pixmap = get_drawable_pixmap(drawable);
10398	struct sna *sna = to_sna_from_pixmap(pixmap);
10399	unsigned int bias = miGetZeroLineBias(drawable->pScreen);
10400	struct sna_fill_op fill;
10401	RegionRec clip;
10402	const BoxRec *last_extents;
10403	BoxRec box[512], *b;
10404	BoxRec *const last_box = box + ARRAY_SIZE(box);
10405	int16_t dx, dy;
10406	void *jump, *ret;
10407
10408	DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n",
10409	     __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage));
10410	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_BOXES))
10411		return false;
10412
10413	get_drawable_deltas(drawable, pixmap, &dx, &dy);
10414
10415	region_set(&clip, extents);
10416	if (clipped) {
10417		if (!region_maybe_clip(&clip, gc->pCompositeClip))
10418			return true;
10419	}
10420	DBG(("%s: [clipped] extents=(%d, %d), (%d, %d), delta=(%d, %d)\n",
10421	     __FUNCTION__,
10422	     clip.extents.x1, clip.extents.y1,
10423	     clip.extents.x2, clip.extents.y2,
10424	     dx, dy));
10425
10426	jump = _jump[(damage != NULL) | !!(dx|dy) << 1];
10427
10428	b = box;
10429	extents = region_rects(&clip);
10430	last_extents = extents + region_num_rects(&clip);
10431	do {
10432		int n = _n;
10433		const xSegment *s = _s;
10434		do {
10435			int16_t sdx, sdy;
10436			int adx, ady, length;
10437			int e, e1, e2, e3;
10438			int x1, x2;
10439			int y1, y2;
10440			int oc1, oc2;
10441			int octant;
10442
10443			x1 = s->x1 + drawable->x;
10444			y1 = s->y1 + drawable->y;
10445			x2 = s->x2 + drawable->x;
10446			y2 = s->y2 + drawable->y;
10447			s++;
10448
10449			DBG(("%s: segment (%d, %d) to (%d, %d)\n",
10450			     __FUNCTION__, x1, y1, x2, y2));
10451			if (x2 == x1 && y2 == y1)
10452				continue;
10453
10454			oc1 = 0;
10455			OUTCODES(oc1, x1, y1, extents);
10456			oc2 = 0;
10457			OUTCODES(oc2, x2, y2, extents);
10458			if (oc1 & oc2)
10459				continue;
10460
10461			CalcLineDeltas(x1, y1, x2, y2,
10462				       adx, ady, sdx, sdy,
10463				       1, 1, octant);
10464
10465			DBG(("%s: adx=(%d, %d), sdx=(%d, %d)\n",
10466			     __FUNCTION__, adx, ady, sdx, sdy));
10467			if (adx == 0 || ady == 0) {
10468				if (x1 <= x2) {
10469					b->x1 = x1;
10470					b->x2 = x2;
10471				} else {
10472					b->x1 = x2;
10473					b->x2 = x1;
10474				}
10475				if (y1 <= y2) {
10476					b->y1 = y1;
10477					b->y2 = y2;
10478				} else {
10479					b->y1 = y2;
10480					b->y2 = y1;
10481				}
10482				b->x2++;
10483				b->y2++;
10484
10485				if ((oc1 | oc2) && !box_intersect(b, extents))
10486					continue;
10487
10488				assert(!box_empty(b));
10489				if (++b == last_box) {
10490					ret = &&rectangle_continue;
10491					goto *jump;
10492rectangle_continue:
10493					b = box;
10494				}
10495			} else if (adx >= ady) {
10496				bool dirty;
10497
10498				/* X-major segment */
10499				e1 = ady << 1;
10500				e2 = e1 - (adx << 1);
10501				e  = e1 - adx;
10502				length = adx;	/* don't draw endpoint in main loop */
10503
10504				FIXUP_ERROR(e, octant, bias);
10505
10506				if (oc1 | oc2) {
10507					int pt1_clipped, pt2_clipped;
10508					int x = x1, y = y1;
10509
10510					if (miZeroClipLine(extents->x1, extents->y1,
10511							   extents->x2-1, extents->y2-1,
10512							   &x1, &y1, &x2, &y2,
10513							   adx, ady,
10514							   &pt1_clipped, &pt2_clipped,
10515							   octant, bias, oc1, oc2) == -1)
10516						continue;
10517
10518					length = abs(x2 - x1);
10519					if (length == 0)
10520						continue;
10521
10522					if (pt1_clipped) {
10523						int clipdx = abs(x1 - x);
10524						int clipdy = abs(y1 - y);
10525						e += clipdy * e2 + (clipdx - clipdy) * e1;
10526					}
10527				}
10528				e3 = e2 - e1;
10529				e  = e - e1;
10530
10531				b->x1 = x1;
10532				b->y1 = y1;
10533				dirty = false;
10534				while (length--) {
10535					dirty = true;
10536					e += e1;
10537					if (e >= 0) {
10538						e += e3;
10539
10540						if (sdx < 0) {
10541							b->x2 = b->x1 + 1;
10542							b->x1 = x1;
10543						} else
10544							b->x2 = x1 + 1;
10545						b->y2 = b->y1 + 1;
10546
10547						DBG(("%s: horizontal step: (%d, %d), box: (%d, %d), (%d, %d)\n",
10548						     __FUNCTION__, x1, y1,
10549						     b->x1, b->y1, b->x2, b->y2));
10550
10551						assert(!box_empty(b));
10552						if (++b == last_box) {
10553							ret = &&X_continue;
10554							goto *jump;
10555X_continue:
10556							b = box;
10557						}
10558
10559						b->x1 = x1 + sdx;
10560						b->y1 = y1 += sdy;
10561						dirty = false;
10562					}
10563					x1 += sdx;
10564				}
10565				if (dirty) {
10566					x1 -= sdx;
10567					DBG(("%s: horizontal tail: (%d, %d)\n",
10568					     __FUNCTION__, x1, y1));
10569					if (sdx < 0) {
10570						b->x2 = b->x1 + 1;
10571						b->x1 = x1;
10572					} else
10573						b->x2 = x1 + 1;
10574					b->y2 = b->y1 + 1;
10575
10576					assert(!box_empty(b));
10577					if (++b == last_box) {
10578						ret = &&X2_continue;
10579						goto *jump;
10580X2_continue:
10581						b = box;
10582					}
10583				}
10584			} else {
10585				bool dirty;
10586
10587				/* Y-major segment */
10588				e1 = adx << 1;
10589				e2 = e1 - (ady << 1);
10590				e  = e1 - ady;
10591				length  = ady;	/* don't draw endpoint in main loop */
10592
10593				SetYMajorOctant(octant);
10594				FIXUP_ERROR(e, octant, bias);
10595
10596				if (oc1 | oc2) {
10597					int pt1_clipped, pt2_clipped;
10598					int x = x1, y = y1;
10599
10600					if (miZeroClipLine(extents->x1, extents->y1,
10601							   extents->x2-1, extents->y2-1,
10602							   &x1, &y1, &x2, &y2,
10603							   adx, ady,
10604							   &pt1_clipped, &pt2_clipped,
10605							   octant, bias, oc1, oc2) == -1)
10606						continue;
10607
10608					length = abs(y2 - y1);
10609					if (length == 0)
10610						continue;
10611
10612					if (pt1_clipped) {
10613						int clipdx = abs(x1 - x);
10614						int clipdy = abs(y1 - y);
10615						e += clipdx * e2 + (clipdy - clipdx) * e1;
10616					}
10617				}
10618
10619				e3 = e2 - e1;
10620				e  = e - e1;
10621
10622				b->x1 = x1;
10623				b->y1 = y1;
10624				dirty = false;
10625				while (length--) {
10626					e += e1;
10627					dirty = true;
10628					if (e >= 0) {
10629						e += e3;
10630
10631						if (sdy < 0) {
10632							b->y2 = b->y1 + 1;
10633							b->y1 = y1;
10634						} else
10635							b->y2 = y1 + 1;
10636						b->x2 = x1 + 1;
10637
10638						assert(!box_empty(b));
10639						if (++b == last_box) {
10640							ret = &&Y_continue;
10641							goto *jump;
10642Y_continue:
10643							b = box;
10644						}
10645
10646						b->x1 = x1 += sdx;
10647						b->y1 = y1 + sdy;
10648						dirty = false;
10649					}
10650					y1 += sdy;
10651				}
10652
10653				if (dirty) {
10654					y1 -= sdy;
10655					if (sdy < 0) {
10656						b->y2 = b->y1 + 1;
10657						b->y1 = y1;
10658					} else
10659						b->y2 = y1 + 1;
10660					b->x2 = x1 + 1;
10661
10662					assert(!box_empty(b));
10663					if (++b == last_box) {
10664						ret = &&Y2_continue;
10665						goto *jump;
10666Y2_continue:
10667						b = box;
10668					}
10669				}
10670			}
10671		} while (--n);
10672	} while (++extents != last_extents);
10673
10674	if (b != box) {
10675		ret = &&done;
10676		goto *jump;
10677	}
10678
10679done:
10680	fill.done(sna, &fill);
10681	assert_pixmap_damage(pixmap);
10682	RegionUninit(&clip);
10683	return true;
10684
10685damage:
10686	sna_damage_add_boxes(damage, box, b-box, 0, 0);
10687no_damage:
10688	fill.boxes(sna, &fill, box, b-box);
10689	goto *ret;
10690
10691no_damage_offset:
10692	{
10693		BoxRec *bb = box;
10694		do {
10695			bb->x1 += dx;
10696			bb->x2 += dx;
10697			bb->y1 += dy;
10698			bb->y2 += dy;
10699		} while (++bb != b);
10700		fill.boxes(sna, &fill, box, b - box);
10701	}
10702	goto *ret;
10703
10704damage_offset:
10705	{
10706		BoxRec *bb = box;
10707		do {
10708			bb->x1 += dx;
10709			bb->x2 += dx;
10710			bb->y1 += dy;
10711			bb->y2 += dy;
10712		} while (++bb != b);
10713		fill.boxes(sna, &fill, box, b - box);
10714		sna_damage_add_boxes(damage, box, b - box, 0, 0);
10715	}
10716	goto *ret;
10717}
10718
10719static unsigned
10720sna_poly_segment_extents(DrawablePtr drawable, GCPtr gc,
10721			 int n, xSegment *seg,
10722			 BoxPtr out)
10723{
10724	BoxRec box;
10725	bool clipped, can_blit;
10726
10727	if (n == 0)
10728		return 0;
10729
10730	if (seg->x2 >= seg->x1) {
10731		box.x1 = seg->x1;
10732		box.x2 = seg->x2;
10733	} else {
10734		box.x2 = seg->x1;
10735		box.x1 = seg->x2;
10736	}
10737
10738	if (seg->y2 >= seg->y1) {
10739		box.y1 = seg->y1;
10740		box.y2 = seg->y2;
10741	} else {
10742		box.y2 = seg->y1;
10743		box.y1 = seg->y2;
10744	}
10745
10746	can_blit = seg->x1 == seg->x2 || seg->y1 == seg->y2;
10747	while (--n) {
10748		seg++;
10749		if (seg->x2 > seg->x1) {
10750			if (seg->x1 < box.x1) box.x1 = seg->x1;
10751			if (seg->x2 > box.x2) box.x2 = seg->x2;
10752		} else {
10753			if (seg->x2 < box.x1) box.x1 = seg->x2;
10754			if (seg->x1 > box.x2) box.x2 = seg->x1;
10755		}
10756
10757		if (seg->y2 > seg->y1) {
10758			if (seg->y1 < box.y1) box.y1 = seg->y1;
10759			if (seg->y2 > box.y2) box.y2 = seg->y2;
10760		} else {
10761			if (seg->y2 < box.y1) box.y1 = seg->y2;
10762			if (seg->y1 > box.y2) box.y2 = seg->y1;
10763		}
10764
10765		if (can_blit && !(seg->x1 == seg->x2 || seg->y1 == seg->y2))
10766			can_blit = false;
10767	}
10768
10769	box.x2++;
10770	box.y2++;
10771
10772	if (gc->lineWidth) {
10773		int extra = gc->lineWidth;
10774		if (gc->capStyle != CapProjecting)
10775			extra >>= 1;
10776		if (extra) {
10777			box.x1 -= extra;
10778			box.x2 += extra;
10779			box.y1 -= extra;
10780			box.y2 += extra;
10781		}
10782	}
10783
10784	DBG(("%s: unclipped, untranslated extents (%d, %d), (%d, %d)\n",
10785	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
10786
10787	clipped = trim_and_translate_box(&box, drawable, gc);
10788	if (box_empty(&box))
10789		return 0;
10790
10791	*out = box;
10792	return 1 | clipped << 1 | can_blit << 2;
10793}
10794
10795static void
10796sna_poly_segment(DrawablePtr drawable, GCPtr gc, int n, xSegment *seg)
10797{
10798	struct sna_pixmap *priv;
10799	struct sna_fill_spans data;
10800	uint32_t color;
10801
10802	DBG(("%s(n=%d, first=((%d, %d), (%d, %d)), lineWidth=%d\n",
10803	     __FUNCTION__,
10804	     n, seg->x1, seg->y1, seg->x2, seg->y2,
10805	     gc->lineWidth));
10806
10807	data.flags = sna_poly_segment_extents(drawable, gc, n, seg,
10808					      &data.region.extents);
10809	if (data.flags == 0)
10810		return;
10811
10812	DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__,
10813	     data.region.extents.x1, data.region.extents.y1,
10814	     data.region.extents.x2, data.region.extents.y2));
10815
10816	data.region.data = NULL;
10817
10818	if (FORCE_FALLBACK)
10819		goto fallback;
10820
10821	if (!ACCEL_POLY_SEGMENT)
10822		goto fallback;
10823
10824	data.pixmap = get_drawable_pixmap(drawable);
10825	data.sna = to_sna_from_pixmap(data.pixmap);
10826	priv = sna_pixmap(data.pixmap);
10827	if (priv == NULL) {
10828		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
10829		goto fallback;
10830	}
10831
10832	if (wedged(data.sna)) {
10833		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
10834		goto fallback;
10835	}
10836
10837	DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lu [%d], rectlinear=%d\n",
10838	     __FUNCTION__,
10839	     gc->fillStyle, gc->fillStyle == FillSolid,
10840	     gc->lineStyle, gc->lineStyle == LineSolid,
10841	     gc->lineWidth,
10842	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask),
10843	     data.flags & RECTILINEAR));
10844	if (!PM_IS_SOLID(drawable, gc->planemask))
10845		goto fallback;
10846
10847	if (gc->lineStyle != LineSolid || gc->lineWidth > 1)
10848		goto spans_fallback;
10849
10850	data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
10851				      &data.region.extents,
10852				      &data.damage);
10853	if (data.bo == NULL)
10854		goto fallback;
10855
10856	if (gc_is_solid(gc, &color)) {
10857		DBG(("%s: trying blt solid fill [%08x, flags=%x] paths\n",
10858		     __FUNCTION__, (unsigned)color, data.flags));
10859
10860		if (data.flags & RECTILINEAR) {
10861			if (sna_poly_segment_blt(drawable,
10862						 data.bo, data.damage,
10863						 gc, color, n, seg,
10864						 &data.region.extents,
10865						 data.flags & IS_CLIPPED))
10866				return;
10867		} else {
10868			if (sna_poly_zero_segment_blt(drawable,
10869						      data.bo, data.damage,
10870						      gc, n, seg,
10871						      &data.region.extents,
10872						      data.flags & IS_CLIPPED))
10873				return;
10874		}
10875	} else if (data.flags & RECTILINEAR) {
10876		/* Try converting these to a set of rectangles instead */
10877		xRectangle *rect;
10878		int i;
10879
10880		DBG(("%s: converting to rectangles\n", __FUNCTION__));
10881
10882		rect = malloc (n * sizeof (xRectangle));
10883		if (rect == NULL)
10884			return;
10885
10886		for (i = 0; i < n; i++) {
10887			if (seg[i].x1 < seg[i].x2) {
10888				rect[i].x = seg[i].x1;
10889				rect[i].width = seg[i].x2 - seg[i].x1 + 1;
10890			} else if (seg[i].x1 > seg[i].x2) {
10891				rect[i].x = seg[i].x2;
10892				rect[i].width = seg[i].x1 - seg[i].x2 + 1;
10893			} else {
10894				rect[i].x = seg[i].x1;
10895				rect[i].width = 1;
10896			}
10897			if (seg[i].y1 < seg[i].y2) {
10898				rect[i].y = seg[i].y1;
10899				rect[i].height = seg[i].y2 - seg[i].y1 + 1;
10900			} else if (seg[i].y1 > seg[i].y2) {
10901				rect[i].y = seg[i].y2;
10902				rect[i].height = seg[i].y1 - seg[i].y2 + 1;
10903			} else {
10904				rect[i].y = seg[i].y1;
10905				rect[i].height = 1;
10906			}
10907
10908			/* don't paint last pixel */
10909			if (gc->capStyle == CapNotLast) {
10910				if (seg[i].x1 == seg[i].x2)
10911					rect[i].height--;
10912				else
10913					rect[i].width--;
10914			}
10915		}
10916
10917		if (gc->fillStyle == FillTiled) {
10918			i = sna_poly_fill_rect_tiled_blt(drawable,
10919							 data.bo, data.damage,
10920							 gc, n, rect,
10921							 &data.region.extents,
10922							 data.flags);
10923		} else {
10924			i = sna_poly_fill_rect_stippled_blt(drawable,
10925							    data.bo, data.damage,
10926							    gc, n, rect,
10927							    &data.region.extents,
10928							    data.flags);
10929		}
10930		free (rect);
10931
10932		if (i)
10933			return;
10934	}
10935
10936spans_fallback:
10937	if ((data.bo = sna_drawable_use_bo(drawable,
10938					   use_line_spans(drawable, gc, &data.region.extents, data.flags),
10939					   &data.region.extents,
10940					   &data.damage))) {
10941		void (*line)(DrawablePtr, GCPtr, int, int, DDXPointPtr);
10942		int i;
10943
10944		DBG(("%s: converting segments into spans\n", __FUNCTION__));
10945
10946		switch (gc->lineStyle) {
10947		default:
10948		case LineSolid:
10949			if (gc->lineWidth == 0)
10950				line = miZeroLine;
10951			else
10952				line = miWideLine;
10953			break;
10954		case LineOnOffDash:
10955		case LineDoubleDash:
10956			if (gc->lineWidth == 0)
10957				line = miZeroDashLine;
10958			else
10959				line = miWideDash;
10960			break;
10961		}
10962
10963		get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy);
10964		sna_gc(gc)->priv = &data;
10965
10966		if (gc->lineWidth == 0 &&
10967		    gc->lineStyle == LineSolid &&
10968		    gc_is_solid(gc, &color)) {
10969			struct sna_fill_op fill;
10970
10971			if (!sna_fill_init_blt(&fill,
10972					       data.sna, data.pixmap,
10973					       data.bo, gc->alu, color,
10974					       FILL_POINTS | FILL_SPANS))
10975				goto fallback;
10976
10977			data.op = &fill;
10978
10979			if ((data.flags & IS_CLIPPED) == 0) {
10980				if (data.dx | data.dy)
10981					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
10982				else
10983					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
10984				sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill;
10985			} else {
10986				if (!region_maybe_clip(&data.region,
10987						       gc->pCompositeClip))
10988					return;
10989
10990				if (region_is_singular(&data.region)) {
10991					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
10992					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents;
10993				} else {
10994					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
10995					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes;
10996				}
10997			}
10998			assert(gc->miTranslate);
10999			gc->ops = &sna_gc_ops__tmp;
11000			for (i = 0; i < n; i++)
11001				line(drawable, gc, CoordModeOrigin, 2,
11002				     (DDXPointPtr)&seg[i]);
11003
11004			fill.done(data.sna, &fill);
11005		} else {
11006			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
11007			sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu;
11008			sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu;
11009			gc->ops = &sna_gc_ops__tmp;
11010
11011			for (i = 0; i < n; i++)
11012				line(drawable, gc, CoordModeOrigin, 2,
11013				     (DDXPointPtr)&seg[i]);
11014		}
11015
11016		gc->ops = (GCOps *)&sna_gc_ops;
11017		if (data.damage) {
11018			if (data.dx | data.dy)
11019				pixman_region_translate(&data.region, data.dx, data.dy);
11020			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
11021			sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap);
11022		}
11023		assert_pixmap_damage(data.pixmap);
11024		RegionUninit(&data.region);
11025		return;
11026	}
11027
11028fallback:
11029	DBG(("%s: fallback\n", __FUNCTION__));
11030	if (!region_maybe_clip(&data.region, gc->pCompositeClip))
11031		return;
11032
11033	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
11034		goto out;
11035	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
11036					     drawable_gc_flags(drawable, gc,
11037							       !(data.flags & RECTILINEAR && n == 1))))
11038		goto out;
11039
11040	if (sigtrap_get() == 0) {
11041		DBG(("%s: fbPolySegment\n", __FUNCTION__));
11042		fbPolySegment(drawable, gc, n, seg);
11043		FALLBACK_FLUSH(drawable);
11044		sigtrap_put();
11045	}
11046out:
11047	sna_gc_move_to_gpu(gc);
11048	RegionUninit(&data.region);
11049}
11050
11051static unsigned
11052sna_poly_rectangle_extents(DrawablePtr drawable, GCPtr gc,
11053			   int n, xRectangle *r,
11054			   BoxPtr out)
11055{
11056	Box32Rec box;
11057	int extra = gc->lineWidth >> 1;
11058	bool clipped;
11059	bool zero = false;
11060
11061	if (n == 0)
11062		return 0;
11063
11064	box.x1 = r->x;
11065	box.y1 = r->y;
11066	box.x2 = box.x1 + r->width;
11067	box.y2 = box.y1 + r->height;
11068	zero |= (r->width | r->height) == 0;
11069
11070	while (--n) {
11071		r++;
11072		zero |= (r->width | r->height) == 0;
11073		box32_add_rect(&box, r);
11074	}
11075
11076	box.x2++;
11077	box.y2++;
11078
11079	if (extra) {
11080		box.x1 -= extra;
11081		box.x2 += extra;
11082		box.y1 -= extra;
11083		box.y2 += extra;
11084		zero = !zero;
11085	} else
11086		zero = true;
11087
11088	DBG(("%s: unclipped original extents: (%d, %d), (%d, %d)\n",
11089	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
11090	clipped = box32_trim_and_translate(&box, drawable, gc);
11091	if (!box32_to_box16(&box, out))
11092		return 0;
11093
11094	DBG(("%s: extents: (%d, %d), (%d, %d), clipped? %d\n",
11095	     __FUNCTION__, out->x1, out->y1, out->x2, out->y2, clipped));
11096	return 1 | clipped << 1 | zero << 2;
11097}
11098
11099static bool
11100sna_poly_rectangle_blt(DrawablePtr drawable,
11101		       struct kgem_bo *bo,
11102		       struct sna_damage **damage,
11103		       GCPtr gc, int n, xRectangle *r,
11104		       const BoxRec *extents, unsigned clipped)
11105{
11106	PixmapPtr pixmap = get_drawable_pixmap(drawable);
11107	struct sna *sna = to_sna_from_pixmap(pixmap);
11108	struct sna_fill_op fill;
11109	BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes);
11110	int16_t dx, dy;
11111	static void * const jump[] = {
11112		&&wide,
11113		&&zero,
11114		&&wide_clipped,
11115		&&zero_clipped,
11116	};
11117
11118	DBG(("%s: n=%d, alu=%d, width=%d, fg=%08lx, damge=%p, clipped?=%d\n",
11119	     __FUNCTION__, n, gc->alu, gc->lineWidth, gc->fgPixel, damage, clipped));
11120	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_BOXES))
11121		return false;
11122
11123	get_drawable_deltas(drawable, pixmap, &dx, &dy);
11124
11125	goto *jump[(gc->lineWidth <= 1) | clipped];
11126
11127zero:
11128	dx += drawable->x;
11129	dy += drawable->y;
11130
11131	do {
11132		xRectangle rr = *r++;
11133
11134		if ((rr.width | rr.height) == 0)
11135			continue; /* XXX -> PolyLine */
11136
11137		DBG(("%s - zero : r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__,
11138		     n, rr.x, rr.y, rr.width, rr.height));
11139		rr.x += dx;
11140		rr.y += dy;
11141
11142		if (b+4 > last_box) {
11143			fill.boxes(sna, &fill, boxes, b-boxes);
11144			if (damage)
11145				sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
11146			b = boxes;
11147		}
11148
11149		if (rr.width <= 1 || rr.height <= 1) {
11150			b->x1 = rr.x;
11151			b->y1 = rr.y;
11152			b->x2 = rr.x + rr.width + (rr.height != 0);
11153			b->y2 = rr.y + rr.height + (rr.width != 0);
11154			DBG(("%s: blt (%d, %d), (%d, %d)\n",
11155			     __FUNCTION__,
11156			     b->x1, b->y1, b->x2,b->y2));
11157			b++;
11158		} else {
11159			b[0].x1 = rr.x;
11160			b[0].y1 = rr.y;
11161			b[0].x2 = rr.x + rr.width + 1;
11162			b[0].y2 = rr.y + 1;
11163
11164			b[1] = b[0];
11165			b[1].y1 += rr.height;
11166			b[1].y2 += rr.height;
11167
11168			b[2].y1 = rr.y + 1;
11169			b[2].y2 = rr.y + rr.height;
11170			b[2].x1 = rr.x;
11171			b[2].x2 = rr.x + 1;
11172
11173			b[3] = b[2];
11174			b[3].x1 += rr.width;
11175			b[3].x2 += rr.width;
11176
11177			b += 4;
11178		}
11179	} while (--n);
11180	goto done;
11181
11182zero_clipped:
11183	{
11184		RegionRec clip;
11185		BoxRec box[4];
11186		int count;
11187
11188		region_set(&clip, extents);
11189		if (!region_maybe_clip(&clip, gc->pCompositeClip))
11190			goto done;
11191
11192		if (clip.data) {
11193			const BoxRec * const clip_start = RegionBoxptr(&clip);
11194			const BoxRec * const clip_end = clip_start + clip.data->numRects;
11195			const BoxRec *c;
11196			do {
11197				xRectangle rr = *r++;
11198
11199				DBG(("%s - zero, clipped complex: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__,
11200				     n, rr.x, rr.y, rr.width, rr.height));
11201
11202				if ((rr.width | rr.height) == 0)
11203					continue; /* XXX -> PolyLine */
11204
11205				rr.x += drawable->x;
11206				rr.y += drawable->y;
11207
11208				if (rr.width <= 1 || rr.height <= 1) {
11209					box[0].x1 = rr.x;
11210					box[0].y1 = rr.y;
11211					box[0].x2 = rr.x + rr.width + (rr.height != 0);
11212					box[0].y2 = rr.y + rr.height + (rr.width != 0);
11213					count = 1;
11214				} else {
11215					box[0].x1 = rr.x;
11216					box[0].y1 = rr.y;
11217					box[0].x2 = rr.x + rr.width + 1;
11218					box[0].y2 = rr.y + 1;
11219
11220					box[1] = box[0];
11221					box[1].y1 += rr.height;
11222					box[1].y2 += rr.height;
11223
11224					box[2].y1 = rr.y + 1;
11225					box[2].y2 = rr.y + rr.height;
11226					box[2].x1 = rr.x;
11227					box[2].x2 = rr.x + 1;
11228
11229					box[3] = box[2];
11230					box[3].x1 += rr.width;
11231					box[3].x2 += rr.width;
11232					count = 4;
11233				}
11234
11235				while (count--) {
11236					c = find_clip_box_for_y(clip_start,
11237								clip_end,
11238								box[count].y1);
11239					while (c != clip_end) {
11240						if (box[count].y2 <= c->y1)
11241							break;
11242
11243						*b = box[count];
11244						if (box_intersect(b, c++)) {
11245							b->x1 += dx;
11246							b->x2 += dx;
11247							b->y1 += dy;
11248							b->y2 += dy;
11249							if (++b == last_box) {
11250								fill.boxes(sna, &fill, boxes, last_box-boxes);
11251								if (damage)
11252									sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11253								b = boxes;
11254							}
11255						}
11256
11257					}
11258				}
11259			} while (--n);
11260		} else {
11261			do {
11262				xRectangle rr = *r++;
11263				DBG(("%s - zero, clip: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__,
11264				     n, rr.x, rr.y, rr.width, rr.height));
11265
11266				if ((rr.width | rr.height) == 0)
11267					continue; /* XXX -> PolyLine */
11268
11269				rr.x += drawable->x;
11270				rr.y += drawable->y;
11271
11272				if (rr.width <= 1 || rr.height <= 1) {
11273					box[0].x1 = rr.x;
11274					box[0].y1 = rr.y;
11275					box[0].x2 = rr.x + rr.width + (rr.height != 0);
11276					box[0].y2 = rr.y + rr.height + (rr.width != 0);
11277					count = 1;
11278				} else {
11279					box[0].x1 = rr.x;
11280					box[0].y1 = rr.y;
11281					box[0].x2 = rr.x + rr.width + 1;
11282					box[0].y2 = rr.y + 1;
11283
11284					box[1] = box[0];
11285					box[1].y1 += rr.height;
11286					box[1].y2 += rr.height;
11287
11288					box[2].y1 = rr.y + 1;
11289					box[2].y2 = rr.y + rr.height;
11290					box[2].x1 = rr.x;
11291					box[2].x2 = rr.x + 1;
11292
11293					box[3] = box[2];
11294					box[3].x1 += rr.width;
11295					box[3].x2 += rr.width;
11296					count = 4;
11297				}
11298
11299				while (count--) {
11300					*b = box[count];
11301					if (box_intersect(b, &clip.extents)) {
11302						b->x1 += dx;
11303						b->x2 += dx;
11304						b->y1 += dy;
11305						b->y2 += dy;
11306						if (++b == last_box) {
11307							fill.boxes(sna, &fill, boxes, last_box-boxes);
11308							if (damage)
11309								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11310							b = boxes;
11311						}
11312					}
11313
11314				}
11315			} while (--n);
11316		}
11317		RegionUninit(&clip);
11318	}
11319	goto done;
11320
11321wide_clipped:
11322	{
11323		RegionRec clip;
11324		BoxRec box[4];
11325		int16_t offset2 = gc->lineWidth;
11326		int16_t offset1 = offset2 >> 1;
11327		int16_t offset3 = offset2 - offset1;
11328
11329		region_set(&clip, extents);
11330		if (!region_maybe_clip(&clip, gc->pCompositeClip))
11331			goto done;
11332
11333		DBG(("%s: wide clipped: extents=((%d, %d), (%d, %d))\n",
11334		     __FUNCTION__,
11335		     clip.extents.x1, clip.extents.y1,
11336		     clip.extents.x2, clip.extents.y2));
11337
11338		if (clip.data) {
11339			const BoxRec * const clip_start = RegionBoxptr(&clip);
11340			const BoxRec * const clip_end = clip_start + clip.data->numRects;
11341			const BoxRec *c;
11342			do {
11343				xRectangle rr = *r++;
11344				int count;
11345
11346				if ((rr.width | rr.height) == 0)
11347					continue; /* XXX -> PolyLine */
11348
11349				rr.x += drawable->x;
11350				rr.y += drawable->y;
11351
11352				if (rr.height <= offset2 || rr.width <= offset2) {
11353					if (rr.height == 0) {
11354						box[0].x1 = rr.x;
11355						box[0].x2 = rr.x + rr.width;
11356					} else {
11357						box[0].x1 = rr.x - offset1;
11358						box[0].x2 = rr.x + rr.width + offset3;
11359					}
11360					if (rr.width == 0) {
11361						box[0].y1 = rr.y;
11362						box[0].y2 = rr.y + rr.height;
11363					} else {
11364						box[0].y1 = rr.y - offset1;
11365						box[0].y2 = rr.y + rr.height + offset3;
11366					}
11367					count = 1;
11368				} else {
11369					box[0].x1 = rr.x - offset1;
11370					box[0].x2 = box[0].x1 + rr.width + offset2;
11371					box[0].y1 = rr.y - offset1;
11372					box[0].y2 = box[0].y1 + offset2;
11373
11374					box[1].x1 = rr.x - offset1;
11375					box[1].x2 = box[1].x1 + offset2;
11376					box[1].y1 = rr.y + offset3;
11377					box[1].y2 = rr.y + rr.height - offset1;
11378
11379					box[2] = box[1];
11380					box[2].x1 += rr.width;
11381					box[2].x2 += rr.width;
11382
11383					box[3] = box[0];
11384					box[3].y1 += rr.height;
11385					box[3].y2 += rr.height;
11386					count = 4;
11387				}
11388
11389				while (count--) {
11390					c = find_clip_box_for_y(clip_start,
11391								clip_end,
11392								box[count].y1);
11393					while (c != clip_end) {
11394						if (box[count].y2 <= c->y1)
11395							break;
11396
11397						*b = box[count];
11398						if (box_intersect(b, c++)) {
11399							b->x1 += dx;
11400							b->x2 += dx;
11401							b->y1 += dy;
11402							b->y2 += dy;
11403							if (++b == last_box) {
11404								fill.boxes(sna, &fill, boxes, last_box-boxes);
11405								if (damage)
11406									sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11407								b = boxes;
11408							}
11409						}
11410					}
11411				}
11412			} while (--n);
11413		} else {
11414			DBG(("%s: singular clip offset1=%d, offset2=%d, offset3=%d\n",
11415			     __FUNCTION__, offset1, offset2, offset3));
11416			do {
11417				xRectangle rr = *r++;
11418				int count;
11419				rr.x += drawable->x;
11420				rr.y += drawable->y;
11421
11422				DBG(("%s: r=(%d, %d)x(%d, %d)\n",
11423				     __FUNCTION__, rr.x, rr.y, rr.width, rr.height));
11424				if (rr.height <= offset2 || rr.width <= offset2) {
11425					if (rr.height == 0) {
11426						box[0].x1 = rr.x;
11427						box[0].x2 = rr.x + rr.width;
11428					} else {
11429						box[0].x1 = rr.x - offset1;
11430						box[0].x2 = box[0].x1 + rr.width + offset2;
11431					}
11432					if (rr.width == 0) {
11433						box[0].y1 = rr.y;
11434						box[0].y2 = rr.y + rr.height;
11435					} else {
11436						box[0].y1 = rr.y - offset1;
11437						box[0].y2 = box[0].y1 + rr.height + offset2;
11438					}
11439					count = 1;
11440				} else {
11441					box[0].x1 = rr.x - offset1;
11442					box[0].x2 = box[0].x1 + rr.width + offset2;
11443					box[0].y1 = rr.y - offset1;
11444					box[0].y2 = box[0].y1 + offset2;
11445					DBG(("%s: box[0]=(%d, %d), (%d, %d)\n",
11446					     __FUNCTION__,
11447					     box[0].x1, box[0].y1,
11448					     box[0].x2, box[0].y2));
11449
11450					box[1].x1 = rr.x - offset1;
11451					box[1].x2 = box[1].x1 + offset2;
11452					box[1].y1 = rr.y + offset3;
11453					box[1].y2 = rr.y + rr.height - offset1;
11454					DBG(("%s: box[1]=(%d, %d), (%d, %d)\n",
11455					     __FUNCTION__,
11456					     box[1].x1, box[1].y1,
11457					     box[1].x2, box[1].y2));
11458
11459					box[2] = box[1];
11460					box[2].x1 += rr.width;
11461					box[2].x2 += rr.width;
11462					DBG(("%s: box[2]=(%d, %d), (%d, %d)\n",
11463					     __FUNCTION__,
11464					     box[2].x1, box[2].y1,
11465					     box[2].x2, box[2].y2));
11466
11467					box[3] = box[0];
11468					box[3].y1 += rr.height;
11469					box[3].y2 += rr.height;
11470					DBG(("%s: box[3]=(%d, %d), (%d, %d)\n",
11471					     __FUNCTION__,
11472					     box[3].x1, box[3].y1,
11473					     box[3].x2, box[3].y2));
11474
11475					count = 4;
11476				}
11477
11478				while (count--) {
11479					*b = box[count];
11480					if (box_intersect(b, &clip.extents)) {
11481						b->x1 += dx;
11482						b->x2 += dx;
11483						b->y1 += dy;
11484						b->y2 += dy;
11485						if (++b == last_box) {
11486							fill.boxes(sna, &fill, boxes, last_box-boxes);
11487							if (damage)
11488								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11489							b = boxes;
11490						}
11491					}
11492				}
11493			} while (--n);
11494		}
11495		RegionUninit(&clip);
11496	}
11497	goto done;
11498
11499wide:
11500	{
11501		int offset2 = gc->lineWidth;
11502		int offset1 = offset2 >> 1;
11503		int offset3 = offset2 - offset1;
11504
11505		dx += drawable->x;
11506		dy += drawable->y;
11507
11508		do {
11509			xRectangle rr = *r++;
11510
11511			if ((rr.width | rr.height) == 0)
11512				continue; /* XXX -> PolyLine */
11513
11514			rr.x += dx;
11515			rr.y += dy;
11516
11517			if (b+4 > last_box) {
11518				fill.boxes(sna, &fill, boxes, last_box-boxes);
11519				if (damage)
11520					sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11521				b = boxes;
11522			}
11523
11524			if (rr.height <= offset2 || rr.width <= offset2) {
11525				if (rr.height == 0) {
11526					b->x1 = rr.x;
11527					b->x2 = rr.x + rr.width;
11528				} else {
11529					b->x1 = rr.x - offset1;
11530					b->x2 = rr.x + rr.width + offset3;
11531				}
11532				if (rr.width == 0) {
11533					b->y1 = rr.y;
11534					b->y2 = rr.y + rr.height;
11535				} else {
11536					b->y1 = rr.y - offset1;
11537					b->y2 = rr.y + rr.height + offset3;
11538				}
11539				b++;
11540			} else {
11541				b[0].x1 = rr.x - offset1;
11542				b[0].x2 = b[0].x1 + rr.width + offset2;
11543				b[0].y1 = rr.y - offset1;
11544				b[0].y2 = b[0].y1 + offset2;
11545
11546				b[1].x1 = rr.x - offset1;
11547				b[1].x2 = b[1].x1 + offset2;
11548				b[1].y1 = rr.y + offset3;
11549				b[1].y2 = rr.y + rr.height - offset1;
11550
11551				b[2] = b[1];
11552				b[2].x1 += rr.width;
11553				b[2].x2 += rr.width;
11554
11555				b[3] = b[0];
11556				b[3].y1 += rr.height;
11557				b[3].y2 += rr.height;
11558				b += 4;
11559			}
11560		} while (--n);
11561	}
11562	goto done;
11563
11564done:
11565	if (b != boxes) {
11566		fill.boxes(sna, &fill, boxes, b-boxes);
11567		if (damage)
11568			sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
11569	}
11570	fill.done(sna, &fill);
11571	assert_pixmap_damage(pixmap);
11572	return true;
11573}
11574
11575static void
11576sna_poly_rectangle(DrawablePtr drawable, GCPtr gc, int n, xRectangle *r)
11577{
11578	PixmapPtr pixmap = get_drawable_pixmap(drawable);
11579	struct sna *sna = to_sna_from_pixmap(pixmap);
11580	struct sna_damage **damage;
11581	struct kgem_bo *bo;
11582	RegionRec region;
11583	unsigned flags;
11584
11585	DBG(("%s(n=%d, first=((%d, %d)x(%d, %d)), lineWidth=%d\n",
11586	     __FUNCTION__,
11587	     n, r->x, r->y, r->width, r->height,
11588	     gc->lineWidth));
11589
11590	flags = sna_poly_rectangle_extents(drawable, gc, n, r, &region.extents);
11591	if (flags == 0)
11592		return;
11593
11594	DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
11595	     region.extents.x1, region.extents.y1,
11596	     region.extents.x2, region.extents.y2,
11597	     flags));
11598
11599	if (FORCE_FALLBACK)
11600		goto fallback;
11601
11602	if (!ACCEL_POLY_RECTANGLE)
11603		goto fallback;
11604
11605	if (wedged(sna)) {
11606		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
11607		goto fallback;
11608	}
11609
11610	DBG(("%s: fill=%d [%d], line=%d [%d], join=%d [%d], mask=%lu [%d]\n",
11611	     __FUNCTION__,
11612	     gc->fillStyle, gc->fillStyle == FillSolid,
11613	     gc->lineStyle, gc->lineStyle == LineSolid,
11614	     gc->joinStyle, gc->joinStyle == JoinMiter,
11615	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask)));
11616
11617	if (!PM_IS_SOLID(drawable, gc->planemask))
11618		goto fallback;
11619
11620	if (flags & RECTILINEAR && gc->fillStyle == FillSolid && gc->lineStyle == LineSolid && gc->joinStyle == JoinMiter) {
11621		DBG(("%s: trying blt solid fill [%08lx] paths\n",
11622		     __FUNCTION__, gc->fgPixel));
11623		if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU,
11624					      &region.extents, &damage)) &&
11625		    sna_poly_rectangle_blt(drawable, bo, damage,
11626					   gc, n, r, &region.extents, flags&2))
11627			return;
11628	} else {
11629		/* Not a trivial outline, but we still maybe able to break it
11630		 * down into simpler operations that we can accelerate.
11631		 */
11632		if (sna_drawable_use_bo(drawable, PREFER_GPU,
11633					&region.extents, &damage)) {
11634			miPolyRectangle(drawable, gc, n, r);
11635			return;
11636		}
11637	}
11638
11639fallback:
11640	DBG(("%s: fallback, clip=%dx[(%d, %d), (%d, %d)]\n", __FUNCTION__,
11641	     region_num_rects(gc->pCompositeClip),
11642	     gc->pCompositeClip->extents.x1, gc->pCompositeClip->extents.y1,
11643	     gc->pCompositeClip->extents.x2, gc->pCompositeClip->extents.y2));
11644
11645	region.data = NULL;
11646	if (!region_maybe_clip(&region, gc->pCompositeClip))
11647		return;
11648
11649	DBG(("%s: CPU region=%dx[(%d, %d), (%d, %d)]\n", __FUNCTION__,
11650	     region_num_rects(&region),
11651	     region.extents.x1, region.extents.y1,
11652	     region.extents.x2, region.extents.y2));
11653	if (!sna_gc_move_to_cpu(gc, drawable, &region))
11654		goto out;
11655	if (!sna_drawable_move_region_to_cpu(drawable, &region,
11656					     drawable_gc_flags(drawable, gc, true)))
11657		goto out;
11658
11659	if (sigtrap_get() == 0) {
11660		DBG(("%s: miPolyRectangle\n", __FUNCTION__));
11661		miPolyRectangle(drawable, gc, n, r);
11662		FALLBACK_FLUSH(drawable);
11663		sigtrap_put();
11664	}
11665out:
11666	sna_gc_move_to_gpu(gc);
11667	RegionUninit(&region);
11668}
11669
11670static unsigned
11671sna_poly_arc_extents(DrawablePtr drawable, GCPtr gc,
11672		     int n, xArc *arc,
11673		     BoxPtr out)
11674{
11675	BoxRec box;
11676	bool clipped;
11677	int v;
11678
11679	if (n == 0)
11680		return 0;
11681
11682	box.x1 = arc->x;
11683	box.x2 = bound(box.x1, arc->width);
11684	box.y1 = arc->y;
11685	box.y2 = bound(box.y1, arc->height);
11686
11687	while (--n) {
11688		arc++;
11689		if (box.x1 > arc->x)
11690			box.x1 = arc->x;
11691		v = bound(arc->x, arc->width);
11692		if (box.x2 < v)
11693			box.x2 = v;
11694		if (box.y1 > arc->y)
11695			box.y1 = arc->y;
11696		v = bound(arc->y, arc->height);
11697		if (box.y2 < v)
11698			box.y2 = v;
11699	}
11700
11701	v = gc->lineWidth >> 1;
11702	if (v) {
11703		box.x1 -= v;
11704		box.x2 += v;
11705		box.y1 -= v;
11706		box.y2 += v;
11707	}
11708
11709	box.x2++;
11710	box.y2++;
11711
11712	clipped = trim_and_translate_box(&box, drawable, gc);
11713	if (box_empty(&box))
11714		return 0;
11715
11716	*out = box;
11717	return 1 | clipped << 1;
11718}
11719
11720static void
11721sna_poly_arc(DrawablePtr drawable, GCPtr gc, int n, xArc *arc)
11722{
11723	struct sna_fill_spans data;
11724	struct sna_pixmap *priv;
11725
11726	DBG(("%s(n=%d, lineWidth=%d\n", __FUNCTION__, n, gc->lineWidth));
11727
11728	data.flags = sna_poly_arc_extents(drawable, gc, n, arc,
11729					  &data.region.extents);
11730	if (data.flags == 0)
11731		return;
11732
11733	DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
11734	     data.region.extents.x1, data.region.extents.y1,
11735	     data.region.extents.x2, data.region.extents.y2,
11736	     data.flags));
11737
11738	data.region.data = NULL;
11739
11740	if (FORCE_FALLBACK)
11741		goto fallback;
11742
11743	if (!ACCEL_POLY_ARC)
11744		goto fallback;
11745
11746	data.pixmap = get_drawable_pixmap(drawable);
11747	data.sna = to_sna_from_pixmap(data.pixmap);
11748	priv = sna_pixmap(data.pixmap);
11749	if (priv == NULL) {
11750		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
11751		goto fallback;
11752	}
11753
11754	if (wedged(data.sna)) {
11755		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
11756		goto fallback;
11757	}
11758
11759	if (!PM_IS_SOLID(drawable, gc->planemask))
11760		goto fallback;
11761
11762	if ((data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
11763					   &data.region.extents, &data.damage))) {
11764		uint32_t color;
11765
11766		DBG(("%s: converting arcs into spans\n", __FUNCTION__));
11767		get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy);
11768
11769		if (gc_is_solid(gc, &color)) {
11770			sna_gc(gc)->priv = &data;
11771
11772			assert(gc->miTranslate);
11773			if (gc->lineStyle == LineSolid) {
11774				struct sna_fill_op fill;
11775
11776				if (!sna_fill_init_blt(&fill,
11777						       data.sna, data.pixmap,
11778						       data.bo, gc->alu, color,
11779						       FILL_POINTS | FILL_SPANS))
11780					goto fallback;
11781
11782				if ((data.flags & IS_CLIPPED) == 0) {
11783					if (data.dx | data.dy)
11784						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
11785					else
11786						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
11787					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill;
11788				} else {
11789					if (!region_maybe_clip(&data.region,
11790							       gc->pCompositeClip))
11791						return;
11792
11793					if (region_is_singular(&data.region)) {
11794						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
11795						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents;
11796					} else {
11797						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
11798						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes;
11799					}
11800				}
11801
11802				data.op = &fill;
11803				gc->ops = &sna_gc_ops__tmp;
11804				if (gc->lineWidth == 0)
11805					miZeroPolyArc(drawable, gc, n, arc);
11806				else
11807					miPolyArc(drawable, gc, n, arc);
11808				gc->ops = (GCOps *)&sna_gc_ops;
11809
11810				fill.done(data.sna, &fill);
11811			} else {
11812				if (!region_maybe_clip(&data.region,
11813						       gc->pCompositeClip))
11814					return;
11815
11816				sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
11817				sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu;
11818
11819				gc->ops = &sna_gc_ops__tmp;
11820				if (gc->lineWidth == 0)
11821					miZeroPolyArc(drawable, gc, n, arc);
11822				else
11823					miPolyArc(drawable, gc, n, arc);
11824				gc->ops = (GCOps *)&sna_gc_ops;
11825			}
11826
11827			if (data.damage) {
11828				if (data.dx | data.dy)
11829					pixman_region_translate(&data.region, data.dx, data.dy);
11830				assert_pixmap_contains_box(data.pixmap, &data.region.extents);
11831				sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap);
11832			}
11833			assert_pixmap_damage(data.pixmap);
11834			RegionUninit(&data.region);
11835			return;
11836		}
11837
11838		/* XXX still around 10x slower for x11perf -ellipse */
11839		if (gc->lineWidth == 0)
11840			miZeroPolyArc(drawable, gc, n, arc);
11841		else
11842			miPolyArc(drawable, gc, n, arc);
11843		return;
11844	}
11845
11846fallback:
11847	DBG(("%s -- fallback\n", __FUNCTION__));
11848	if (!region_maybe_clip(&data.region, gc->pCompositeClip))
11849		return;
11850
11851	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
11852		goto out;
11853	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
11854					     drawable_gc_flags(drawable, gc, true)))
11855		goto out;
11856
11857	if (sigtrap_get() == 0) {
11858		DBG(("%s -- fbPolyArc\n", __FUNCTION__));
11859		fbPolyArc(drawable, gc, n, arc);
11860		FALLBACK_FLUSH(drawable);
11861		sigtrap_put();
11862	}
11863out:
11864	sna_gc_move_to_gpu(gc);
11865	RegionUninit(&data.region);
11866}
11867
11868static bool
11869sna_poly_fill_rect_blt(DrawablePtr drawable,
11870		       struct kgem_bo *bo,
11871		       struct sna_damage **damage,
11872		       GCPtr gc, uint32_t pixel,
11873		       int n, const xRectangle *rect,
11874		       const BoxRec *extents,
11875		       unsigned flags)
11876{
11877	PixmapPtr pixmap = get_drawable_pixmap(drawable);
11878	struct sna *sna = to_sna_from_pixmap(pixmap);
11879	struct sna_fill_op fill;
11880	BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes);
11881	int16_t dx, dy;
11882
11883	DBG(("%s pixmap=%ld x %d [(%d, %d)x(%d, %d)...]+(%d,%d), clipped?=%d\n",
11884	     __FUNCTION__, pixmap->drawable.serialNumber, n,
11885	     rect->x, rect->y, rect->width, rect->height,
11886	     drawable->x, drawable->y,
11887	     flags&2));
11888
11889	if (n == 1 && region_is_singular(gc->pCompositeClip)) {
11890		BoxRec r;
11891		bool success = true;
11892
11893		r.x1 = rect->x + drawable->x;
11894		r.y1 = rect->y + drawable->y;
11895		r.x2 = bound(r.x1, rect->width);
11896		r.y2 = bound(r.y1, rect->height);
11897		if (box_intersect(&r, &gc->pCompositeClip->extents)) {
11898			if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
11899				r.x1 += dx; r.y1 += dy;
11900				r.x2 += dx; r.y2 += dy;
11901			}
11902			DBG(("%s: using fill_one() fast path: (%d, %d), (%d, %d). alu=%d, pixel=%08x, damage?=%d\n",
11903			     __FUNCTION__, r.x1, r.y1, r.x2, r.y2, gc->alu, pixel, damage != NULL));
11904
11905			assert_pixmap_contains_box(pixmap, &r);
11906			if (sna->render.fill_one(sna, pixmap, bo, pixel,
11907						 r.x1, r.y1, r.x2, r.y2,
11908						 gc->alu)) {
11909				if (r.x2 - r.x1 == pixmap->drawable.width &&
11910				    r.y2 - r.y1 == pixmap->drawable.height) {
11911					if (damage) {
11912						sna_damage_all(damage, pixmap);
11913						damage = NULL;
11914					}
11915					if (flags & OVERWRITES) {
11916						struct sna_pixmap *priv = sna_pixmap(pixmap);
11917						if (bo == priv->gpu_bo) {
11918							assert(damage == NULL || damage == &priv->gpu_damage);
11919							assert(priv->gpu_bo->proxy == NULL);
11920							sna_damage_destroy(&priv->cpu_damage);
11921							list_del(&priv->flush_list);
11922							priv->clear = true;
11923							priv->clear_color = gc->alu == GXcopyInverted ? ~pixel & ((1 << gc->depth) - 1) : pixel;
11924
11925							DBG(("%s: pixmap=%ld, marking clear [%08x]\n",
11926							     __FUNCTION__, pixmap->drawable.serialNumber, priv->clear_color));
11927						}
11928					}
11929				}
11930				if (damage)
11931					sna_damage_add_box(damage, &r);
11932				assert_pixmap_damage(pixmap);
11933			} else
11934				success = false;
11935		}
11936
11937		return success;
11938	}
11939
11940	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_BOXES)) {
11941		DBG(("%s: unsupported blt\n", __FUNCTION__));
11942		return false;
11943	}
11944
11945	get_drawable_deltas(drawable, pixmap, &dx, &dy);
11946	if ((flags & IS_CLIPPED) == 0) {
11947		dx += drawable->x;
11948		dy += drawable->y;
11949
11950		sna_damage_add_rectangles(damage, rect, n, dx, dy);
11951		if (dx|dy) {
11952			do {
11953				unsigned nbox = n;
11954				if (nbox > ARRAY_SIZE(boxes))
11955					nbox = ARRAY_SIZE(boxes);
11956				n -= nbox;
11957				while (nbox >= 2) {
11958					b[0].x1 = rect[0].x + dx;
11959					b[0].y1 = rect[0].y + dy;
11960					b[0].x2 = b[0].x1 + rect[0].width;
11961					b[0].y2 = b[0].y1 + rect[0].height;
11962
11963					b[1].x1 = rect[1].x + dx;
11964					b[1].y1 = rect[1].y + dy;
11965					b[1].x2 = b[1].x1 + rect[1].width;
11966					b[1].y2 = b[1].y1 + rect[1].height;
11967
11968					b += 2;
11969					rect += 2;
11970					nbox -= 2;
11971				}
11972				if (nbox) {
11973					b->x1 = rect->x + dx;
11974					b->y1 = rect->y + dy;
11975					b->x2 = b->x1 + rect->width;
11976					b->y2 = b->y1 + rect->height;
11977					b++;
11978					rect++;
11979				}
11980				fill.boxes(sna, &fill, boxes, b-boxes);
11981				b = boxes;
11982			} while (n);
11983		} else {
11984			do {
11985				unsigned nbox = n;
11986				if (nbox > ARRAY_SIZE(boxes))
11987					nbox = ARRAY_SIZE(boxes);
11988				n -= nbox;
11989				while (nbox >= 2) {
11990					b[0].x1 = rect[0].x;
11991					b[0].y1 = rect[0].y;
11992					b[0].x2 = b[0].x1 + rect[0].width;
11993					b[0].y2 = b[0].y1 + rect[0].height;
11994
11995					b[1].x1 = rect[1].x;
11996					b[1].y1 = rect[1].y;
11997					b[1].x2 = b[1].x1 + rect[1].width;
11998					b[1].y2 = b[1].y1 + rect[1].height;
11999
12000					b += 2;
12001					rect += 2;
12002					nbox -= 2;
12003				}
12004				if (nbox) {
12005					b->x1 = rect->x;
12006					b->y1 = rect->y;
12007					b->x2 = b->x1 + rect->width;
12008					b->y2 = b->y1 + rect->height;
12009					b++;
12010					rect++;
12011				}
12012				fill.boxes(sna, &fill, boxes, b-boxes);
12013				b = boxes;
12014			} while (n);
12015		}
12016	} else {
12017		RegionRec clip;
12018
12019		region_set(&clip, extents);
12020		if (!region_maybe_clip(&clip, gc->pCompositeClip))
12021			goto done;
12022
12023		if (clip.data == NULL) {
12024			do {
12025				b->x1 = rect->x + drawable->x;
12026				b->y1 = rect->y + drawable->y;
12027				b->x2 = bound(b->x1, rect->width);
12028				b->y2 = bound(b->y1, rect->height);
12029				rect++;
12030
12031				if (box_intersect(b, &clip.extents)) {
12032					b->x1 += dx;
12033					b->x2 += dx;
12034					b->y1 += dy;
12035					b->y2 += dy;
12036					if (++b == last_box) {
12037						fill.boxes(sna, &fill, boxes, last_box-boxes);
12038						if (damage)
12039							sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
12040						b = boxes;
12041					}
12042				}
12043			} while (--n);
12044		} else {
12045			const BoxRec * const clip_start = RegionBoxptr(&clip);
12046			const BoxRec * const clip_end = clip_start + clip.data->numRects;
12047			const BoxRec *c;
12048
12049			do {
12050				BoxRec box;
12051
12052				box.x1 = rect->x + drawable->x;
12053				box.y1 = rect->y + drawable->y;
12054				box.x2 = bound(box.x1, rect->width);
12055				box.y2 = bound(box.y1, rect->height);
12056				rect++;
12057
12058				c = find_clip_box_for_y(clip_start,
12059							clip_end,
12060							box.y1);
12061				while (c != clip_end) {
12062					if (box.y2 <= c->y1)
12063						break;
12064
12065					*b = box;
12066					if (box_intersect(b, c++)) {
12067						b->x1 += dx;
12068						b->x2 += dx;
12069						b->y1 += dy;
12070						b->y2 += dy;
12071						if (++b == last_box) {
12072							fill.boxes(sna, &fill, boxes, last_box-boxes);
12073							if (damage)
12074								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
12075							b = boxes;
12076						}
12077					}
12078
12079				}
12080			} while (--n);
12081		}
12082
12083		RegionUninit(&clip);
12084		if (b != boxes) {
12085			fill.boxes(sna, &fill, boxes, b-boxes);
12086			if (damage)
12087				sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
12088		}
12089	}
12090done:
12091	fill.done(sna, &fill);
12092	assert_pixmap_damage(pixmap);
12093	return true;
12094}
12095
12096static uint32_t
12097get_pixel(PixmapPtr pixmap)
12098{
12099	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber));
12100	if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
12101		return 0;
12102
12103	switch (pixmap->drawable.bitsPerPixel) {
12104	case 32: return *(uint32_t *)pixmap->devPrivate.ptr;
12105	case 16: return *(uint16_t *)pixmap->devPrivate.ptr;
12106	default: return *(uint8_t *)pixmap->devPrivate.ptr;
12107	}
12108}
12109
12110inline static int
12111_use_fill_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags)
12112{
12113	if (USE_SPANS)
12114		return USE_SPANS > 0;
12115
12116	if (gc->fillStyle == FillTiled && !gc->tileIsPixel &&
12117	    sna_pixmap_is_gpu(gc->tile.pixmap)) {
12118		DBG(("%s: source is already on the gpu\n", __FUNCTION__));
12119		return PREFER_GPU | FORCE_GPU;
12120	}
12121
12122	return PREFER_GPU;
12123}
12124
12125static int
12126use_fill_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags)
12127{
12128	int ret = _use_fill_spans(drawable, gc, extents, flags);
12129	DBG(("%s? %d\n", __FUNCTION__, ret));
12130	return ret;
12131}
12132
12133static void
12134sna_poly_fill_polygon(DrawablePtr draw, GCPtr gc,
12135		      int shape, int mode,
12136		      int n, DDXPointPtr pt)
12137{
12138	struct sna_fill_spans data;
12139	struct sna_pixmap *priv;
12140
12141	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
12142	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
12143	     (gc->fillStyle == FillSolid ||
12144	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
12145	     gc->fillStyle, gc->tileIsPixel,
12146	     gc->alu));
12147	DBG(("%s: draw=%ld, offset=(%d, %d), size=%dx%d\n",
12148	     __FUNCTION__, draw->serialNumber,
12149	     draw->x, draw->y, draw->width, draw->height));
12150
12151	data.flags = sna_poly_point_extents(draw, gc, mode, n, pt,
12152					    &data.region.extents);
12153	if (data.flags == 0) {
12154		DBG(("%s, nothing to do\n", __FUNCTION__));
12155		return;
12156	}
12157
12158	DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
12159	     data.region.extents.x1, data.region.extents.y1,
12160	     data.region.extents.x2, data.region.extents.y2,
12161	     data.flags));
12162
12163	data.region.data = NULL;
12164
12165	if (FORCE_FALLBACK)
12166		goto fallback;
12167
12168	if (!ACCEL_POLY_FILL_POLYGON)
12169		goto fallback;
12170
12171	data.pixmap = get_drawable_pixmap(draw);
12172	data.sna = to_sna_from_pixmap(data.pixmap);
12173	priv = sna_pixmap(data.pixmap);
12174	if (priv == NULL) {
12175		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
12176		goto fallback;
12177	}
12178
12179	if (wedged(data.sna)) {
12180		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
12181		goto fallback;
12182	}
12183
12184	if (!PM_IS_SOLID(draw, gc->planemask))
12185		goto fallback;
12186
12187	if ((data.bo = sna_drawable_use_bo(draw,
12188					   use_fill_spans(draw, gc, &data.region.extents, data.flags),
12189					   &data.region.extents,
12190					   &data.damage))) {
12191		uint32_t color;
12192
12193		sna_gc(gc)->priv = &data;
12194		get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy);
12195
12196		if (gc_is_solid(gc, &color)) {
12197			struct sna_fill_op fill;
12198
12199			if (!sna_fill_init_blt(&fill,
12200					       data.sna, data.pixmap,
12201					       data.bo, gc->alu, color,
12202					       FILL_SPANS))
12203				goto fallback;
12204
12205			data.op = &fill;
12206
12207			if ((data.flags & IS_CLIPPED) == 0) {
12208				if (data.dx | data.dy)
12209					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
12210				else
12211					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
12212			} else {
12213				if (!region_maybe_clip(&data.region,
12214						       gc->pCompositeClip))
12215					return;
12216
12217				if (region_is_singular(&data.region))
12218					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
12219				else
12220					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
12221			}
12222			assert(gc->miTranslate);
12223			gc->ops = &sna_gc_ops__tmp;
12224
12225			miFillPolygon(draw, gc, shape, mode, n, pt);
12226			fill.done(data.sna, &fill);
12227		} else {
12228			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
12229			gc->ops = &sna_gc_ops__tmp;
12230
12231			miFillPolygon(draw, gc, shape, mode, n, pt);
12232		}
12233
12234		gc->ops = (GCOps *)&sna_gc_ops;
12235		if (data.damage) {
12236			if (data.dx | data.dy)
12237				pixman_region_translate(&data.region, data.dx, data.dy);
12238			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
12239			sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap);
12240		}
12241		assert_pixmap_damage(data.pixmap);
12242		RegionUninit(&data.region);
12243		return;
12244	}
12245
12246fallback:
12247	DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__,
12248	     data.region.extents.x1, data.region.extents.y1,
12249	     data.region.extents.x2, data.region.extents.y2));
12250	if (!region_maybe_clip(&data.region, gc->pCompositeClip)) {
12251		DBG(("%s: nothing to do, all clipped\n", __FUNCTION__));
12252		return;
12253	}
12254
12255	if (!sna_gc_move_to_cpu(gc, draw, &data.region))
12256		goto out;
12257	if (!sna_drawable_move_region_to_cpu(draw, &data.region,
12258					     drawable_gc_flags(draw, gc, true)))
12259		goto out;
12260
12261	if (sigtrap_get() == 0) {
12262		DBG(("%s: fallback -- miFillPolygon -> sna_fill_spans__cpu\n",
12263		     __FUNCTION__));
12264		miFillPolygon(draw, gc, shape, mode, n, pt);
12265		sigtrap_put();
12266	}
12267out:
12268	sna_gc_move_to_gpu(gc);
12269	RegionUninit(&data.region);
12270}
12271
12272static struct kgem_bo *
12273sna_pixmap_get_source_bo(PixmapPtr pixmap)
12274{
12275	struct sna_pixmap *priv = sna_pixmap(pixmap);
12276	unsigned flags;
12277	BoxRec box;
12278
12279	box.x1 = box.y1 = 0;
12280	box.x2 = pixmap->drawable.width;
12281	box.y2 = pixmap->drawable.height;
12282
12283	DBG(("%s(pixmap=%ld, size=%dx%d)\n", __FUNCTION__,
12284	     pixmap->drawable.serialNumber, pixmap->drawable.width, pixmap->drawable.height));
12285
12286	if (priv == NULL) {
12287		DBG(("%s: unattached, uploading data into temporary\n", __FUNCTION__));
12288		return kgem_upload_source_image(&to_sna_from_pixmap(pixmap)->kgem,
12289						pixmap->devPrivate.ptr, &box,
12290						pixmap->devKind,
12291						pixmap->drawable.bitsPerPixel);
12292	}
12293
12294	if (priv->gpu_damage) {
12295		if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT))
12296			return kgem_bo_reference(priv->gpu_bo);
12297	} else if (priv->cpu_damage) {
12298		if (priv->cpu_bo)
12299			return kgem_bo_reference(priv->cpu_bo);
12300	} else {
12301		if (priv->gpu_bo)
12302			return kgem_bo_reference(priv->gpu_bo);
12303		if (priv->cpu_bo)
12304			return kgem_bo_reference(priv->cpu_bo);
12305	}
12306
12307	flags = MOVE_READ | MOVE_ASYNC_HINT;
12308	if (priv->gpu_bo && priv->gpu_bo->proxy) {
12309		struct kgem_bo *bo = priv->gpu_bo;
12310		if (bo->rq == NULL && (bo->snoop || bo->pitch >= 4096))
12311			flags |= __MOVE_FORCE;
12312	}
12313	if (priv->gpu_bo == NULL) {
12314		if (++priv->source_count > SOURCE_BIAS)
12315			flags |= __MOVE_FORCE;
12316	}
12317
12318	if (!sna_pixmap_move_to_gpu(pixmap, flags)) {
12319		struct kgem_bo *upload;
12320
12321		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
12322			return NULL;
12323
12324		upload = kgem_upload_source_image(&to_sna_from_pixmap(pixmap)->kgem,
12325						  pixmap->devPrivate.ptr, &box,
12326						  pixmap->devKind,
12327						  pixmap->drawable.bitsPerPixel);
12328		if (upload == NULL)
12329			return NULL;
12330
12331		if (priv->gpu_bo == NULL) {
12332			DBG(("%s: adding upload cache to pixmap=%ld\n",
12333			     __FUNCTION__, pixmap->drawable.serialNumber));
12334			assert(upload->proxy != NULL);
12335			kgem_proxy_bo_attach(upload, &priv->gpu_bo);
12336		}
12337
12338		return upload;
12339	}
12340
12341	return kgem_bo_reference(priv->gpu_bo);
12342}
12343
12344/*
12345static bool
12346tile(DrawablePtr drawable,
12347	struct kgem_bo *bo, struct sna_damage **damage,
12348	PixmapPtr tile, const DDXPointRec * const origin, int alu,
12349	int n, xRectangle *rect,
12350	const BoxRec *extents, unsigned clipped)
12351	*/
12352
12353static bool
12354sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
12355				 struct kgem_bo *bo, struct sna_damage **damage,
12356				 struct kgem_bo *tile_bo, GCPtr gc,
12357				 int n, const xRectangle *r,
12358				 const BoxRec *extents, unsigned clipped)
12359{
12360	PixmapPtr pixmap = get_drawable_pixmap(drawable);
12361	struct sna *sna = to_sna_from_pixmap(pixmap);
12362	const DDXPointRec * const origin = &gc->patOrg;
12363	uint32_t br00, br13;
12364	int tx, ty;
12365	int16_t dx, dy;
12366	uint32_t *b;
12367
12368	if (NO_TILE_8x8)
12369		return false;
12370
12371	DBG(("%s x %d [(%d, %d)x(%d, %d)...], clipped=%x, origin=(%d, %d)\n",
12372	     __FUNCTION__, n, r->x, r->y, r->width, r->height, clipped, origin->x, origin->y));
12373
12374	DBG(("%s: tile_bo tiling=%d, pitch=%d\n", __FUNCTION__, tile_bo->tiling, tile_bo->pitch));
12375	if (tile_bo->tiling)
12376		return false;
12377
12378	if (!kgem_bo_can_blt(&sna->kgem, bo) ||
12379	    !kgem_bo_can_blt(&sna->kgem, tile_bo))
12380		return false;
12381
12382	assert(tile_bo->pitch == 8 * drawable->bitsPerPixel >> 3);
12383
12384	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
12385	assert(kgem_bo_can_blt(&sna->kgem, bo));
12386	if (!kgem_check_batch(&sna->kgem, 10+2*3) ||
12387	    !kgem_check_reloc(&sna->kgem, 2) ||
12388	    !kgem_check_many_bo_fenced(&sna->kgem, bo, tile_bo, NULL)) {
12389		kgem_submit(&sna->kgem);
12390		if (!kgem_check_many_bo_fenced(&sna->kgem, bo, tile_bo, NULL))
12391			return false;
12392		_kgem_set_mode(&sna->kgem, KGEM_BLT);
12393	}
12394	kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
12395
12396	get_drawable_deltas(drawable, pixmap, &dx, &dy);
12397	assert(extents->x1 + dx >= 0);
12398	assert(extents->y1 + dy >= 0);
12399	assert(extents->x2 + dx <= pixmap->drawable.width);
12400	assert(extents->y2 + dy <= pixmap->drawable.height);
12401
12402	br00 = XY_SCANLINE_BLT;
12403	tx = (-drawable->x - dx - origin->x) % 8;
12404	if (tx < 0)
12405		tx += 8;
12406	ty = (-drawable->y - dy - origin->y) % 8;
12407	if (ty < 0)
12408		ty += 8;
12409	br00 |= tx << 12 | ty << 8;
12410
12411	br13 = bo->pitch;
12412	if (sna->kgem.gen >= 040 && bo->tiling) {
12413		br00 |= BLT_DST_TILED;
12414		br13 >>= 2;
12415	}
12416	br13 |= blt_depth(drawable->depth) << 24;
12417	br13 |= fill_ROP[gc->alu] << 16;
12418
12419	if (!clipped) {
12420		dx += drawable->x;
12421		dy += drawable->y;
12422
12423		sna_damage_add_rectangles(damage, r, n, dx, dy);
12424		if (n == 1) {
12425			DBG(("%s: rect=(%d, %d)x(%d, %d) + (%d, %d), tile=(%d, %d)\n",
12426			     __FUNCTION__, r->x, r->y, r->width, r->height, dx, dy, tx, ty));
12427
12428			assert(r->x + dx >= 0);
12429			assert(r->y + dy >= 0);
12430			assert(r->x + dx + r->width  <= pixmap->drawable.width);
12431			assert(r->y + dy + r->height <= pixmap->drawable.height);
12432
12433			assert(sna->kgem.mode == KGEM_BLT);
12434			b = sna->kgem.batch + sna->kgem.nbatch;
12435			if (sna->kgem.gen >= 0100) {
12436				b[0] = XY_PAT_BLT | 3 << 20 | (br00 & 0x7f00) | 6;
12437				b[1] = br13;
12438				b[2] = (r->y + dy) << 16 | (r->x + dx);
12439				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
12440				*(uint64_t *)(b+4) =
12441					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12442							 I915_GEM_DOMAIN_RENDER << 16 |
12443							 I915_GEM_DOMAIN_RENDER |
12444							 KGEM_RELOC_FENCED,
12445							 0);
12446				*(uint64_t *)(b+6) =
12447					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, tile_bo,
12448							 I915_GEM_DOMAIN_RENDER << 16 |
12449							 KGEM_RELOC_FENCED,
12450							 0);
12451				sna->kgem.nbatch += 8;
12452			} else {
12453				b[0] = XY_PAT_BLT | 3 << 20 | (br00 & 0x7f00) | 4;
12454				b[1] = br13;
12455				b[2] = (r->y + dy) << 16 | (r->x + dx);
12456				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
12457				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12458						      I915_GEM_DOMAIN_RENDER << 16 |
12459						      I915_GEM_DOMAIN_RENDER |
12460						      KGEM_RELOC_FENCED,
12461						      0);
12462				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, tile_bo,
12463						      I915_GEM_DOMAIN_RENDER << 16 |
12464						      KGEM_RELOC_FENCED,
12465						      0);
12466				sna->kgem.nbatch += 6;
12467			}
12468		} else do {
12469			int n_this_time, rem;
12470
12471			assert(sna->kgem.mode == KGEM_BLT);
12472			b = sna->kgem.batch + sna->kgem.nbatch;
12473			if (sna->kgem.gen >= 0100) {
12474				b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
12475				b[1] = br13;
12476				b[2] = 0;
12477				b[3] = 0;
12478				*(uint64_t *)(b+4) =
12479					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12480							 I915_GEM_DOMAIN_RENDER << 16 |
12481							 I915_GEM_DOMAIN_RENDER |
12482							 KGEM_RELOC_FENCED,
12483							 0);
12484				b[6] = gc->bgPixel;
12485				b[7] = gc->fgPixel;
12486				*(uint64_t *)(b+8) =
12487					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo,
12488							 I915_GEM_DOMAIN_RENDER << 16 |
12489							 KGEM_RELOC_FENCED,
12490							 0);
12491				sna->kgem.nbatch += 10;
12492			} else {
12493				b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6;
12494				b[1] = br13;
12495				b[2] = 0;
12496				b[3] = 0;
12497				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12498						      I915_GEM_DOMAIN_RENDER << 16 |
12499						      I915_GEM_DOMAIN_RENDER |
12500						      KGEM_RELOC_FENCED,
12501						      0);
12502				b[5] = gc->bgPixel;
12503				b[6] = gc->fgPixel;
12504				b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
12505						      I915_GEM_DOMAIN_RENDER << 16 |
12506						      KGEM_RELOC_FENCED,
12507						      0);
12508				sna->kgem.nbatch += 8;
12509			}
12510
12511			n_this_time = n;
12512			rem = kgem_batch_space(&sna->kgem);
12513			if (3*n_this_time > rem)
12514				n_this_time = rem / 3;
12515			assert(n_this_time);
12516			n -= n_this_time;
12517
12518			assert(sna->kgem.mode == KGEM_BLT);
12519			b = sna->kgem.batch + sna->kgem.nbatch;
12520			sna->kgem.nbatch += 3*n_this_time;
12521			do {
12522				assert(r->x + dx >= 0);
12523				assert(r->y + dy >= 0);
12524				assert(r->x + dx + r->width  <= pixmap->drawable.width);
12525				assert(r->y + dy + r->height <= pixmap->drawable.height);
12526
12527				b[0] = br00;
12528				b[1] = (r->y + dy) << 16 | (r->x + dx);
12529				b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
12530				b += 3; r++;
12531			} while (--n_this_time);
12532
12533			if (!n)
12534				break;
12535
12536			_kgem_submit(&sna->kgem);
12537			_kgem_set_mode(&sna->kgem, KGEM_BLT);
12538			kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
12539		} while (1);
12540	} else {
12541		RegionRec clip;
12542		uint16_t unwind_batch, unwind_reloc;
12543
12544		region_set(&clip, extents);
12545		if (!region_maybe_clip(&clip, gc->pCompositeClip))
12546			goto done;
12547
12548		unwind_batch = sna->kgem.nbatch;
12549		unwind_reloc = sna->kgem.nreloc;
12550
12551		assert(sna->kgem.mode == KGEM_BLT);
12552		b = sna->kgem.batch + sna->kgem.nbatch;
12553		if (sna->kgem.gen >= 0100) {
12554			b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
12555			b[1] = br13;
12556			b[2] = 0;
12557			b[3] = 0;
12558			*(uint64_t *)(b+4) =
12559				kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12560						 I915_GEM_DOMAIN_RENDER << 16 |
12561						 I915_GEM_DOMAIN_RENDER |
12562						 KGEM_RELOC_FENCED,
12563						 0);
12564			b[6] = gc->bgPixel;
12565			b[7] = gc->fgPixel;
12566			*(uint64_t *)(b+8) =
12567				kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo,
12568						 I915_GEM_DOMAIN_RENDER << 16 |
12569						 KGEM_RELOC_FENCED,
12570						 0);
12571			sna->kgem.nbatch += 10;
12572		} else {
12573			b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6;
12574			b[1] = br13;
12575			b[2] = 0;
12576			b[3] = 0;
12577			b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12578					      I915_GEM_DOMAIN_RENDER << 16 |
12579					      I915_GEM_DOMAIN_RENDER |
12580					      KGEM_RELOC_FENCED,
12581					      0);
12582			b[5] = gc->bgPixel;
12583			b[6] = gc->fgPixel;
12584			b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
12585					      I915_GEM_DOMAIN_RENDER << 16 |
12586					      KGEM_RELOC_FENCED,
12587					      0);
12588			sna->kgem.nbatch += 8;
12589		}
12590
12591		if (clip.data == NULL) {
12592			const BoxRec *c = &clip.extents;
12593			DBG(("%s: simple clip, %d boxes\n", __FUNCTION__, n));
12594			while (n--) {
12595				BoxRec box;
12596
12597				box.x1 = r->x + drawable->x;
12598				box.y1 = r->y + drawable->y;
12599				box.x2 = bound(box.x1, r->width);
12600				box.y2 = bound(box.y1, r->height);
12601				r++;
12602
12603				if (box_intersect(&box, c)) {
12604					if (!kgem_check_batch(&sna->kgem, 3)) {
12605						_kgem_submit(&sna->kgem);
12606						_kgem_set_mode(&sna->kgem, KGEM_BLT);
12607						kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
12608
12609						unwind_batch = sna->kgem.nbatch;
12610						unwind_reloc = sna->kgem.nreloc;
12611
12612						assert(sna->kgem.mode == KGEM_BLT);
12613						b = sna->kgem.batch + sna->kgem.nbatch;
12614						if (sna->kgem.gen >= 0100) {
12615							b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
12616							b[1] = br13;
12617							b[2] = 0;
12618							b[3] = 0;
12619							*(uint64_t *)(b+4) =
12620								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12621										 I915_GEM_DOMAIN_RENDER << 16 |
12622										 I915_GEM_DOMAIN_RENDER |
12623										 KGEM_RELOC_FENCED,
12624										 0);
12625							b[6] = gc->bgPixel;
12626							b[7] = gc->fgPixel;
12627							*(uint64_t *)(b+8) =
12628								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo,
12629										 I915_GEM_DOMAIN_RENDER << 16 |
12630										 KGEM_RELOC_FENCED,
12631										 0);
12632							sna->kgem.nbatch += 10;
12633						} else {
12634							b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6;
12635							b[1] = br13;
12636							b[2] = 0;
12637							b[3] = 0;
12638							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12639									      I915_GEM_DOMAIN_RENDER << 16 |
12640									      I915_GEM_DOMAIN_RENDER |
12641									      KGEM_RELOC_FENCED,
12642									      0);
12643							b[5] = gc->bgPixel;
12644							b[6] = gc->fgPixel;
12645							b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
12646									      I915_GEM_DOMAIN_RENDER << 16 |
12647									      KGEM_RELOC_FENCED,
12648									      0);
12649							sna->kgem.nbatch += 8;
12650						}
12651					}
12652
12653					assert(box.x1 + dx >= 0);
12654					assert(box.y1 + dy >= 0);
12655					assert(box.x2 + dx <= pixmap->drawable.width);
12656					assert(box.y2 + dy <= pixmap->drawable.height);
12657
12658					DBG(("%s: box=(%d, %d),(%d, %d) + (%d, %d), tile=(%d, %d)\n",
12659					     __FUNCTION__, box.x1, box.y1, box.x2, box.y2, dx, dy, tx, ty));
12660
12661					assert(sna->kgem.mode == KGEM_BLT);
12662					b = sna->kgem.batch + sna->kgem.nbatch;
12663					b[0] = br00;
12664					b[1] = (box.y1 + dy) << 16 | (box.x1 + dx);
12665					b[2] = (box.y2 + dy) << 16 | (box.x2 + dx);
12666					sna->kgem.nbatch += 3;
12667				}
12668			}
12669		} else {
12670			const BoxRec * const clip_start = RegionBoxptr(&clip);
12671			const BoxRec * const clip_end = clip_start + clip.data->numRects;
12672			const BoxRec *c;
12673
12674			DBG(("%s: complex clip (%ld cliprects), %d boxes\n", __FUNCTION__, (long)clip.data->numRects, n));
12675			do {
12676				BoxRec box;
12677
12678				box.x1 = r->x + drawable->x;
12679				box.y1 = r->y + drawable->y;
12680				box.x2 = bound(box.x1, r->width);
12681				box.y2 = bound(box.y1, r->height);
12682				DBG(("%s: rect=(%d, %d), (%d, %d), box=(%d, %d), (%d, %d)\n", __FUNCTION__,
12683				     r->x, r->y, r->width, r->height,
12684				     box.x1, box.y1, box.x2, box.y2));
12685				r++;
12686
12687				c = find_clip_box_for_y(clip_start,
12688							clip_end,
12689							box.y1);
12690				while (c != clip_end) {
12691					BoxRec bb;
12692
12693					DBG(("%s: clip=(%d, %d), (%d, %d)\n", __FUNCTION__, c->x1, c->y1, c->x2, c->y2));
12694
12695					if (box.y2 <= c->y1)
12696						break;
12697
12698					bb = box;
12699					if (box_intersect(&bb, c++)) {
12700						if (!kgem_check_batch(&sna->kgem, 3)) {
12701							DBG(("%s: emitting split batch\n", __FUNCTION__));
12702							_kgem_submit(&sna->kgem);
12703							_kgem_set_mode(&sna->kgem, KGEM_BLT);
12704							kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
12705
12706							unwind_batch = sna->kgem.nbatch;
12707							unwind_reloc = sna->kgem.nreloc;
12708
12709							assert(sna->kgem.mode == KGEM_BLT);
12710							b = sna->kgem.batch + sna->kgem.nbatch;
12711							if (sna->kgem.gen >= 0100) {
12712								b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
12713								b[1] = br13;
12714								b[2] = 0;
12715								b[3] = 0;
12716								*(uint64_t *)(b+4) =
12717									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12718											 I915_GEM_DOMAIN_RENDER << 16 |
12719											 I915_GEM_DOMAIN_RENDER |
12720											 KGEM_RELOC_FENCED,
12721											 0);
12722								b[6] = gc->bgPixel;
12723								b[7] = gc->fgPixel;
12724								*(uint64_t *)(b+8) =
12725									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo,
12726											 I915_GEM_DOMAIN_RENDER << 16 |
12727											 KGEM_RELOC_FENCED,
12728											 0);
12729								sna->kgem.nbatch += 10;
12730							} else {
12731								b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6;
12732								b[1] = br13;
12733								b[2] = 0;
12734								b[3] = 0;
12735								b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12736										      I915_GEM_DOMAIN_RENDER << 16 |
12737										      I915_GEM_DOMAIN_RENDER |
12738										      KGEM_RELOC_FENCED,
12739										      0);
12740								b[5] = gc->bgPixel;
12741								b[6] = gc->fgPixel;
12742								b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
12743										      I915_GEM_DOMAIN_RENDER << 16 |
12744										      KGEM_RELOC_FENCED,
12745										      0);
12746								sna->kgem.nbatch += 8;
12747							}
12748						}
12749
12750						assert(bb.x1 + dx >= 0);
12751						assert(bb.y1 + dy >= 0);
12752						assert(bb.x2 + dx <= pixmap->drawable.width);
12753						assert(bb.y2 + dy <= pixmap->drawable.height);
12754
12755						DBG(("%s: emit box=(%d, %d),(%d, %d) + (%d, %d), tile=(%d, %d) [relative to drawable: (%d, %d)]\n",
12756						     __FUNCTION__, bb.x1, bb.y1, bb.x2, bb.y2, dx, dy, tx, ty, bb.x1 - drawable->x, bb.y1 - drawable->y));
12757
12758						assert(sna->kgem.mode == KGEM_BLT);
12759						b = sna->kgem.batch + sna->kgem.nbatch;
12760						b[0] = br00;
12761						b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx);
12762						b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx);
12763						sna->kgem.nbatch += 3;
12764					}
12765				}
12766			} while (--n);
12767		}
12768
12769		if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) {
12770			sna->kgem.nbatch = unwind_batch;
12771			sna->kgem.nreloc = unwind_reloc;
12772			if (sna->kgem.nbatch == 0)
12773				kgem_bo_pair_undo(&sna->kgem, bo, tile_bo);
12774		}
12775	}
12776done:
12777	assert_pixmap_damage(pixmap);
12778	blt_done(sna);
12779	return true;
12780}
12781
12782static bool tile8(int x)
12783{
12784	switch(x) {
12785	case 1:
12786	case 2:
12787	case 4:
12788	case 8:
12789		return true;
12790	default:
12791		return false;
12792	}
12793}
12794
12795static int next8(int x, int max)
12796{
12797	if (x > 2 && x <= 4)
12798		x = 4;
12799	else if (x < 8)
12800		x = 8;
12801	return MIN(x, max);
12802}
12803
12804static bool
12805sna_poly_fill_rect_tiled_nxm_blt(DrawablePtr drawable,
12806				 struct kgem_bo *bo,
12807				 struct sna_damage **damage,
12808				 GCPtr gc, int n, const xRectangle *rect,
12809				 const BoxRec *extents, unsigned clipped)
12810{
12811	PixmapPtr pixmap = get_drawable_pixmap(drawable);
12812	struct sna *sna = to_sna_from_pixmap(pixmap);
12813	PixmapPtr tile = gc->tile.pixmap;
12814	int w, h, tx, ty, tw, th, bpp = tile->drawable.bitsPerPixel;
12815	const DDXPointRec origin = gc->patOrg;
12816	struct kgem_bo *upload;
12817	bool ret = false;
12818	uint8_t *src;
12819	void *ptr;
12820
12821	tx = 0, tw = tile->drawable.width;
12822	if (!tile8(tw) && tw > extents->x2 - extents->x1) {
12823		tx = (extents->x1 - gc->patOrg.x - drawable->x) % tw;
12824		if (tx < 0)
12825			tx += tw;
12826		tw = next8(extents->x2 - extents->x1, tw);
12827		gc->patOrg.x = extents->x1 - drawable->x;
12828	}
12829
12830	ty = 0, th = tile->drawable.height;
12831	if (!tile8(th) && th > extents->y2 - extents->y1) {
12832		ty = (extents->y1 - gc->patOrg.y - drawable->y) % th;
12833		if (ty < 0)
12834			ty += th;
12835		th = next8(extents->y2 - extents->y1, th);
12836		gc->patOrg.y = extents->y1 - drawable->y;
12837	}
12838
12839	DBG(("%s: %dx%d+%d+%d (full tile size %dx%d)\n", __FUNCTION__,
12840	     tw, th, tx, ty, tile->drawable.width, tile->drawable.height));
12841	assert(tx < tile->drawable.width && tx >= 0);
12842	assert(ty < tile->drawable.height && ty >= 0);
12843	assert(tw && tw <= 8 && tw <= tile->drawable.width);
12844	assert(is_power_of_two(tw));
12845	assert(th && th <= 8 && th <= tile->drawable.height);
12846	assert(is_power_of_two(th));
12847
12848	if (!sna_pixmap_move_to_cpu(tile, MOVE_READ))
12849		goto out_gc;
12850
12851	assert(tile->devKind);
12852	assert(has_coherent_ptr(sna, sna_pixmap(tile), MOVE_READ));
12853
12854	src = tile->devPrivate.ptr;
12855	src += tile->devKind * ty;
12856	src += tx * bpp/8;
12857
12858	if ((tw | th) == 1) {
12859		uint32_t pixel;
12860		switch (bpp) {
12861			case 32: pixel = *(uint32_t *)src; break;
12862			case 16: pixel = *(uint16_t *)src; break;
12863			default: pixel = *(uint8_t *)src; break;
12864		}
12865		return sna_poly_fill_rect_blt(drawable, bo, damage,
12866					      gc, pixel, n, rect,
12867					      extents, clipped);
12868	}
12869
12870	upload = kgem_create_buffer(&sna->kgem, 8*bpp, KGEM_BUFFER_WRITE, &ptr);
12871	if (upload == NULL)
12872		goto out_gc;
12873
12874	upload->pitch = bpp; /* for sanity checks */
12875
12876	if (sigtrap_get() == 0) {
12877		uint8_t *dst = ptr;
12878		if (tx + tw > tile->drawable.width ||
12879		    ty + th > tile->drawable.height) {
12880			int sy = ty;
12881			src = tile->devPrivate.ptr;
12882			for (h = 0; h < th; h++) {
12883				int sx = tx;
12884				for (w = 0; w < tw; w++) {
12885					memcpy(dst + w*bpp/8, src + sy * tile->devKind + sx*bpp/8, bpp/8);
12886					if (++sx == tile->drawable.width)
12887						sx = 0;
12888				}
12889				w *= bpp/8;
12890				while (w < bpp) {
12891					memcpy(dst+w, dst, w);
12892					w *= 2;
12893				}
12894				if (++sy == tile->drawable.height)
12895					sy = 0;
12896				dst += bpp;
12897			}
12898			while (h < 8) {
12899				memcpy(dst, ptr, bpp*h);
12900				dst += bpp * h;
12901				h *= 2;
12902			}
12903		} else {
12904			for (h = 0; h < th; h++) {
12905				w = tw*bpp/8;
12906				memcpy(dst, src, w);
12907				while (w < bpp) {
12908					memcpy(dst+w, dst, w);
12909					w *= 2;
12910				}
12911				assert(w == bpp);
12912
12913				src += tile->devKind;
12914				dst += bpp;
12915			}
12916			while (h < 8) {
12917				memcpy(dst, ptr, bpp*h);
12918				dst += bpp * h;
12919				h *= 2;
12920			}
12921			assert(h == 8);
12922		}
12923
12924		ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage,
12925						       upload, gc, n, rect,
12926						       extents, clipped);
12927		sigtrap_put();
12928	}
12929
12930	kgem_bo_destroy(&sna->kgem, upload);
12931out_gc:
12932	gc->patOrg = origin;
12933	return ret;
12934}
12935
12936inline static bool tile_is_solid(GCPtr gc, uint32_t *pixel)
12937{
12938	PixmapPtr tile = gc->tile.pixmap;
12939	struct sna_pixmap *priv;
12940
12941	if ((tile->drawable.width | tile->drawable.height) == 1) {
12942		DBG(("%s: single pixel tile pixmap, converting to solid fill\n", __FUNCTION__));
12943		*pixel = get_pixel(tile);
12944		return true;
12945	}
12946
12947	priv = sna_pixmap(tile);
12948	if (priv == NULL || !priv->clear)
12949		return false;
12950
12951	DBG(("%s: tile is clear, converting to solid fill\n", __FUNCTION__));
12952	*pixel = priv->clear_color;
12953	return true;
12954}
12955
12956static bool
12957sna_poly_fill_rect_tiled_blt(DrawablePtr drawable,
12958			     struct kgem_bo *bo,
12959			     struct sna_damage **damage,
12960			     GCPtr gc, int n, xRectangle *rect,
12961			     const BoxRec *extents, unsigned clipped)
12962{
12963	PixmapPtr pixmap = get_drawable_pixmap(drawable);
12964	struct sna *sna = to_sna_from_pixmap(pixmap);
12965	PixmapPtr tile = gc->tile.pixmap;
12966	struct kgem_bo *tile_bo;
12967	const DDXPointRec * const origin = &gc->patOrg;
12968	struct sna_copy_op copy;
12969	CARD32 alu = gc->alu;
12970	int tile_width, tile_height;
12971	int16_t dx, dy;
12972	uint32_t pixel;
12973
12974	DBG(("%s pixmap=%ld, x %d [(%d, %d)x(%d, %d)...], clipped? %d\n",
12975	     __FUNCTION__, pixmap->drawable.serialNumber,
12976	     n, rect->x, rect->y, rect->width, rect->height,
12977	     clipped));
12978
12979	assert(tile->drawable.depth == drawable->depth);
12980	assert(bo);
12981
12982	if (tile_is_solid(gc, &pixel))
12983		return sna_poly_fill_rect_blt(drawable, bo, damage,
12984					      gc, pixel,
12985					      n, rect,
12986					      extents, clipped);
12987
12988	/* XXX [248]x[238] tiling can be reduced to a pattern fill.
12989	 * Also we can do the lg2 reduction for BLT and use repeat modes for
12990	 * RENDER.
12991	 */
12992
12993	tile_width = tile->drawable.width;
12994	tile_height = tile->drawable.height;
12995	if ((tile_width | tile_height) == 8) {
12996		bool ret;
12997
12998		DBG(("%s: have 8x8 tile, using BLT fast path\n", __FUNCTION__));
12999
13000		tile_bo = sna_pixmap_get_source_bo(tile);
13001		if (tile_bo == NULL) {
13002			DBG(("%s: unable to move tile go GPU, fallback\n",
13003			     __FUNCTION__));
13004			return false;
13005		}
13006
13007		ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage,
13008						       tile_bo, gc, n, rect,
13009						       extents, clipped);
13010		if (ret) {
13011			kgem_bo_destroy(&sna->kgem, tile_bo);
13012			return true;
13013		}
13014	} else {
13015		int w = tile_width, h = tile_height;
13016		struct sna_pixmap *priv = sna_pixmap(tile);
13017
13018		if (priv == NULL || priv->gpu_damage == NULL) {
13019			w = next8(extents->x2 - extents->x1, w);
13020			h = next8(extents->y2 - extents->y1, h);
13021		}
13022
13023		DBG(("%s: not 8x8, triming size for tile: %dx%d from %dx%d (area %dx%d)\n",
13024		     __FUNCTION__, w, h, tile_width, tile_height, extents->x2-extents->x1, extents->y2-extents->y1));
13025
13026		if ((w|h) < 0x10 && is_power_of_two(w) && is_power_of_two(h) &&
13027		    sna_poly_fill_rect_tiled_nxm_blt(drawable, bo, damage,
13028						     gc, n, rect,
13029						     extents, clipped))
13030			return true;
13031
13032		tile_bo = sna_pixmap_get_source_bo(tile);
13033		if (tile_bo == NULL) {
13034			DBG(("%s: unable to move tile go GPU, fallback\n",
13035						__FUNCTION__));
13036			return false;
13037		}
13038	}
13039
13040	if (!sna_copy_init_blt(&copy, sna, tile, tile_bo, pixmap, bo, alu)) {
13041		DBG(("%s: unsupported blt\n", __FUNCTION__));
13042		kgem_bo_destroy(&sna->kgem, tile_bo);
13043		return false;
13044	}
13045
13046	get_drawable_deltas(drawable, pixmap, &dx, &dy);
13047	DBG(("%s: drawable offset into pixmap(%ld) = (%d, %d)\n",
13048	     __FUNCTION__, pixmap->drawable.serialNumber, dx, dy));
13049	if (!clipped) {
13050		dx += drawable->x;
13051		dy += drawable->y;
13052
13053		sna_damage_add_rectangles(damage, rect, n, dx, dy);
13054		do {
13055			xRectangle r = *rect++;
13056			int16_t tile_y = (r.y - origin->y) % tile_height;
13057			if (tile_y < 0)
13058				tile_y += tile_height;
13059
13060			assert(r.x + dx >= 0);
13061			assert(r.y + dy >= 0);
13062			assert(r.x + dx + r.width  <= pixmap->drawable.width);
13063			assert(r.y + dy + r.height <= pixmap->drawable.height);
13064
13065			r.y += dy;
13066			do {
13067				int16_t width = r.width;
13068				int16_t x = r.x + dx, tile_x;
13069				int16_t h = tile_height - tile_y;
13070				if (h > r.height)
13071					h = r.height;
13072				r.height -= h;
13073
13074				tile_x = (r.x - origin->x) % tile_width;
13075				if (tile_x < 0)
13076					tile_x += tile_width;
13077
13078				do {
13079					int16_t w = tile_width - tile_x;
13080					if (w > width)
13081						w = width;
13082					width -= w;
13083
13084					copy.blt(sna, &copy,
13085						 tile_x, tile_y,
13086						 w, h,
13087						 x, r.y);
13088
13089					x += w;
13090					tile_x = 0;
13091				} while (width);
13092				r.y += h;
13093				tile_y = 0;
13094			} while (r.height);
13095		} while (--n);
13096	} else {
13097		RegionRec clip;
13098
13099		region_set(&clip, extents);
13100		if (!region_maybe_clip(&clip, gc->pCompositeClip))
13101			goto done;
13102
13103		if (clip.data == NULL) {
13104			const BoxRec *box = &clip.extents;
13105			DBG(("%s: single clip box [(%d, %d), (%d, %d)]\n",
13106			     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
13107			while (n--) {
13108				BoxRec r;
13109
13110				r.x1 = rect->x + drawable->x;
13111				r.y1 = rect->y + drawable->y;
13112				r.x2 = bound(r.x1, rect->width);
13113				r.y2 = bound(r.y1, rect->height);
13114				rect++;
13115
13116				DBG(("%s: rectangle [(%d, %d), (%d, %d)]\n",
13117				     __FUNCTION__, r.x1, r.y1, r.x2, r.y2));
13118
13119				if (box_intersect(&r, box)) {
13120					int height = r.y2 - r.y1;
13121					int dst_y = r.y1;
13122					int tile_y = (r.y1 - drawable->y - origin->y) % tile_height;
13123					if (tile_y < 0)
13124						tile_y += tile_height;
13125
13126					assert(r.x1 + dx >= 0);
13127					assert(r.y1 + dy >= 0);
13128					assert(r.x2 + dx <= pixmap->drawable.width);
13129					assert(r.y2 + dy <= pixmap->drawable.height);
13130
13131					while (height) {
13132						int width = r.x2 - r.x1;
13133						int dst_x = r.x1, tile_x;
13134						int h = tile_height - tile_y;
13135						if (h > height)
13136							h = height;
13137						height -= h;
13138
13139						tile_x = (r.x1 - drawable->x - origin->x) % tile_width;
13140						if (tile_x < 0)
13141							tile_x += tile_width;
13142
13143						while (width > 0) {
13144							int w = tile_width - tile_x;
13145							if (w > width)
13146								w = width;
13147							width -= w;
13148
13149							copy.blt(sna, &copy,
13150								 tile_x, tile_y,
13151								 w, h,
13152								 dst_x + dx, dst_y + dy);
13153							if (damage) {
13154								BoxRec b;
13155
13156								b.x1 = dst_x + dx;
13157								b.y1 = dst_y + dy;
13158								b.x2 = b.x1 + w;
13159								b.y2 = b.y1 + h;
13160
13161								assert_pixmap_contains_box(pixmap, &b);
13162								sna_damage_add_box(damage, &b);
13163							}
13164
13165							dst_x += w;
13166							tile_x = 0;
13167						}
13168						dst_y += h;
13169						tile_y = 0;
13170					}
13171				}
13172			}
13173		} else {
13174			while (n--) {
13175				RegionRec region;
13176				const BoxRec *box;
13177				int nbox;
13178
13179				region.extents.x1 = rect->x + drawable->x;
13180				region.extents.y1 = rect->y + drawable->y;
13181				region.extents.x2 = bound(region.extents.x1, rect->width);
13182				region.extents.y2 = bound(region.extents.y1, rect->height);
13183				rect++;
13184
13185				DBG(("%s: rectangle [(%d, %d), (%d, %d)]\n",
13186				     __FUNCTION__,
13187				     region.extents.x1,
13188				     region.extents.y1,
13189				     region.extents.x2,
13190				     region.extents.y2));
13191
13192				region.data = NULL;
13193				RegionIntersect(&region, &region, &clip);
13194
13195				assert(region.extents.x1 + dx >= 0);
13196				assert(region.extents.y1 + dy >= 0);
13197				assert(region.extents.x2 + dx <= pixmap->drawable.width);
13198				assert(region.extents.y2 + dy <= pixmap->drawable.height);
13199
13200				nbox = region_num_rects(&region);
13201				box = region_rects(&region);
13202				DBG(("%s: split into %d boxes after clipping\n", __FUNCTION__, nbox));
13203				while (nbox--) {
13204					int height = box->y2 - box->y1;
13205					int dst_y = box->y1;
13206					int tile_y = (box->y1 - drawable->y - origin->y) % tile_height;
13207					if (tile_y < 0)
13208						tile_y += tile_height;
13209
13210					while (height) {
13211						int width = box->x2 - box->x1;
13212						int dst_x = box->x1, tile_x;
13213						int h = tile_height - tile_y;
13214						if (h > height)
13215							h = height;
13216						height -= h;
13217
13218						tile_x = (box->x1 - drawable->x - origin->x) % tile_width;
13219						if (tile_x < 0)
13220							tile_x += tile_width;
13221
13222						while (width > 0) {
13223							int w = tile_width - tile_x;
13224							if (w > width)
13225								w = width;
13226							width -= w;
13227
13228							copy.blt(sna, &copy,
13229								 tile_x, tile_y,
13230								 w, h,
13231								 dst_x + dx, dst_y + dy);
13232							if (damage) {
13233								BoxRec b;
13234
13235								b.x1 = dst_x + dx;
13236								b.y1 = dst_y + dy;
13237								b.x2 = b.x1 + w;
13238								b.y2 = b.y1 + h;
13239
13240								assert_pixmap_contains_box(pixmap, &b);
13241								sna_damage_add_box(damage, &b);
13242							}
13243
13244							dst_x += w;
13245							tile_x = 0;
13246						}
13247						dst_y += h;
13248						tile_y = 0;
13249					}
13250					box++;
13251				}
13252
13253				RegionUninit(&region);
13254			}
13255		}
13256
13257		RegionUninit(&clip);
13258	}
13259done:
13260	copy.done(sna, &copy);
13261	assert_pixmap_damage(pixmap);
13262	kgem_bo_destroy(&sna->kgem, tile_bo);
13263	return true;
13264}
13265
13266static bool
13267sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
13268				    struct kgem_bo *bo,
13269				    struct sna_damage **damage,
13270				    GCPtr gc, int n, xRectangle *r,
13271				    const BoxRec *extents, unsigned clipped)
13272{
13273	PixmapPtr pixmap = get_drawable_pixmap(drawable);
13274	struct sna *sna = to_sna_from_pixmap(pixmap);
13275	uint32_t pat[2] = {0, 0}, br00, br13;
13276	int16_t dx, dy;
13277	uint32_t *b;
13278
13279	if (NO_STIPPLE_8x8)
13280		return false;
13281
13282	DBG(("%s: alu=%d, upload (%d, %d), (%d, %d), origin (%d, %d)\n",
13283	     __FUNCTION__, gc->alu,
13284	     extents->x1, extents->y1,
13285	     extents->x2, extents->y2,
13286	     gc->patOrg.x, gc->patOrg.y));
13287
13288	get_drawable_deltas(drawable, pixmap, &dx, &dy);
13289	{
13290		int px, py;
13291
13292		px = (0 - gc->patOrg.x - drawable->x - dx) % 8;
13293		if (px < 0)
13294			px += 8;
13295
13296		py = (0 - gc->patOrg.y - drawable->y - dy) % 8;
13297		if (py < 0)
13298			py += 8;
13299		DBG(("%s: pat offset (%d, %d)\n", __FUNCTION__ ,px, py));
13300
13301		br00 = XY_SCANLINE_BLT | px << 12 | py << 8 | 3 << 20;
13302		br13 = bo->pitch;
13303		if (sna->kgem.gen >= 040 && bo->tiling) {
13304			br00 |= BLT_DST_TILED;
13305			br13 >>= 2;
13306		}
13307		br13 |= (gc->fillStyle == FillStippled) << 28;
13308		br13 |= blt_depth(drawable->depth) << 24;
13309		br13 |= fill_ROP[gc->alu] << 16;
13310	}
13311
13312	assert(gc->stipple->devKind);
13313	{
13314		uint8_t *dst = (uint8_t *)pat;
13315		const uint8_t *src = gc->stipple->devPrivate.ptr;
13316		int stride = gc->stipple->devKind;
13317		int j = gc->stipple->drawable.height;
13318		do {
13319			*dst++ = byte_reverse(*src);
13320			src += stride;
13321		} while (--j);
13322	}
13323
13324	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
13325	assert(kgem_bo_can_blt(&sna->kgem, bo));
13326	if (!kgem_check_batch(&sna->kgem, 10 + 2*3) ||
13327	    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13328	    !kgem_check_reloc(&sna->kgem, 1)) {
13329		kgem_submit(&sna->kgem);
13330		if (!kgem_check_bo_fenced(&sna->kgem, bo))
13331			return false;
13332		_kgem_set_mode(&sna->kgem, KGEM_BLT);
13333	}
13334	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
13335
13336	if (!clipped) {
13337		dx += drawable->x;
13338		dy += drawable->y;
13339
13340		sna_damage_add_rectangles(damage, r, n, dx, dy);
13341		if (n == 1) {
13342			DBG(("%s: single unclipped rect (%d, %d)x(%d, %d)\n",
13343			     __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height));
13344
13345			assert(sna->kgem.mode == KGEM_BLT);
13346			b = sna->kgem.batch + sna->kgem.nbatch;
13347			if (sna->kgem.gen >= 0100) {
13348				b[0] = XY_MONO_PAT | (br00 & 0x7f00) | 3<<20 | 8;
13349				b[1] = br13;
13350				b[2] = (r->y + dy) << 16 | (r->x + dx);
13351				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13352				*(uint64_t *)(b+4) =
13353					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13354							 I915_GEM_DOMAIN_RENDER << 16 |
13355							 I915_GEM_DOMAIN_RENDER |
13356							 KGEM_RELOC_FENCED,
13357							 0);
13358				b[6] = gc->bgPixel;
13359				b[7] = gc->fgPixel;
13360				b[8] = pat[0];
13361				b[9] = pat[1];
13362				sna->kgem.nbatch += 10;
13363			} else {
13364				b[0] = XY_MONO_PAT | (br00 & 0x7f00) | 3<<20 | 7;
13365				b[1] = br13;
13366				b[2] = (r->y + dy) << 16 | (r->x + dx);
13367				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13368				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13369						      I915_GEM_DOMAIN_RENDER << 16 |
13370						      I915_GEM_DOMAIN_RENDER |
13371						      KGEM_RELOC_FENCED,
13372						      0);
13373				b[5] = gc->bgPixel;
13374				b[6] = gc->fgPixel;
13375				b[7] = pat[0];
13376				b[8] = pat[1];
13377				sna->kgem.nbatch += 9;
13378			}
13379		} else do {
13380			int n_this_time, rem;
13381
13382			assert(sna->kgem.mode == KGEM_BLT);
13383			b = sna->kgem.batch + sna->kgem.nbatch;
13384			if (sna->kgem.gen >= 0100) {
13385				b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
13386				b[1] = br13;
13387				b[2] = 0;
13388				b[3] = 0;
13389				*(uint64_t *)(b+4) =
13390					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13391							 I915_GEM_DOMAIN_RENDER << 16 |
13392							 I915_GEM_DOMAIN_RENDER |
13393							 KGEM_RELOC_FENCED,
13394							 0);
13395				b[6] = gc->bgPixel;
13396				b[7] = gc->fgPixel;
13397				b[8] = pat[0];
13398				b[9] = pat[1];
13399				sna->kgem.nbatch += 10;
13400			} else {
13401				b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7;
13402				b[1] = br13;
13403				b[2] = 0;
13404				b[3] = 0;
13405				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13406						      I915_GEM_DOMAIN_RENDER << 16 |
13407						      I915_GEM_DOMAIN_RENDER |
13408						      KGEM_RELOC_FENCED,
13409						      0);
13410				b[5] = gc->bgPixel;
13411				b[6] = gc->fgPixel;
13412				b[7] = pat[0];
13413				b[8] = pat[1];
13414				sna->kgem.nbatch += 9;
13415			}
13416
13417			n_this_time = n;
13418			rem = kgem_batch_space(&sna->kgem);
13419			if (3*n_this_time > rem)
13420				n_this_time = rem / 3;
13421			assert(n_this_time);
13422			n -= n_this_time;
13423
13424			assert(sna->kgem.mode == KGEM_BLT);
13425			b = sna->kgem.batch + sna->kgem.nbatch;
13426			sna->kgem.nbatch += 3 * n_this_time;
13427			do {
13428				DBG(("%s: rect (%d, %d)x(%d, %d)\n",
13429				     __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height));
13430				assert(r->x + dx >= 0);
13431				assert(r->y + dy >= 0);
13432				assert(r->x + dx + r->width  <= pixmap->drawable.width);
13433				assert(r->y + dy + r->height <= pixmap->drawable.height);
13434
13435				b[0] = br00;
13436				b[1] = (r->y + dy) << 16 | (r->x + dx);
13437				b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13438
13439				b += 3; r++;
13440			} while(--n_this_time);
13441
13442			if (!n)
13443				break;
13444
13445			_kgem_submit(&sna->kgem);
13446			_kgem_set_mode(&sna->kgem, KGEM_BLT);
13447			kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
13448		} while (1);
13449	} else {
13450		RegionRec clip;
13451
13452		region_set(&clip, extents);
13453		if (!region_maybe_clip(&clip, gc->pCompositeClip))
13454			return true;
13455
13456		assert(sna->kgem.mode == KGEM_BLT);
13457		b = sna->kgem.batch + sna->kgem.nbatch;
13458		if (sna->kgem.gen >= 0100) {
13459			b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
13460			b[1] = br13;
13461			b[2] = 0;
13462			b[3] = 0;
13463			*(uint64_t *)(b+4) =
13464				kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13465						 I915_GEM_DOMAIN_RENDER << 16 |
13466						 I915_GEM_DOMAIN_RENDER |
13467						 KGEM_RELOC_FENCED,
13468						 0);
13469			b[6] = gc->bgPixel;
13470			b[7] = gc->fgPixel;
13471			b[8] = pat[0];
13472			b[9] = pat[1];
13473			sna->kgem.nbatch += 10;
13474		} else {
13475			b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7;
13476			b[1] = br13;
13477			b[2] = 0;
13478			b[3] = 0;
13479			b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13480					      I915_GEM_DOMAIN_RENDER << 16 |
13481					      I915_GEM_DOMAIN_RENDER |
13482					      KGEM_RELOC_FENCED,
13483					      0);
13484			b[5] = gc->bgPixel;
13485			b[6] = gc->fgPixel;
13486			b[7] = pat[0];
13487			b[8] = pat[1];
13488			sna->kgem.nbatch += 9;
13489		}
13490
13491		if (clip.data == NULL) {
13492			do {
13493				BoxRec box;
13494
13495				box.x1 = r->x + drawable->x;
13496				box.y1 = r->y + drawable->y;
13497				box.x2 = bound(box.x1, r->width);
13498				box.y2 = bound(box.y1, r->height);
13499				r++;
13500
13501				if (box_intersect(&box, &clip.extents)) {
13502					if (!kgem_check_batch(&sna->kgem, 3)) {
13503						_kgem_submit(&sna->kgem);
13504						_kgem_set_mode(&sna->kgem, KGEM_BLT);
13505						kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
13506
13507						assert(sna->kgem.mode == KGEM_BLT);
13508						b = sna->kgem.batch + sna->kgem.nbatch;
13509						if (sna->kgem.gen >= 0100) {
13510							b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
13511							b[1] = br13;
13512							b[2] = 0;
13513							b[3] = 0;
13514							*(uint64_t *)(b+4) =
13515								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13516										 I915_GEM_DOMAIN_RENDER << 16 |
13517										 I915_GEM_DOMAIN_RENDER |
13518										 KGEM_RELOC_FENCED,
13519										 0);
13520							b[6] = gc->bgPixel;
13521							b[7] = gc->fgPixel;
13522							b[8] = pat[0];
13523							b[9] = pat[1];
13524							sna->kgem.nbatch += 10;
13525						} else {
13526							b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7;
13527							b[1] = br13;
13528							b[2] = 0;
13529							b[3] = 0;
13530							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13531									      I915_GEM_DOMAIN_RENDER << 16 |
13532									      I915_GEM_DOMAIN_RENDER |
13533									      KGEM_RELOC_FENCED,
13534									      0);
13535							b[5] = gc->bgPixel;
13536							b[6] = gc->fgPixel;
13537							b[7] = pat[0];
13538							b[8] = pat[1];
13539							sna->kgem.nbatch += 9;
13540						}
13541					}
13542
13543					assert(sna->kgem.mode == KGEM_BLT);
13544					b = sna->kgem.batch + sna->kgem.nbatch;
13545					sna->kgem.nbatch += 3;
13546					b[0] = br00;
13547					b[1] = (box.y1 + dy) << 16 | (box.x1 + dx);
13548					b[2] = (box.y2 + dy) << 16 | (box.x2 + dx);
13549				}
13550			} while (--n);
13551		} else {
13552			const BoxRec * const clip_start = RegionBoxptr(&clip);
13553			const BoxRec * const clip_end = clip_start + clip.data->numRects;
13554			const BoxRec *c;
13555
13556			do {
13557				BoxRec box;
13558
13559				box.x1 = r->x + drawable->x;
13560				box.y1 = r->y + drawable->y;
13561				box.x2 = bound(box.x1, r->width);
13562				box.y2 = bound(box.y1, r->height);
13563				r++;
13564
13565				c = find_clip_box_for_y(clip_start,
13566							clip_end,
13567							box.y1);
13568				while (c != clip_end) {
13569					BoxRec bb;
13570					if (box.y2 <= c->y1)
13571						break;
13572
13573					bb = box;
13574					if (box_intersect(&bb, c++)) {
13575						if (!kgem_check_batch(&sna->kgem, 3)) {
13576							_kgem_submit(&sna->kgem);
13577							_kgem_set_mode(&sna->kgem, KGEM_BLT);
13578							kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
13579
13580							assert(sna->kgem.mode == KGEM_BLT);
13581							b = sna->kgem.batch + sna->kgem.nbatch;
13582							if (sna->kgem.gen >= 0100) {
13583								b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
13584								b[1] = br13;
13585								b[2] = 0;
13586								b[3] = 0;
13587								*(uint64_t *)(b+4) =
13588									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13589											 I915_GEM_DOMAIN_RENDER << 16 |
13590											 I915_GEM_DOMAIN_RENDER |
13591											 KGEM_RELOC_FENCED,
13592											 0);
13593								b[6] = gc->bgPixel;
13594								b[7] = gc->fgPixel;
13595								b[8] = pat[0];
13596								b[9] = pat[1];
13597								sna->kgem.nbatch += 10;
13598							} else {
13599								b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7;
13600								b[1] = br13;
13601								b[2] = 0;
13602								b[3] = 0;
13603								b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13604										      I915_GEM_DOMAIN_RENDER << 16 |
13605										      I915_GEM_DOMAIN_RENDER |
13606										      KGEM_RELOC_FENCED,
13607										      0);
13608								b[5] = gc->bgPixel;
13609								b[6] = gc->fgPixel;
13610								b[7] = pat[0];
13611								b[8] = pat[1];
13612								sna->kgem.nbatch += 9;
13613							}
13614						}
13615
13616						assert(sna->kgem.mode == KGEM_BLT);
13617						b = sna->kgem.batch + sna->kgem.nbatch;
13618						sna->kgem.nbatch += 3;
13619						b[0] = br00;
13620						b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx);
13621						b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx);
13622					}
13623				}
13624			} while (--n);
13625		}
13626	}
13627
13628	assert_pixmap_damage(pixmap);
13629	blt_done(sna);
13630	return true;
13631}
13632
13633static bool
13634sna_poly_fill_rect_stippled_nxm_blt(DrawablePtr drawable,
13635				    struct kgem_bo *bo,
13636				    struct sna_damage **damage,
13637				    GCPtr gc, int n, xRectangle *r,
13638				    const BoxRec *extents, unsigned clipped)
13639{
13640	PixmapPtr scratch, stipple;
13641	uint8_t bytes[8], *dst = bytes;
13642	const uint8_t *src, *end;
13643	int j, stride;
13644	bool ret;
13645
13646	DBG(("%s: expanding %dx%d stipple to 8x8\n",
13647	     __FUNCTION__,
13648	     gc->stipple->drawable.width,
13649	     gc->stipple->drawable.height));
13650
13651	scratch = GetScratchPixmapHeader(drawable->pScreen,
13652					 8, 8, 1, 1, 1, bytes);
13653	if (scratch == NullPixmap)
13654		return false;
13655
13656	stipple = gc->stipple;
13657	gc->stipple = scratch;
13658
13659	assert(stipple->devKind);
13660	stride = stipple->devKind;
13661	src = stipple->devPrivate.ptr;
13662	end = src + stride * stipple->drawable.height;
13663	for(j = 0; j < 8; j++) {
13664		switch (stipple->drawable.width) {
13665		case 1: *dst = (*src & 1) * 0xff; break;
13666		case 2: *dst = (*src & 3) * 0x55; break;
13667		case 4: *dst = (*src & 15) * 0x11; break;
13668		case 8: *dst = *src; break;
13669		default: assert(0); break;
13670		}
13671		dst++;
13672		src += stride;
13673		if (src == end)
13674			src = stipple->devPrivate.ptr;
13675	}
13676
13677	ret = sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage,
13678						  gc, n, r, extents, clipped);
13679
13680	gc->stipple = stipple;
13681	FreeScratchPixmapHeader(scratch);
13682
13683	return ret;
13684}
13685
13686static bool
13687sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
13688				  struct kgem_bo *bo,
13689				  struct sna_damage **damage,
13690				  GCPtr gc, int n, xRectangle *r,
13691				  const BoxRec *extents, unsigned clipped)
13692{
13693	PixmapPtr pixmap = get_drawable_pixmap(drawable);
13694	struct sna *sna = to_sna_from_pixmap(pixmap);
13695	PixmapPtr stipple = gc->stipple;
13696	const DDXPointRec *origin = &gc->patOrg;
13697	int16_t dx, dy;
13698	uint32_t br00, br13;
13699
13700	DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%x\n", __FUNCTION__,
13701	     extents->x1, extents->y1,
13702	     extents->x2, extents->y2,
13703	     origin->x, origin->y,
13704	     clipped));
13705
13706	get_drawable_deltas(drawable, pixmap, &dx, &dy);
13707	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
13708	assert(kgem_bo_can_blt(&sna->kgem, bo));
13709	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
13710
13711	br00 = 3 << 20;
13712	br13 = bo->pitch;
13713	if (sna->kgem.gen >= 040 && bo->tiling) {
13714		br00 |= BLT_DST_TILED;
13715		br13 >>= 2;
13716	}
13717	br13 |= (gc->fillStyle == FillStippled) << 29;
13718	br13 |= blt_depth(drawable->depth) << 24;
13719	br13 |= copy_ROP[gc->alu] << 16;
13720
13721	if (!clipped) {
13722		dx += drawable->x;
13723		dy += drawable->y;
13724
13725		sna_damage_add_rectangles(damage, r, n, dx, dy);
13726		do {
13727			int bx1 = (r->x - origin->x) & ~7;
13728			int bx2 = (r->x + r->width - origin->x + 7) & ~7;
13729			int bw = (bx2 - bx1)/8;
13730			int bh = r->height;
13731			int bstride = ALIGN(bw, 2);
13732			int src_stride;
13733			uint8_t *dst, *src;
13734			uint32_t *b;
13735
13736			DBG(("%s: rect (%d, %d)x(%d, %d) stipple [%d,%d, src_stride=%d]\n",
13737			     __FUNCTION__,
13738			     r->x, r->y, r->width, r->height,
13739			     bx1, bx2, bstride*bh));
13740
13741			src_stride = bstride*bh;
13742			assert(src_stride > 0);
13743			if (src_stride <= 128) {
13744				src_stride = ALIGN(src_stride, 8) / 4;
13745				assert(src_stride <= 32);
13746				if (!kgem_check_batch(&sna->kgem, 8+src_stride) ||
13747				    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13748				    !kgem_check_reloc(&sna->kgem, 1)) {
13749					kgem_submit(&sna->kgem);
13750					if (!kgem_check_bo_fenced(&sna->kgem, bo))
13751						return false;
13752					_kgem_set_mode(&sna->kgem, KGEM_BLT);
13753				}
13754				kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
13755
13756				assert(sna->kgem.mode == KGEM_BLT);
13757				b = sna->kgem.batch + sna->kgem.nbatch;
13758				if (sna->kgem.gen >= 0100) {
13759					b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00;
13760					b[0] |= ((r->x - origin->x) & 7) << 17;
13761					b[1] = br13;
13762					b[2] = (r->y + dy) << 16 | (r->x + dx);
13763					b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13764					*(uint64_t *)(b+4) =
13765						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13766								 I915_GEM_DOMAIN_RENDER << 16 |
13767								 I915_GEM_DOMAIN_RENDER |
13768								 KGEM_RELOC_FENCED,
13769								 0);
13770					b[6] = gc->bgPixel;
13771					b[7] = gc->fgPixel;
13772
13773					dst = (uint8_t *)&b[8];
13774					sna->kgem.nbatch += 8 + src_stride;
13775				} else {
13776					b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
13777					b[0] |= ((r->x - origin->x) & 7) << 17;
13778					b[1] = br13;
13779					b[2] = (r->y + dy) << 16 | (r->x + dx);
13780					b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13781					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13782							      I915_GEM_DOMAIN_RENDER << 16 |
13783							      I915_GEM_DOMAIN_RENDER |
13784							      KGEM_RELOC_FENCED,
13785							      0);
13786					b[5] = gc->bgPixel;
13787					b[6] = gc->fgPixel;
13788
13789					dst = (uint8_t *)&b[7];
13790					sna->kgem.nbatch += 7 + src_stride;
13791				}
13792				assert(stipple->devKind);
13793				src_stride = stipple->devKind;
13794				src = stipple->devPrivate.ptr;
13795				src += (r->y - origin->y) * src_stride + bx1/8;
13796				src_stride -= bstride;
13797				do {
13798					int i = bstride;
13799					do {
13800						*dst++ = byte_reverse(*src++);
13801						*dst++ = byte_reverse(*src++);
13802						i -= 2;
13803					} while (i);
13804					src += src_stride;
13805				} while (--bh);
13806			} else {
13807				struct kgem_bo *upload;
13808				void *ptr;
13809
13810				if (!kgem_check_batch(&sna->kgem, 10) ||
13811				    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13812				    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
13813					kgem_submit(&sna->kgem);
13814					if (!kgem_check_bo_fenced(&sna->kgem, bo))
13815						return false;
13816					_kgem_set_mode(&sna->kgem, KGEM_BLT);
13817				}
13818				kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
13819
13820				upload = kgem_create_buffer(&sna->kgem,
13821							    bstride*bh,
13822							    KGEM_BUFFER_WRITE_INPLACE,
13823							    &ptr);
13824				if (!upload)
13825					break;
13826
13827				if (sigtrap_get() == 0) {
13828					dst = ptr;
13829					assert(stipple->devKind);
13830					src_stride = stipple->devKind;
13831					src = stipple->devPrivate.ptr;
13832					src += (r->y - origin->y) * src_stride + bx1/8;
13833					src_stride -= bstride;
13834					do {
13835						int i = bstride;
13836						do {
13837							*dst++ = byte_reverse(*src++);
13838							*dst++ = byte_reverse(*src++);
13839							i -= 2;
13840						} while (i);
13841						src += src_stride;
13842					} while (--bh);
13843
13844					assert(sna->kgem.mode == KGEM_BLT);
13845					b = sna->kgem.batch + sna->kgem.nbatch;
13846					if (sna->kgem.gen >= 0100) {
13847						b[0] = XY_MONO_SRC_COPY | br00 | 8;
13848						b[0] |= ((r->x - origin->x) & 7) << 17;
13849						b[1] = br13;
13850						b[2] = (r->y + dy) << 16 | (r->x + dx);
13851						b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13852						*(uint64_t *)(b+4) =
13853							kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13854									I915_GEM_DOMAIN_RENDER << 16 |
13855									I915_GEM_DOMAIN_RENDER |
13856									KGEM_RELOC_FENCED,
13857									0);
13858						*(uint64_t *)(b+6) =
13859							kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
13860									I915_GEM_DOMAIN_RENDER << 16 |
13861									KGEM_RELOC_FENCED,
13862									0);
13863						b[8] = gc->bgPixel;
13864						b[9] = gc->fgPixel;
13865						sna->kgem.nbatch += 10;
13866					} else {
13867						b[0] = XY_MONO_SRC_COPY | br00 | 6;
13868						b[0] |= ((r->x - origin->x) & 7) << 17;
13869						b[1] = br13;
13870						b[2] = (r->y + dy) << 16 | (r->x + dx);
13871						b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13872						b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13873								I915_GEM_DOMAIN_RENDER << 16 |
13874								I915_GEM_DOMAIN_RENDER |
13875								KGEM_RELOC_FENCED,
13876								0);
13877						b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
13878								I915_GEM_DOMAIN_RENDER << 16 |
13879								KGEM_RELOC_FENCED,
13880								0);
13881						b[6] = gc->bgPixel;
13882						b[7] = gc->fgPixel;
13883
13884						sna->kgem.nbatch += 8;
13885					}
13886					sigtrap_put();
13887				}
13888
13889				kgem_bo_destroy(&sna->kgem, upload);
13890			}
13891
13892			r++;
13893		} while (--n);
13894	} else {
13895		RegionRec clip;
13896		DDXPointRec pat;
13897
13898		region_set(&clip, extents);
13899		if (!region_maybe_clip(&clip, gc->pCompositeClip))
13900			return true;
13901
13902		DBG(("%s: clip.extents=[(%d, %d), (%d, %d)] region?=%d\n",
13903		     __FUNCTION__,
13904		     clip.extents.x1, clip.extents.y1,
13905		     clip.extents.x2, clip.extents.y2,
13906		     clip.data ? clip.data->numRects : 0));
13907
13908		pat.x = origin->x + drawable->x;
13909		pat.y = origin->y + drawable->y;
13910
13911		if (clip.data == NULL) {
13912			do {
13913				BoxRec box;
13914				int bx1, bx2, bw, bh, bstride;
13915				int src_stride;
13916				uint8_t *dst, *src;
13917				uint32_t *b;
13918				struct kgem_bo *upload;
13919				void *ptr;
13920
13921				box.x1 = r->x + drawable->x;
13922				box.x2 = bound(box.x1, r->width);
13923				box.y1 = r->y + drawable->y;
13924				box.y2 = bound(box.y1, r->height);
13925				r++;
13926
13927				if (!box_intersect(&box, &clip.extents))
13928					continue;
13929
13930				bx1 = (box.x1 - pat.x) & ~7;
13931				bx2 = (box.x2 - pat.x + 7) & ~7;
13932				bw = (bx2 - bx1)/8;
13933				bh = box.y2 - box.y1;
13934				bstride = ALIGN(bw, 2);
13935
13936				DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d], pitch=%d, stride=%d, len=%d\n",
13937				     __FUNCTION__,
13938				     r->x, r->y, r->width, r->height,
13939				     box.x1, box.y1, box.x2, box.y2,
13940				     bx1, bx2, bw, bstride, bstride*bh));
13941
13942				src_stride = bstride*bh;
13943				assert(src_stride > 0);
13944				if (src_stride <= 128) {
13945					src_stride = ALIGN(src_stride, 8) / 4;
13946					assert(src_stride <= 32);
13947					if (!kgem_check_batch(&sna->kgem, 8+src_stride) ||
13948					    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13949					    !kgem_check_reloc(&sna->kgem, 1)) {
13950						kgem_submit(&sna->kgem);
13951						if (!kgem_check_bo_fenced(&sna->kgem, bo))
13952							return false;
13953						_kgem_set_mode(&sna->kgem, KGEM_BLT);
13954					}
13955					kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
13956
13957					assert(sna->kgem.mode == KGEM_BLT);
13958					b = sna->kgem.batch + sna->kgem.nbatch;
13959					if (sna->kgem.gen >= 0100) {
13960						b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00;
13961						b[0] |= ((box.x1 - pat.x) & 7) << 17;
13962						b[1] = br13;
13963						b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13964						b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13965						*(uint64_t *)(b+4) =
13966							kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13967									 I915_GEM_DOMAIN_RENDER << 16 |
13968									 I915_GEM_DOMAIN_RENDER |
13969									 KGEM_RELOC_FENCED,
13970									 0);
13971						b[6] = gc->bgPixel;
13972						b[7] = gc->fgPixel;
13973
13974						dst = (uint8_t *)&b[8];
13975						sna->kgem.nbatch += 8 + src_stride;
13976					} else {
13977						b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
13978						b[0] |= ((box.x1 - pat.x) & 7) << 17;
13979						b[1] = br13;
13980						b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13981						b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13982						b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13983								      I915_GEM_DOMAIN_RENDER << 16 |
13984								      I915_GEM_DOMAIN_RENDER |
13985								      KGEM_RELOC_FENCED,
13986								      0);
13987						b[5] = gc->bgPixel;
13988						b[6] = gc->fgPixel;
13989
13990						dst = (uint8_t *)&b[7];
13991						sna->kgem.nbatch += 7 + src_stride;
13992					}
13993
13994					assert(stipple->devKind);
13995					src_stride = stipple->devKind;
13996					src = stipple->devPrivate.ptr;
13997					src += (box.y1 - pat.y) * src_stride + bx1/8;
13998					src_stride -= bstride;
13999					do {
14000						int i = bstride;
14001						do {
14002							*dst++ = byte_reverse(*src++);
14003							*dst++ = byte_reverse(*src++);
14004							i -= 2;
14005						} while (i);
14006						src += src_stride;
14007					} while (--bh);
14008				} else {
14009					if (!kgem_check_batch(&sna->kgem, 10) ||
14010					    !kgem_check_bo_fenced(&sna->kgem, bo) ||
14011					    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
14012						kgem_submit(&sna->kgem);
14013						if (!kgem_check_bo_fenced(&sna->kgem, bo))
14014							return false;
14015						_kgem_set_mode(&sna->kgem, KGEM_BLT);
14016					}
14017					kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
14018
14019					upload = kgem_create_buffer(&sna->kgem,
14020								    bstride*bh,
14021								    KGEM_BUFFER_WRITE_INPLACE,
14022								    &ptr);
14023					if (!upload)
14024						break;
14025
14026					if (sigtrap_get() == 0) {
14027						dst = ptr;
14028						assert(stipple->devKind);
14029						src_stride = stipple->devKind;
14030						src = stipple->devPrivate.ptr;
14031						src += (box.y1 - pat.y) * src_stride + bx1/8;
14032						src_stride -= bstride;
14033						do {
14034							int i = bstride;
14035							do {
14036								*dst++ = byte_reverse(*src++);
14037								*dst++ = byte_reverse(*src++);
14038								i -= 2;
14039							} while (i);
14040							src += src_stride;
14041						} while (--bh);
14042
14043						assert(sna->kgem.mode == KGEM_BLT);
14044						b = sna->kgem.batch + sna->kgem.nbatch;
14045						if (sna->kgem.gen >= 0100) {
14046							b[0] = XY_MONO_SRC_COPY | br00 | 8;
14047							b[0] |= ((box.x1 - pat.x) & 7) << 17;
14048							b[1] = br13;
14049							b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
14050							b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
14051							*(uint64_t *)(b+4) =
14052								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14053										I915_GEM_DOMAIN_RENDER << 16 |
14054										I915_GEM_DOMAIN_RENDER |
14055										KGEM_RELOC_FENCED,
14056										0);
14057							*(uint64_t *)(b+6) =
14058								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
14059										I915_GEM_DOMAIN_RENDER << 16 |
14060										KGEM_RELOC_FENCED,
14061										0);
14062							b[8] = gc->bgPixel;
14063							b[9] = gc->fgPixel;
14064							sna->kgem.nbatch += 10;
14065						} else {
14066							b[0] = XY_MONO_SRC_COPY | br00 | 6;
14067							b[0] |= ((box.x1 - pat.x) & 7) << 17;
14068							b[1] = br13;
14069							b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
14070							b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
14071							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14072									I915_GEM_DOMAIN_RENDER << 16 |
14073									I915_GEM_DOMAIN_RENDER |
14074									KGEM_RELOC_FENCED,
14075									0);
14076							b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
14077									I915_GEM_DOMAIN_RENDER << 16 |
14078									KGEM_RELOC_FENCED,
14079									0);
14080							b[6] = gc->bgPixel;
14081							b[7] = gc->fgPixel;
14082
14083							sna->kgem.nbatch += 8;
14084						}
14085						sigtrap_put();
14086					}
14087					kgem_bo_destroy(&sna->kgem, upload);
14088				}
14089			} while (--n);
14090		} else {
14091			const BoxRec * const clip_start = RegionBoxptr(&clip);
14092			const BoxRec * const clip_end = clip_start + clip.data->numRects;
14093			const BoxRec *c;
14094
14095			do {
14096				BoxRec unclipped;
14097				int bx1, bx2, bw, bh, bstride;
14098				int src_stride;
14099				uint8_t *dst, *src;
14100				uint32_t *b;
14101				struct kgem_bo *upload;
14102				void *ptr;
14103
14104				unclipped.x1 = r->x + drawable->x;
14105				unclipped.x2 = bound(unclipped.x1, r->width);
14106				unclipped.y1 = r->y + drawable->y;
14107				unclipped.y2 = bound(unclipped.y1, r->height);
14108				r++;
14109
14110				c = find_clip_box_for_y(clip_start,
14111							clip_end,
14112							unclipped.y1);
14113				while (c != clip_end) {
14114					BoxRec box;
14115
14116					if (unclipped.y2 <= c->y1)
14117						break;
14118
14119					box = unclipped;
14120					if (!box_intersect(&box, c++))
14121						continue;
14122
14123					bx1 = (box.x1 - pat.x) & ~7;
14124					bx2 = (box.x2 - pat.x + 7) & ~7;
14125					bw = (bx2 - bx1)/8;
14126					bh = box.y2 - box.y1;
14127					bstride = ALIGN(bw, 2);
14128
14129					DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d]\n",
14130					     __FUNCTION__,
14131					     r->x, r->y, r->width, r->height,
14132					     box.x1, box.y1, box.x2, box.y2,
14133					     bx1, bx2));
14134
14135					src_stride = bstride*bh;
14136					assert(src_stride > 0);
14137					if (src_stride <= 128) {
14138						src_stride = ALIGN(src_stride, 8) / 4;
14139						assert(src_stride <= 32);
14140						if (!kgem_check_batch(&sna->kgem, 8+src_stride) ||
14141						    !kgem_check_bo_fenced(&sna->kgem, bo) ||
14142						    !kgem_check_reloc(&sna->kgem, 1)) {
14143							kgem_submit(&sna->kgem);
14144							if (!kgem_check_bo_fenced(&sna->kgem, bo))
14145								return false;
14146							_kgem_set_mode(&sna->kgem, KGEM_BLT);
14147						}
14148						kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
14149
14150						assert(sna->kgem.mode == KGEM_BLT);
14151						b = sna->kgem.batch + sna->kgem.nbatch;
14152						if (sna->kgem.gen >= 0100) {
14153							b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00;
14154							b[0] |= ((box.x1 - pat.x) & 7) << 17;
14155							b[1] = br13;
14156							b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
14157							b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
14158							*(uint64_t *)(b+4) =
14159								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14160										 I915_GEM_DOMAIN_RENDER << 16 |
14161										 I915_GEM_DOMAIN_RENDER |
14162										 KGEM_RELOC_FENCED,
14163										 0);
14164							b[6] = gc->bgPixel;
14165							b[7] = gc->fgPixel;
14166
14167							dst = (uint8_t *)&b[8];
14168							sna->kgem.nbatch += 8 + src_stride;
14169						} else {
14170							b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
14171							b[0] |= ((box.x1 - pat.x) & 7) << 17;
14172							b[1] = br13;
14173							b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
14174							b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
14175							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14176									      I915_GEM_DOMAIN_RENDER << 16 |
14177									      I915_GEM_DOMAIN_RENDER |
14178									      KGEM_RELOC_FENCED,
14179									      0);
14180							b[5] = gc->bgPixel;
14181							b[6] = gc->fgPixel;
14182
14183							dst = (uint8_t *)&b[7];
14184							sna->kgem.nbatch += 7 + src_stride;
14185						}
14186						assert(stipple->devKind);
14187						src_stride = stipple->devKind;
14188						src = stipple->devPrivate.ptr;
14189						src += (box.y1 - pat.y) * src_stride + bx1/8;
14190						src_stride -= bstride;
14191						do {
14192							int i = bstride;
14193							do {
14194								*dst++ = byte_reverse(*src++);
14195								*dst++ = byte_reverse(*src++);
14196								i -= 2;
14197							} while (i);
14198							src += src_stride;
14199						} while (--bh);
14200					} else {
14201						if (!kgem_check_batch(&sna->kgem, 10) ||
14202						    !kgem_check_bo_fenced(&sna->kgem, bo) ||
14203						    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
14204							kgem_submit(&sna->kgem);
14205							if (!kgem_check_bo_fenced(&sna->kgem, bo))
14206								return false;
14207							_kgem_set_mode(&sna->kgem, KGEM_BLT);
14208						}
14209						kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
14210
14211						upload = kgem_create_buffer(&sna->kgem,
14212									    bstride*bh,
14213									    KGEM_BUFFER_WRITE_INPLACE,
14214									    &ptr);
14215						if (!upload)
14216							break;
14217
14218						if (sigtrap_get() == 0) {
14219							dst = ptr;
14220							assert(stipple->devKind);
14221							src_stride = stipple->devKind;
14222							src = stipple->devPrivate.ptr;
14223							src += (box.y1 - pat.y) * src_stride + bx1/8;
14224							src_stride -= bstride;
14225							do {
14226								int i = bstride;
14227								do {
14228									*dst++ = byte_reverse(*src++);
14229									*dst++ = byte_reverse(*src++);
14230									i -= 2;
14231								} while (i);
14232								src += src_stride;
14233							} while (--bh);
14234
14235							assert(sna->kgem.mode == KGEM_BLT);
14236							b = sna->kgem.batch + sna->kgem.nbatch;
14237							if (sna->kgem.gen >= 0100) {
14238								b[0] = XY_MONO_SRC_COPY | br00 | 8;
14239								b[0] |= ((box.x1 - pat.x) & 7) << 17;
14240								b[1] = br13;
14241								b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
14242								b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
14243								*(uint64_t *)(b+4) =
14244									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14245											I915_GEM_DOMAIN_RENDER << 16 |
14246											I915_GEM_DOMAIN_RENDER |
14247											KGEM_RELOC_FENCED,
14248											0);
14249								*(uint64_t *)(b+6) =
14250									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
14251											I915_GEM_DOMAIN_RENDER << 16 |
14252											KGEM_RELOC_FENCED,
14253											0);
14254								b[8] = gc->bgPixel;
14255								b[9] = gc->fgPixel;
14256								sna->kgem.nbatch += 10;
14257							} else {
14258								b[0] = XY_MONO_SRC_COPY | br00 | 6;
14259								b[0] |= ((box.x1 - pat.x) & 7) << 17;
14260								b[1] = br13;
14261								b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
14262								b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
14263								b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14264										I915_GEM_DOMAIN_RENDER << 16 |
14265										I915_GEM_DOMAIN_RENDER |
14266										KGEM_RELOC_FENCED,
14267										0);
14268								b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
14269										I915_GEM_DOMAIN_RENDER << 16 |
14270										KGEM_RELOC_FENCED,
14271										0);
14272								b[6] = gc->bgPixel;
14273								b[7] = gc->fgPixel;
14274
14275								sna->kgem.nbatch += 8;
14276							}
14277							sigtrap_put();
14278						}
14279						kgem_bo_destroy(&sna->kgem, upload);
14280					}
14281				}
14282			} while (--n);
14283
14284		}
14285	}
14286
14287	blt_done(sna);
14288	return true;
14289}
14290
14291static void
14292sna_poly_fill_rect_stippled_n_box__imm(struct sna *sna,
14293				       struct kgem_bo *bo,
14294				       uint32_t br00, uint32_t br13,
14295				       const GC *gc,
14296				       const BoxRec *box,
14297				       const DDXPointRec *origin)
14298{
14299	int x1, x2, y1, y2;
14300	uint32_t *b;
14301
14302	for (y1 = box->y1; y1 < box->y2; y1 = y2) {
14303		int oy = (y1 - origin->y) % gc->stipple->drawable.height;
14304		if (oy < 0)
14305			oy += gc->stipple->drawable.height;
14306
14307		y2 = box->y2;
14308		if (y2 - y1 > gc->stipple->drawable.height - oy)
14309			y2 = y1 + gc->stipple->drawable.height - oy;
14310
14311		for (x1 = box->x1; x1 < box->x2; x1 = x2) {
14312			int bx1, bx2, bw, bh, len, ox;
14313			uint8_t *dst, *src;
14314
14315			x2 = box->x2;
14316			ox = (x1 - origin->x) % gc->stipple->drawable.width;
14317			if (ox < 0)
14318				ox += gc->stipple->drawable.width;
14319			bx1 = ox & ~7;
14320			bx2 = ox + (x2 - x1);
14321			if (bx2 > gc->stipple->drawable.width) {
14322				bx2 = gc->stipple->drawable.width;
14323				x2 = x1 + bx2-ox;
14324			}
14325			bw = (bx2 - bx1 + 7)/8;
14326			bw = ALIGN(bw, 2);
14327			bh = y2 - y1;
14328
14329			DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d\n",
14330			     __FUNCTION__,
14331			     x1, y1, x2-x1, y2-y1,
14332			     origin->x, origin->y,
14333			     ox, oy, bx1, bx2,
14334			     gc->stipple->drawable.width,
14335			     gc->stipple->drawable.height));
14336
14337			len = bw*bh;
14338			len = ALIGN(len, 8) / 4;
14339			assert(len > 0);
14340			assert(len <= 32);
14341			if (!kgem_check_batch(&sna->kgem, 8+len) ||
14342			    !kgem_check_bo_fenced(&sna->kgem, bo) ||
14343			    !kgem_check_reloc(&sna->kgem, 1)) {
14344				kgem_submit(&sna->kgem);
14345				if (!kgem_check_bo_fenced(&sna->kgem, bo))
14346					return; /* XXX fallback? */
14347				_kgem_set_mode(&sna->kgem, KGEM_BLT);
14348			}
14349			kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
14350
14351			assert(sna->kgem.mode == KGEM_BLT);
14352			b = sna->kgem.batch + sna->kgem.nbatch;
14353			if (sna->kgem.gen >= 0100) {
14354				b[0] = br00 | (6 + len) | (ox & 7) << 17;
14355				b[1] = br13;
14356				b[2] = y1 << 16 | x1;
14357				b[3] = y2 << 16 | x2;
14358				*(uint64_t *)(b+4) =
14359					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14360							 I915_GEM_DOMAIN_RENDER << 16 |
14361							 I915_GEM_DOMAIN_RENDER |
14362							 KGEM_RELOC_FENCED,
14363							 0);
14364				b[6] = gc->bgPixel;
14365				b[7] = gc->fgPixel;
14366				dst = (uint8_t *)&b[8];
14367				sna->kgem.nbatch += 8 + len;
14368			} else {
14369				b[0] = br00 | (5 + len) | (ox & 7) << 17;
14370				b[1] = br13;
14371				b[2] = y1 << 16 | x1;
14372				b[3] = y2 << 16 | x2;
14373				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14374						      I915_GEM_DOMAIN_RENDER << 16 |
14375						      I915_GEM_DOMAIN_RENDER |
14376						      KGEM_RELOC_FENCED,
14377						      0);
14378				b[5] = gc->bgPixel;
14379				b[6] = gc->fgPixel;
14380				dst = (uint8_t *)&b[7];
14381				sna->kgem.nbatch += 7 + len;
14382			}
14383
14384			assert(gc->stipple->devKind);
14385			len = gc->stipple->devKind;
14386			src = gc->stipple->devPrivate.ptr;
14387			src += oy*len + ox/8;
14388			len -= bw;
14389			do {
14390				int i = bw;
14391				do {
14392					*dst++ = byte_reverse(*src++);
14393					*dst++ = byte_reverse(*src++);
14394					i -= 2;
14395				} while (i);
14396				src += len;
14397			} while (--bh);
14398		}
14399	}
14400}
14401
14402static void
14403sna_poly_fill_rect_stippled_n_box(struct sna *sna,
14404				  struct kgem_bo *bo,
14405				  struct kgem_bo **tile,
14406				  uint32_t br00, uint32_t br13,
14407				  const GC *gc,
14408				  const BoxRec *box,
14409				  const DDXPointRec *origin)
14410{
14411	int x1, x2, y1, y2;
14412	int w = gc->stipple->drawable.width;
14413	int h = gc->stipple->drawable.height;
14414	int stride = gc->stipple->devKind;
14415	uint32_t *b;
14416
14417	assert(stride);
14418	if ((((box->y2-box->y1) | (box->x2-box->x1)) & ~31) == 0) {
14419		br00 = XY_MONO_SRC_COPY_IMM |(br00 & (BLT_DST_TILED | 3 << 20));
14420		sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
14421						       br00, br13, gc,
14422						       box, origin);
14423		return;
14424	}
14425
14426	for (y1 = box->y1; y1 < box->y2; y1 = y2) {
14427		int row, oy = (y1 - origin->y) % gc->stipple->drawable.height;
14428		if (oy < 0)
14429			oy += h;
14430
14431		y2 = box->y2;
14432		if (y2 - y1 > h - oy)
14433			y2 = y1 + h - oy;
14434
14435		row = oy * stride;
14436		for (x1 = box->x1; x1 < box->x2; x1 = x2) {
14437			int bx1, bx2, bw, bh, len, ox;
14438			bool use_tile;
14439
14440			x2 = box->x2;
14441			ox = (x1 - origin->x) % w;
14442			if (ox < 0)
14443				ox += w;
14444			bx1 = ox & ~7;
14445			bx2 = ox + (x2 - x1);
14446			if (bx2 > w) {
14447				bx2 = w;
14448				x2 = x1 + bx2-ox;
14449			}
14450
14451			use_tile = y2-y1 == h && x2-x1 == w;
14452
14453			DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d, full tile?=%d\n",
14454			     __FUNCTION__,
14455			     x1, y1, x2-x1, y2-y1,
14456			     origin->x, origin->y,
14457			     ox, oy, bx1, bx2, w, h,
14458			     use_tile));
14459
14460			bw = (bx2 - bx1 + 7)/8;
14461			bw = ALIGN(bw, 2);
14462			bh = y2 - y1;
14463
14464			len = bw*bh;
14465			len = ALIGN(len, 8) / 4;
14466			assert(len > 0);
14467			if (!kgem_check_batch(&sna->kgem, 8+len) ||
14468			    !kgem_check_bo_fenced(&sna->kgem, bo) ||
14469			    !kgem_check_reloc(&sna->kgem, 2)) {
14470				kgem_submit(&sna->kgem);
14471				if (!kgem_check_bo_fenced(&sna->kgem, bo))
14472					return; /* XXX fallback? */
14473				_kgem_set_mode(&sna->kgem, KGEM_BLT);
14474			}
14475			kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
14476
14477			assert(sna->kgem.mode == KGEM_BLT);
14478			b = sna->kgem.batch + sna->kgem.nbatch;
14479
14480			if (!use_tile && len <= 32) {
14481				uint8_t *dst, *src;
14482
14483				if (sna->kgem.gen >= 0100) {
14484					b[0] = XY_MONO_SRC_COPY_IMM;
14485					b[0] |= (br00 & (BLT_DST_TILED | 3 << 20));
14486					b[0] |= (ox & 7) << 17;
14487					b[0] |= (6 + len);
14488					b[1] = br13;
14489					b[2] = y1 << 16 | x1;
14490					b[3] = y2 << 16 | x2;
14491					*(uint64_t *)(b+4) =
14492						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14493								 I915_GEM_DOMAIN_RENDER << 16 |
14494								 I915_GEM_DOMAIN_RENDER |
14495								 KGEM_RELOC_FENCED,
14496								 0);
14497					b[6] = gc->bgPixel;
14498					b[7] = gc->fgPixel;
14499
14500					dst = (uint8_t *)&b[8];
14501					sna->kgem.nbatch += 8 + len;
14502				} else {
14503					b[0] = XY_MONO_SRC_COPY_IMM;
14504					b[0] |= (br00 & (BLT_DST_TILED | 3 << 20));
14505					b[0] |= (ox & 7) << 17;
14506					b[0] |= (5 + len);
14507					b[1] = br13;
14508					b[2] = y1 << 16 | x1;
14509					b[3] = y2 << 16 | x2;
14510					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14511							      I915_GEM_DOMAIN_RENDER << 16 |
14512							      I915_GEM_DOMAIN_RENDER |
14513							      KGEM_RELOC_FENCED,
14514							      0);
14515					b[5] = gc->bgPixel;
14516					b[6] = gc->fgPixel;
14517
14518					dst = (uint8_t *)&b[7];
14519					sna->kgem.nbatch += 7 + len;
14520				}
14521
14522				assert(gc->stipple->devKind);
14523				len = gc->stipple->devKind;
14524				src = gc->stipple->devPrivate.ptr;
14525				src += oy*len + ox/8;
14526				len -= bw;
14527				do {
14528					int i = bw;
14529					do {
14530						*dst++ = byte_reverse(*src++);
14531						*dst++ = byte_reverse(*src++);
14532						i -= 2;
14533					} while (i);
14534					src += len;
14535				} while (--bh);
14536			} else {
14537				bool has_tile = use_tile && *tile;
14538				struct kgem_bo *upload;
14539				uint8_t *dst, *src;
14540				void *ptr;
14541
14542				if (has_tile) {
14543					upload = kgem_bo_reference(*tile);
14544				} else {
14545					upload = kgem_create_buffer(&sna->kgem, bw*bh,
14546								    KGEM_BUFFER_WRITE_INPLACE,
14547								    &ptr);
14548					if (!upload)
14549						return;
14550				}
14551
14552				assert(sna->kgem.mode == KGEM_BLT);
14553				b = sna->kgem.batch + sna->kgem.nbatch;
14554				if (sna->kgem.gen >= 0100) {
14555					b[0] = br00 | (ox & 7) << 17 | 8;
14556					b[1] = br13;
14557					b[2] = y1 << 16 | x1;
14558					b[3] = y2 << 16 | x2;
14559					*(uint64_t *)(b+4) =
14560						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14561								 I915_GEM_DOMAIN_RENDER << 16 |
14562								 I915_GEM_DOMAIN_RENDER |
14563								 KGEM_RELOC_FENCED,
14564								 0);
14565					*(uint64_t *)(b+6) =
14566						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
14567							       I915_GEM_DOMAIN_RENDER << 16 |
14568							       KGEM_RELOC_FENCED,
14569							       0);
14570					b[8] = gc->bgPixel;
14571					b[9] = gc->fgPixel;
14572					sna->kgem.nbatch += 10;
14573				} else {
14574					b[0] = br00 | (ox & 7) << 17 | 6;
14575					b[1] = br13;
14576					b[2] = y1 << 16 | x1;
14577					b[3] = y2 << 16 | x2;
14578					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14579							      I915_GEM_DOMAIN_RENDER << 16 |
14580							      I915_GEM_DOMAIN_RENDER |
14581							      KGEM_RELOC_FENCED,
14582							      0);
14583					b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
14584							      I915_GEM_DOMAIN_RENDER << 16 |
14585							      KGEM_RELOC_FENCED,
14586							      0);
14587					b[6] = gc->bgPixel;
14588					b[7] = gc->fgPixel;
14589					sna->kgem.nbatch += 8;
14590				}
14591
14592				if (!has_tile) {
14593					dst = ptr;
14594					len = stride;
14595					src = gc->stipple->devPrivate.ptr;
14596					src += row + (ox >> 3);
14597					len -= bw;
14598					do {
14599						int i = bw;
14600						do {
14601							*dst++ = byte_reverse(*src++);
14602							*dst++ = byte_reverse(*src++);
14603							i -= 2;
14604						} while (i);
14605						src += len;
14606					} while (--bh);
14607					if (use_tile)
14608						*tile = kgem_bo_reference(upload);
14609				}
14610
14611				kgem_bo_destroy(&sna->kgem, upload);
14612			}
14613		}
14614	}
14615}
14616
14617static bool
14618sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable,
14619				       struct kgem_bo *bo,
14620				       struct sna_damage **damage,
14621				       GCPtr gc, int n, xRectangle *r,
14622				       const BoxRec *extents, unsigned clipped)
14623{
14624	PixmapPtr pixmap = get_drawable_pixmap(drawable);
14625	struct sna *sna = to_sna_from_pixmap(pixmap);
14626	DDXPointRec origin = gc->patOrg;
14627	int16_t dx, dy;
14628	uint32_t br00, br13;
14629
14630	DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__,
14631	     extents->x1, extents->y1,
14632	     extents->x2, extents->y2,
14633	     origin.x, origin.y,
14634	     clipped, gc->alu, gc->fillStyle == FillOpaqueStippled));
14635
14636	get_drawable_deltas(drawable, pixmap, &dx, &dy);
14637	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
14638	assert(kgem_bo_can_blt(&sna->kgem, bo));
14639	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
14640
14641	br00 = XY_MONO_SRC_COPY_IMM | 3 << 20;
14642	br13 = bo->pitch;
14643	if (sna->kgem.gen >= 040 && bo->tiling) {
14644		br00 |= BLT_DST_TILED;
14645		br13 >>= 2;
14646	}
14647	br13 |= (gc->fillStyle == FillStippled) << 29;
14648	br13 |= blt_depth(drawable->depth) << 24;
14649	br13 |= copy_ROP[gc->alu] << 16;
14650
14651	origin.x += dx + drawable->x;
14652	origin.y += dy + drawable->y;
14653
14654	if (!clipped) {
14655		dx += drawable->x;
14656		dy += drawable->y;
14657
14658		sna_damage_add_rectangles(damage, r, n, dx, dy);
14659		do {
14660			BoxRec box;
14661
14662			box.x1 = r->x + dx;
14663			box.y1 = r->y + dy;
14664			box.x2 = box.x1 + r->width;
14665			box.y2 = box.y1 + r->height;
14666
14667			sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
14668							       br00, br13, gc,
14669							       &box, &origin);
14670			r++;
14671		} while (--n);
14672	} else {
14673		RegionRec clip;
14674
14675		region_set(&clip, extents);
14676		if (!region_maybe_clip(&clip, gc->pCompositeClip)) {
14677			DBG(("%s: all clipped\n", __FUNCTION__));
14678			return true;
14679		}
14680
14681		if (clip.data == NULL) {
14682			DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n",
14683			     __FUNCTION__,
14684			     clip.extents.x1, clip.extents.y1,
14685			     clip.extents.x2, clip.extents.y2));
14686			do {
14687				BoxRec box;
14688
14689				box.x1 = r->x + drawable->x;
14690				box.x2 = bound(box.x1, r->width);
14691				box.y1 = r->y + drawable->y;
14692				box.y2 = bound(box.y1, r->height);
14693				r++;
14694
14695				DBG(("%s: box (%d, %d), (%d, %d)\n",
14696				     __FUNCTION__,
14697				     box.x1, box.y1, box.x2, box.y2));
14698				if (!box_intersect(&box, &clip.extents))
14699					continue;
14700
14701				box.x1 += dx; box.x2 += dx;
14702				box.y1 += dy; box.y2 += dy;
14703
14704				sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
14705								       br00, br13, gc,
14706								       &box, &origin);
14707			} while (--n);
14708		} else {
14709			const BoxRec * const clip_start = RegionBoxptr(&clip);
14710			const BoxRec * const clip_end = clip_start + clip.data->numRects;
14711			const BoxRec *c;
14712
14713			DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__,
14714			     clip_start->x1, clip_start->y1,
14715			     clip_start->x2, clip_start->y2,
14716			     clip_end->x1, clip_end->y1,
14717			     clip_end->x2, clip_end->y2));
14718			do {
14719				BoxRec unclipped;
14720
14721				unclipped.x1 = r->x + drawable->x;
14722				unclipped.x2 = bound(unclipped.x1, r->width);
14723				unclipped.y1 = r->y + drawable->y;
14724				unclipped.y2 = bound(unclipped.y1, r->height);
14725				r++;
14726
14727				c = find_clip_box_for_y(clip_start,
14728							clip_end,
14729							unclipped.y1);
14730				while (c != clip_end) {
14731					BoxRec box;
14732
14733					if (unclipped.y2 <= c->y1)
14734						break;
14735
14736					box = unclipped;
14737					if (!box_intersect(&box, c++))
14738						continue;
14739
14740					box.x1 += dx; box.x2 += dx;
14741					box.y1 += dy; box.y2 += dy;
14742
14743					sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
14744									       br00, br13, gc,
14745									       &box, &origin);
14746				}
14747			} while (--n);
14748		}
14749	}
14750
14751	assert_pixmap_damage(pixmap);
14752	blt_done(sna);
14753	return true;
14754}
14755
14756static bool
14757sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable,
14758				  struct kgem_bo *bo,
14759				  struct sna_damage **damage,
14760				  GCPtr gc, int n, xRectangle *r,
14761				  const BoxRec *extents, unsigned clipped)
14762{
14763	PixmapPtr pixmap = get_drawable_pixmap(drawable);
14764	struct sna *sna = to_sna_from_pixmap(pixmap);
14765	DDXPointRec origin = gc->patOrg;
14766	struct kgem_bo *tile = NULL;
14767	int16_t dx, dy;
14768	uint32_t br00, br13;
14769
14770	DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__,
14771	     extents->x1, extents->y1,
14772	     extents->x2, extents->y2,
14773	     origin.x, origin.y,
14774	     clipped, gc->alu, gc->fillStyle == FillOpaqueStippled));
14775
14776	if (((gc->stipple->drawable.width | gc->stipple->drawable.height) & ~31) == 0)
14777		return sna_poly_fill_rect_stippled_n_blt__imm(drawable,
14778							      bo, damage,
14779							      gc, n, r,
14780							      extents, clipped);
14781
14782	get_drawable_deltas(drawable, pixmap, &dx, &dy);
14783	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
14784	assert(kgem_bo_can_blt(&sna->kgem, bo));
14785	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
14786
14787	br00 = XY_MONO_SRC_COPY | 3 << 20;
14788	br13 = bo->pitch;
14789	if (sna->kgem.gen >= 040 && bo->tiling) {
14790		br00 |= BLT_DST_TILED;
14791		br13 >>= 2;
14792	}
14793	br13 |= (gc->fillStyle == FillStippled) << 29;
14794	br13 |= blt_depth(drawable->depth) << 24;
14795	br13 |= copy_ROP[gc->alu] << 16;
14796
14797	origin.x += dx + drawable->x;
14798	origin.y += dy + drawable->y;
14799
14800	if (!clipped) {
14801		dx += drawable->x;
14802		dy += drawable->y;
14803
14804		sna_damage_add_rectangles(damage, r, n, dx, dy);
14805		do {
14806			BoxRec box;
14807
14808			box.x1 = r->x + dx;
14809			box.y1 = r->y + dy;
14810			box.x2 = box.x1 + r->width;
14811			box.y2 = box.y1 + r->height;
14812
14813			sna_poly_fill_rect_stippled_n_box(sna, bo, &tile,
14814							  br00, br13, gc,
14815							  &box, &origin);
14816			r++;
14817		} while (--n);
14818	} else {
14819		RegionRec clip;
14820
14821		region_set(&clip, extents);
14822		if (!region_maybe_clip(&clip, gc->pCompositeClip)) {
14823			DBG(("%s: all clipped\n", __FUNCTION__));
14824			return true;
14825		}
14826
14827		if (clip.data == NULL) {
14828			DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n",
14829			     __FUNCTION__,
14830			     clip.extents.x1, clip.extents.y1,
14831			     clip.extents.x2, clip.extents.y2));
14832			do {
14833				BoxRec box;
14834
14835				box.x1 = r->x + drawable->x;
14836				box.x2 = bound(box.x1, r->width);
14837				box.y1 = r->y + drawable->y;
14838				box.y2 = bound(box.y1, r->height);
14839				r++;
14840
14841				DBG(("%s: box (%d, %d), (%d, %d)\n",
14842				     __FUNCTION__,
14843				     box.x1, box.y1, box.x2, box.y2));
14844				if (!box_intersect(&box, &clip.extents))
14845					continue;
14846
14847				box.x1 += dx; box.x2 += dx;
14848				box.y1 += dy; box.y2 += dy;
14849
14850				sna_poly_fill_rect_stippled_n_box(sna, bo, &tile,
14851								  br00, br13, gc,
14852								  &box, &origin);
14853			} while (--n);
14854		} else {
14855			const BoxRec * const clip_start = RegionBoxptr(&clip);
14856			const BoxRec * const clip_end = clip_start + clip.data->numRects;
14857			const BoxRec *c;
14858
14859			DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__,
14860			     clip_start->x1, clip_start->y1,
14861			     clip_start->x2, clip_start->y2,
14862			     clip_end->x1, clip_end->y1,
14863			     clip_end->x2, clip_end->y2));
14864			do {
14865				BoxRec unclipped;
14866
14867				unclipped.x1 = r->x + drawable->x;
14868				unclipped.x2 = bound(unclipped.x1, r->width);
14869				unclipped.y1 = r->y + drawable->y;
14870				unclipped.y2 = bound(unclipped.y1, r->height);
14871				r++;
14872
14873				c = find_clip_box_for_y(clip_start,
14874							clip_end,
14875							unclipped.y1);
14876				while (c != clip_end) {
14877					BoxRec box;
14878
14879					if (unclipped.y2 <= c->y1)
14880						break;
14881
14882					box = unclipped;
14883					if (!box_intersect(&box, c++))
14884						continue;
14885
14886					box.x1 += dx; box.x2 += dx;
14887					box.y1 += dy; box.y2 += dy;
14888
14889					sna_poly_fill_rect_stippled_n_box(sna, bo, &tile,
14890									  br00, br13, gc,
14891									  &box, &origin);
14892				}
14893			} while (--n);
14894		}
14895	}
14896
14897	assert_pixmap_damage(pixmap);
14898	if (tile)
14899		kgem_bo_destroy(&sna->kgem, tile);
14900	blt_done(sna);
14901	return true;
14902}
14903
14904static bool
14905sna_poly_fill_rect_stippled_blt(DrawablePtr drawable,
14906				struct kgem_bo *bo,
14907				struct sna_damage **damage,
14908				GCPtr gc, int n, xRectangle *rect,
14909				const BoxRec *extents, unsigned clipped)
14910{
14911
14912	PixmapPtr stipple = gc->stipple;
14913	PixmapPtr pixmap = get_drawable_pixmap(drawable);
14914
14915	if (bo->tiling == I915_TILING_Y) {
14916		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
14917		/* This is cheating, but only the gpu_bo can be tiled */
14918		assert(bo == __sna_pixmap_get_bo(pixmap));
14919		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
14920		if (bo == NULL) {
14921			DBG(("%s: fallback -- unable to change tiling\n",
14922			     __FUNCTION__));
14923			return false;
14924		}
14925	}
14926
14927	if (!kgem_bo_can_blt(&to_sna_from_pixmap(pixmap)->kgem, bo))
14928		return false;
14929
14930	if (!sna_drawable_move_to_cpu(&stipple->drawable, MOVE_READ))
14931		return false;
14932
14933	DBG(("%s: origin (%d, %d), extents (stipple): (%d, %d), stipple size %dx%d\n",
14934	     __FUNCTION__, gc->patOrg.x, gc->patOrg.y,
14935	     extents->x2 - gc->patOrg.x - drawable->x,
14936	     extents->y2 - gc->patOrg.y - drawable->y,
14937	     stipple->drawable.width, stipple->drawable.height));
14938
14939	if ((stipple->drawable.width | stipple->drawable.height) == 8)
14940		return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage,
14941							   gc, n, rect,
14942							   extents, clipped);
14943
14944	if ((stipple->drawable.width | stipple->drawable.height) <= 0xc &&
14945	    is_power_of_two(stipple->drawable.width) &&
14946	    is_power_of_two(stipple->drawable.height))
14947		return sna_poly_fill_rect_stippled_nxm_blt(drawable, bo, damage,
14948							   gc, n, rect,
14949							   extents, clipped);
14950
14951	if (extents->x1 - gc->patOrg.x - drawable->x >= 0 &&
14952	    extents->x2 - gc->patOrg.x - drawable->x <= stipple->drawable.width &&
14953	    extents->y1 - gc->patOrg.y - drawable->y >= 0 &&
14954	    extents->y2 - gc->patOrg.y - drawable->y <= stipple->drawable.height) {
14955		if (stipple->drawable.width <= 8 && stipple->drawable.height <= 8)
14956			return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage,
14957								   gc, n, rect,
14958								   extents, clipped);
14959		else
14960			return sna_poly_fill_rect_stippled_1_blt(drawable, bo, damage,
14961								 gc, n, rect,
14962								 extents, clipped);
14963	} else {
14964		return sna_poly_fill_rect_stippled_n_blt(drawable, bo, damage,
14965							 gc, n, rect,
14966							 extents, clipped);
14967	}
14968}
14969
14970static unsigned
14971sna_poly_fill_rect_extents(DrawablePtr drawable, GCPtr gc,
14972			   int *_n, xRectangle **_r,
14973			   BoxPtr out)
14974{
14975	int n;
14976	xRectangle *r;
14977	Box32Rec box;
14978	bool clipped;
14979
14980	if (*_n == 0)
14981		return 0;
14982
14983	DBG(("%s: [0] = (%d, %d)x(%d, %d)\n",
14984	     __FUNCTION__, (*_r)->x, (*_r)->y, (*_r)->width, (*_r)->height));
14985
14986	/* Remove any zero-size rectangles from the array */
14987	while (*_n && ((*_r)->width == 0 || (*_r)->height == 0))
14988		--*_n, ++*_r;
14989
14990	if (*_n == 0)
14991		return 0;
14992
14993	n = *_n;
14994	r = *_r;
14995
14996	box.x1 = r->x;
14997	box.x2 = box.x1 + r->width;
14998	box.y1 = r->y;
14999	box.y2 = box.y1 + r->height;
15000	r++;
15001
15002	while (--n) {
15003		if (r->width == 0 || r->height == 0)
15004			goto slow;
15005
15006		box32_add_rect(&box, r++);
15007	}
15008	goto done;
15009slow:
15010	{
15011		xRectangle *rr = r;
15012		do {
15013			do {
15014				--*_n, r++;
15015			} while (--n && (r->width == 0 || r->height == 0));
15016			while (n && r->width && r->height) {
15017				box32_add_rect(&box, r);
15018				*rr++ = *r++;
15019				n--;
15020			}
15021		} while (n);
15022	}
15023done:
15024
15025	clipped = box32_trim_and_translate(&box, drawable, gc);
15026	if (!box32_to_box16(&box, out))
15027		return 0;
15028
15029	return 1 | clipped << 1;
15030}
15031
15032static void
15033sna_poly_fill_rect(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect)
15034{
15035	PixmapPtr pixmap = get_drawable_pixmap(draw);
15036	struct sna *sna = to_sna_from_pixmap(pixmap);
15037	struct sna_pixmap *priv = sna_pixmap(pixmap);
15038	struct sna_damage **damage;
15039	struct kgem_bo *bo;
15040	RegionRec region;
15041	unsigned flags, hint;
15042	uint32_t color;
15043
15044	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
15045	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
15046	     (gc->fillStyle == FillSolid ||
15047	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
15048	     gc->fillStyle, gc->tileIsPixel,
15049	     gc->alu));
15050
15051	flags = sna_poly_fill_rect_extents(draw, gc, &n, &rect, &region.extents);
15052	if (flags == 0) {
15053		DBG(("%s, nothing to do\n", __FUNCTION__));
15054		return;
15055	}
15056
15057	DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
15058	     region.extents.x1, region.extents.y1,
15059	     region.extents.x2, region.extents.y2,
15060	     flags));
15061
15062	if (FORCE_FALLBACK || !ACCEL_POLY_FILL_RECT) {
15063		DBG(("%s: fallback forced\n", __FUNCTION__));
15064		goto fallback;
15065	}
15066
15067	if (priv == NULL) {
15068		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
15069		goto fallback;
15070	}
15071
15072	if (wedged(sna)) {
15073		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
15074		goto fallback;
15075	}
15076
15077	if (!PM_IS_SOLID(draw, gc->planemask)) {
15078		DBG(("%s: fallback -- planemask=0x%lx (not-solid)\n",
15079		     __FUNCTION__, gc->planemask));
15080		goto fallback;
15081	}
15082
15083	if (alu_overwrites(gc->alu))
15084		flags |= OVERWRITES;
15085
15086	/* Clear the cpu damage so that we refresh the GPU status of the
15087	 * pixmap upon a redraw after a period of inactivity.
15088	 */
15089	hint = PREFER_GPU;
15090	if (n == 1 && gc->fillStyle != FillStippled && flags & OVERWRITES) {
15091		int16_t dx, dy;
15092
15093		region.data = NULL;
15094
15095		if (get_drawable_deltas(draw, pixmap, &dx, &dy)) {
15096			DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy));
15097			RegionTranslate(&region, dx, dy);
15098		}
15099
15100		if ((flags & IS_CLIPPED) == 0) {
15101			hint |= IGNORE_DAMAGE;
15102			if (region_subsumes_drawable(&region, &pixmap->drawable)) {
15103				discard_cpu_damage(sna, priv);
15104				hint |= REPLACES;
15105			} else {
15106				if (priv->cpu_damage &&
15107				    region_subsumes_damage(&region, priv->cpu_damage))
15108					discard_cpu_damage(sna, priv);
15109			}
15110		}
15111		if (priv->cpu_damage == NULL) {
15112			if (priv->gpu_bo &&
15113			    (hint & REPLACES ||
15114			     box_covers_pixmap(pixmap, &region.extents) ||
15115			     box_inplace(pixmap, &region.extents))) {
15116				DBG(("%s: promoting to full GPU\n",
15117				     __FUNCTION__));
15118				assert(priv->gpu_bo->proxy == NULL);
15119				sna_damage_all(&priv->gpu_damage, pixmap);
15120			}
15121			DBG(("%s: dropping last-cpu hint\n", __FUNCTION__));
15122			priv->cpu = false;
15123		}
15124
15125		if (dx | dy)
15126			RegionTranslate(&region, -dx, -dy);
15127	}
15128
15129	/* If the source is already on the GPU, keep the operation on the GPU */
15130	if (gc->fillStyle == FillTiled && !gc->tileIsPixel &&
15131	    sna_pixmap_is_gpu(gc->tile.pixmap)) {
15132		DBG(("%s: source is already on the gpu\n", __FUNCTION__));
15133		hint |= FORCE_GPU;
15134	}
15135
15136	bo = sna_drawable_use_bo(draw, hint, &region.extents, &damage);
15137	if (bo == NULL) {
15138		DBG(("%s: not using GPU, hint=%x\n", __FUNCTION__, hint));
15139		goto fallback;
15140	}
15141	if (hint & REPLACES && UNDO)
15142		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
15143
15144	if (gc_is_solid(gc, &color)) {
15145		DBG(("%s: solid fill [%08x], testing for blt\n",
15146		     __FUNCTION__, color));
15147
15148		if (sna_poly_fill_rect_blt(draw,
15149					   bo, damage,
15150					   gc, color, n, rect,
15151					   &region.extents, flags))
15152			return;
15153	} else if (gc->fillStyle == FillTiled) {
15154		DBG(("%s: tiled fill, testing for blt\n", __FUNCTION__));
15155
15156		if (sna_poly_fill_rect_tiled_blt(draw, bo, damage,
15157						 gc, n, rect,
15158						 &region.extents, flags))
15159			return;
15160	} else {
15161		DBG(("%s: stippled fill, testing for blt\n", __FUNCTION__));
15162
15163		if (sna_poly_fill_rect_stippled_blt(draw, bo, damage,
15164						    gc, n, rect,
15165						    &region.extents, flags))
15166			return;
15167	}
15168
15169fallback:
15170	DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__,
15171	     region.extents.x1, region.extents.y1,
15172	     region.extents.x2, region.extents.y2));
15173	region.data = NULL;
15174	if (!region_maybe_clip(&region, gc->pCompositeClip)) {
15175		DBG(("%s: nothing to do, all clipped\n", __FUNCTION__));
15176		return;
15177	}
15178
15179	if (!sna_gc_move_to_cpu(gc, draw, &region))
15180		goto out;
15181	if (!sna_drawable_move_region_to_cpu(draw, &region,
15182					     drawable_gc_flags(draw, gc, n > 1)))
15183		goto out;
15184
15185	if (sigtrap_get() == 0) {
15186		DBG(("%s: fallback - fbPolyFillRect\n", __FUNCTION__));
15187		fbPolyFillRect(draw, gc, n, rect);
15188		FALLBACK_FLUSH(draw);
15189		sigtrap_put();
15190	}
15191out:
15192	sna_gc_move_to_gpu(gc);
15193	RegionUninit(&region);
15194}
15195
15196static void
15197sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *r)
15198{
15199	struct sna_fill_spans *data = sna_gc(gc)->priv;
15200	uint32_t color;
15201
15202	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
15203	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
15204	     (gc->fillStyle == FillSolid ||
15205	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
15206	     gc->fillStyle, gc->tileIsPixel,
15207	     gc->alu));
15208
15209	assert(PM_IS_SOLID(draw, gc->planemask));
15210	if (n == 0)
15211		return;
15212
15213	/* The mi routines do not attempt to keep the spans it generates
15214	 * within the clip, so we must run them through the clipper.
15215	 */
15216
15217	if (gc_is_solid(gc, &color)) {
15218		(void)sna_poly_fill_rect_blt(draw,
15219					     data->bo, NULL,
15220					     gc, color, n, r,
15221					     &data->region.extents,
15222					     IS_CLIPPED);
15223	} else if (gc->fillStyle == FillTiled) {
15224		(void)sna_poly_fill_rect_tiled_blt(draw,
15225						   data->bo, NULL,
15226						   gc, n, r,
15227						   &data->region.extents,
15228						   IS_CLIPPED);
15229	} else {
15230		(void)sna_poly_fill_rect_stippled_blt(draw,
15231						    data->bo, NULL,
15232						    gc, n, r,
15233						    &data->region.extents,
15234						    IS_CLIPPED);
15235	}
15236}
15237
15238static void
15239sna_poly_fill_arc(DrawablePtr draw, GCPtr gc, int n, xArc *arc)
15240{
15241	struct sna_fill_spans data;
15242	struct sna_pixmap *priv;
15243
15244	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
15245	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
15246	     (gc->fillStyle == FillSolid ||
15247	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
15248	     gc->fillStyle, gc->tileIsPixel,
15249	     gc->alu));
15250
15251	data.flags = sna_poly_arc_extents(draw, gc, n, arc,
15252					  &data.region.extents);
15253	if (data.flags == 0)
15254		return;
15255
15256	DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
15257	     data.region.extents.x1, data.region.extents.y1,
15258	     data.region.extents.x2, data.region.extents.y2,
15259	     data.flags));
15260
15261	data.region.data = NULL;
15262
15263	if (FORCE_FALLBACK)
15264		goto fallback;
15265
15266	if (!ACCEL_POLY_FILL_ARC)
15267		goto fallback;
15268
15269	data.pixmap = get_drawable_pixmap(draw);
15270	data.sna = to_sna_from_pixmap(data.pixmap);
15271	priv = sna_pixmap(data.pixmap);
15272	if (priv == NULL) {
15273		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
15274		goto fallback;
15275	}
15276
15277	if (wedged(data.sna)) {
15278		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
15279		goto fallback;
15280	}
15281
15282	if (!PM_IS_SOLID(draw, gc->planemask))
15283		goto fallback;
15284
15285	if ((data.bo = sna_drawable_use_bo(draw,
15286					   use_fill_spans(draw, gc, &data.region.extents, data.flags),
15287					   &data.region.extents,
15288					   &data.damage))) {
15289		uint32_t color;
15290
15291		get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy);
15292		sna_gc(gc)->priv = &data;
15293
15294		if (gc_is_solid(gc, &color)) {
15295			struct sna_fill_op fill;
15296
15297			if (!sna_fill_init_blt(&fill,
15298					       data.sna, data.pixmap,
15299					       data.bo, gc->alu, color,
15300					       FILL_SPANS))
15301				goto fallback;
15302
15303			data.op = &fill;
15304
15305			if ((data.flags & IS_CLIPPED) == 0) {
15306				if (data.dx | data.dy)
15307					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
15308				else
15309					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
15310			} else {
15311				if (!region_maybe_clip(&data.region,
15312						       gc->pCompositeClip))
15313					return;
15314
15315				if (region_is_singular(&data.region))
15316					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
15317				else
15318					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
15319			}
15320			assert(gc->miTranslate);
15321			gc->ops = &sna_gc_ops__tmp;
15322
15323			miPolyFillArc(draw, gc, n, arc);
15324			fill.done(data.sna, &fill);
15325		} else {
15326			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
15327			gc->ops = &sna_gc_ops__tmp;
15328
15329			miPolyFillArc(draw, gc, n, arc);
15330		}
15331
15332		gc->ops = (GCOps *)&sna_gc_ops;
15333		if (data.damage) {
15334			if (data.dx | data.dy)
15335				pixman_region_translate(&data.region, data.dx, data.dy);
15336			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
15337			sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap);
15338		}
15339		assert_pixmap_damage(data.pixmap);
15340		RegionUninit(&data.region);
15341		return;
15342	}
15343
15344fallback:
15345	DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__,
15346	     data.region.extents.x1, data.region.extents.y1,
15347	     data.region.extents.x2, data.region.extents.y2));
15348	if (!region_maybe_clip(&data.region, gc->pCompositeClip)) {
15349		DBG(("%s: nothing to do, all clipped\n", __FUNCTION__));
15350		return;
15351	}
15352
15353	if (!sna_gc_move_to_cpu(gc, draw, &data.region))
15354		goto out;
15355	if (!sna_drawable_move_region_to_cpu(draw, &data.region,
15356					     drawable_gc_flags(draw, gc, true)))
15357		goto out;
15358
15359	if (sigtrap_get() == 0) {
15360		DBG(("%s: fallback -- miPolyFillArc -> sna_fill_spans__cpu\n",
15361		     __FUNCTION__));
15362		miPolyFillArc(draw, gc, n, arc);
15363		sigtrap_put();
15364	}
15365out:
15366	sna_gc_move_to_gpu(gc);
15367	RegionUninit(&data.region);
15368}
15369
15370struct sna_font {
15371	CharInfoRec glyphs8[256];
15372	CharInfoRec *glyphs16[256];
15373};
15374#define GLYPH_INVALID (void *)1
15375#define GLYPH_EMPTY (void *)2
15376
15377static Bool
15378sna_realize_font(ScreenPtr screen, FontPtr font)
15379{
15380	struct sna_font *priv;
15381
15382	DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key));
15383
15384	priv = calloc(1, sizeof(struct sna_font));
15385	if (priv == NULL)
15386		return FALSE;
15387
15388	if (!FontSetPrivate(font, sna_font_key, priv)) {
15389		free(priv);
15390		return FALSE;
15391	}
15392
15393	return TRUE;
15394}
15395
15396static Bool
15397sna_unrealize_font(ScreenPtr screen, FontPtr font)
15398{
15399	struct sna_font *priv = FontGetPrivate(font, sna_font_key);
15400	int i, j;
15401
15402	DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key));
15403
15404	if (priv == NULL)
15405		return TRUE;
15406
15407	for (i = 0; i < 256; i++) {
15408		if ((uintptr_t)priv->glyphs8[i].bits & ~3)
15409			free(priv->glyphs8[i].bits);
15410	}
15411	for (j = 0; j < 256; j++) {
15412		if (priv->glyphs16[j] == NULL)
15413			continue;
15414
15415		for (i = 0; i < 256; i++) {
15416			if ((uintptr_t)priv->glyphs16[j][i].bits & ~3)
15417				free(priv->glyphs16[j][i].bits);
15418		}
15419		free(priv->glyphs16[j]);
15420	}
15421	free(priv);
15422
15423	FontSetPrivate(font, sna_font_key, NULL);
15424	return TRUE;
15425}
15426
15427static bool
15428sna_glyph_blt(DrawablePtr drawable, GCPtr gc,
15429	      int _x, int _y, unsigned int _n,
15430	      CharInfoPtr *_info,
15431	      RegionRec *clip,
15432	      uint32_t fg, uint32_t bg,
15433	      bool transparent)
15434{
15435	PixmapPtr pixmap = get_drawable_pixmap(drawable);
15436	struct sna *sna = to_sna_from_pixmap(pixmap);
15437	struct kgem_bo *bo;
15438	struct sna_damage **damage;
15439	const BoxRec *extents, *last_extents;
15440	uint32_t *b;
15441	int16_t dx, dy;
15442	uint32_t br00;
15443	uint16_t unwind_batch, unwind_reloc;
15444	unsigned hint;
15445
15446	uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S;
15447
15448	DBG(("%s (%d, %d) x %d, fg=%08x, bg=%08x alu=%02x\n",
15449	     __FUNCTION__, _x, _y, _n, fg, bg, rop));
15450
15451	if (wedged(sna)) {
15452		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
15453		return false;
15454	}
15455
15456	if (!transparent && clip->data == NULL)
15457		hint = PREFER_GPU | IGNORE_DAMAGE;
15458	else
15459		hint = PREFER_GPU;
15460
15461	bo = sna_drawable_use_bo(drawable, hint, &clip->extents, &damage);
15462	if (bo == NULL)
15463		return false;
15464
15465	if (bo->tiling == I915_TILING_Y) {
15466		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
15467		assert(bo == __sna_pixmap_get_bo(pixmap));
15468		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
15469		if (bo == NULL) {
15470			DBG(("%s: fallback -- unable to change tiling\n",
15471			     __FUNCTION__));
15472			return false;
15473		}
15474	}
15475
15476	if (!kgem_bo_can_blt(&sna->kgem, bo))
15477		return false;
15478
15479	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
15480		RegionTranslate(clip, dx, dy);
15481	_x += drawable->x + dx;
15482	_y += drawable->y + dy;
15483
15484	extents = region_rects(clip);
15485	last_extents = extents + region_num_rects(clip);
15486
15487	if (!transparent) { /* emulate miImageGlyphBlt */
15488		if (!sna_blt_fill_boxes(sna, GXcopy,
15489					bo, drawable->bitsPerPixel,
15490					bg, extents, last_extents - extents)) {
15491			RegionTranslate(clip, -dx, -dy);
15492			return false;
15493		}
15494	}
15495
15496	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
15497	assert(kgem_bo_can_blt(&sna->kgem, bo));
15498	if (!kgem_check_batch(&sna->kgem, 20) ||
15499	    !kgem_check_bo_fenced(&sna->kgem, bo) ||
15500	    !kgem_check_reloc(&sna->kgem, 1)) {
15501		kgem_submit(&sna->kgem);
15502		if (!kgem_check_bo_fenced(&sna->kgem, bo)) {
15503			RegionTranslate(clip, -dx, -dy);
15504			return false;
15505		}
15506		_kgem_set_mode(&sna->kgem, KGEM_BLT);
15507	}
15508	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
15509
15510	DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
15511	     __FUNCTION__,
15512	     extents->x1, extents->y1,
15513	     extents->x2, extents->y2));
15514
15515	unwind_batch = sna->kgem.nbatch;
15516	unwind_reloc = sna->kgem.nreloc;
15517
15518	assert(sna->kgem.mode == KGEM_BLT);
15519	b = sna->kgem.batch + sna->kgem.nbatch;
15520	if (sna->kgem.gen >= 0100) {
15521		b[0] = XY_SETUP_BLT | 3 << 20 | 8;
15522		b[1] = bo->pitch;
15523		if (sna->kgem.gen >= 040 && bo->tiling) {
15524			b[0] |= BLT_DST_TILED;
15525			b[1] >>= 2;
15526		}
15527		b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15528		b[2] = extents->y1 << 16 | extents->x1;
15529		b[3] = extents->y2 << 16 | extents->x2;
15530		*(uint64_t *)(b+4) =
15531			kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
15532					 I915_GEM_DOMAIN_RENDER << 16 |
15533					 I915_GEM_DOMAIN_RENDER |
15534					 KGEM_RELOC_FENCED,
15535					 0);
15536		b[6] = bg;
15537		b[7] = fg;
15538		b[8] = 0;
15539		b[9] = 0;
15540		sna->kgem.nbatch += 10;
15541	} else {
15542		b[0] = XY_SETUP_BLT | 3 << 20 | 6;
15543		b[1] = bo->pitch;
15544		if (sna->kgem.gen >= 040 && bo->tiling) {
15545			b[0] |= BLT_DST_TILED;
15546			b[1] >>= 2;
15547		}
15548		b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15549		b[2] = extents->y1 << 16 | extents->x1;
15550		b[3] = extents->y2 << 16 | extents->x2;
15551		b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
15552				      I915_GEM_DOMAIN_RENDER << 16 |
15553				      I915_GEM_DOMAIN_RENDER |
15554				      KGEM_RELOC_FENCED,
15555				      0);
15556		b[5] = bg;
15557		b[6] = fg;
15558		b[7] = 0;
15559		sna->kgem.nbatch += 8;
15560	}
15561
15562	br00 = XY_TEXT_IMMEDIATE_BLT;
15563	if (bo->tiling && sna->kgem.gen >= 040)
15564		br00 |= BLT_DST_TILED;
15565
15566	do {
15567		CharInfoPtr *info = _info;
15568		int x = _x, y = _y, n = _n;
15569
15570		do {
15571			CharInfoPtr c = *info++;
15572			int w = GLYPHWIDTHPIXELS(c);
15573			int h = GLYPHHEIGHTPIXELS(c);
15574			int w8 = (w + 7) >> 3;
15575			int x1, y1, len;
15576
15577			if (c->bits == GLYPH_EMPTY)
15578				goto skip;
15579
15580			len = (w8 * h + 7) >> 3 << 1;
15581			x1 = x + c->metrics.leftSideBearing;
15582			y1 = y - c->metrics.ascent;
15583
15584			DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__,
15585			     x,y, x1, y1, w, w8, h, len));
15586
15587			if (x1 >= extents->x2 || y1 >= extents->y2)
15588				goto skip;
15589			if (x1 + w <= extents->x1 || y1 + h <= extents->y1)
15590				goto skip;
15591
15592			assert(len > 0);
15593			if (!kgem_check_batch(&sna->kgem, 3+len)) {
15594				_kgem_submit(&sna->kgem);
15595				_kgem_set_mode(&sna->kgem, KGEM_BLT);
15596				kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
15597
15598				DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n",
15599				     __FUNCTION__,
15600				     extents->x1, extents->y1,
15601				     extents->x2, extents->y2));
15602
15603				unwind_batch = sna->kgem.nbatch;
15604				unwind_reloc = sna->kgem.nreloc;
15605
15606				assert(sna->kgem.mode == KGEM_BLT);
15607				b = sna->kgem.batch + sna->kgem.nbatch;
15608				if (sna->kgem.gen >= 0100) {
15609					b[0] = XY_SETUP_BLT | 3 << 20 | 8;
15610					b[1] = bo->pitch;
15611					if (bo->tiling) {
15612						b[0] |= BLT_DST_TILED;
15613						b[1] >>= 2;
15614					}
15615					b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15616					b[2] = extents->y1 << 16 | extents->x1;
15617					b[3] = extents->y2 << 16 | extents->x2;
15618					*(uint64_t *)(b+4) =
15619						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
15620								 I915_GEM_DOMAIN_RENDER << 16 |
15621								 I915_GEM_DOMAIN_RENDER |
15622								 KGEM_RELOC_FENCED,
15623								 0);
15624					b[6] = bg;
15625					b[7] = fg;
15626					b[8] = 0;
15627					b[9] = 0;
15628					sna->kgem.nbatch += 10;
15629				} else {
15630					b[0] = XY_SETUP_BLT | 3 << 20 | 6;
15631					b[1] = bo->pitch;
15632					if (sna->kgem.gen >= 040 && bo->tiling) {
15633						b[0] |= BLT_DST_TILED;
15634						b[1] >>= 2;
15635					}
15636					b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15637					b[2] = extents->y1 << 16 | extents->x1;
15638					b[3] = extents->y2 << 16 | extents->x2;
15639					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
15640							      I915_GEM_DOMAIN_RENDER << 16 |
15641							      I915_GEM_DOMAIN_RENDER |
15642							      KGEM_RELOC_FENCED,
15643							      0);
15644					b[5] = bg;
15645					b[6] = fg;
15646					b[7] = 0;
15647					sna->kgem.nbatch += 8;
15648				}
15649			}
15650
15651			assert(sna->kgem.mode == KGEM_BLT);
15652			b = sna->kgem.batch + sna->kgem.nbatch;
15653			sna->kgem.nbatch += 3 + len;
15654
15655			b[0] = br00 | (1 + len);
15656			b[1] = (uint16_t)y1 << 16 | (uint16_t)x1;
15657			b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w);
15658			{
15659				uint64_t *src = (uint64_t *)c->bits;
15660				uint64_t *dst = (uint64_t *)(b + 3);
15661				do  {
15662					*dst++ = *src++;
15663					len -= 2;
15664				} while (len);
15665			}
15666
15667			if (damage) {
15668				BoxRec r;
15669
15670				r.x1 = x1;
15671				r.y1 = y1;
15672				r.x2 = x1 + w;
15673				r.y2 = y1 + h;
15674				if (box_intersect(&r, extents))
15675					sna_damage_add_box(damage, &r);
15676			}
15677skip:
15678			x += c->metrics.characterWidth;
15679		} while (--n);
15680
15681		if (++extents == last_extents)
15682			break;
15683
15684		if (kgem_check_batch(&sna->kgem, 3)) {
15685			assert(sna->kgem.mode == KGEM_BLT);
15686			b = sna->kgem.batch + sna->kgem.nbatch;
15687			sna->kgem.nbatch += 3;
15688
15689			DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
15690			     __FUNCTION__,
15691			     extents->x1, extents->y1,
15692			     extents->x2, extents->y2));
15693
15694			b[0] = XY_SETUP_CLIP;
15695			b[1] = extents->y1 << 16 | extents->x1;
15696			b[2] = extents->y2 << 16 | extents->x2;
15697		}
15698	} while (1);
15699
15700	if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) {
15701		sna->kgem.nbatch = unwind_batch;
15702		sna->kgem.nreloc = unwind_reloc;
15703		if (sna->kgem.nbatch == 0)
15704			kgem_bo_undo(&sna->kgem, bo);
15705	}
15706
15707	assert_pixmap_damage(pixmap);
15708	blt_done(sna);
15709	return true;
15710}
15711
15712static void
15713sna_glyph_extents(FontPtr font,
15714		  CharInfoPtr *info,
15715		  unsigned long count,
15716		  ExtentInfoRec *extents)
15717{
15718	extents->drawDirection = font->info.drawDirection;
15719	extents->fontAscent = font->info.fontAscent;
15720	extents->fontDescent = font->info.fontDescent;
15721
15722	extents->overallAscent = info[0]->metrics.ascent;
15723	extents->overallDescent = info[0]->metrics.descent;
15724	extents->overallLeft = info[0]->metrics.leftSideBearing;
15725	extents->overallRight = info[0]->metrics.rightSideBearing;
15726	extents->overallWidth = info[0]->metrics.characterWidth;
15727
15728	while (--count) {
15729		CharInfoPtr p =*++info;
15730		int v;
15731
15732		if (p->metrics.ascent > extents->overallAscent)
15733			extents->overallAscent = p->metrics.ascent;
15734		if (p->metrics.descent > extents->overallDescent)
15735			extents->overallDescent = p->metrics.descent;
15736
15737		v = extents->overallWidth + p->metrics.leftSideBearing;
15738		if (v < extents->overallLeft)
15739			extents->overallLeft = v;
15740
15741		v = extents->overallWidth + p->metrics.rightSideBearing;
15742		if (v > extents->overallRight)
15743			extents->overallRight = v;
15744
15745		extents->overallWidth += p->metrics.characterWidth;
15746	}
15747}
15748
15749static bool sna_set_glyph(CharInfoPtr in, CharInfoPtr out)
15750{
15751	int w = GLYPHWIDTHPIXELS(in);
15752	int h = GLYPHHEIGHTPIXELS(in);
15753	int stride = GLYPHWIDTHBYTESPADDED(in);
15754	uint8_t *dst, *src;
15755	int clear = 1;
15756
15757	out->metrics = in->metrics;
15758
15759	/* Skip empty glyphs */
15760	if (w == 0 || h == 0 || ((w|h) == 1 && (in->bits[0] & 1) == 0)) {
15761		out->bits = GLYPH_EMPTY;
15762		return true;
15763	}
15764
15765	w = (w + 7) >> 3;
15766
15767	out->bits = malloc((w*h + 7) & ~7);
15768	if (out->bits == NULL)
15769		return false;
15770
15771	VG(memset(out->bits, 0, (w*h + 7) & ~7));
15772	src = (uint8_t *)in->bits;
15773	dst = (uint8_t *)out->bits;
15774	stride -= w;
15775	do {
15776		int i = w;
15777		do {
15778			clear &= *src == 0;
15779			*dst++ = byte_reverse(*src++);
15780		} while (--i);
15781		src += stride;
15782	} while (--h);
15783
15784	if (clear) {
15785		free(out->bits);
15786		out->bits = GLYPH_EMPTY;
15787	}
15788
15789	return true;
15790}
15791
15792inline static bool sna_get_glyph8(FontPtr font, struct sna_font *priv,
15793				  uint8_t g, CharInfoPtr *out)
15794{
15795	unsigned long n;
15796	CharInfoPtr p, ret;
15797
15798	p = &priv->glyphs8[g];
15799	if (p->bits) {
15800		*out = p;
15801		return p->bits != GLYPH_INVALID;
15802	}
15803
15804	font->get_glyphs(font, 1, &g, Linear8Bit, &n, &ret);
15805	if (n == 0) {
15806		p->bits = GLYPH_INVALID;
15807		return false;
15808	}
15809
15810	return sna_set_glyph(ret, *out = p);
15811}
15812
15813inline static bool sna_get_glyph16(FontPtr font, struct sna_font *priv,
15814				   uint16_t g, CharInfoPtr *out)
15815{
15816	unsigned long n;
15817	CharInfoPtr page, p, ret;
15818
15819	page = priv->glyphs16[g>>8];
15820	if (page == NULL)
15821		page = priv->glyphs16[g>>8] = calloc(256, sizeof(CharInfoRec));
15822
15823	p = &page[g&0xff];
15824	if (p->bits) {
15825		*out = p;
15826		return p->bits != GLYPH_INVALID;
15827	}
15828
15829	font->get_glyphs(font, 1, (unsigned char *)&g,
15830			 FONTLASTROW(font) ? TwoD16Bit : Linear16Bit,
15831			 &n, &ret);
15832	if (n == 0) {
15833		p->bits = GLYPH_INVALID;
15834		return false;
15835	}
15836
15837	return sna_set_glyph(ret, *out = p);
15838}
15839
15840static inline bool sna_font_too_large(FontPtr font)
15841{
15842	int top = max(FONTMAXBOUNDS(font, ascent), FONTASCENT(font));
15843	int bot = max(FONTMAXBOUNDS(font, descent), FONTDESCENT(font));
15844	int width = max(FONTMAXBOUNDS(font, characterWidth), -FONTMINBOUNDS(font, characterWidth));
15845	DBG(("%s? (%d + %d) x %d: %d > 124\n", __FUNCTION__,
15846	     top, bot, width, (top + bot) * (width + 7)/8));
15847	return (top + bot) * (width + 7)/8 > 124;
15848}
15849
15850static int
15851sna_poly_text8(DrawablePtr drawable, GCPtr gc,
15852	       int x, int y,
15853	       int count, char *chars)
15854{
15855	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
15856	CharInfoPtr info[255];
15857	ExtentInfoRec extents;
15858	RegionRec region;
15859	long unsigned i, n;
15860	uint32_t fg;
15861
15862	for (i = n = 0; i < count; i++) {
15863		if (sna_get_glyph8(gc->font, priv, chars[i], &info[n]))
15864			n++;
15865	}
15866	if (n == 0)
15867		return x;
15868
15869	sna_glyph_extents(gc->font, info, n, &extents);
15870	region.extents.x1 = x + extents.overallLeft;
15871	region.extents.y1 = y - extents.overallAscent;
15872	region.extents.x2 = x + extents.overallRight;
15873	region.extents.y2 = y + extents.overallDescent;
15874
15875	translate_box(&region.extents, drawable);
15876	clip_box(&region.extents, gc);
15877	if (box_empty(&region.extents))
15878		return x + extents.overallRight;
15879
15880	region.data = NULL;
15881	if (!region_maybe_clip(&region, gc->pCompositeClip))
15882		return x + extents.overallRight;
15883
15884	if (FORCE_FALLBACK)
15885		goto fallback;
15886
15887	if (!ACCEL_POLY_TEXT8)
15888		goto fallback;
15889
15890	if (sna_font_too_large(gc->font))
15891		goto fallback;
15892
15893	if (!PM_IS_SOLID(drawable, gc->planemask))
15894		goto fallback;
15895
15896	if (!gc_is_solid(gc, &fg))
15897		goto fallback;
15898
15899	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region, fg, -1, true)) {
15900fallback:
15901		DBG(("%s: fallback\n", __FUNCTION__));
15902		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
15903				     Linear8Bit, &n, info);
15904
15905		if (!sna_gc_move_to_cpu(gc, drawable, &region))
15906			goto out;
15907		if (!sna_drawable_move_region_to_cpu(drawable, &region,
15908						     MOVE_READ | MOVE_WRITE))
15909			goto out;
15910
15911		if (sigtrap_get() == 0) {
15912			DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
15913			fbPolyGlyphBlt(drawable, gc, x, y, n,
15914				       info, FONTGLYPHS(gc->font));
15915			FALLBACK_FLUSH(drawable);
15916			sigtrap_put();
15917		}
15918out:
15919		sna_gc_move_to_gpu(gc);
15920	}
15921	RegionUninit(&region);
15922	return x + extents.overallRight;
15923}
15924
15925static int
15926sna_poly_text16(DrawablePtr drawable, GCPtr gc,
15927		int x, int y,
15928		int count, unsigned short *chars)
15929{
15930	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
15931	CharInfoPtr info[255];
15932	ExtentInfoRec extents;
15933	RegionRec region;
15934	long unsigned i, n;
15935	uint32_t fg;
15936
15937	for (i = n = 0; i < count; i++) {
15938		if (sna_get_glyph16(gc->font, priv, chars[i], &info[n]))
15939			n++;
15940	}
15941	if (n == 0)
15942		return x;
15943
15944	sna_glyph_extents(gc->font, info, n, &extents);
15945	region.extents.x1 = x + extents.overallLeft;
15946	region.extents.y1 = y - extents.overallAscent;
15947	region.extents.x2 = x + extents.overallRight;
15948	region.extents.y2 = y + extents.overallDescent;
15949
15950	translate_box(&region.extents, drawable);
15951	clip_box(&region.extents, gc);
15952	if (box_empty(&region.extents))
15953		return x + extents.overallRight;
15954
15955	region.data = NULL;
15956	if (!region_maybe_clip(&region, gc->pCompositeClip))
15957		return x + extents.overallRight;
15958
15959	if (FORCE_FALLBACK)
15960		goto fallback;
15961
15962	if (!ACCEL_POLY_TEXT16)
15963		goto fallback;
15964
15965	if (sna_font_too_large(gc->font))
15966		goto fallback;
15967
15968	if (!PM_IS_SOLID(drawable, gc->planemask))
15969		goto fallback;
15970
15971	if (!gc_is_solid(gc, &fg))
15972		goto fallback;
15973
15974	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region, fg, -1, true)) {
15975fallback:
15976		DBG(("%s: fallback\n", __FUNCTION__));
15977		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
15978				     FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit,
15979				     &n, info);
15980
15981		if (!sna_gc_move_to_cpu(gc, drawable, &region))
15982			goto out;
15983		if (!sna_drawable_move_region_to_cpu(drawable, &region,
15984						     MOVE_READ | MOVE_WRITE))
15985			goto out;
15986
15987		if (sigtrap_get() == 0) {
15988			DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
15989			fbPolyGlyphBlt(drawable, gc, x, y, n,
15990				       info, FONTGLYPHS(gc->font));
15991			FALLBACK_FLUSH(drawable);
15992			sigtrap_put();
15993		}
15994out:
15995		sna_gc_move_to_gpu(gc);
15996	}
15997	RegionUninit(&region);
15998	return x + extents.overallRight;
15999}
16000
16001static void
16002sna_image_text8(DrawablePtr drawable, GCPtr gc,
16003		int x, int y,
16004		int count, char *chars)
16005{
16006	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
16007	CharInfoPtr info[255];
16008	ExtentInfoRec extents;
16009	RegionRec region;
16010	long unsigned i, n;
16011
16012	for (i = n = 0; i < count; i++) {
16013		if (sna_get_glyph8(gc->font, priv, chars[i], &info[n]))
16014			n++;
16015	}
16016	if (n == 0)
16017		return;
16018
16019	sna_glyph_extents(gc->font, info, n, &extents);
16020	region.extents.x1 = x + MIN(0, extents.overallLeft);
16021	region.extents.y1 = y - extents.fontAscent;
16022	region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight);
16023	region.extents.y2 = y + extents.fontDescent;
16024
16025	DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n",
16026	     __FUNCTION__, n, count,
16027	     extents.overallLeft, extents.overallRight, extents.overallWidth,
16028	     extents.fontAscent, extents.fontDescent,
16029	     region.extents.x1, region.extents.y1,
16030	     region.extents.x2, region.extents.y2));
16031
16032	translate_box(&region.extents, drawable);
16033	clip_box(&region.extents, gc);
16034	if (box_empty(&region.extents))
16035		return;
16036
16037	region.data = NULL;
16038	if (!region_maybe_clip(&region, gc->pCompositeClip))
16039		return;
16040
16041	DBG(("%s: clipped extents (%d, %d), (%d, %d)\n",
16042	     __FUNCTION__,
16043	     region.extents.x1, region.extents.y1,
16044	     region.extents.x2, region.extents.y2));
16045
16046	if (FORCE_FALLBACK)
16047		goto fallback;
16048
16049	if (!ACCEL_IMAGE_TEXT8)
16050		goto fallback;
16051
16052	if (sna_font_too_large(gc->font))
16053		goto fallback;
16054
16055	if (!PM_IS_SOLID(drawable, gc->planemask))
16056		goto fallback;
16057
16058	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region,
16059			   gc->fgPixel, gc->bgPixel, false)) {
16060fallback:
16061		DBG(("%s: fallback\n", __FUNCTION__));
16062		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
16063				     Linear8Bit, &n, info);
16064
16065		if (!sna_gc_move_to_cpu(gc, drawable, &region))
16066			goto out;
16067		if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_WRITE))
16068			goto out;
16069
16070		if (sigtrap_get() == 0) {
16071			DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
16072			fbImageGlyphBlt(drawable, gc, x, y, n,
16073					info, FONTGLYPHS(gc->font));
16074			FALLBACK_FLUSH(drawable);
16075			sigtrap_put();
16076		}
16077out:
16078		sna_gc_move_to_gpu(gc);
16079	}
16080	RegionUninit(&region);
16081}
16082
16083static void
16084sna_image_text16(DrawablePtr drawable, GCPtr gc,
16085		int x, int y,
16086		int count, unsigned short *chars)
16087{
16088	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
16089	CharInfoPtr info[255];
16090	ExtentInfoRec extents;
16091	RegionRec region;
16092	long unsigned i, n;
16093
16094	for (i = n = 0; i < count; i++) {
16095		if (sna_get_glyph16(gc->font, priv, chars[i], &info[n]))
16096			n++;
16097	}
16098	if (n == 0)
16099		return;
16100
16101	sna_glyph_extents(gc->font, info, n, &extents);
16102	region.extents.x1 = x + MIN(0, extents.overallLeft);
16103	region.extents.y1 = y - extents.fontAscent;
16104	region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight);
16105	region.extents.y2 = y + extents.fontDescent;
16106
16107	DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n",
16108	     __FUNCTION__, n, count,
16109	     extents.overallLeft, extents.overallRight, extents.overallWidth,
16110	     extents.fontAscent, extents.fontDescent,
16111	     region.extents.x1, region.extents.y1,
16112	     region.extents.x2, region.extents.y2));
16113
16114	translate_box(&region.extents, drawable);
16115	clip_box(&region.extents, gc);
16116	if (box_empty(&region.extents))
16117		return;
16118
16119	region.data = NULL;
16120	if (!region_maybe_clip(&region, gc->pCompositeClip))
16121		return;
16122
16123	DBG(("%s: clipped extents (%d, %d), (%d, %d)\n",
16124	     __FUNCTION__,
16125	     region.extents.x1, region.extents.y1,
16126	     region.extents.x2, region.extents.y2));
16127
16128	if (FORCE_FALLBACK)
16129		goto fallback;
16130
16131	if (!ACCEL_IMAGE_TEXT16)
16132		goto fallback;
16133
16134	if (sna_font_too_large(gc->font))
16135		goto fallback;
16136
16137	if (!PM_IS_SOLID(drawable, gc->planemask))
16138		goto fallback;
16139
16140	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region,
16141			   gc->fgPixel, gc->bgPixel, false)) {
16142fallback:
16143		DBG(("%s: fallback\n", __FUNCTION__));
16144		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
16145				     FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit,
16146				     &n, info);
16147
16148		if (!sna_gc_move_to_cpu(gc, drawable, &region))
16149			goto out;
16150		if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_WRITE))
16151			goto out;
16152
16153		if (sigtrap_get() == 0) {
16154			DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
16155			fbImageGlyphBlt(drawable, gc, x, y, n,
16156					info, FONTGLYPHS(gc->font));
16157			FALLBACK_FLUSH(drawable);
16158			sigtrap_put();
16159		}
16160out:
16161		sna_gc_move_to_gpu(gc);
16162	}
16163	RegionUninit(&region);
16164}
16165
16166/* XXX Damage bypasses the Text interface and so we lose our custom gluphs */
16167static bool
16168sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc,
16169		       int _x, int _y, unsigned int _n,
16170		       CharInfoPtr *_info, pointer _base,
16171		       struct kgem_bo *bo,
16172		       struct sna_damage **damage,
16173		       RegionPtr clip,
16174		       uint32_t fg, uint32_t bg,
16175		       bool transparent)
16176{
16177	PixmapPtr pixmap = get_drawable_pixmap(drawable);
16178	struct sna *sna = to_sna_from_pixmap(pixmap);
16179	const BoxRec *extents, *last_extents;
16180	uint32_t *b;
16181	int16_t dx, dy;
16182	uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S;
16183	uint16_t unwind_batch, unwind_reloc;
16184
16185	DBG(("%s: pixmap=%ld, bo=%d, damage=%p, fg=%08x, bg=%08x\n",
16186	     __FUNCTION__, pixmap->drawable.serialNumber, bo->handle, damage, fg, bg));
16187
16188	if (bo->tiling == I915_TILING_Y) {
16189		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
16190		assert(bo == __sna_pixmap_get_bo(pixmap));
16191		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
16192		if (bo == NULL) {
16193			DBG(("%s: fallback -- unable to change tiling\n",
16194			     __FUNCTION__));
16195			return false;
16196		}
16197	}
16198
16199	if (!kgem_bo_can_blt(&sna->kgem, bo))
16200		return false;
16201
16202	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
16203		RegionTranslate(clip, dx, dy);
16204	_x += drawable->x + dx;
16205	_y += drawable->y + dy;
16206
16207	extents = region_rects(clip);
16208	last_extents = extents + region_num_rects(clip);
16209
16210	if (!transparent) { /* emulate miImageGlyphBlt */
16211		if (!sna_blt_fill_boxes(sna, GXcopy,
16212					bo, drawable->bitsPerPixel,
16213					bg, extents, last_extents - extents)) {
16214			RegionTranslate(clip, -dx, -dy);
16215			return false;
16216		}
16217	}
16218
16219	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
16220	assert(kgem_bo_can_blt(&sna->kgem, bo));
16221	if (!kgem_check_batch(&sna->kgem, 20) ||
16222	    !kgem_check_bo_fenced(&sna->kgem, bo) ||
16223	    !kgem_check_reloc(&sna->kgem, 1)) {
16224		kgem_submit(&sna->kgem);
16225		if (!kgem_check_bo_fenced(&sna->kgem, bo)) {
16226			RegionTranslate(clip, -dx, -dy);
16227			return false;
16228		}
16229		_kgem_set_mode(&sna->kgem, KGEM_BLT);
16230	}
16231	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
16232
16233	unwind_batch = sna->kgem.nbatch;
16234	unwind_reloc = sna->kgem.nreloc;
16235
16236	DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
16237	     __FUNCTION__,
16238	     extents->x1, extents->y1,
16239	     extents->x2, extents->y2));
16240
16241	assert(sna->kgem.mode == KGEM_BLT);
16242	b = sna->kgem.batch + sna->kgem.nbatch;
16243	if (sna->kgem.gen >= 0100) {
16244		b[0] = XY_SETUP_BLT | 1 << 20 | 8;
16245		b[1] = bo->pitch;
16246		if (sna->kgem.gen >= 040 && bo->tiling) {
16247			b[0] |= BLT_DST_TILED;
16248			b[1] >>= 2;
16249		}
16250		b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
16251		b[2] = extents->y1 << 16 | extents->x1;
16252		b[3] = extents->y2 << 16 | extents->x2;
16253		*(uint64_t *)(b+4) =
16254			kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
16255					 I915_GEM_DOMAIN_RENDER << 16 |
16256					 I915_GEM_DOMAIN_RENDER |
16257					 KGEM_RELOC_FENCED,
16258					 0);
16259		b[6] = bg;
16260		b[7] = fg;
16261		b[8] = 0;
16262		b[9] = 0;
16263		sna->kgem.nbatch += 10;
16264	} else {
16265		b[0] = XY_SETUP_BLT | 1 << 20 | 6;
16266		b[1] = bo->pitch;
16267		if (sna->kgem.gen >= 040 && bo->tiling) {
16268			b[0] |= BLT_DST_TILED;
16269			b[1] >>= 2;
16270		}
16271		b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
16272		b[2] = extents->y1 << 16 | extents->x1;
16273		b[3] = extents->y2 << 16 | extents->x2;
16274		b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
16275				      I915_GEM_DOMAIN_RENDER << 16 |
16276				      I915_GEM_DOMAIN_RENDER |
16277				      KGEM_RELOC_FENCED,
16278				      0);
16279		b[5] = bg;
16280		b[6] = fg;
16281		b[7] = 0;
16282		sna->kgem.nbatch += 8;
16283	}
16284
16285	do {
16286		CharInfoPtr *info = _info;
16287		int x = _x, y = _y, n = _n;
16288
16289		do {
16290			CharInfoPtr c = *info++;
16291			uint8_t *glyph = FONTGLYPHBITS(base, c);
16292			int w = GLYPHWIDTHPIXELS(c);
16293			int h = GLYPHHEIGHTPIXELS(c);
16294			int stride = GLYPHWIDTHBYTESPADDED(c);
16295			int w8 = (w + 7) >> 3;
16296			int x1, y1, len, i;
16297			uint8_t *byte;
16298
16299			if (w == 0 || h == 0)
16300				goto skip;
16301
16302			len = (w8 * h + 7) >> 3 << 1;
16303			x1 = x + c->metrics.leftSideBearing;
16304			y1 = y - c->metrics.ascent;
16305
16306			DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__,
16307			     x,y, x1, y1, w, w8, h, len));
16308
16309			if (x1 >= extents->x2 || y1 >= extents->y2 ||
16310			    x1 + w <= extents->x1 || y1 + h <= extents->y1) {
16311				DBG(("%s: glyph is clipped (%d, %d)x(%d,%d) against extents (%d, %d), (%d, %d)\n",
16312				     __FUNCTION__,
16313				     x1, y1, w, h,
16314				     extents->x1, extents->y1,
16315				     extents->x2, extents->y2));
16316				goto skip;
16317			}
16318
16319			{
16320				int clear = 1, j = h;
16321				uint8_t *g = glyph;
16322
16323				do {
16324					i = w8;
16325					do {
16326						clear = *g++ == 0;
16327					} while (clear && --i);
16328					g += stride - w8;
16329				} while (clear && --j);
16330				if (clear) {
16331					DBG(("%s: skipping clear glyph for ImageGlyph\n",
16332					     __FUNCTION__));
16333					goto skip;
16334				}
16335			}
16336
16337			assert(len > 0);
16338			if (!kgem_check_batch(&sna->kgem, 3+len)) {
16339				_kgem_submit(&sna->kgem);
16340				_kgem_set_mode(&sna->kgem, KGEM_BLT);
16341				kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
16342
16343				unwind_batch = sna->kgem.nbatch;
16344				unwind_reloc = sna->kgem.nreloc;
16345
16346				DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n",
16347				     __FUNCTION__,
16348				     extents->x1, extents->y1,
16349				     extents->x2, extents->y2));
16350
16351				assert(sna->kgem.mode == KGEM_BLT);
16352				b = sna->kgem.batch + sna->kgem.nbatch;
16353				if (sna->kgem.gen >= 0100) {
16354					b[0] = XY_SETUP_BLT | 1 << 20 | 8;
16355					b[1] = bo->pitch;
16356					if (bo->tiling) {
16357						b[0] |= BLT_DST_TILED;
16358						b[1] >>= 2;
16359					}
16360					b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
16361					b[2] = extents->y1 << 16 | extents->x1;
16362					b[3] = extents->y2 << 16 | extents->x2;
16363					*(uint64_t *)(b+4) =
16364						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
16365								 I915_GEM_DOMAIN_RENDER << 16 |
16366								 I915_GEM_DOMAIN_RENDER |
16367								 KGEM_RELOC_FENCED,
16368								 0);
16369					b[6] = bg;
16370					b[7] = fg;
16371					b[8] = 0;
16372					b[9] = 0;
16373					sna->kgem.nbatch += 10;
16374				} else {
16375					b[0] = XY_SETUP_BLT | 1 << 20 | 6;
16376					b[1] = bo->pitch;
16377					if (sna->kgem.gen >= 040 && bo->tiling) {
16378						b[0] |= BLT_DST_TILED;
16379						b[1] >>= 2;
16380					}
16381					b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
16382					b[2] = extents->y1 << 16 | extents->x1;
16383					b[3] = extents->y2 << 16 | extents->x2;
16384					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
16385							      I915_GEM_DOMAIN_RENDER << 16 |
16386							      I915_GEM_DOMAIN_RENDER |
16387							      KGEM_RELOC_FENCED,
16388							      0);
16389					b[5] = bg;
16390					b[6] = fg;
16391					b[7] = 0;
16392					sna->kgem.nbatch += 8;
16393				}
16394			}
16395
16396			assert(sna->kgem.mode == KGEM_BLT);
16397			b = sna->kgem.batch + sna->kgem.nbatch;
16398			sna->kgem.nbatch += 3 + len;
16399
16400			b[0] = XY_TEXT_IMMEDIATE_BLT | (1 + len);
16401			if (bo->tiling && sna->kgem.gen >= 040)
16402				b[0] |= BLT_DST_TILED;
16403			b[1] = (uint16_t)y1 << 16 | (uint16_t)x1;
16404			b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w);
16405
16406			byte = (uint8_t *)&b[3];
16407			stride -= w8;
16408			do {
16409				i = w8;
16410				do {
16411					*byte++ = byte_reverse(*glyph++);
16412				} while (--i);
16413				glyph += stride;
16414			} while (--h);
16415			while ((byte - (uint8_t *)&b[3]) & 7)
16416				*byte++ = 0;
16417			assert((uint32_t *)byte == sna->kgem.batch + sna->kgem.nbatch);
16418
16419			if (damage) {
16420				BoxRec r;
16421
16422				r.x1 = x1;
16423				r.y1 = y1;
16424				r.x2 = x1 + w;
16425				r.y2 = y1 + h;
16426				if (box_intersect(&r, extents))
16427					sna_damage_add_box(damage, &r);
16428			}
16429skip:
16430			x += c->metrics.characterWidth;
16431		} while (--n);
16432
16433		if (++extents == last_extents)
16434			break;
16435
16436		if (kgem_check_batch(&sna->kgem, 3 + 5)) {
16437			assert(sna->kgem.mode == KGEM_BLT);
16438			b = sna->kgem.batch + sna->kgem.nbatch;
16439			sna->kgem.nbatch += 3;
16440
16441			DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
16442			     __FUNCTION__,
16443			     extents->x1, extents->y1,
16444			     extents->x2, extents->y2));
16445
16446			b[0] = XY_SETUP_CLIP;
16447			b[1] = extents->y1 << 16 | extents->x1;
16448			b[2] = extents->y2 << 16 | extents->x2;
16449		}
16450	} while (1);
16451
16452	if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) {
16453		sna->kgem.nbatch = unwind_batch;
16454		sna->kgem.nreloc = unwind_reloc;
16455		if (sna->kgem.nbatch == 0)
16456			kgem_bo_undo(&sna->kgem, bo);
16457	}
16458
16459	assert_pixmap_damage(pixmap);
16460	blt_done(sna);
16461	return true;
16462}
16463
16464static void
16465sna_image_glyph(DrawablePtr drawable, GCPtr gc,
16466		int x, int y, unsigned int n,
16467		CharInfoPtr *info, pointer base)
16468{
16469	PixmapPtr pixmap = get_drawable_pixmap(drawable);
16470	struct sna *sna = to_sna_from_pixmap(pixmap);
16471	ExtentInfoRec extents;
16472	RegionRec region;
16473	struct sna_damage **damage;
16474	struct kgem_bo *bo;
16475	unsigned hint;
16476
16477	if (n == 0)
16478		return;
16479
16480	sna_glyph_extents(gc->font, info, n, &extents);
16481	region.extents.x1 = x + MIN(0, extents.overallLeft);
16482	region.extents.y1 = y - extents.fontAscent;
16483	region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight);
16484	region.extents.y2 = y + extents.fontDescent;
16485
16486	DBG(("%s: count=%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n",
16487	     __FUNCTION__, n,
16488	     extents.overallLeft, extents.overallRight, extents.overallWidth,
16489	     extents.fontAscent, extents.fontDescent,
16490	     region.extents.x1, region.extents.y1,
16491	     region.extents.x2, region.extents.y2));
16492
16493	translate_box(&region.extents, drawable);
16494	clip_box(&region.extents, gc);
16495	if (box_empty(&region.extents))
16496		return;
16497
16498	DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__,
16499	     region.extents.x1, region.extents.y1,
16500	     region.extents.x2, region.extents.y2));
16501
16502	region.data = NULL;
16503	if (!region_maybe_clip(&region, gc->pCompositeClip))
16504		return;
16505
16506	if (FORCE_FALLBACK)
16507		goto fallback;
16508
16509	if (!ACCEL_IMAGE_GLYPH)
16510		goto fallback;
16511
16512	if (wedged(sna)) {
16513		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
16514		goto fallback;
16515	}
16516
16517	if (!PM_IS_SOLID(drawable, gc->planemask))
16518		goto fallback;
16519
16520	if (sna_font_too_large(gc->font))
16521		goto fallback;
16522
16523	if (region.data == NULL)
16524		hint = IGNORE_DAMAGE | PREFER_GPU;
16525	else
16526		hint = PREFER_GPU;
16527	if ((bo = sna_drawable_use_bo(drawable, hint,
16528				      &region.extents, &damage)) &&
16529	    sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base,
16530				   bo, damage, &region,
16531				   gc->fgPixel, gc->bgPixel, false))
16532		goto out;
16533
16534fallback:
16535	DBG(("%s: fallback\n", __FUNCTION__));
16536	if (!sna_gc_move_to_cpu(gc, drawable, &region))
16537		goto out_gc;
16538	if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_WRITE))
16539		goto out_gc;
16540
16541	if (sigtrap_get() == 0) {
16542		DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
16543		fbImageGlyphBlt(drawable, gc, x, y, n, info, base);
16544		FALLBACK_FLUSH(drawable);
16545		sigtrap_put();
16546	}
16547out_gc:
16548	sna_gc_move_to_gpu(gc);
16549out:
16550	RegionUninit(&region);
16551}
16552
16553static void
16554sna_poly_glyph(DrawablePtr drawable, GCPtr gc,
16555	       int x, int y, unsigned int n,
16556	       CharInfoPtr *info, pointer base)
16557{
16558	PixmapPtr pixmap = get_drawable_pixmap(drawable);
16559	struct sna *sna = to_sna_from_pixmap(pixmap);
16560	ExtentInfoRec extents;
16561	RegionRec region;
16562	struct sna_damage **damage;
16563	struct kgem_bo *bo;
16564	uint32_t fg;
16565
16566	if (n == 0)
16567		return;
16568
16569	sna_glyph_extents(gc->font, info, n, &extents);
16570	region.extents.x1 = x + extents.overallLeft;
16571	region.extents.y1 = y - extents.overallAscent;
16572	region.extents.x2 = x + extents.overallRight;
16573	region.extents.y2 = y + extents.overallDescent;
16574
16575	translate_box(&region.extents, drawable);
16576	clip_box(&region.extents, gc);
16577	if (box_empty(&region.extents))
16578		return;
16579
16580	DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__,
16581	     region.extents.x1, region.extents.y1,
16582	     region.extents.x2, region.extents.y2));
16583
16584	region.data = NULL;
16585	if (!region_maybe_clip(&region, gc->pCompositeClip))
16586		return;
16587
16588	if (FORCE_FALLBACK)
16589		goto fallback;
16590
16591	if (!ACCEL_POLY_GLYPH)
16592		goto fallback;
16593
16594	if (wedged(sna)) {
16595		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
16596		goto fallback;
16597	}
16598
16599	if (!PM_IS_SOLID(drawable, gc->planemask))
16600		goto fallback;
16601
16602	if (!gc_is_solid(gc, &fg))
16603		goto fallback;
16604
16605	if (sna_font_too_large(gc->font))
16606		goto fallback;
16607
16608	if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU,
16609				      &region.extents, &damage)) &&
16610	    sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base,
16611				   bo, damage, &region, fg, -1, true))
16612		goto out;
16613
16614fallback:
16615	DBG(("%s: fallback\n", __FUNCTION__));
16616	if (!sna_gc_move_to_cpu(gc, drawable, &region))
16617		goto out_gc;
16618	if (!sna_drawable_move_region_to_cpu(drawable, &region,
16619					     MOVE_READ | MOVE_WRITE))
16620		goto out_gc;
16621
16622	if (sigtrap_get() == 0) {
16623		DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
16624		fbPolyGlyphBlt(drawable, gc, x, y, n, info, base);
16625		FALLBACK_FLUSH(drawable);
16626		sigtrap_put();
16627	}
16628out_gc:
16629	sna_gc_move_to_gpu(gc);
16630out:
16631	RegionUninit(&region);
16632}
16633
16634static bool
16635sna_push_pixels_solid_blt(GCPtr gc,
16636			  PixmapPtr bitmap,
16637			  DrawablePtr drawable,
16638			  RegionPtr region)
16639{
16640	PixmapPtr pixmap = get_drawable_pixmap(drawable);
16641	struct sna *sna = to_sna_from_pixmap(pixmap);
16642	struct sna_damage **damage;
16643	struct kgem_bo *bo;
16644	const BoxRec *box;
16645	int16_t dx, dy;
16646	int n;
16647	uint8_t rop = copy_ROP[gc->alu];
16648
16649	bo = sna_drawable_use_bo(drawable, PREFER_GPU, &region->extents, &damage);
16650	if (bo == NULL)
16651		return false;
16652
16653	if (bo->tiling == I915_TILING_Y) {
16654		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
16655		assert(bo == __sna_pixmap_get_bo(pixmap));
16656		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
16657		if (bo == NULL) {
16658			DBG(("%s: fallback -- unable to change tiling\n",
16659			     __FUNCTION__));
16660			return false;
16661		}
16662	}
16663
16664	if (!kgem_bo_can_blt(&sna->kgem, bo))
16665		return false;
16666
16667	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
16668		RegionTranslate(region, dx, dy);
16669
16670	assert_pixmap_contains_box(pixmap, RegionExtents(region));
16671	if (damage)
16672		sna_damage_add_to_pixmap(damage, region, pixmap);
16673	assert_pixmap_damage(pixmap);
16674
16675	DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__,
16676	     region->extents.x1, region->extents.y1,
16677	     region->extents.x2, region->extents.y2));
16678
16679	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
16680	assert(kgem_bo_can_blt(&sna->kgem, bo));
16681	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
16682
16683	/* Region is pre-clipped and translated into pixmap space */
16684	box = region_rects(region);
16685	n = region_num_rects(region);
16686	do {
16687		int bx1 = (box->x1 - region->extents.x1) & ~7;
16688		int bx2 = (box->x2 - region->extents.x1 + 7) & ~7;
16689		int bw = (bx2 - bx1)/8;
16690		int bh = box->y2 - box->y1;
16691		int bstride = ALIGN(bw, 2);
16692		struct kgem_bo *upload;
16693		void *ptr;
16694
16695		if (!kgem_check_batch(&sna->kgem, 10) ||
16696		    !kgem_check_bo_fenced(&sna->kgem, bo) ||
16697		    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
16698			kgem_submit(&sna->kgem);
16699			if (!kgem_check_bo_fenced(&sna->kgem, bo))
16700				return false;
16701			_kgem_set_mode(&sna->kgem, KGEM_BLT);
16702		}
16703		kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
16704
16705		upload = kgem_create_buffer(&sna->kgem,
16706					    bstride*bh,
16707					    KGEM_BUFFER_WRITE_INPLACE,
16708					    &ptr);
16709		if (!upload)
16710			break;
16711
16712		if (sigtrap_get() == 0) {
16713			uint8_t *dst = ptr;
16714
16715			int src_stride = bitmap->devKind;
16716			uint8_t *src;
16717			uint32_t *b;
16718
16719			assert(src_stride);
16720			src = (uint8_t*)bitmap->devPrivate.ptr;
16721			src += (box->y1 - region->extents.y1) * src_stride + bx1/8;
16722			src_stride -= bstride;
16723			do {
16724				int i = bstride;
16725				do {
16726					*dst++ = byte_reverse(*src++);
16727					*dst++ = byte_reverse(*src++);
16728					i -= 2;
16729				} while (i);
16730				src += src_stride;
16731			} while (--bh);
16732
16733			assert(sna->kgem.mode == KGEM_BLT);
16734			b = sna->kgem.batch + sna->kgem.nbatch;
16735			if (sna->kgem.gen >= 0100) {
16736				b[0] = XY_MONO_SRC_COPY | 3 << 20 | 8;
16737				b[0] |= ((box->x1 - region->extents.x1) & 7) << 17;
16738				b[1] = bo->pitch;
16739				if (sna->kgem.gen >= 040 && bo->tiling) {
16740					b[0] |= BLT_DST_TILED;
16741					b[1] >>= 2;
16742				}
16743				b[1] |= 1 << 29;
16744				b[1] |= blt_depth(drawable->depth) << 24;
16745				b[1] |= rop << 16;
16746				b[2] = box->y1 << 16 | box->x1;
16747				b[3] = box->y2 << 16 | box->x2;
16748				*(uint64_t *)(b+4) =
16749					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
16750							I915_GEM_DOMAIN_RENDER << 16 |
16751							I915_GEM_DOMAIN_RENDER |
16752							KGEM_RELOC_FENCED,
16753							0);
16754				*(uint64_t *)(b+6) =
16755					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
16756							I915_GEM_DOMAIN_RENDER << 16 |
16757							KGEM_RELOC_FENCED,
16758							0);
16759				b[8] = gc->bgPixel;
16760				b[9] = gc->fgPixel;
16761				sna->kgem.nbatch += 10;
16762			} else {
16763				b[0] = XY_MONO_SRC_COPY | 3 << 20 | 6;
16764				b[0] |= ((box->x1 - region->extents.x1) & 7) << 17;
16765				b[1] = bo->pitch;
16766				if (sna->kgem.gen >= 040 && bo->tiling) {
16767					b[0] |= BLT_DST_TILED;
16768					b[1] >>= 2;
16769				}
16770				b[1] |= 1 << 29;
16771				b[1] |= blt_depth(drawable->depth) << 24;
16772				b[1] |= rop << 16;
16773				b[2] = box->y1 << 16 | box->x1;
16774				b[3] = box->y2 << 16 | box->x2;
16775				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
16776						I915_GEM_DOMAIN_RENDER << 16 |
16777						I915_GEM_DOMAIN_RENDER |
16778						KGEM_RELOC_FENCED,
16779						0);
16780				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
16781						I915_GEM_DOMAIN_RENDER << 16 |
16782						KGEM_RELOC_FENCED,
16783						0);
16784				b[6] = gc->bgPixel;
16785				b[7] = gc->fgPixel;
16786
16787				sna->kgem.nbatch += 8;
16788			}
16789			sigtrap_put();
16790		}
16791
16792		kgem_bo_destroy(&sna->kgem, upload);
16793
16794		box++;
16795	} while (--n);
16796
16797	blt_done(sna);
16798	return true;
16799}
16800
16801static void
16802sna_push_pixels(GCPtr gc, PixmapPtr bitmap, DrawablePtr drawable,
16803		int w, int h,
16804		int x, int y)
16805{
16806	RegionRec region;
16807
16808	if (w == 0 || h == 0)
16809		return;
16810
16811	DBG(("%s (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
16812
16813	region.extents.x1 = x;
16814	region.extents.y1 = y;
16815	region.extents.x2 = region.extents.x1 + w;
16816	region.extents.y2 = region.extents.y1 + h;
16817
16818	clip_box(&region.extents, gc);
16819	if (box_empty(&region.extents))
16820		return;
16821
16822	DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__,
16823	     region.extents.x1, region.extents.y1,
16824	     region.extents.x2, region.extents.y2));
16825
16826	region.data = NULL;
16827	if (!region_maybe_clip(&region, gc->pCompositeClip))
16828		return;
16829
16830	switch (gc->fillStyle) {
16831	case FillSolid:
16832		if (sna_push_pixels_solid_blt(gc, bitmap, drawable, &region))
16833			return;
16834		break;
16835	default:
16836		break;
16837	}
16838
16839	DBG(("%s: fallback\n", __FUNCTION__));
16840	if (!sna_gc_move_to_cpu(gc, drawable, &region))
16841		goto out;
16842	if (!sna_pixmap_move_to_cpu(bitmap, MOVE_READ))
16843		goto out;
16844	if (!sna_drawable_move_region_to_cpu(drawable, &region,
16845					     drawable_gc_flags(drawable, gc, false)))
16846		goto out;
16847
16848	if (sigtrap_get() == 0) {
16849		DBG(("%s: fallback, fbPushPixels(%d, %d, %d %d)\n",
16850		     __FUNCTION__, w, h, x, y));
16851		fbPushPixels(gc, bitmap, drawable, w, h, x, y);
16852		FALLBACK_FLUSH(drawable);
16853		sigtrap_put();
16854	}
16855out:
16856	sna_gc_move_to_gpu(gc);
16857	RegionUninit(&region);
16858}
16859
16860static const GCOps sna_gc_ops = {
16861	sna_fill_spans,
16862	sna_set_spans,
16863	sna_put_image,
16864	sna_copy_area,
16865	sna_copy_plane,
16866	sna_poly_point,
16867	sna_poly_line,
16868	sna_poly_segment,
16869	sna_poly_rectangle,
16870	sna_poly_arc,
16871	sna_poly_fill_polygon,
16872	sna_poly_fill_rect,
16873	sna_poly_fill_arc,
16874	sna_poly_text8,
16875	sna_poly_text16,
16876	sna_image_text8,
16877	sna_image_text16,
16878	sna_image_glyph,
16879	sna_poly_glyph,
16880	sna_push_pixels,
16881};
16882
16883static const GCOps sna_gc_ops__cpu = {
16884	fbFillSpans,
16885	fbSetSpans,
16886	fbPutImage,
16887	fbCopyArea,
16888	fbCopyPlane,
16889	sna_poly_point__cpu,
16890	fbPolyLine,
16891	fbPolySegment,
16892	miPolyRectangle,
16893	fbPolyArc,
16894	miFillPolygon,
16895	fbPolyFillRect,
16896	miPolyFillArc,
16897	miPolyText8,
16898	miPolyText16,
16899	miImageText8,
16900	miImageText16,
16901	fbImageGlyphBlt,
16902	fbPolyGlyphBlt,
16903	fbPushPixels
16904};
16905
16906static GCOps sna_gc_ops__tmp = {
16907	sna_fill_spans,
16908	sna_set_spans,
16909	sna_put_image,
16910	sna_copy_area,
16911	sna_copy_plane,
16912	sna_poly_point,
16913	sna_poly_line,
16914	sna_poly_segment,
16915	sna_poly_rectangle,
16916	sna_poly_arc,
16917	sna_poly_fill_polygon,
16918	sna_poly_fill_rect,
16919	sna_poly_fill_arc,
16920	sna_poly_text8,
16921	sna_poly_text16,
16922	sna_image_text8,
16923	sna_image_text16,
16924	sna_image_glyph,
16925	sna_poly_glyph,
16926	sna_push_pixels,
16927};
16928
16929static void
16930sna_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable)
16931{
16932	DBG(("%s(%p) changes=%lx, previous serial=%lx, drawable=%lx\n", __FUNCTION__, gc,
16933	     changes, gc->serialNumber, drawable->serialNumber));
16934
16935	if (changes & (GCClipMask|GCSubwindowMode) ||
16936	    drawable->serialNumber != (gc->serialNumber & DRAWABLE_SERIAL_BITS) ||
16937	    (has_clip(gc) && (changes & (GCClipXOrigin | GCClipYOrigin)))) {
16938		DBG(("%s: recomputing clip\n", __FUNCTION__));
16939		miComputeCompositeClip(gc, drawable);
16940		DBG(("%s: composite clip=%dx[(%d, %d), (%d, %d)] [%p]\n",
16941		     __FUNCTION__,
16942		     region_num_rects(gc->pCompositeClip),
16943		     gc->pCompositeClip->extents.x1,
16944		     gc->pCompositeClip->extents.y1,
16945		     gc->pCompositeClip->extents.x2,
16946		     gc->pCompositeClip->extents.y2,
16947		     gc->pCompositeClip));
16948	}
16949
16950	assert(gc->pCompositeClip);
16951	assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.x1 >= drawable->x);
16952	assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.y1 >= drawable->y);
16953	assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.x2 - drawable->x <= drawable->width);
16954	assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.y2 - drawable->y <= drawable->height);
16955
16956	sna_gc(gc)->changes |= changes;
16957	sna_gc(gc)->serial = gc->serialNumber;
16958}
16959
16960static const GCFuncs sna_gc_funcs = {
16961	sna_validate_gc,
16962	miChangeGC,
16963	miCopyGC,
16964	miDestroyGC,
16965	miChangeClip,
16966	miDestroyClip,
16967	miCopyClip
16968};
16969
16970static const GCFuncs sna_gc_funcs__cpu = {
16971	fbValidateGC,
16972	miChangeGC,
16973	miCopyGC,
16974	miDestroyGC,
16975	miChangeClip,
16976	miDestroyClip,
16977	miCopyClip
16978};
16979
16980static int sna_create_gc(GCPtr gc)
16981{
16982	gc->miTranslate = 1;
16983	gc->fExpose = 1;
16984
16985	gc->freeCompClip = 0;
16986	gc->pCompositeClip = 0;
16987#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,19,99,1,0)
16988	gc->pRotatedPixmap = 0;
16989#endif
16990
16991	fb_gc(gc)->bpp = bits_per_pixel(gc->depth);
16992
16993	gc->funcs = (GCFuncs *)&sna_gc_funcs;
16994	gc->ops = (GCOps *)&sna_gc_ops;
16995	return true;
16996}
16997
16998static bool
16999sna_get_image__inplace(PixmapPtr pixmap,
17000		       RegionPtr region,
17001		       char *dst,
17002		       unsigned flags,
17003		       bool idle)
17004{
17005	struct sna_pixmap *priv = sna_pixmap(pixmap);
17006	struct sna *sna = to_sna_from_pixmap(pixmap);
17007	char *src;
17008
17009	if (!USE_INPLACE)
17010		return false;
17011
17012	assert(priv && priv->gpu_bo);
17013
17014	switch (priv->gpu_bo->tiling) {
17015	case I915_TILING_Y:
17016		return false;
17017	case I915_TILING_X:
17018		if (!sna->kgem.memcpy_from_tiled_x)
17019			return false;
17020	default:
17021		break;
17022	}
17023
17024	if ((flags & MOVE_INPLACE_HINT) == 0 &&
17025	    !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC))
17026		return false;
17027
17028	if (idle && __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
17029		return false;
17030
17031	if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ))
17032		return false;
17033
17034	assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
17035	assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
17036
17037	if (kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC)) {
17038		src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
17039		if (src == NULL)
17040			return false;
17041
17042		kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC);
17043	} else {
17044		src = kgem_bo_map__wc(&sna->kgem, priv->gpu_bo);
17045		if (src == NULL)
17046			return false;
17047
17048		kgem_bo_sync__gtt(&sna->kgem, priv->gpu_bo);
17049	}
17050
17051	if (sigtrap_get())
17052		return false;
17053
17054	if (priv->gpu_bo->tiling) {
17055		DBG(("%s: download through a tiled CPU map\n", __FUNCTION__));
17056		memcpy_from_tiled_x(&sna->kgem, src, dst,
17057				    pixmap->drawable.bitsPerPixel,
17058				    priv->gpu_bo->pitch,
17059				    PixmapBytePad(region->extents.x2 - region->extents.x1,
17060						  pixmap->drawable.depth),
17061				    region->extents.x1, region->extents.y1,
17062				    0, 0,
17063				    region->extents.x2 - region->extents.x1,
17064				    region->extents.y2 - region->extents.y1);
17065	} else {
17066		DBG(("%s: download through a linear CPU map\n", __FUNCTION__));
17067		memcpy_blt(src, dst,
17068			   pixmap->drawable.bitsPerPixel,
17069			   priv->gpu_bo->pitch,
17070			   PixmapBytePad(region->extents.x2 - region->extents.x1,
17071					 pixmap->drawable.depth),
17072			   region->extents.x1, region->extents.y1,
17073			   0, 0,
17074			   region->extents.x2 - region->extents.x1,
17075			   region->extents.y2 - region->extents.y1);
17076		if (!priv->shm) {
17077			pixmap->devPrivate.ptr = src;
17078			pixmap->devKind = priv->gpu_bo->pitch;
17079			priv->mapped = src == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
17080			assert_pixmap_map(pixmap, priv);
17081			priv->cpu &= priv->mapped == MAPPED_CPU;
17082		}
17083	}
17084
17085	sigtrap_put();
17086	return true;
17087}
17088
17089static bool
17090sna_get_image__blt(PixmapPtr pixmap,
17091		   RegionPtr region,
17092		   char *dst,
17093		   unsigned flags)
17094{
17095	struct sna_pixmap *priv = sna_pixmap(pixmap);
17096	struct sna *sna = to_sna_from_pixmap(pixmap);
17097	struct kgem_bo *dst_bo;
17098	bool ok = false;
17099	int pitch;
17100
17101	assert(priv && priv->gpu_bo);
17102
17103	if (!sna->kgem.has_userptr || !USE_USERPTR_DOWNLOADS)
17104		return false;
17105
17106	if (!sna->kgem.can_blt_cpu)
17107		return false;
17108
17109	if ((priv->create & (KGEM_CAN_CREATE_GTT | KGEM_CAN_CREATE_LARGE)) == KGEM_CAN_CREATE_GTT &&
17110	    kgem_bo_can_map(&sna->kgem, priv->gpu_bo)) {
17111		if (flags & (MOVE_WHOLE_HINT | MOVE_INPLACE_HINT))
17112			return false;
17113
17114		if (priv->gpu_damage == NULL)
17115			return false;
17116
17117		assert(priv->gpu_bo);
17118		if (!__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
17119			return false;
17120	} else {
17121		if (priv->gpu_damage == NULL)
17122			return false;
17123
17124		assert(priv->gpu_bo);
17125	}
17126
17127	if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ))
17128		return false;
17129
17130	DBG(("%s: download through a temporary map\n", __FUNCTION__));
17131
17132	assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
17133	assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
17134
17135	pitch = PixmapBytePad(region->extents.x2 - region->extents.x1,
17136			      pixmap->drawable.depth);
17137	dst_bo = kgem_create_map(&sna->kgem, dst,
17138				 pitch * (region->extents.y2 - region->extents.y1),
17139				 false);
17140	if (dst_bo) {
17141		dst_bo->pitch = pitch;
17142		kgem_bo_mark_unreusable(dst_bo);
17143
17144		ok = sna->render.copy_boxes(sna, GXcopy,
17145					    &pixmap->drawable, priv->gpu_bo, 0, 0,
17146					    &pixmap->drawable, dst_bo,
17147					    -region->extents.x1,
17148					    -region->extents.y1,
17149					    &region->extents, 1,
17150					    COPY_LAST);
17151
17152		kgem_bo_sync__cpu(&sna->kgem, dst_bo);
17153		assert(dst_bo->rq == NULL);
17154		kgem_bo_destroy(&sna->kgem, dst_bo);
17155	}
17156
17157	return ok;
17158}
17159
17160static bool
17161sna_get_image__fast(PixmapPtr pixmap,
17162		   RegionPtr region,
17163		   char *dst,
17164		   unsigned flags)
17165{
17166	struct sna_pixmap *priv = sna_pixmap(pixmap);
17167
17168	DBG(("%s: attached?=%d, has gpu damage?=%d\n",
17169	     __FUNCTION__, priv != NULL,  priv && priv->gpu_damage));
17170	if (priv == NULL || priv->gpu_damage == NULL)
17171		return false;
17172
17173	if (priv->clear && sigtrap_get() == 0) {
17174		int w = region->extents.x2 - region->extents.x1;
17175		int h = region->extents.y2 - region->extents.y1;
17176		int pitch = PixmapBytePad(w, pixmap->drawable.depth);
17177
17178		DBG(("%s: applying clear [%08x]\n",
17179		     __FUNCTION__, priv->clear_color));
17180		assert(DAMAGE_IS_ALL(priv->gpu_damage));
17181		assert(priv->cpu_damage == NULL);
17182		sigtrap_assert_active();
17183
17184		if (priv->clear_color == 0 ||
17185		    pixmap->drawable.bitsPerPixel == 8 ||
17186		    priv->clear_color == (1U << pixmap->drawable.depth) - 1) {
17187			DBG(("%s: memset clear [%02x]\n",
17188			     __FUNCTION__, priv->clear_color & 0xff));
17189			memset(dst, priv->clear_color, pitch * h);
17190		} else {
17191			pixman_fill((uint32_t *)dst,
17192				    pitch/sizeof(uint32_t),
17193				    pixmap->drawable.bitsPerPixel,
17194				    0, 0,
17195				    w, h,
17196				    priv->clear_color);
17197		}
17198
17199		sigtrap_put();
17200		return true;
17201	}
17202
17203	if (!DAMAGE_IS_ALL(priv->gpu_damage) &&
17204	    !sna_damage_contains_box__no_reduce(priv->gpu_damage,
17205						&region->extents))
17206		return false;
17207
17208	if (sna_get_image__inplace(pixmap, region, dst, flags, true))
17209		return true;
17210
17211	if (sna_get_image__blt(pixmap, region, dst, flags))
17212		return true;
17213
17214	if (sna_get_image__inplace(pixmap, region, dst, flags, false))
17215		return true;
17216
17217	return false;
17218}
17219
17220static void
17221sna_get_image(DrawablePtr drawable,
17222	      int x, int y, int w, int h,
17223	      unsigned int format, unsigned long mask,
17224	      char *dst)
17225{
17226	RegionRec region;
17227	unsigned int flags;
17228
17229	if (!fbDrawableEnabled(drawable))
17230		return;
17231
17232	DBG(("%s: pixmap=%ld (%d, %d)x(%d, %d), format=%d, mask=%lx, depth=%d\n",
17233	     __FUNCTION__,
17234	     (long)get_drawable_pixmap(drawable)->drawable.serialNumber,
17235	     x, y, w, h, format, mask, drawable->depth));
17236
17237	flags = MOVE_READ;
17238	if ((w | h) == 1)
17239		flags |= MOVE_INPLACE_HINT;
17240	if (w == drawable->width)
17241		flags |= MOVE_WHOLE_HINT;
17242
17243	if (ACCEL_GET_IMAGE &&
17244	    !FORCE_FALLBACK &&
17245	    format == ZPixmap &&
17246	    drawable->bitsPerPixel >= 8) {
17247		PixmapPtr pixmap = get_drawable_pixmap(drawable);
17248		int16_t dx, dy;
17249
17250		get_drawable_deltas(drawable, pixmap, &dx, &dy);
17251		region.extents.x1 = x + drawable->x + dx;
17252		region.extents.y1 = y + drawable->y + dy;
17253		region.extents.x2 = region.extents.x1 + w;
17254		region.extents.y2 = region.extents.y1 + h;
17255		region.data = NULL;
17256
17257		if (sna_get_image__fast(pixmap, &region, dst, flags))
17258			goto apply_planemask;
17259
17260		if (!sna_drawable_move_region_to_cpu(&pixmap->drawable,
17261						     &region, flags))
17262			return;
17263
17264		DBG(("%s: copy box (%d, %d), (%d, %d)\n",
17265		     __FUNCTION__,
17266		     region.extents.x1, region.extents.y1,
17267		     region.extents.x2, region.extents.y2));
17268		assert(has_coherent_ptr(to_sna_from_pixmap(pixmap), sna_pixmap(pixmap), MOVE_READ));
17269		if (sigtrap_get() == 0) {
17270			assert(pixmap->devKind);
17271			memcpy_blt(pixmap->devPrivate.ptr, dst, drawable->bitsPerPixel,
17272				   pixmap->devKind, PixmapBytePad(w, drawable->depth),
17273				   region.extents.x1, region.extents.y1, 0, 0, w, h);
17274			sigtrap_put();
17275		}
17276
17277apply_planemask:
17278		if (!PM_IS_SOLID(drawable, mask)) {
17279			FbStip pm = fbReplicatePixel(mask, drawable->bitsPerPixel);
17280			FbStip *d = (FbStip *)dst;
17281			int i, n = PixmapBytePad(w, drawable->depth) / sizeof(FbStip) * h;
17282
17283			for (i = 0; i < n; i++)
17284				d[i] &= pm;
17285		}
17286	} else {
17287		region.extents.x1 = x + drawable->x;
17288		region.extents.y1 = y + drawable->y;
17289		region.extents.x2 = region.extents.x1 + w;
17290		region.extents.y2 = region.extents.y1 + h;
17291		region.data = NULL;
17292
17293		if (sna_drawable_move_region_to_cpu(drawable, &region, flags))
17294			fbGetImage(drawable, x, y, w, h, format, mask, dst);
17295	}
17296}
17297
17298static void
17299sna_get_spans(DrawablePtr drawable, int wMax,
17300	      DDXPointPtr pt, int *width, int n, char *start)
17301{
17302	RegionRec region;
17303
17304	if (!fbDrawableEnabled(drawable))
17305		return;
17306
17307	if (sna_spans_extents(drawable, NULL, n, pt, width, &region.extents) == 0)
17308		return;
17309
17310	region.data = NULL;
17311	if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_READ))
17312		return;
17313
17314	fbGetSpans(drawable, wMax, pt, width, n, start);
17315}
17316
17317static void
17318sna_copy_window(WindowPtr win, DDXPointRec origin, RegionPtr src)
17319{
17320	PixmapPtr pixmap = get_window_pixmap(win);
17321	struct sna *sna = to_sna_from_pixmap(pixmap);
17322	RegionRec dst;
17323	int dx, dy;
17324
17325	DBG(("%s origin=(%d, %d)\n", __FUNCTION__, origin.x, origin.y));
17326	if (!fbWindowEnabled(win))
17327		return;
17328
17329	dx = origin.x - win->drawable.x;
17330	dy = origin.y - win->drawable.y;
17331	RegionTranslate(src, -dx, -dy);
17332
17333	RegionNull(&dst);
17334	RegionIntersect(&dst, &win->borderClip, src);
17335	if (box_empty(&dst.extents))
17336		return;
17337
17338#ifdef COMPOSITE
17339	if (pixmap->screen_x | pixmap->screen_y)
17340		RegionTranslate(&dst, -pixmap->screen_x, -pixmap->screen_y);
17341#endif
17342
17343	if (wedged(sna) || FORCE_FALLBACK || !ACCEL_COPY_WINDOW) {
17344		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
17345		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE))
17346			return;
17347
17348		if (sigtrap_get() == 0) {
17349			miCopyRegion(&pixmap->drawable, &pixmap->drawable,
17350				     0, &dst, dx, dy, fbCopyNtoN, 0, NULL);
17351			sigtrap_put();
17352		}
17353	} else {
17354		sna_self_copy_boxes(&pixmap->drawable, &pixmap->drawable, NULL,
17355				    &dst, dx, dy, 0, NULL);
17356	}
17357
17358	RegionUninit(&dst);
17359}
17360
17361static Bool sna_change_window_attributes(WindowPtr win, unsigned long mask)
17362{
17363	bool ret = true;
17364
17365	DBG(("%s\n", __FUNCTION__));
17366
17367	/* Check if the fb layer wishes to modify the attached pixmaps,
17368	 * to fix up mismatches between the window and pixmap depths.
17369	 */
17370	if (mask & CWBackPixmap && win->backgroundState == BackgroundPixmap) {
17371		DBG(("%s: flushing background pixmap\n", __FUNCTION__));
17372		ret &= sna_validate_pixmap(&win->drawable, win->background.pixmap);
17373	}
17374
17375	if (mask & CWBorderPixmap && win->borderIsPixel == false) {
17376		DBG(("%s: flushing border pixmap\n", __FUNCTION__));
17377		ret &= sna_validate_pixmap(&win->drawable, win->border.pixmap);
17378	}
17379
17380	return ret;
17381}
17382
17383void sna_accel_flush(struct sna *sna)
17384{
17385	struct sna_pixmap *priv;
17386
17387	/* XXX we should be able to reduce the frequency of flushes further
17388	 * by checking for outgoing damage events or sync replies. Tricky,
17389	 * and doesn't appear to mitigate the performance loss.
17390	 */
17391	DBG(("%s: flush?=%d, dirty?=%d\n", __FUNCTION__,
17392	     sna->kgem.flush, !list_is_empty(&sna->flush_pixmaps)));
17393
17394	/* flush any pending damage from shadow copies to tfp clients */
17395	while (!list_is_empty(&sna->flush_pixmaps)) {
17396		bool ret;
17397
17398		priv = list_first_entry(&sna->flush_pixmaps,
17399					struct sna_pixmap, flush_list);
17400
17401		list_del(&priv->flush_list);
17402		if (priv->shm) {
17403			DBG(("%s: syncing SHM pixmap=%ld (refcnt=%d)\n",
17404			     __FUNCTION__,
17405			     priv->pixmap->drawable.serialNumber,
17406			     priv->pixmap->refcnt));
17407			assert(!priv->flush);
17408			ret = sna_pixmap_move_to_cpu(priv->pixmap,
17409						     MOVE_READ | MOVE_WRITE);
17410			assert(!ret || priv->gpu_bo == NULL);
17411			if (priv->pixmap->refcnt == 0) {
17412				sna_damage_destroy(&priv->cpu_damage);
17413				__sna_free_pixmap(sna, priv->pixmap, priv);
17414			}
17415		} else {
17416			unsigned hints;
17417			DBG(("%s: flushing DRI pixmap=%ld\n", __FUNCTION__,
17418			     priv->pixmap->drawable.serialNumber));
17419			assert(priv->flush);
17420			hints = MOVE_READ | __MOVE_FORCE;
17421			if (priv->flush & FLUSH_WRITE)
17422				hints |= MOVE_WRITE;
17423			if (sna_pixmap_move_to_gpu(priv->pixmap, hints)) {
17424				if (priv->flush & FLUSH_WRITE) {
17425					kgem_bo_unclean(&sna->kgem, priv->gpu_bo);
17426					sna_damage_all(&priv->gpu_damage, priv->pixmap);
17427					assert(priv->cpu_damage == NULL);
17428					assert(priv->clear == false);
17429				}
17430			}
17431		}
17432		(void)ret;
17433	}
17434
17435	if (sna->kgem.flush)
17436		kgem_submit(&sna->kgem);
17437}
17438
17439static void
17440sna_shm_flush_callback(CallbackListPtr *list,
17441		       pointer user_data, pointer call_data)
17442{
17443	struct sna *sna = user_data;
17444
17445	if (!sna->needs_shm_flush)
17446		return;
17447
17448	sna_accel_flush(sna);
17449	sna->needs_shm_flush = false;
17450}
17451
17452static void
17453sna_flush_callback(CallbackListPtr *list, pointer user_data, pointer call_data)
17454{
17455	struct sna *sna = user_data;
17456
17457#if 0 /* XXX requires mesa to implement glXWaitX()! */
17458	if (!sna->needs_dri_flush)
17459		return;
17460
17461	sna_accel_flush(sna);
17462	sna->needs_dri_flush = false;
17463#else
17464	sna_accel_flush(sna);
17465#endif
17466}
17467
17468static void
17469sna_event_callback(CallbackListPtr *list, pointer user_data, pointer call_data)
17470{
17471	EventInfoRec *eventinfo = call_data;
17472	struct sna *sna = user_data;
17473	int i;
17474
17475	if (sna->needs_dri_flush)
17476		return;
17477
17478	for (i = 0; i < eventinfo->count; i++) {
17479		if (eventinfo->events[i].u.u.type == sna->damage_event) {
17480			sna->needs_dri_flush = true;
17481			return;
17482		}
17483	}
17484}
17485
17486static struct sna_pixmap *sna_accel_scanout(struct sna *sna)
17487{
17488	struct sna_pixmap *priv;
17489
17490	if (sna->mode.front_active == 0)
17491		return NULL;
17492
17493	assert(sna->vblank_interval);
17494	assert(sna->front);
17495	assert(!sna->mode.hidden);
17496
17497	priv = sna_pixmap(sna->front);
17498	if (priv->gpu_bo == NULL)
17499		return NULL;
17500
17501	return priv;
17502}
17503
17504#define TIME currentTime.milliseconds
17505static void sna_accel_disarm_timer(struct sna *sna, int id)
17506{
17507	DBG(("%s[%d] (time=%ld)\n", __FUNCTION__, id, (long)TIME));
17508	sna->timer_active &= ~(1<<id);
17509}
17510
17511static bool has_offload_slaves(struct sna *sna)
17512{
17513#if HAS_PIXMAP_SHARING
17514	ScreenPtr screen = to_screen_from_sna(sna);
17515	PixmapDirtyUpdatePtr dirty;
17516
17517	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
17518		assert(dirty->src == sna->front);
17519		if (RegionNotEmpty(DamageRegion(dirty->damage)))
17520			return true;
17521	}
17522#endif
17523	return false;
17524}
17525
17526static bool has_shadow(struct sna *sna)
17527{
17528	DamagePtr damage;
17529
17530	if (!sna->mode.shadow_enabled)
17531		return false;
17532
17533	damage = sna->mode.shadow_damage;
17534	assert(damage);
17535
17536	DBG(("%s: has pending damage? %d, outstanding flips: %d\n",
17537	     __FUNCTION__,
17538	     RegionNotEmpty(DamageRegion(damage)),
17539	     sna->mode.flip_active));
17540
17541	return RegionNotEmpty(DamageRegion(damage));
17542}
17543
17544static bool start_flush(struct sna *sna)
17545{
17546	struct sna_pixmap *scanout;
17547
17548	if (has_offload_slaves(sna)) {
17549		DBG(("%s: has offload slaves\n", __FUNCTION__));
17550		return true;
17551	}
17552
17553	if (has_shadow(sna)) {
17554		DBG(("%s: has dirty shadow\n", __FUNCTION__));
17555		return true;
17556	}
17557
17558	scanout = sna_accel_scanout(sna);
17559	if (!scanout)
17560		return false;
17561
17562	if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) {
17563		scanout->gpu_bo->needs_flush = true;
17564		return true;
17565	}
17566
17567	if (scanout->cpu_damage || scanout->gpu_bo->needs_flush)
17568		return true;
17569
17570	kgem_scanout_flush(&sna->kgem, scanout->gpu_bo);
17571	return false;
17572}
17573
17574static bool stop_flush(struct sna *sna, struct sna_pixmap *scanout)
17575{
17576	DBG(("%s: scanout=%d shadow?=%d, slaves?=%d, (cpu?=%d || gpu?=%d))\n",
17577	     __FUNCTION__,
17578	     scanout && scanout->gpu_bo ? scanout->gpu_bo->handle : 0,
17579	     has_shadow(sna), has_offload_slaves(sna),
17580	     scanout && scanout->cpu_damage != NULL,
17581	     scanout && scanout->gpu_bo && scanout->gpu_bo->rq != NULL));
17582
17583	if (has_offload_slaves(sna))
17584		return true;
17585
17586	if (has_shadow(sna))
17587		return true;
17588
17589	if (!scanout)
17590		return false;
17591
17592	if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) {
17593		scanout->gpu_bo->needs_flush = true;
17594		return true;
17595	}
17596
17597	return scanout->cpu_damage || scanout->gpu_bo->needs_flush;
17598}
17599
17600static void timer_enable(struct sna *sna, int whom, int interval)
17601{
17602	if (!sna->timer_active)
17603		UpdateCurrentTimeIf();
17604	sna->timer_active |= 1 << whom;
17605	sna->timer_expire[whom] = TIME + interval;
17606	DBG(("%s (time=%ld), starting timer %d\n", __FUNCTION__, (long)TIME, whom));
17607}
17608
17609static bool sna_scanout_do_flush(struct sna *sna)
17610{
17611	int interval = sna->vblank_interval ?: 50;
17612	if (sna->timer_active & (1<<(FLUSH_TIMER))) {
17613		int32_t delta = sna->timer_expire[FLUSH_TIMER] - TIME;
17614		DBG(("%s: flush timer active: delta=%d\n",
17615		     __FUNCTION__, delta));
17616		if (delta <= 3) {
17617			DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME));
17618			sna->timer_expire[FLUSH_TIMER] = TIME + interval;
17619			return true;
17620		}
17621	} else {
17622		if (start_flush(sna))
17623			timer_enable(sna, FLUSH_TIMER, interval/2);
17624	}
17625
17626	return false;
17627}
17628
17629static bool sna_accel_do_throttle(struct sna *sna)
17630{
17631	if (sna->timer_active & (1<<(THROTTLE_TIMER))) {
17632		int32_t delta = sna->timer_expire[THROTTLE_TIMER] - TIME;
17633		if (delta <= 3) {
17634			DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME));
17635			sna->timer_expire[THROTTLE_TIMER] = TIME + 20;
17636			return true;
17637		}
17638	} else if (!sna->kgem.need_retire) {
17639		DBG(("%s -- no pending activity\n", __FUNCTION__));
17640	} else
17641		timer_enable(sna, THROTTLE_TIMER, 20);
17642
17643	return false;
17644}
17645
17646static bool sna_accel_do_expire(struct sna *sna)
17647{
17648	if (sna->timer_active & (1<<(EXPIRE_TIMER))) {
17649		int32_t delta = sna->timer_expire[EXPIRE_TIMER] - TIME;
17650		if (delta <= 3) {
17651			DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME));
17652			sna->timer_expire[EXPIRE_TIMER] =
17653				TIME + MAX_INACTIVE_TIME * 1000;
17654			return true;
17655		}
17656	} else if (sna->kgem.need_expire)
17657		timer_enable(sna, EXPIRE_TIMER, MAX_INACTIVE_TIME * 1000);
17658
17659	return false;
17660}
17661
17662static void sna_accel_post_damage(struct sna *sna)
17663{
17664#if HAS_PIXMAP_SHARING
17665#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 25
17666#define slave_dst secondary_dst
17667#define master_pixmap primary_pixmap
17668#endif
17669	ScreenPtr screen = to_screen_from_sna(sna);
17670	PixmapDirtyUpdatePtr dirty;
17671
17672	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
17673		RegionRec region, *damage;
17674		PixmapPtr src, dst;
17675		const BoxRec *box;
17676		int16_t dx, dy;
17677		int n;
17678
17679		damage = DamageRegion(dirty->damage);
17680		if (RegionNil(damage))
17681			continue;
17682
17683		src = (PixmapPtr)dirty->src;
17684		dst = dirty->slave_dst->master_pixmap;
17685
17686		region.extents.x1 = dirty->x;
17687		region.extents.x2 = dirty->x + dst->drawable.width;
17688		region.extents.y1 = dirty->y;
17689		region.extents.y2 = dirty->y + dst->drawable.height;
17690		region.data = NULL;
17691
17692		DBG(("%s: pushing damage ((%d, %d), (%d, %d))x%d to slave pixmap=%d, ((%d, %d), (%d, %d))\n", __FUNCTION__,
17693		     damage->extents.x1, damage->extents.y1,
17694		     damage->extents.x2, damage->extents.y2,
17695		     region_num_rects(damage),
17696		     dst->drawable.serialNumber,
17697		     region.extents.x1, region.extents.y1,
17698		     region.extents.x2, region.extents.y2));
17699
17700		RegionIntersect(&region, &region, damage);
17701		if (RegionNil(&region))
17702			goto skip;
17703
17704		dx = -dirty->x;
17705		dy = -dirty->y;
17706#if HAS_DIRTYTRACKING2
17707		dx += dirty->dst_x;
17708		dy += dirty->dst_y;
17709#endif
17710		RegionTranslate(&region, dx, dy);
17711		DamageRegionAppend(&dirty->slave_dst->drawable, &region);
17712
17713		DBG(("%s: slave:  ((%d, %d), (%d, %d))x%d\n", __FUNCTION__,
17714		     region.extents.x1, region.extents.y1,
17715		     region.extents.x2, region.extents.y2,
17716		     region_num_rects(&region)));
17717
17718		box = region_rects(&region);
17719		n = region_num_rects(&region);
17720		if (wedged(sna)) {
17721fallback:
17722			if (!sna_pixmap_move_to_cpu(src, MOVE_READ))
17723				goto skip;
17724
17725			if (!sna_pixmap_move_to_cpu(dst, MOVE_READ | MOVE_WRITE | MOVE_INPLACE_HINT))
17726				goto skip;
17727
17728			if (sigtrap_get() == 0) {
17729				assert(src->drawable.bitsPerPixel == dst->drawable.bitsPerPixel);
17730				do {
17731					DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n",
17732					     __FUNCTION__,
17733					     box->x1 - dx, box->y1 - dy,
17734					     box->x1, box->y1,
17735					     box->x2 - box->x1, box->y2 - box->y1));
17736
17737					assert(box->x2 > box->x1);
17738					assert(box->y2 > box->y1);
17739
17740					assert(box->x1 - dx >= 0);
17741					assert(box->y1 - dy >= 0);
17742					assert(box->x2 - dx <= src->drawable.width);
17743					assert(box->y2 - dy <= src->drawable.height);
17744
17745					assert(box->x1 >= 0);
17746					assert(box->y1 >= 0);
17747					assert(box->x2 <= src->drawable.width);
17748					assert(box->y2 <= src->drawable.height);
17749
17750					assert(has_coherent_ptr(sna, sna_pixmap(src), MOVE_READ));
17751					assert(has_coherent_ptr(sna, sna_pixmap(dst), MOVE_WRITE));
17752					assert(src->devKind);
17753					assert(dst->devKind);
17754					memcpy_blt(src->devPrivate.ptr,
17755						   dst->devPrivate.ptr,
17756						   src->drawable.bitsPerPixel,
17757						   src->devKind, dst->devKind,
17758						   box->x1 - dx,      box->y1 - dy,
17759						   box->x1,           box->y1,
17760						   box->x2 - box->x1, box->y2 - box->y1);
17761					box++;
17762				} while (--n);
17763				sigtrap_put();
17764			}
17765		} else {
17766			if (!sna_pixmap_move_to_gpu(src, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE))
17767				goto fallback;
17768
17769			if (!sna_pixmap_move_to_gpu(dst, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE))
17770				goto fallback;
17771
17772			if (!sna->render.copy_boxes(sna, GXcopy,
17773						    &src->drawable, __sna_pixmap_get_bo(src), -dx, -dy,
17774						    &dst->drawable, __sna_pixmap_get_bo(dst),   0,   0,
17775						    box, n, COPY_LAST))
17776				goto fallback;
17777
17778			/* Before signalling the slave via ProcessPending,
17779			 * ensure not only the batch is submitted as the
17780			 * slave may be using the Damage callback to perform
17781			 * its copy, but also that the memory must be coherent
17782			 * - we need to treat it as uncached for the PCI slave
17783			 * will bypass LLC.
17784			 */
17785			kgem_bo_sync__gtt(&sna->kgem, __sna_pixmap_get_bo(dst));
17786		}
17787
17788		DamageRegionProcessPending(&dirty->slave_dst->drawable);
17789skip:
17790		RegionUninit(&region);
17791		DamageEmpty(dirty->damage);
17792	}
17793#endif
17794}
17795
17796static void sna_scanout_flush(struct sna *sna)
17797{
17798	struct sna_pixmap *priv = sna_accel_scanout(sna);
17799	bool busy;
17800
17801	DBG(("%s (time=%ld), cpu damage? %d, exec? %d nbatch=%d, busy? %d\n",
17802	     __FUNCTION__, (long)TIME,
17803	     priv && priv->cpu_damage,
17804	     priv && priv->gpu_bo->exec != NULL,
17805	     sna->kgem.nbatch,
17806	     sna->kgem.busy));
17807
17808	busy = stop_flush(sna, priv);
17809	if (!sna->kgem.busy && !busy)
17810		sna_accel_disarm_timer(sna, FLUSH_TIMER);
17811	sna->kgem.busy = busy;
17812
17813	if (priv &&
17814	    sna->mode.shadow_damage == NULL &&
17815	    sna_pixmap_force_to_gpu(priv->pixmap,
17816				    MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT))
17817		kgem_scanout_flush(&sna->kgem, priv->gpu_bo);
17818
17819	sna_mode_redisplay(sna);
17820	sna_accel_post_damage(sna);
17821}
17822
17823static void sna_accel_throttle(struct sna *sna)
17824{
17825	DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME));
17826
17827	if (sna->kgem.need_throttle) {
17828		kgem_submit(&sna->kgem);
17829		kgem_throttle(&sna->kgem);
17830	}
17831
17832	if (!sna->kgem.need_retire)
17833		sna_accel_disarm_timer(sna, THROTTLE_TIMER);
17834}
17835
17836static void sna_pixmap_expire(struct sna *sna)
17837{
17838	while (sna->freed_pixmap) {
17839		PixmapPtr pixmap = __pop_freed_pixmap(sna);
17840		free(sna_pixmap(pixmap));
17841		FreePixmap(pixmap);
17842	}
17843}
17844
17845static void sna_accel_expire(struct sna *sna)
17846{
17847	DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME));
17848
17849	kgem_expire_cache(&sna->kgem);
17850	sna_pixmap_expire(sna);
17851
17852	if (!sna->kgem.need_expire)
17853		sna_accel_disarm_timer(sna, EXPIRE_TIMER);
17854}
17855
17856#ifdef DEBUG_MEMORY
17857static bool sna_accel_do_debug_memory(struct sna *sna)
17858{
17859	int32_t delta = sna->timer_expire[DEBUG_MEMORY_TIMER] - TIME;
17860
17861	if (delta <= 3) {
17862		sna->timer_expire[DEBUG_MEMORY_TIMER] = TIME + 10 * 1000;
17863		return true;
17864	} else
17865		return false;
17866}
17867
17868static void sna_accel_debug_memory(struct sna *sna)
17869{
17870	ErrorF("Allocated pixmaps: %d (cached: %d), bo: %d, %lu bytes (CPU bo: %d, %lu bytes)\n",
17871	       sna->debug_memory.pixmap_allocs,
17872	       sna->debug_memory.pixmap_cached,
17873	       sna->kgem.debug_memory.bo_allocs,
17874	       (unsigned long)sna->kgem.debug_memory.bo_bytes,
17875	       sna->debug_memory.cpu_bo_allocs,
17876	       (unsigned long)sna->debug_memory.cpu_bo_bytes);
17877
17878#ifdef VALGRIND_DO_ADDED_LEAK_CHECK
17879	VG(VALGRIND_DO_ADDED_LEAK_CHECK);
17880#endif
17881}
17882
17883#else
17884#define sna_accel_do_debug_memory(x) 0
17885static void sna_accel_debug_memory(struct sna *sna) { }
17886#endif
17887
17888static ShmFuncs shm_funcs = { sna_pixmap_create_shm, NULL };
17889
17890static PixmapPtr
17891sna_get_window_pixmap(WindowPtr window)
17892{
17893	return get_window_pixmap(window);
17894}
17895
17896static void
17897sna_set_window_pixmap(WindowPtr window, PixmapPtr pixmap)
17898{
17899	DBG(("%s: window=%ld, old pixmap=%ld new pixmap=%ld\n",
17900	     __FUNCTION__, window->drawable.id,
17901	     get_window_pixmap(window) ? get_window_pixmap(window)->drawable.serialNumber : 0,
17902	     pixmap->drawable.serialNumber));
17903
17904	sna_dri2_decouple_window(window);
17905
17906	*(PixmapPtr *)__get_private(window, sna_window_key) = pixmap;
17907}
17908
17909struct sna_visit_set_pixmap_window {
17910	PixmapPtr old, new;
17911};
17912
17913static int
17914sna_visit_set_window_pixmap(WindowPtr window, pointer data)
17915{
17916    struct sna_visit_set_pixmap_window *visit = data;
17917
17918    if (sna_get_window_pixmap(window) == visit->old) {
17919	    window->drawable.pScreen->SetWindowPixmap(window, visit->new);
17920	    return WT_WALKCHILDREN;
17921    }
17922
17923    return WT_DONTWALKCHILDREN;
17924}
17925
17926static void
17927migrate_dirty_tracking(PixmapPtr old_front, PixmapPtr new_front)
17928{
17929#if HAS_PIXMAP_SHARING
17930	ScreenPtr screen = old_front->drawable.pScreen;
17931	PixmapDirtyUpdatePtr dirty, safe;
17932
17933	xorg_list_for_each_entry_safe(dirty, safe, &screen->pixmap_dirty_list, ent) {
17934		assert(dirty->src == old_front);
17935		if ((PixmapPtr)dirty->src != old_front)
17936			continue;
17937
17938		DamageUnregister(&dirty->src->drawable, dirty->damage);
17939		DamageDestroy(dirty->damage);
17940
17941		dirty->damage = DamageCreate(NULL, NULL,
17942					     DamageReportNone,
17943					     TRUE, screen, screen);
17944		if (!dirty->damage) {
17945			xorg_list_del(&dirty->ent);
17946			free(dirty);
17947			continue;
17948		}
17949
17950		DamageRegister(&new_front->drawable, dirty->damage);
17951		dirty->src = (DrawablePtr)new_front;
17952	}
17953#endif
17954}
17955
17956static void
17957sna_set_screen_pixmap(PixmapPtr pixmap)
17958{
17959	ScreenPtr screen = pixmap->drawable.pScreen;
17960	PixmapPtr old_front = screen->devPrivate;
17961	WindowPtr root;
17962
17963	DBG(("%s: changing from pixmap=%ld to pixmap=%ld, (sna->front=%ld)\n",
17964	     __FUNCTION__,
17965	     old_front ? (long)old_front->drawable.serialNumber : 0,
17966	     pixmap ? (long)pixmap->drawable.serialNumber : 0,
17967	     to_sna_from_pixmap(pixmap)->front ? (long)to_sna_from_pixmap(pixmap)->front->drawable.serialNumber : 0));
17968
17969	assert(to_sna_from_pixmap(pixmap) == to_sna_from_screen(screen));
17970	assert(to_sna_from_pixmap(pixmap)->front == old_front);
17971
17972	if (old_front) {
17973		assert(to_sna_from_pixmap(old_front)->front == old_front);
17974		migrate_dirty_tracking(old_front, pixmap);
17975	}
17976
17977	root = get_root_window(screen);
17978	if (root) {
17979		struct sna_visit_set_pixmap_window visit = { old_front, pixmap };
17980		TraverseTree(root, sna_visit_set_window_pixmap, &visit);
17981		assert(fbGetWindowPixmap(root) == pixmap);
17982	}
17983
17984	to_sna_from_pixmap(pixmap)->front = pixmap;
17985	screen->devPrivate = pixmap;
17986	pixmap->refcnt++;
17987
17988	if (old_front)
17989		screen->DestroyPixmap(old_front);
17990}
17991
17992static Bool
17993sna_create_window(WindowPtr win)
17994{
17995	DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
17996	sna_set_window_pixmap(win, win->drawable.pScreen->devPrivate);
17997	return TRUE;
17998}
17999
18000static Bool
18001sna_map_window(WindowPtr win)
18002{
18003	return TRUE;
18004}
18005
18006static Bool
18007sna_position_window(WindowPtr win, int x, int y)
18008{
18009	return TRUE;
18010}
18011
18012static Bool
18013sna_unmap_window(WindowPtr win)
18014{
18015	return TRUE;
18016}
18017
18018static Bool
18019sna_destroy_window(WindowPtr win)
18020{
18021	DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
18022	sna_video_destroy_window(win);
18023	sna_dri2_destroy_window(win);
18024	return TRUE;
18025}
18026
18027static void
18028sna_query_best_size(int class,
18029		    unsigned short *width, unsigned short *height,
18030		    ScreenPtr screen)
18031{
18032	unsigned short w;
18033
18034	switch (class) {
18035	case CursorShape:
18036		if (*width > screen->width)
18037			*width = screen->width;
18038		if (*height > screen->height)
18039			*height = screen->height;
18040		break;
18041
18042	case TileShape:
18043	case StippleShape:
18044		w = *width;
18045		if ((w & (w - 1)) && w < FB_UNIT) {
18046			for (w = 1; w < *width; w <<= 1)
18047				;
18048			*width = w;
18049		}
18050		break;
18051	}
18052}
18053
18054static void sna_store_colors(ColormapPtr cmap, int n, xColorItem *def)
18055{
18056}
18057
18058static bool sna_picture_init(ScreenPtr screen)
18059{
18060	PictureScreenPtr ps;
18061
18062	DBG(("%s\n", __FUNCTION__));
18063
18064	if (!miPictureInit(screen, NULL, 0))
18065		return false;
18066
18067	ps = GetPictureScreen(screen);
18068	assert(ps != NULL);
18069	assert(ps->CreatePicture != NULL);
18070	assert(ps->DestroyPicture != NULL);
18071
18072	ps->Composite = sna_composite;
18073	ps->CompositeRects = sna_composite_rectangles;
18074	ps->Glyphs = sna_glyphs;
18075	if (xf86IsEntityShared(xf86ScreenToScrn(screen)->entityList[0]))
18076		ps->Glyphs = sna_glyphs__shared;
18077	ps->UnrealizeGlyph = sna_glyph_unrealize;
18078	ps->AddTraps = sna_add_traps;
18079	ps->Trapezoids = sna_composite_trapezoids;
18080#if HAS_PIXMAN_TRIANGLES
18081	ps->Triangles = sna_composite_triangles;
18082#if PICTURE_SCREEN_VERSION >= 2
18083	ps->TriStrip = sna_composite_tristrip;
18084	ps->TriFan = sna_composite_trifan;
18085#endif
18086#endif
18087
18088	return true;
18089}
18090
18091static bool sna_option_accel_none(struct sna *sna)
18092{
18093	const char *s;
18094
18095	if (wedged(sna))
18096		return true;
18097
18098	if (!xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_ENABLE, TRUE))
18099		return true;
18100
18101	if (sna->kgem.gen >= 0120)
18102		return true;
18103
18104	if (!intel_option_cast_to_bool(sna->Options,
18105				       OPTION_ACCEL_METHOD,
18106				       !IS_DEFAULT_ACCEL_METHOD(NOACCEL)))
18107		return false;
18108
18109#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
18110	s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD);
18111	if (s == NULL)
18112		return IS_DEFAULT_ACCEL_METHOD(NOACCEL);
18113
18114	return strcasecmp(s, "none") == 0;
18115#else
18116	return IS_DEFAULT_ACCEL_METHOD(NOACCEL);
18117#endif
18118}
18119
18120static bool sna_option_accel_blt(struct sna *sna)
18121{
18122	const char *s;
18123
18124	assert(sna->kgem.gen < 0120);
18125
18126	s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD);
18127	if (s == NULL)
18128		return false;
18129
18130	return strcasecmp(s, "blt") == 0;
18131}
18132
18133#if HAVE_NOTIFY_FD
18134static void sna_accel_notify(int fd, int ready, void *data)
18135{
18136	sna_mode_wakeup(data);
18137}
18138#endif
18139
18140bool sna_accel_init(ScreenPtr screen, struct sna *sna)
18141{
18142	const char *backend;
18143
18144	DBG(("%s\n", __FUNCTION__));
18145
18146	sna_font_key = AllocateFontPrivateIndex();
18147
18148	list_init(&sna->flush_pixmaps);
18149	list_init(&sna->active_pixmaps);
18150
18151	SetNotifyFd(sna->kgem.fd, sna_accel_notify, X_NOTIFY_READ, sna);
18152
18153#ifdef DEBUG_MEMORY
18154	sna->timer_expire[DEBUG_MEMORY_TIMER] = GetTimeInMillis()+ 10 * 1000;
18155#endif
18156
18157	screen->defColormap = FakeClientID(0);
18158	/* let CreateDefColormap do whatever it wants for pixels */
18159	screen->blackPixel = screen->whitePixel = (Pixel) 0;
18160	screen->QueryBestSize = sna_query_best_size;
18161	assert(screen->GetImage == NULL);
18162	screen->GetImage = sna_get_image;
18163	assert(screen->GetSpans == NULL);
18164	screen->GetSpans = sna_get_spans;
18165	assert(screen->CreateWindow == NULL);
18166	screen->CreateWindow = sna_create_window;
18167	assert(screen->DestroyWindow == NULL);
18168	screen->DestroyWindow = sna_destroy_window;
18169	screen->PositionWindow = sna_position_window;
18170	screen->ChangeWindowAttributes = sna_change_window_attributes;
18171	screen->RealizeWindow = sna_map_window;
18172	screen->UnrealizeWindow = sna_unmap_window;
18173	screen->CopyWindow = sna_copy_window;
18174	assert(screen->CreatePixmap == NULL);
18175	screen->CreatePixmap = sna_create_pixmap;
18176	assert(screen->DestroyPixmap == NULL);
18177	screen->DestroyPixmap = sna_destroy_pixmap;
18178#ifdef CREATE_PIXMAP_USAGE_SHARED
18179	screen->SharePixmapBacking = sna_share_pixmap_backing;
18180	screen->SetSharedPixmapBacking = sna_set_shared_pixmap_backing;
18181#endif
18182	screen->RealizeFont = sna_realize_font;
18183	screen->UnrealizeFont = sna_unrealize_font;
18184	assert(screen->CreateGC == NULL);
18185	screen->CreateGC = sna_create_gc;
18186	screen->CreateColormap = miInitializeColormap;
18187	screen->DestroyColormap = (void (*)(ColormapPtr)) NoopDDA;
18188	screen->InstallColormap = miInstallColormap;
18189	screen->UninstallColormap = miUninstallColormap;
18190	screen->ListInstalledColormaps = miListInstalledColormaps;
18191	screen->ResolveColor = miResolveColor;
18192	assert(screen->StoreColors == NULL);
18193	screen->StoreColors = sna_store_colors;
18194	screen->BitmapToRegion = fbBitmapToRegion;
18195
18196#if HAS_PIXMAP_SHARING
18197	screen->StartPixmapTracking = PixmapStartDirtyTracking;
18198	screen->StopPixmapTracking = PixmapStopDirtyTracking;
18199#endif
18200
18201	assert(screen->GetWindowPixmap == NULL);
18202	screen->GetWindowPixmap = sna_get_window_pixmap;
18203	assert(screen->SetWindowPixmap == NULL);
18204	screen->SetWindowPixmap = sna_set_window_pixmap;
18205
18206	screen->SetScreenPixmap = sna_set_screen_pixmap;
18207
18208	if (sna->kgem.has_userptr)
18209		ShmRegisterFuncs(screen, &shm_funcs);
18210	else
18211		ShmRegisterFbFuncs(screen);
18212
18213	if (!sna_picture_init(screen))
18214		return false;
18215
18216	backend = no_render_init(sna);
18217	if (sna_option_accel_none(sna)) {
18218		backend = "disabled";
18219		sna->kgem.wedged = true;
18220		sna_render_mark_wedged(sna);
18221	} else if (sna_option_accel_blt(sna))
18222		(void)backend;
18223	else if (sna->kgem.gen >= 0110)
18224		backend = gen9_render_init(sna, backend);
18225	else if (sna->kgem.gen >= 0100)
18226		backend = gen8_render_init(sna, backend);
18227	else if (sna->kgem.gen >= 070)
18228		backend = gen7_render_init(sna, backend);
18229	else if (sna->kgem.gen >= 060)
18230		backend = gen6_render_init(sna, backend);
18231	else if (sna->kgem.gen >= 050)
18232		backend = gen5_render_init(sna, backend);
18233	else if (sna->kgem.gen >= 040)
18234		backend = gen4_render_init(sna, backend);
18235	else if (sna->kgem.gen >= 030)
18236		backend = gen3_render_init(sna, backend);
18237	else if (sna->kgem.gen >= 020)
18238		backend = gen2_render_init(sna, backend);
18239
18240	DBG(("%s(backend=%s, prefer_gpu=%x)\n",
18241	     __FUNCTION__, backend, sna->render.prefer_gpu));
18242
18243	kgem_reset(&sna->kgem);
18244	sigtrap_init();
18245
18246	xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
18247		   "SNA initialized with %s backend\n",
18248		   backend);
18249
18250	return true;
18251}
18252
18253void sna_accel_create(struct sna *sna)
18254{
18255	ExtensionEntry *damage;
18256
18257	DBG(("%s\n", __FUNCTION__));
18258
18259	damage = CheckExtension("DAMAGE");
18260	if (damage)
18261		sna->damage_event = damage->eventBase + XDamageNotify;
18262
18263	if (!sna_glyphs_create(sna))
18264		goto fail;
18265
18266	if (!sna_gradients_create(sna))
18267		goto fail;
18268
18269	if (!sna_composite_create(sna))
18270		goto fail;
18271
18272	return;
18273
18274fail:
18275	xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
18276		   "Failed to allocate caches, disabling RENDER acceleration\n");
18277	no_render_init(sna);
18278}
18279
18280static void sna_shm_watch_flush(struct sna *sna, int enable)
18281{
18282	DBG(("%s: enable=%d\n", __FUNCTION__, enable));
18283	assert(enable);
18284
18285	if (sna->watch_shm_flush == 0) {
18286		DBG(("%s: installing shm watchers\n", __FUNCTION__));
18287		assert(enable > 0);
18288
18289		if (!AddCallback(&FlushCallback, sna_shm_flush_callback, sna))
18290			return;
18291
18292		sna->watch_shm_flush++;
18293	}
18294
18295	sna->watch_shm_flush += enable;
18296}
18297
18298void sna_watch_flush(struct sna *sna, int enable)
18299{
18300	DBG(("%s: enable=%d\n", __FUNCTION__, enable));
18301	assert(enable);
18302
18303	if (sna->watch_dri_flush == 0) {
18304		int err = 0;
18305
18306		DBG(("%s: installing watchers\n", __FUNCTION__));
18307		assert(enable > 0);
18308
18309		if (!sna->damage_event)
18310			return;
18311
18312		if (!AddCallback(&EventCallback, sna_event_callback, sna))
18313			err = 1;
18314
18315		if (!AddCallback(&FlushCallback, sna_flush_callback, sna))
18316			err = 1;
18317
18318		if (err) {
18319			xf86DrvMsg(sna->scrn->scrnIndex, X_Error,
18320				   "Failed to attach ourselves to the flush callbacks, expect missing synchronisation with DRI clients (e.g a compositor)\n");
18321		}
18322
18323		sna->watch_dri_flush++;
18324	}
18325
18326	sna->watch_dri_flush += enable;
18327}
18328
18329void sna_accel_leave(struct sna *sna)
18330{
18331	DBG(("%s\n", __FUNCTION__));
18332	sna_scanout_flush(sna);
18333
18334	/* as root we always have permission to render */
18335	if (geteuid() == 0)
18336		return;
18337
18338	/* as a user, we can only render now if we have a rendernode */
18339	if (intel_has_render_node(sna->dev))
18340		return;
18341
18342	/* no longer authorized to use our fd */
18343	DBG(("%s: dropping render privileges\n", __FUNCTION__));
18344
18345	kgem_submit(&sna->kgem);
18346	sna->kgem.wedged |= 2;
18347}
18348
18349void sna_accel_enter(struct sna *sna)
18350{
18351	DBG(("%s\n", __FUNCTION__));
18352	sna->kgem.wedged &= kgem_is_wedged(&sna->kgem);
18353	kgem_throttle(&sna->kgem);
18354}
18355
18356void sna_accel_close(struct sna *sna)
18357{
18358	DBG(("%s\n", __FUNCTION__));
18359
18360	sna_composite_close(sna);
18361	sna_gradients_close(sna);
18362	sna_glyphs_close(sna);
18363
18364	sna_pixmap_expire(sna);
18365
18366	DeleteCallback(&FlushCallback, sna_shm_flush_callback, sna);
18367	DeleteCallback(&FlushCallback, sna_flush_callback, sna);
18368	DeleteCallback(&EventCallback, sna_event_callback, sna);
18369	RemoveNotifyFd(sna->kgem.fd);
18370
18371	kgem_cleanup_cache(&sna->kgem);
18372}
18373
18374void sna_accel_block(struct sna *sna, struct timeval **tv)
18375{
18376	sigtrap_assert_inactive();
18377
18378	if (sna->kgem.need_retire)
18379		kgem_retire(&sna->kgem);
18380	kgem_retire__buffers(&sna->kgem);
18381
18382	if (sna->timer_active)
18383		UpdateCurrentTimeIf();
18384
18385	if (sna->kgem.nbatch &&
18386	    (sna->kgem.scanout_busy ||
18387	     kgem_ring_is_idle(&sna->kgem, sna->kgem.ring))) {
18388		DBG(("%s: GPU idle, flushing\n", __FUNCTION__));
18389		_kgem_submit(&sna->kgem);
18390	}
18391
18392	if (sna->mode.dirty)
18393		sna_crtc_config_notify(xf86ScrnToScreen(sna->scrn));
18394
18395restart:
18396	if (sna_scanout_do_flush(sna))
18397		sna_scanout_flush(sna);
18398	assert(sna_accel_scanout(sna) == NULL ||
18399	       !sna_accel_scanout(sna)->gpu_bo->needs_flush ||
18400	       sna->timer_active & (1<<(FLUSH_TIMER)));
18401
18402	if (sna_accel_do_throttle(sna))
18403		sna_accel_throttle(sna);
18404	assert(!sna->kgem.need_retire ||
18405	       sna->timer_active & (1<<(THROTTLE_TIMER)));
18406
18407	if (sna_accel_do_expire(sna))
18408		sna_accel_expire(sna);
18409	assert(!sna->kgem.need_expire ||
18410	       sna->timer_active & (1<<(EXPIRE_TIMER)));
18411
18412	if (sna_accel_do_debug_memory(sna))
18413		sna_accel_debug_memory(sna);
18414
18415	if (sna->watch_shm_flush == 1) {
18416		DBG(("%s: removing shm watchers\n", __FUNCTION__));
18417		DeleteCallback(&FlushCallback, sna_shm_flush_callback, sna);
18418		sna->watch_shm_flush = 0;
18419	}
18420
18421	if (sna->watch_dri_flush == 1) {
18422		DBG(("%s: removing dri watchers\n", __FUNCTION__));
18423		DeleteCallback(&FlushCallback, sna_flush_callback, sna);
18424		DeleteCallback(&EventCallback, sna_event_callback, sna);
18425		sna->watch_dri_flush = 0;
18426	}
18427
18428	if (sna->timer_active & 1) {
18429		int32_t timeout;
18430
18431		DBG(("%s: evaluating timers, active=%x\n",
18432		     __FUNCTION__, sna->timer_active));
18433
18434		timeout = sna->timer_expire[FLUSH_TIMER] - TIME;
18435		DBG(("%s: flush timer expires in %d [%d]\n",
18436		     __FUNCTION__, timeout, sna->timer_expire[FLUSH_TIMER]));
18437		if (timeout < 3)
18438			goto restart;
18439
18440		if (*tv == NULL) {
18441			*tv = &sna->timer_tv;
18442			goto set_tv;
18443		}
18444		if ((*tv)->tv_sec * 1000 + (*tv)->tv_usec / 1000 > timeout) {
18445set_tv:
18446			(*tv)->tv_sec = timeout / 1000;
18447			(*tv)->tv_usec = timeout % 1000 * 1000;
18448		}
18449	}
18450
18451	sna->kgem.scanout_busy = false;
18452
18453	if (FAULT_INJECTION && (rand() % FAULT_INJECTION) == 0) {
18454		DBG(("%s hardware acceleration\n",
18455		     sna->kgem.wedged ? "Re-enabling" : "Disabling"));
18456		kgem_submit(&sna->kgem);
18457		sna->kgem.wedged = !sna->kgem.wedged;
18458	}
18459}
18460
18461void sna_accel_free(struct sna *sna)
18462{
18463	DBG(("%s\n", __FUNCTION__));
18464	sigtrap_assert_inactive();
18465}
18466