sna_accel.c revision 63ef14f0
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
42#include <dixfontstr.h>
43
44#include <mi.h>
45#include <migc.h>
46#include <miline.h>
47#include <micmap.h>
48#ifdef RENDER
49#include <mipict.h>
50#endif
51#include <shmint.h>
52
53#include <X11/extensions/damageproto.h>
54
55#include <sys/time.h>
56#include <sys/mman.h>
57#include <sys/ioctl.h>
58#include <unistd.h>
59
60#ifdef HAVE_VALGRIND
61#include <valgrind.h>
62#include <memcheck.h>
63#endif
64
65#define FAULT_INJECTION 0
66
67#define FORCE_INPLACE 0
68#define FORCE_FALLBACK 0
69#define FORCE_FLUSH 0
70#define FORCE_FULL_SYNC 0 /* https://bugs.freedesktop.org/show_bug.cgi?id=61628 */
71
72#define DEFAULT_PIXMAP_TILING I915_TILING_X
73#define DEFAULT_SCANOUT_TILING I915_TILING_X
74
75#define USE_INPLACE 1
76#define USE_SPANS 0 /* -1 force CPU, 1 force GPU */
77#define USE_CPU_BO 1
78#define USE_USERPTR_UPLOADS 1
79#define USE_USERPTR_DOWNLOADS 1
80#define USE_COW 1
81#define UNDO 1
82
83#define MIGRATE_ALL 0
84#define DBG_NO_PARTIAL_MOVE_TO_CPU 0
85#define DBG_NO_CPU_UPLOAD 0
86#define DBG_NO_CPU_DOWNLOAD 0
87
88#define ACCEL_FILL_SPANS 1
89#define ACCEL_SET_SPANS 1
90#define ACCEL_PUT_IMAGE 1
91#define ACCEL_GET_IMAGE 1
92#define ACCEL_COPY_AREA 1
93#define ACCEL_COPY_PLANE 1
94#define ACCEL_COPY_WINDOW 1
95#define ACCEL_POLY_POINT 1
96#define ACCEL_POLY_LINE 1
97#define ACCEL_POLY_SEGMENT 1
98#define ACCEL_POLY_RECTANGLE 1
99#define ACCEL_POLY_ARC 1
100#define ACCEL_POLY_FILL_POLYGON 1
101#define ACCEL_POLY_FILL_RECT 1
102#define ACCEL_POLY_FILL_ARC 1
103#define ACCEL_POLY_TEXT8 1
104#define ACCEL_POLY_TEXT16 1
105#define ACCEL_POLY_GLYPH 1
106#define ACCEL_IMAGE_TEXT8 1
107#define ACCEL_IMAGE_TEXT16 1
108#define ACCEL_IMAGE_GLYPH 1
109#define ACCEL_PUSH_PIXELS 1
110
111#define NO_TILE_8x8 0
112#define NO_STIPPLE_8x8 0
113
114#define IS_COW_OWNER(ptr) ((uintptr_t)(ptr) & 1)
115#define MAKE_COW_OWNER(ptr) ((void*)((uintptr_t)(ptr) | 1))
116#define COW(ptr) (void *)((uintptr_t)(ptr) & ~1)
117
118#define IS_CLIPPED	0x2
119#define RECTILINEAR	0x4
120#define OVERWRITES	0x8
121
122#if XFONT2_CLIENT_FUNCS_VERSION >= 1
123#define AllocateFontPrivateIndex() xfont2_allocate_font_private_index()
124#define FontSetPrivate(font, idx, data) xfont2_font_set_private(font, idx, data)
125#endif
126
127#if 0
128static void __sna_fallback_flush(DrawablePtr d)
129{
130	PixmapPtr pixmap = get_drawable_pixmap(d);
131	struct sna *sna = to_sna_from_pixmap(pixmap);
132	struct sna_pixmap *priv;
133	BoxRec box;
134	PixmapPtr tmp;
135	int i, j;
136	char *src, *dst;
137
138	DBG(("%s: uploading CPU damage...\n", __FUNCTION__));
139	priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ);
140	if (priv == NULL)
141		return;
142
143	DBG(("%s: downloading GPU damage...\n", __FUNCTION__));
144	if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
145		return;
146
147	box.x1 = box.y1 = 0;
148	box.x2 = pixmap->drawable.width;
149	box.y2 = pixmap->drawable.height;
150
151	tmp = sna_pixmap_create_unattached(pixmap->drawable.pScreen,
152					   pixmap->drawable.width,
153					   pixmap->drawable.height,
154					   pixmap->drawable.depth,
155					   0);
156
157	DBG(("%s: comparing with direct read...\n", __FUNCTION__));
158	sna_read_boxes(sna, tmp, priv->gpu_bo, &box, 1);
159
160	src = pixmap->devPrivate.ptr;
161	dst = tmp->devPrivate.ptr;
162	for (i = 0; i < tmp->drawable.height; i++) {
163		if (memcmp(src, dst, tmp->drawable.width * tmp->drawable.bitsPerPixel >> 3)) {
164			for (j = 0; src[j] == dst[j]; j++)
165				;
166			ERR(("mismatch at (%d, %d)\n",
167			     8*j / tmp->drawable.bitsPerPixel, i));
168			abort();
169		}
170		src += pixmap->devKind;
171		dst += tmp->devKind;
172	}
173	tmp->drawable.pScreen->DestroyPixmap(tmp);
174}
175#define FALLBACK_FLUSH(d) __sna_fallback_flush(d)
176#else
177#define FALLBACK_FLUSH(d)
178#endif
179
180static int sna_font_key;
181
182static const uint8_t copy_ROP[] = {
183	ROP_0,		/* GXclear */
184	ROP_DSa,	/* GXand */
185	ROP_SDna,	/* GXandReverse */
186	ROP_S,		/* GXcopy */
187	ROP_DSna,	/* GXandInverted */
188	ROP_D,		/* GXnoop */
189	ROP_DSx,	/* GXxor */
190	ROP_DSo,	/* GXor */
191	ROP_DSon,	/* GXnor */
192	ROP_DSxn,	/* GXequiv */
193	ROP_Dn,		/* GXinvert */
194	ROP_SDno,	/* GXorReverse */
195	ROP_Sn,		/* GXcopyInverted */
196	ROP_DSno,	/* GXorInverted */
197	ROP_DSan,	/* GXnand */
198	ROP_1		/* GXset */
199};
200static const uint8_t fill_ROP[] = {
201	ROP_0,
202	ROP_DPa,
203	ROP_PDna,
204	ROP_P,
205	ROP_DPna,
206	ROP_D,
207	ROP_DPx,
208	ROP_DPo,
209	ROP_DPon,
210	ROP_PDxn,
211	ROP_Dn,
212	ROP_PDno,
213	ROP_Pn,
214	ROP_DPno,
215	ROP_DPan,
216	ROP_1
217};
218
219static const GCOps sna_gc_ops;
220static const GCOps sna_gc_ops__cpu;
221static GCOps sna_gc_ops__tmp;
222static const GCFuncs sna_gc_funcs;
223static const GCFuncs sna_gc_funcs__cpu;
224
225static void sna_shm_watch_flush(struct sna *sna, int enable);
226static void
227sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect);
228
229static inline void region_set(RegionRec *r, const BoxRec *b)
230{
231	r->extents = *b;
232	r->data = NULL;
233}
234
235static inline bool region_maybe_clip(RegionRec *r, RegionRec *clip)
236{
237	if (clip->data && !RegionIntersect(r, r, clip))
238		return false;
239
240	return !box_empty(&r->extents);
241}
242
243static inline bool region_is_singular(const RegionRec *r)
244{
245	return r->data == NULL;
246}
247
248static inline bool region_is_unclipped(const RegionRec *r, int w, int h)
249{
250	return (region_is_singular(r) &&
251		w == r->extents.x2 - r->extents.x1 &&
252		h == r->extents.y2 - r->extents.y1);
253}
254
255typedef struct box32 {
256	int32_t x1, y1, x2, y2;
257} Box32Rec;
258
259#define PM_IS_SOLID(_draw, _pm) \
260	(((_pm) & FbFullMask((_draw)->depth)) == FbFullMask((_draw)->depth))
261
262#ifndef NDEBUG
263static void _assert_pixmap_contains_box(PixmapPtr pixmap, const BoxRec *box, const char *function)
264{
265	if (box->x1 < 0 || box->y1 < 0 ||
266	    box->x2 > pixmap->drawable.width ||
267	    box->y2 > pixmap->drawable.height)
268	{
269		FatalError("%s: damage box [(%d, %d), (%d, %d)] is beyond the pixmap=%ld size=%dx%d\n",
270			   function, box->x1, box->y1, box->x2, box->y2,
271			   pixmap->drawable.serialNumber,
272			   pixmap->drawable.width,
273			   pixmap->drawable.height);
274	}
275}
276
277static void
278_assert_pixmap_contains_damage(PixmapPtr pixmap, struct sna_damage *damage, const char *function)
279{
280	if (damage == NULL)
281		return;
282
283	_assert_pixmap_contains_box(pixmap, &DAMAGE_PTR(damage)->extents, function);
284}
285#define assert_pixmap_contains_damage(p,d) _assert_pixmap_contains_damage(p, d, __FUNCTION__)
286#else
287#define assert_pixmap_contains_damage(p,d)
288#endif
289
290#define __assert_pixmap_damage(p) do { \
291	struct sna_pixmap *priv__ = sna_pixmap(p); \
292	if (priv__) { \
293		assert(priv__->gpu_damage == NULL || priv__->gpu_bo); \
294		assert(priv__->gpu_bo == NULL || priv__->gpu_bo->refcnt); \
295		assert(priv__->cpu_bo == NULL || priv__->cpu_bo->refcnt); \
296		assert_pixmap_contains_damage(p, priv__->gpu_damage); \
297		assert_pixmap_contains_damage(p, priv__->cpu_damage); \
298		assert_pixmap_map(p, priv__); \
299	} \
300} while (0)
301
302#ifdef DEBUG_PIXMAP
303static void _assert_pixmap_contains_box_with_offset(PixmapPtr pixmap, const BoxRec *box, int dx, int dy, const char *function)
304{
305	BoxRec b = *box;
306	b.x1 += dx; b.x2 += dx;
307	b.y1 += dy; b.y2 += dy;
308	_assert_pixmap_contains_box(pixmap, &b, function);
309}
310
311static void _assert_pixmap_contains_boxes(PixmapPtr pixmap, const BoxRec *box, int n, int dx, int dy, const char *function)
312{
313	BoxRec extents;
314
315	extents = *box;
316	while (--n) {
317		++box;
318
319		if (box->x1 < extents.x1)
320			extents.x1 = box->x1;
321		if (box->x2 > extents.x2)
322			extents.x2 = box->x2;
323
324		if (box->y1 < extents.y1)
325			extents.y1 = box->y1;
326		if (box->y2 > extents.y2)
327			extents.y2 = box->y2;
328	}
329	extents.x1 += dx;
330	extents.x2 += dx;
331	extents.y1 += dy;
332	extents.y2 += dy;
333	_assert_pixmap_contains_box(pixmap, &extents, function);
334}
335
336
337static void _assert_pixmap_contains_points(PixmapPtr pixmap, const DDXPointRec *pt, int n, int dx, int dy, const char *function)
338{
339	BoxRec extents;
340
341	extents.x2 = extents.x1 = pt->x;
342	extents.y2 = extents.y1 = pt->y;
343	while (--n) {
344		++pt;
345
346		if (pt->x < extents.x1)
347			extents.x1 = pt->x;
348		else if (pt->x > extents.x2)
349			extents.x2 = pt->x;
350
351		if (pt->y < extents.y1)
352			extents.y1 = pt->y;
353		else if (pt->y > extents.y2)
354			extents.y2 = pt->y;
355	}
356	extents.x1 += dx;
357	extents.x2 += dx + 1;
358	extents.y1 += dy;
359	extents.y2 += dy + 1;
360	_assert_pixmap_contains_box(pixmap, &extents, function);
361}
362
363static void _assert_drawable_contains_box(DrawablePtr drawable, const BoxRec *box, const char *function)
364{
365	if (box->x1 < drawable->x ||
366	    box->y1 < drawable->y ||
367	    box->x2 > drawable->x + drawable->width ||
368	    box->y2 > drawable->y + drawable->height)
369	{
370		FatalError("%s: damage box is beyond the drawable: box=(%d, %d), (%d, %d), drawable=(%d, %d)x(%d, %d)\n",
371			   function,
372			   box->x1, box->y1, box->x2, box->y2,
373			   drawable->x, drawable->y,
374			   drawable->width, drawable->height);
375	}
376}
377
378static void assert_pixmap_damage(PixmapPtr p)
379{
380	struct sna_pixmap *priv;
381	RegionRec reg, cpu, gpu;
382
383	priv = sna_pixmap(p);
384	if (priv == NULL)
385		return;
386
387	__assert_pixmap_damage(p);
388
389	if (priv->clear) {
390		assert(DAMAGE_IS_ALL(priv->gpu_damage));
391		assert(priv->cpu_damage == NULL);
392	}
393
394	if (DAMAGE_IS_ALL(priv->gpu_damage) && DAMAGE_IS_ALL(priv->cpu_damage)) {
395		/* special upload buffer */
396		assert(priv->gpu_bo && priv->gpu_bo->proxy);
397		assert(priv->cpu_bo == NULL);
398		return;
399	}
400
401	assert(!DAMAGE_IS_ALL(priv->gpu_damage) || priv->cpu_damage == NULL);
402	assert(!DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL);
403
404	/* Avoid reducing damage to minimise interferrence */
405	RegionNull(&reg);
406	RegionNull(&gpu);
407	RegionNull(&cpu);
408
409	if (priv->gpu_damage)
410		_sna_damage_debug_get_region(DAMAGE_PTR(priv->gpu_damage), &gpu);
411
412	if (priv->cpu_damage)
413		_sna_damage_debug_get_region(DAMAGE_PTR(priv->cpu_damage), &cpu);
414
415	RegionIntersect(&reg, &cpu, &gpu);
416	assert(RegionNil(&reg));
417
418	RegionUninit(&reg);
419	RegionUninit(&gpu);
420	RegionUninit(&cpu);
421}
422
423#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__)
424#define assert_pixmap_contains_box_with_offset(p, b, dx, dy) _assert_pixmap_contains_box_with_offset(p, b, dx, dy, __FUNCTION__)
425#define assert_drawable_contains_box(d, b) _assert_drawable_contains_box(d, b, __FUNCTION__)
426#define assert_pixmap_contains_boxes(p, b, n, x, y) _assert_pixmap_contains_boxes(p, b, n, x, y, __FUNCTION__)
427#define assert_pixmap_contains_points(p, pt, n, x, y) _assert_pixmap_contains_points(p, pt, n, x, y, __FUNCTION__)
428
429#else
430#define assert_pixmap_contains_box(p, b)
431#define assert_pixmap_contains_box_with_offset(p, b, dx, dy)
432#define assert_pixmap_contains_boxes(p, b, n, x, y)
433#define assert_pixmap_contains_points(p, pt, n, x, y)
434#define assert_drawable_contains_box(d, b)
435#ifndef NDEBUG
436#define assert_pixmap_damage(p) __assert_pixmap_damage(p)
437#else
438#define assert_pixmap_damage(p)
439#endif
440#endif
441
442jmp_buf sigjmp[4];
443volatile sig_atomic_t sigtrap;
444
445static int sigtrap_handler(int sig)
446{
447	/* XXX rate-limited squawk? */
448	DBG(("%s(sig=%d) sigtrap=%d\n", __FUNCTION__, sig, sigtrap));
449	sna_threads_trap(sig);
450
451	if (sigtrap)
452		siglongjmp(sigjmp[--sigtrap], sig);
453
454	return -1;
455}
456
457static void sigtrap_init(void)
458{
459#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0)
460	OsRegisterSigWrapper(sigtrap_handler);
461#endif
462}
463
464inline static bool
465sna_fill_init_blt(struct sna_fill_op *fill,
466		  struct sna *sna,
467		  PixmapPtr pixmap,
468		  struct kgem_bo *bo,
469		  uint8_t alu,
470		  uint32_t pixel,
471		  unsigned flags)
472{
473	return sna->render.fill(sna, alu, pixmap, bo, pixel, flags, fill);
474}
475
476static bool
477sna_copy_init_blt(struct sna_copy_op *copy,
478		  struct sna *sna,
479		  PixmapPtr src, struct kgem_bo *src_bo,
480		  PixmapPtr dst, struct kgem_bo *dst_bo,
481		  uint8_t alu)
482{
483	memset(copy, 0, sizeof(*copy));
484	return sna->render.copy(sna, alu, src, src_bo, dst, dst_bo, copy);
485}
486
487static void sna_pixmap_free_gpu(struct sna *sna, struct sna_pixmap *priv)
488{
489	DBG(("%s: handle=%d (pinned? %d)\n", __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->pinned));
490	assert(priv->gpu_damage == NULL || priv->gpu_bo);
491
492	if (priv->cow)
493		sna_pixmap_undo_cow(sna, priv, MOVE_WRITE);
494	assert(priv->cow == NULL);
495
496	if (priv->move_to_gpu) {
497		sna_pixmap_discard_shadow_damage(priv, NULL);
498		priv->move_to_gpu(sna, priv, MOVE_WRITE);
499	}
500
501	sna_damage_destroy(&priv->gpu_damage);
502	priv->clear = false;
503
504	if (priv->gpu_bo) {
505		if (!priv->pinned) {
506			assert(!priv->flush);
507			assert(!priv->move_to_gpu);
508			sna_pixmap_unmap(priv->pixmap, priv);
509			kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
510			priv->gpu_bo = NULL;
511		} else
512			kgem_bo_undo(&sna->kgem, priv->gpu_bo);
513	}
514
515	/* and reset the upload counter */
516	priv->source_count = SOURCE_BIAS;
517}
518
519static bool must_check
520sna_pixmap_alloc_cpu(struct sna *sna,
521		     PixmapPtr pixmap,
522		     struct sna_pixmap *priv,
523		     unsigned flags)
524{
525	/* Restore after a GTT mapping? */
526	assert(priv->gpu_damage == NULL || priv->gpu_bo);
527	assert(!priv->shm);
528	if (priv->ptr)
529		goto done;
530
531	DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
532	assert(priv->stride);
533
534	if (priv->create & KGEM_CAN_CREATE_CPU) {
535		unsigned hint;
536
537		DBG(("%s: allocating CPU buffer (%dx%d)\n", __FUNCTION__,
538		     pixmap->drawable.width, pixmap->drawable.height));
539
540		hint = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE;
541		if ((flags & MOVE_ASYNC_HINT) ||
542		    (priv->gpu_damage && !priv->clear && kgem_bo_is_busy(priv->gpu_bo) && sna->kgem.can_blt_cpu))
543			hint = 0;
544
545		priv->cpu_bo = kgem_create_cpu_2d(&sna->kgem,
546						  pixmap->drawable.width,
547						  pixmap->drawable.height,
548						  pixmap->drawable.bitsPerPixel,
549						  hint);
550		if (priv->cpu_bo) {
551			priv->ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo);
552			if (priv->ptr) {
553				DBG(("%s: allocated CPU handle=%d (snooped? %d)\n", __FUNCTION__,
554				     priv->cpu_bo->handle, priv->cpu_bo->snoop));
555				priv->stride = priv->cpu_bo->pitch;
556#ifdef DEBUG_MEMORY
557				sna->debug_memory.cpu_bo_allocs++;
558				sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo);
559#endif
560			} else {
561				kgem_bo_destroy(&sna->kgem, priv->cpu_bo);
562				priv->cpu_bo = NULL;
563			}
564		}
565	}
566
567	if (priv->ptr == NULL) {
568		DBG(("%s: allocating ordinary memory for shadow pixels [%d bytes]\n",
569		     __FUNCTION__, priv->stride * pixmap->drawable.height));
570		priv->ptr = malloc(priv->stride * pixmap->drawable.height);
571	}
572
573done:
574	assert(priv->stride);
575	assert(!priv->mapped);
576	pixmap->devPrivate.ptr = PTR(priv->ptr);
577	pixmap->devKind = priv->stride;
578	return priv->ptr != NULL;
579}
580
581static void __sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv)
582{
583	if (priv->cpu_bo) {
584		DBG(("%s: discarding CPU buffer, handle=%d, size=%d\n",
585		     __FUNCTION__, priv->cpu_bo->handle, kgem_bo_size(priv->cpu_bo)));
586#ifdef DEBUG_MEMORY
587		sna->debug_memory.cpu_bo_allocs--;
588		sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
589#endif
590		if (priv->cpu_bo->flush) {
591			assert(!priv->cpu_bo->reusable);
592			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
593			sna_shm_watch_flush(sna, -1);
594		}
595		kgem_bo_destroy(&sna->kgem, priv->cpu_bo);
596	} else if (!IS_STATIC_PTR(priv->ptr))
597		free(priv->ptr);
598}
599
600static bool sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv, bool active)
601{
602	if (active)
603		return false;
604
605	if (IS_STATIC_PTR(priv->ptr))
606		return false;
607
608	if (priv->ptr == NULL)
609		return true;
610
611	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, priv->pixmap->drawable.serialNumber));
612	__sna_pixmap_free_cpu(sna, priv);
613
614	priv->cpu_bo = NULL;
615	priv->ptr = NULL;
616
617	if (priv->mapped == MAPPED_NONE)
618		priv->pixmap->devPrivate.ptr = NULL;
619
620	return true;
621}
622
623static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap)
624{
625#if DEFAULT_PIXMAP_TILING == I915_TILING_NONE
626	return I915_TILING_NONE;
627#elif DEFAULT_PIXMAP_TILING == I915_TILING_X
628	return I915_TILING_X;
629#else
630	/* Try to avoid hitting the Y-tiling GTT mapping bug on 855GM */
631	if (sna->kgem.gen == 021)
632		return I915_TILING_X;
633
634	/* Only on later generations was the render pipeline
635	 * more flexible than the BLT. So on gen2/3, prefer to
636	 * keep large objects accessible through the BLT.
637	 */
638	if (sna->kgem.gen < 040 &&
639	    (pixmap->drawable.width  > sna->render.max_3d_size ||
640	     pixmap->drawable.height > sna->render.max_3d_size))
641		return I915_TILING_X;
642
643	return I915_TILING_Y;
644#endif
645}
646
647pure static uint32_t sna_pixmap_default_tiling(struct sna *sna, PixmapPtr pixmap)
648{
649	/* Also adjust tiling if it is not supported or likely to
650	 * slow us down,
651	 */
652	return kgem_choose_tiling(&sna->kgem,
653				  default_tiling(sna, pixmap),
654				  pixmap->drawable.width,
655				  pixmap->drawable.height,
656				  pixmap->drawable.bitsPerPixel);
657}
658
659struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling)
660{
661	struct sna_pixmap *priv = sna_pixmap(pixmap);
662	struct sna *sna = to_sna_from_pixmap(pixmap);
663	struct kgem_bo *bo;
664	BoxRec box;
665
666	DBG(("%s: changing tiling %d -> %d for %dx%d pixmap\n",
667	     __FUNCTION__, priv->gpu_bo->tiling, tiling,
668	     pixmap->drawable.width, pixmap->drawable.height));
669	assert(priv->gpu_damage == NULL || priv->gpu_bo);
670	assert(priv->gpu_bo->tiling != tiling);
671
672	if (priv->pinned) {
673		DBG(("%s: can't convert pinned bo\n", __FUNCTION__));
674		return NULL;
675	}
676
677	if (wedged(sna)) {
678		DBG(("%s: can't convert bo, wedged\n", __FUNCTION__));
679		return NULL;
680	}
681
682	assert_pixmap_damage(pixmap);
683	assert(!priv->move_to_gpu);
684
685	bo = kgem_create_2d(&sna->kgem,
686			    pixmap->drawable.width,
687			    pixmap->drawable.height,
688			    pixmap->drawable.bitsPerPixel,
689			    tiling, 0);
690	if (bo == NULL) {
691		DBG(("%s: allocation failed\n", __FUNCTION__));
692		return NULL;
693	}
694
695	if (bo->tiling == priv->gpu_bo->tiling) {
696		DBG(("%s: tiling request failed\n", __FUNCTION__));
697		kgem_bo_destroy(&sna->kgem, bo);
698		return NULL;
699	}
700
701	box.x1 = box.y1 = 0;
702	box.x2 = pixmap->drawable.width;
703	box.y2 = pixmap->drawable.height;
704
705	if (!sna->render.copy_boxes(sna, GXcopy,
706				    &pixmap->drawable, priv->gpu_bo, 0, 0,
707				    &pixmap->drawable, bo, 0, 0,
708				    &box, 1, 0)) {
709		DBG(("%s: copy failed\n", __FUNCTION__));
710		kgem_bo_destroy(&sna->kgem, bo);
711		return NULL;
712	}
713
714	sna_pixmap_unmap(pixmap, priv);
715	kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
716
717	return priv->gpu_bo = bo;
718}
719
720static inline void sna_set_pixmap(PixmapPtr pixmap, struct sna_pixmap *sna)
721{
722	((void **)__get_private(pixmap, sna_pixmap_key))[1] = sna;
723	assert(sna_pixmap(pixmap) == sna);
724}
725
726static struct sna_pixmap *
727_sna_pixmap_init(struct sna_pixmap *priv, PixmapPtr pixmap)
728{
729	list_init(&priv->flush_list);
730	list_init(&priv->cow_list);
731	priv->source_count = SOURCE_BIAS;
732	priv->pixmap = pixmap;
733
734	return priv;
735}
736
737static struct sna_pixmap *
738_sna_pixmap_reset(PixmapPtr pixmap)
739{
740	struct sna_pixmap *priv;
741
742	assert(pixmap->drawable.type == DRAWABLE_PIXMAP);
743	assert(pixmap->drawable.class == 0);
744	assert(pixmap->drawable.x == 0);
745	assert(pixmap->drawable.y == 0);
746
747	priv = sna_pixmap(pixmap);
748	assert(priv != NULL);
749
750	memset(priv, 0, sizeof(*priv));
751	return _sna_pixmap_init(priv, pixmap);
752}
753
754static struct sna_pixmap *sna_pixmap_attach(PixmapPtr pixmap)
755{
756	struct sna_pixmap *priv;
757
758	priv = calloc(1, sizeof(*priv));
759	if (!priv)
760		return NULL;
761
762	sna_set_pixmap(pixmap, priv);
763	return _sna_pixmap_init(priv, pixmap);
764}
765
766struct sna_pixmap *sna_pixmap_attach_to_bo(PixmapPtr pixmap, struct kgem_bo *bo)
767{
768	struct sna_pixmap *priv;
769
770	assert(bo);
771	assert(bo->proxy == NULL);
772	assert(bo->unique_id);
773
774	priv = sna_pixmap_attach(pixmap);
775	if (!priv)
776		return NULL;
777
778	DBG(("%s: attaching %s handle=%d to pixmap=%ld\n",
779	     __FUNCTION__, bo->snoop ? "CPU" : "GPU", bo->handle, pixmap->drawable.serialNumber));
780
781	assert(!priv->mapped);
782	assert(!priv->move_to_gpu);
783
784	if (bo->snoop) {
785		priv->cpu_bo = bo;
786		sna_damage_all(&priv->cpu_damage, pixmap);
787	} else {
788		priv->gpu_bo = bo;
789		sna_damage_all(&priv->gpu_damage, pixmap);
790	}
791
792	return priv;
793}
794
795static int bits_per_pixel(int depth)
796{
797	switch (depth) {
798	case 1: return 1;
799	case 4:
800	case 8: return 8;
801	case 15:
802	case 16: return 16;
803	case 24:
804	case 30:
805	case 32: return 32;
806	default: return 0;
807	}
808}
809static PixmapPtr
810create_pixmap(struct sna *sna, ScreenPtr screen,
811	      int width, int height, int depth,
812	      unsigned usage_hint)
813{
814	PixmapPtr pixmap;
815	size_t datasize;
816	size_t stride;
817	int base, bpp;
818
819	bpp = bits_per_pixel(depth);
820	if (bpp == 0)
821		return NullPixmap;
822
823	stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
824	if (stride / 4 > 32767 || height > 32767)
825		return NullPixmap;
826
827	datasize = height * stride;
828	base = screen->totalPixmapSize;
829	if (datasize && base & 15) {
830		int adjust = 16 - (base & 15);
831		base += adjust;
832		datasize += adjust;
833	}
834
835	DBG(("%s: allocating pixmap %dx%d, depth=%d/%d, size=%ld\n",
836	     __FUNCTION__, width, height, depth, bpp, (long)datasize));
837	pixmap = AllocatePixmap(screen, datasize);
838	if (!pixmap)
839		return NullPixmap;
840
841	((void **)__get_private(pixmap, sna_pixmap_key))[0] = sna;
842	assert(to_sna_from_pixmap(pixmap) == sna);
843
844	pixmap->drawable.type = DRAWABLE_PIXMAP;
845	pixmap->drawable.class = 0;
846	pixmap->drawable.pScreen = screen;
847	pixmap->drawable.depth = depth;
848	pixmap->drawable.bitsPerPixel = bpp;
849	pixmap->drawable.id = 0;
850	pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
851	pixmap->drawable.x = 0;
852	pixmap->drawable.y = 0;
853	pixmap->drawable.width = width;
854	pixmap->drawable.height = height;
855	pixmap->devKind = stride;
856	pixmap->refcnt = 1;
857	pixmap->devPrivate.ptr = datasize ? (char *)pixmap + base : NULL;
858
859#ifdef COMPOSITE
860	pixmap->screen_x = 0;
861	pixmap->screen_y = 0;
862#endif
863
864	pixmap->usage_hint = usage_hint;
865#if DEBUG_MEMORY
866	sna->debug_memory.pixmap_allocs++;
867#endif
868
869	DBG(("%s: serial=%ld, usage=%d, %dx%d\n",
870	     __FUNCTION__,
871	     pixmap->drawable.serialNumber,
872	     pixmap->usage_hint,
873	     pixmap->drawable.width,
874	     pixmap->drawable.height));
875
876	return pixmap;
877}
878
879static PixmapPtr
880__pop_freed_pixmap(struct sna *sna)
881{
882	PixmapPtr pixmap;
883
884	assert(sna->freed_pixmap);
885
886	pixmap = sna->freed_pixmap;
887	sna->freed_pixmap = pixmap->devPrivate.ptr;
888
889	DBG(("%s: reusing freed pixmap=%ld header\n",
890	     __FUNCTION__, pixmap->drawable.serialNumber));
891
892	assert(pixmap->refcnt == 0);
893	assert(pixmap->devKind = 0xdeadbeef);
894	assert(sna_pixmap(pixmap));
895	assert(sna_pixmap(pixmap)->header);
896
897#if DEBUG_MEMORY
898	sna->debug_memory.pixmap_cached--;
899#endif
900
901	return pixmap;
902}
903
904inline static PixmapPtr
905create_pixmap_hdr(struct sna *sna, ScreenPtr screen,
906		  int width, int height, int depth, int usage,
907		  struct sna_pixmap **priv)
908{
909	PixmapPtr pixmap;
910
911	if (sna->freed_pixmap == NULL) {
912		pixmap = create_pixmap(sna, screen, 0, 0, depth, usage);
913		if (pixmap == NullPixmap)
914			return NullPixmap;
915
916		*priv = sna_pixmap_attach(pixmap);
917		if (!*priv) {
918			FreePixmap(pixmap);
919			return NullPixmap;
920		}
921	} else {
922		pixmap = __pop_freed_pixmap(sna);
923		*priv = _sna_pixmap_reset(pixmap);
924
925		assert(pixmap->drawable.type == DRAWABLE_PIXMAP);
926		assert(pixmap->drawable.class == 0);
927		assert(pixmap->drawable.pScreen == screen);
928		assert(pixmap->drawable.x == 0);
929		assert(pixmap->drawable.y == 0);
930
931		pixmap->drawable.id = 0;
932
933		pixmap->drawable.depth = depth;
934		pixmap->drawable.bitsPerPixel = bits_per_pixel(depth);
935		pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
936
937		pixmap->devKind = 0;
938		pixmap->devPrivate.ptr = NULL;
939
940#ifdef COMPOSITE
941		pixmap->screen_x = 0;
942		pixmap->screen_y = 0;
943#endif
944
945#if DEBUG_MEMORY
946		sna->debug_memory.pixmap_allocs++;
947#endif
948
949		pixmap->refcnt = 1;
950	}
951
952	DBG(("%s: pixmap=%ld, width=%d, height=%d, usage=%d\n", __FUNCTION__,
953	     pixmap->drawable.serialNumber, width, height, usage));
954	pixmap->drawable.width = width;
955	pixmap->drawable.height = height;
956	pixmap->usage_hint = usage;
957
958	(*priv)->header = true;
959	return pixmap;
960}
961
962static PixmapPtr
963sna_pixmap_create_shm(ScreenPtr screen,
964		      int width, int height, int depth,
965		      char *addr)
966{
967	struct sna *sna = to_sna_from_screen(screen);
968	int bpp = bits_per_pixel(depth);
969	int pitch = PixmapBytePad(width, depth);
970	struct sna_pixmap *priv;
971	PixmapPtr pixmap;
972
973	DBG(("%s(%dx%d, depth=%d, bpp=%d, pitch=%d)\n",
974	     __FUNCTION__, width, height, depth, bpp, pitch));
975
976	if (wedged(sna) || bpp == 0 || pitch*height < 4096) {
977fallback:
978		pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth);
979		if (pixmap == NULL)
980			return NULL;
981
982		if (!screen->ModifyPixmapHeader(pixmap, width, height, depth,
983						bpp, pitch, addr)) {
984			screen->DestroyPixmap(pixmap);
985			return NULL;
986		}
987
988		return pixmap;
989	}
990
991	pixmap = create_pixmap_hdr(sna, screen, width, height, depth, 0, &priv);
992	if (pixmap == NullPixmap) {
993		DBG(("%s: allocation failed\n", __FUNCTION__));
994		goto fallback;
995	}
996
997	priv->cpu_bo = kgem_create_map(&sna->kgem, addr, pitch*height, false);
998	if (priv->cpu_bo == NULL) {
999		DBG(("%s: mapping SHM segment failed\n", __FUNCTION__));
1000		sna_pixmap_destroy(pixmap);
1001		goto fallback;
1002	}
1003	priv->cpu_bo->pitch = pitch;
1004	kgem_bo_mark_unreusable(priv->cpu_bo);
1005	sna_shm_watch_flush(sna, 1);
1006#ifdef DEBUG_MEMORY
1007	sna->debug_memory.cpu_bo_allocs++;
1008	sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo);
1009#endif
1010
1011	/* Be wary as we cannot cache SHM Pixmap in our freed cache */
1012	priv->header = false;
1013	priv->cpu = true;
1014	priv->shm = true;
1015	priv->stride = pitch;
1016	priv->ptr = MAKE_STATIC_PTR(addr);
1017	sna_damage_all(&priv->cpu_damage, pixmap);
1018
1019	pixmap->devKind = pitch;
1020	pixmap->devPrivate.ptr = addr;
1021
1022	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
1023	     __FUNCTION__,
1024	     pixmap->drawable.serialNumber,
1025	     pixmap->drawable.width,
1026	     pixmap->drawable.height,
1027	     pixmap->usage_hint));
1028	return pixmap;
1029}
1030
1031PixmapPtr
1032sna_pixmap_create_unattached(ScreenPtr screen,
1033			     int width, int height, int depth)
1034{
1035	return create_pixmap(to_sna_from_screen(screen),
1036			     screen, width, height, depth,
1037			     -1);
1038}
1039
1040static PixmapPtr
1041sna_pixmap_create_scratch(ScreenPtr screen,
1042			  int width, int height, int depth,
1043			  uint32_t tiling)
1044{
1045	struct sna *sna = to_sna_from_screen(screen);
1046	struct sna_pixmap *priv;
1047	PixmapPtr pixmap;
1048	int bpp;
1049
1050	DBG(("%s(%d, %d, %d, tiling=%d)\n", __FUNCTION__,
1051	     width, height, depth, tiling));
1052
1053	bpp = bits_per_pixel(depth);
1054	if (tiling == I915_TILING_Y &&
1055	    (sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0)
1056		tiling = I915_TILING_X;
1057
1058	if (tiling == I915_TILING_Y &&
1059	    (width > sna->render.max_3d_size ||
1060	     height > sna->render.max_3d_size))
1061		tiling = I915_TILING_X;
1062
1063	tiling = kgem_choose_tiling(&sna->kgem, tiling, width, height, bpp);
1064
1065	/* you promise never to access this via the cpu... */
1066	pixmap = create_pixmap_hdr(sna, screen, width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH, &priv);
1067	if (pixmap == NullPixmap)
1068		return NullPixmap;
1069
1070	priv->stride = PixmapBytePad(width, depth);
1071
1072	priv->gpu_bo = kgem_create_2d(&sna->kgem,
1073				      width, height, bpp, tiling,
1074				      CREATE_TEMPORARY);
1075	if (priv->gpu_bo == NULL) {
1076		free(priv);
1077		FreePixmap(pixmap);
1078		return NullPixmap;
1079	}
1080
1081	sna_damage_all(&priv->gpu_damage, pixmap);
1082
1083	assert(to_sna_from_pixmap(pixmap) == sna);
1084	assert(pixmap->drawable.pScreen == screen);
1085	assert(pixmap->refcnt == 1);
1086
1087	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
1088	     __FUNCTION__,
1089	     pixmap->drawable.serialNumber,
1090	     pixmap->drawable.width,
1091	     pixmap->drawable.height,
1092	     pixmap->usage_hint));
1093	return pixmap;
1094}
1095
1096static unsigned small_copy(const RegionRec *region)
1097{
1098	if ((region->extents.x2 - region->extents.x1)*(region->extents.y2 - region->extents.y1) < 1024) {
1099		DBG(("%s: region:%dx%d\n", __FUNCTION__,
1100		     (region->extents.x2 - region->extents.x1),
1101		     (region->extents.y2 - region->extents.y1)));
1102		return COPY_SMALL;
1103	}
1104
1105	return 0;
1106}
1107
1108#ifdef CREATE_PIXMAP_USAGE_SHARED
1109static Bool
1110sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle)
1111{
1112	struct sna *sna = to_sna_from_pixmap(pixmap);
1113	struct sna_pixmap *priv;
1114	int fd;
1115
1116	DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
1117
1118	priv = sna_pixmap_move_to_gpu(pixmap,
1119				      MOVE_READ | MOVE_WRITE | __MOVE_DRI | __MOVE_PRIME | __MOVE_FORCE);
1120	if (priv == NULL)
1121		return FALSE;
1122
1123	assert(!priv->shm);
1124	assert(priv->gpu_bo);
1125	assert(priv->stride);
1126
1127	/* XXX negotiate format and stride restrictions */
1128	if (priv->gpu_bo->tiling != I915_TILING_NONE ||
1129	    priv->gpu_bo->pitch & 255) {
1130		struct kgem_bo *bo;
1131		BoxRec box;
1132
1133		DBG(("%s: removing tiling %d, and aligning pitch %d for %dx%d pixmap=%ld\n",
1134		     __FUNCTION__, priv->gpu_bo->tiling, priv->gpu_bo->pitch,
1135		     pixmap->drawable.width, pixmap->drawable.height,
1136		     pixmap->drawable.serialNumber));
1137
1138		if (priv->pinned) {
1139			DBG(("%s: can't convert pinned %x bo\n", __FUNCTION__,
1140			     priv->pinned));
1141			return FALSE;
1142		}
1143
1144		assert_pixmap_damage(pixmap);
1145
1146		bo = kgem_create_2d(&sna->kgem,
1147				    pixmap->drawable.width,
1148				    pixmap->drawable.height,
1149				    pixmap->drawable.bitsPerPixel,
1150				    I915_TILING_NONE,
1151				    CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT);
1152		if (bo == NULL) {
1153			DBG(("%s: allocation failed\n", __FUNCTION__));
1154			return FALSE;
1155		}
1156
1157		box.x1 = box.y1 = 0;
1158		box.x2 = pixmap->drawable.width;
1159		box.y2 = pixmap->drawable.height;
1160
1161		assert(!wedged(sna)); /* XXX */
1162		if (!sna->render.copy_boxes(sna, GXcopy,
1163					    &pixmap->drawable, priv->gpu_bo, 0, 0,
1164					    &pixmap->drawable, bo, 0, 0,
1165					    &box, 1, 0)) {
1166			DBG(("%s: copy failed\n", __FUNCTION__));
1167			kgem_bo_destroy(&sna->kgem, bo);
1168			return FALSE;
1169		}
1170
1171		sna_pixmap_unmap(pixmap, priv);
1172		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1173		priv->gpu_bo = bo;
1174	}
1175	assert(priv->gpu_bo->tiling == I915_TILING_NONE);
1176	assert((priv->gpu_bo->pitch & 255) == 0);
1177
1178	/* And export the bo->pitch via pixmap->devKind */
1179	if (!priv->mapped) {
1180		void *ptr;
1181
1182		ptr = kgem_bo_map__async(&sna->kgem, priv->gpu_bo);
1183		if (ptr == NULL)
1184			return FALSE;
1185
1186		pixmap->devPrivate.ptr = ptr;
1187		pixmap->devKind = priv->gpu_bo->pitch;
1188		priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
1189	}
1190	assert_pixmap_map(pixmap, priv);
1191
1192	fd = kgem_bo_export_to_prime(&sna->kgem, priv->gpu_bo);
1193	if (fd == -1)
1194		return FALSE;
1195
1196	priv->pinned |= PIN_PRIME;
1197
1198	*fd_handle = (void *)(intptr_t)fd;
1199	return TRUE;
1200}
1201
1202static Bool
1203sna_set_shared_pixmap_backing(PixmapPtr pixmap, void *fd_handle)
1204{
1205	struct sna *sna = to_sna_from_pixmap(pixmap);
1206	struct sna_pixmap *priv;
1207	struct kgem_bo *bo;
1208
1209	DBG(("%s: pixmap=%ld, size=%dx%d, depth=%d/%d, stride=%d\n",
1210	     __FUNCTION__, pixmap->drawable.serialNumber,
1211	     pixmap->drawable.width, pixmap->drawable.height,
1212	     pixmap->drawable.depth, pixmap->drawable.bitsPerPixel,
1213	     pixmap->devKind));
1214
1215	priv = sna_pixmap(pixmap);
1216	if (priv == NULL)
1217		return FALSE;
1218
1219	if (priv->pinned & ~PIN_PRIME)
1220		return FALSE;
1221
1222	assert(!priv->flush);
1223
1224	if (priv->gpu_bo) {
1225		priv->clear = false;
1226		sna_damage_destroy(&priv->gpu_damage);
1227		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1228		priv->gpu_bo = NULL;
1229		priv->pinned = 0;
1230	}
1231
1232	assert(!priv->pinned);
1233
1234	assert(priv->cpu_bo == NULL);
1235	assert(priv->cpu_damage == NULL);
1236
1237	assert(priv->gpu_bo == NULL);
1238	assert(priv->gpu_damage == NULL);
1239
1240	bo = kgem_create_for_prime(&sna->kgem,
1241				   (intptr_t)fd_handle,
1242				   pixmap->devKind * pixmap->drawable.height);
1243	if (bo == NULL)
1244		return FALSE;
1245
1246	sna_damage_all(&priv->gpu_damage, pixmap);
1247
1248	bo->pitch = pixmap->devKind;
1249	priv->stride = pixmap->devKind;
1250
1251	assert(!priv->mapped);
1252	priv->gpu_bo = bo;
1253	priv->pinned |= PIN_PRIME;
1254
1255	close((intptr_t)fd_handle);
1256	return TRUE;
1257}
1258
1259static PixmapPtr
1260sna_create_pixmap_shared(struct sna *sna, ScreenPtr screen,
1261			 int width, int height, int depth)
1262{
1263	PixmapPtr pixmap;
1264	struct sna_pixmap *priv;
1265
1266	DBG(("%s: width=%d, height=%d, depth=%d\n",
1267	     __FUNCTION__, width, height, depth));
1268
1269	/* Create a stub to be attached later */
1270	pixmap = create_pixmap_hdr(sna, screen,
1271				   width, height, depth, 0,
1272				   &priv);
1273	if (pixmap == NullPixmap)
1274		return NullPixmap;
1275
1276	assert(!priv->mapped);
1277	priv->stride = 0;
1278	priv->create = 0;
1279
1280	if (width|height) {
1281		priv->gpu_bo = kgem_create_2d(&sna->kgem,
1282					      width, height,
1283					      pixmap->drawable.bitsPerPixel,
1284					      I915_TILING_NONE,
1285					      CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT);
1286		if (priv->gpu_bo == NULL) {
1287			free(priv);
1288			FreePixmap(pixmap);
1289			return NullPixmap;
1290		}
1291
1292		/* minimal interface for sharing is linear, 256 byte pitch */
1293		assert(priv->gpu_bo->tiling == I915_TILING_NONE);
1294		assert((priv->gpu_bo->pitch & 255) == 0);
1295
1296		pixmap->devPrivate.ptr =
1297			kgem_bo_map__async(&sna->kgem, priv->gpu_bo);
1298		if (pixmap->devPrivate.ptr == NULL) {
1299			kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1300			free(priv);
1301			FreePixmap(pixmap);
1302			return FALSE;
1303		}
1304
1305		pixmap->devKind = priv->gpu_bo->pitch;
1306
1307		priv->stride = priv->gpu_bo->pitch;
1308		priv->mapped = pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
1309		assert_pixmap_map(pixmap, priv);
1310
1311		sna_damage_all(&priv->gpu_damage, pixmap);
1312	}
1313
1314	return pixmap;
1315}
1316#endif
1317
1318static PixmapPtr sna_create_pixmap(ScreenPtr screen,
1319				   int width, int height, int depth,
1320				   unsigned int usage)
1321{
1322	struct sna *sna = to_sna_from_screen(screen);
1323	PixmapPtr pixmap;
1324	struct sna_pixmap *priv;
1325	unsigned flags;
1326	int pad;
1327	void *ptr;
1328
1329	DBG(("%s(%d, %d, %d, usage=%x)\n", __FUNCTION__,
1330	     width, height, depth, usage));
1331
1332#ifdef CREATE_PIXMAP_USAGE_SHARED
1333	if (usage == CREATE_PIXMAP_USAGE_SHARED)
1334		return sna_create_pixmap_shared(sna, screen,
1335						width, height, depth);
1336#endif
1337
1338	if ((width|height) == 0) {
1339		usage = -1;
1340		goto fallback;
1341	}
1342	assert(width && height);
1343
1344	flags = kgem_can_create_2d(&sna->kgem, width, height, depth);
1345	if (flags == 0) {
1346		DBG(("%s: can not use GPU, just creating shadow\n",
1347		     __FUNCTION__));
1348		goto fallback;
1349	}
1350
1351	if (unlikely((sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0))
1352		flags &= ~KGEM_CAN_CREATE_GPU;
1353	if (wedged(sna) && usage != SNA_CREATE_FB)
1354		flags &= ~KGEM_CAN_CREATE_GTT;
1355
1356	DBG(("%s: usage=%d, flags=%x\n", __FUNCTION__, usage, flags));
1357	switch (usage) {
1358	case CREATE_PIXMAP_USAGE_SCRATCH:
1359		if (flags & KGEM_CAN_CREATE_GPU)
1360			return sna_pixmap_create_scratch(screen,
1361							 width, height, depth,
1362							 I915_TILING_X);
1363		else
1364			goto fallback;
1365
1366	case SNA_CREATE_SCRATCH:
1367		if (flags & (KGEM_CAN_CREATE_CPU | KGEM_CAN_CREATE_GPU))
1368			return sna_pixmap_create_scratch(screen,
1369							 width, height, depth,
1370							 I915_TILING_Y);
1371		else
1372			return NullPixmap;
1373	}
1374
1375	if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE)
1376		flags &= ~KGEM_CAN_CREATE_GPU;
1377	if (usage == CREATE_PIXMAP_USAGE_BACKING_PIXMAP)
1378		usage = 0;
1379
1380	pad = PixmapBytePad(width, depth);
1381	if (pad * height < 4096) {
1382		DBG(("%s: small buffer [%d], attaching to shadow pixmap\n",
1383		     __FUNCTION__, pad * height));
1384		pixmap = create_pixmap(sna, screen,
1385				       width, height, depth, usage);
1386		if (pixmap == NullPixmap)
1387			return NullPixmap;
1388
1389		ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr);
1390		pad = pixmap->devKind;
1391		flags &= ~(KGEM_CAN_CREATE_GPU | KGEM_CAN_CREATE_CPU);
1392
1393		priv = sna_pixmap_attach(pixmap);
1394		if (priv == NULL) {
1395			free(pixmap);
1396			goto fallback;
1397		}
1398	} else {
1399		DBG(("%s: creating GPU pixmap %dx%d, stride=%d, flags=%x\n",
1400		     __FUNCTION__, width, height, pad, flags));
1401
1402		pixmap = create_pixmap_hdr(sna, screen, width, height, depth, usage, &priv);
1403		if (pixmap == NullPixmap)
1404			return NullPixmap;
1405
1406		ptr = NULL;
1407	}
1408
1409	priv->stride = pad;
1410	priv->create = flags;
1411	priv->ptr = ptr;
1412
1413	assert(to_sna_from_pixmap(pixmap) == sna);
1414	assert(pixmap->drawable.pScreen == screen);
1415	assert(pixmap->refcnt == 1);
1416
1417	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
1418	     __FUNCTION__,
1419	     pixmap->drawable.serialNumber,
1420	     pixmap->drawable.width,
1421	     pixmap->drawable.height,
1422	     pixmap->usage_hint));
1423	return pixmap;
1424
1425fallback:
1426	return create_pixmap(sna, screen, width, height, depth, usage);
1427}
1428
1429void sna_add_flush_pixmap(struct sna *sna,
1430			  struct sna_pixmap *priv,
1431			  struct kgem_bo *bo)
1432{
1433	DBG(("%s: marking pixmap=%ld for flushing\n",
1434	     __FUNCTION__, priv->pixmap->drawable.serialNumber));
1435	assert(bo);
1436	assert(bo->flush);
1437	assert(priv->gpu_damage == NULL || priv->gpu_bo);
1438	list_move(&priv->flush_list, &sna->flush_pixmaps);
1439
1440	if (bo->exec == NULL && sna->kgem.nbatch && kgem_is_idle(&sna->kgem)) {
1441		DBG(("%s: new flush bo, flushing before\n", __FUNCTION__));
1442		_kgem_submit(&sna->kgem);
1443	}
1444}
1445
1446static void __sna_free_pixmap(struct sna *sna,
1447			      PixmapPtr pixmap,
1448			      struct sna_pixmap *priv)
1449{
1450	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber));
1451	list_del(&priv->flush_list);
1452
1453	assert(priv->gpu_damage == NULL);
1454	assert(priv->cpu_damage == NULL);
1455
1456	__sna_pixmap_free_cpu(sna, priv);
1457
1458	if (priv->flush)
1459		sna_watch_flush(sna, -1);
1460
1461#if !NDEBUG
1462	pixmap->devKind = 0xdeadbeef;
1463#endif
1464	if (priv->header) {
1465		assert(pixmap->drawable.pScreen == to_screen_from_sna(sna));
1466		assert(!priv->shm);
1467		pixmap->devPrivate.ptr = sna->freed_pixmap;
1468		sna->freed_pixmap = pixmap;
1469#if DEBUG_MEMORY
1470		sna->debug_memory.pixmap_cached++;
1471#endif
1472	} else {
1473		free(priv);
1474		FreePixmap(pixmap);
1475	}
1476}
1477
1478static Bool sna_destroy_pixmap(PixmapPtr pixmap)
1479{
1480	struct sna *sna;
1481	struct sna_pixmap *priv;
1482
1483	assert(pixmap->refcnt > 0);
1484	if (--pixmap->refcnt)
1485		return TRUE;
1486
1487#if DEBUG_MEMORY
1488	to_sna_from_pixmap(pixmap)->debug_memory.pixmap_allocs--;
1489#endif
1490
1491	priv = sna_pixmap(pixmap);
1492	DBG(("%s: pixmap=%ld, attached?=%d\n",
1493	     __FUNCTION__, pixmap->drawable.serialNumber, priv != NULL));
1494	if (priv == NULL) {
1495		FreePixmap(pixmap);
1496		return TRUE;
1497	}
1498
1499	assert_pixmap_damage(pixmap);
1500	sna = to_sna_from_pixmap(pixmap);
1501
1502	sna_damage_destroy(&priv->gpu_damage);
1503	sna_damage_destroy(&priv->cpu_damage);
1504
1505	list_del(&priv->cow_list);
1506	if (priv->cow) {
1507		struct sna_cow *cow = COW(priv->cow);
1508		DBG(("%s: pixmap=%ld discarding cow, refcnt=%d\n",
1509		     __FUNCTION__, pixmap->drawable.serialNumber, cow->refcnt));
1510		assert(cow->refcnt);
1511		if (!--cow->refcnt)
1512			free(cow);
1513		priv->cow = NULL;
1514	} else
1515		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
1516
1517	if (priv->move_to_gpu)
1518		(void)priv->move_to_gpu(sna, priv, 0);
1519
1520	/* Always release the gpu bo back to the lower levels of caching */
1521	if (priv->gpu_bo) {
1522		sna_pixmap_unmap(pixmap, priv);
1523		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1524		priv->gpu_bo = NULL;
1525	}
1526
1527	if (priv->shm && kgem_bo_is_busy(priv->cpu_bo)) {
1528		DBG(("%s: deferring release of active SHM pixmap=%ld\n",
1529		     __FUNCTION__, pixmap->drawable.serialNumber));
1530		add_shm_flush(sna, priv);
1531		kgem_bo_submit(&sna->kgem, priv->cpu_bo); /* XXX ShmDetach */
1532	} else
1533		__sna_free_pixmap(sna, pixmap, priv);
1534	return TRUE;
1535}
1536
1537void sna_pixmap_destroy(PixmapPtr pixmap)
1538{
1539	assert(pixmap->refcnt == 1);
1540	assert(sna_pixmap(pixmap) == NULL || sna_pixmap(pixmap)->header == true);
1541
1542	sna_destroy_pixmap(pixmap);
1543}
1544
1545static inline bool has_coherent_map(struct sna *sna,
1546				    struct kgem_bo *bo,
1547				    unsigned flags)
1548{
1549	assert(bo);
1550
1551	if (kgem_bo_mapped(&sna->kgem, bo))
1552		return true;
1553
1554	if (bo->tiling == I915_TILING_Y)
1555		return false;
1556
1557	return kgem_bo_can_map__cpu(&sna->kgem, bo, flags & MOVE_WRITE);
1558}
1559
1560static inline bool has_coherent_ptr(struct sna *sna, struct sna_pixmap *priv, unsigned flags)
1561{
1562	if (priv == NULL)
1563		return true;
1564
1565	if (flags & MOVE_ASYNC_HINT) {
1566		/* Not referencing the pointer itself, so do not care */
1567		return true;
1568	}
1569
1570	if (!priv->mapped) {
1571		if (!priv->cpu_bo)
1572			return true;
1573
1574		assert(!priv->cpu_bo->needs_flush || (flags & MOVE_WRITE) == 0);
1575		assert(priv->pixmap->devKind == priv->cpu_bo->pitch);
1576		return priv->pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu);
1577	}
1578
1579	assert(!priv->move_to_gpu || (flags & MOVE_WRITE) == 0);
1580
1581	assert_pixmap_map(priv->pixmap, priv);
1582	assert(priv->pixmap->devKind == priv->gpu_bo->pitch);
1583
1584	if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu)) {
1585		assert(priv->mapped == MAPPED_CPU);
1586
1587		if (priv->gpu_bo->tiling != I915_TILING_NONE)
1588			return false;
1589
1590		return flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE);
1591	}
1592
1593	if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__gtt)) {
1594		assert(priv->mapped == MAPPED_GTT);
1595
1596		if (priv->gpu_bo->tiling == I915_TILING_Y && sna->kgem.gen == 0x21)
1597			return false;
1598
1599		return true;
1600	}
1601
1602	if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__wc)) {
1603		assert(priv->mapped == MAPPED_GTT);
1604		return true;
1605	}
1606
1607	return false;
1608}
1609
1610static inline bool pixmap_inplace(struct sna *sna,
1611				  PixmapPtr pixmap,
1612				  struct sna_pixmap *priv,
1613				  unsigned flags)
1614{
1615	if (FORCE_INPLACE)
1616		return FORCE_INPLACE > 0;
1617
1618	if (wedged(sna) && !priv->pinned) {
1619		DBG(("%s: no, wedged and unpinned; pull pixmap back to CPU\n", __FUNCTION__));
1620		return false;
1621	}
1622
1623	if (priv->move_to_gpu && flags & MOVE_WRITE)
1624		return false;
1625
1626	if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) {
1627		if (priv->clear) {
1628			DBG(("%s: no, clear GPU bo is busy\n", __FUNCTION__));
1629			return false;
1630		}
1631
1632		if (flags & MOVE_ASYNC_HINT) {
1633			DBG(("%s: no, async hint and GPU bo is busy\n", __FUNCTION__));
1634			return false;
1635		}
1636
1637		if ((flags & (MOVE_WRITE | MOVE_READ)) == (MOVE_WRITE | MOVE_READ)) {
1638			DBG(("%s: no, GPU bo is busy\n", __FUNCTION__));
1639			return false;
1640		}
1641
1642		if ((flags & MOVE_READ) == 0) {
1643			DBG(("%s: %s, GPU bo is busy, but not reading\n", __FUNCTION__, priv->pinned ? "no" : "yes"));
1644			return !priv->pinned;
1645		}
1646	}
1647
1648	if (priv->mapped) {
1649		DBG(("%s: %s, already mapped\n", __FUNCTION__, has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no"));
1650		return has_coherent_map(sna, priv->gpu_bo, flags);
1651	}
1652
1653	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) {
1654		DBG(("%s: yes, has CPU bo and is active on CPU\n", __FUNCTION__));
1655		return true;
1656	}
1657
1658	if (priv->cpu_bo && priv->cpu) {
1659		DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__));
1660		return false;
1661	}
1662
1663	if (flags & MOVE_READ &&
1664	    (priv->cpu || priv->cpu_damage || priv->gpu_damage == NULL)) {
1665		DBG(("%s:, no, reading and has CPU damage\n", __FUNCTION__));
1666		return false;
1667	}
1668
1669	return (priv->stride * pixmap->drawable.height >> 12) >
1670		sna->kgem.half_cpu_cache_pages;
1671}
1672
1673static bool sna_pixmap_alloc_gpu(struct sna *sna,
1674				 PixmapPtr pixmap,
1675				 struct sna_pixmap *priv,
1676				 unsigned flags)
1677{
1678	uint32_t tiling;
1679
1680	/* Use tiling by default, but disable per user request */
1681	if (pixmap->usage_hint == SNA_CREATE_FB && (sna->flags & SNA_LINEAR_FB) == 0) {
1682		flags |= CREATE_SCANOUT;
1683		tiling = kgem_choose_tiling(&sna->kgem,
1684					    -DEFAULT_SCANOUT_TILING,
1685					    pixmap->drawable.width,
1686					    pixmap->drawable.height,
1687					    pixmap->drawable.bitsPerPixel);
1688	} else
1689		tiling = sna_pixmap_default_tiling(sna, pixmap);
1690
1691	DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
1692
1693	priv->gpu_bo = kgem_create_2d(&sna->kgem,
1694				      pixmap->drawable.width,
1695				      pixmap->drawable.height,
1696				      pixmap->drawable.bitsPerPixel,
1697				      tiling, flags);
1698	return priv->gpu_bo != NULL;
1699}
1700
1701static bool
1702sna_pixmap_create_mappable_gpu(PixmapPtr pixmap,
1703			       bool can_replace)
1704{
1705	struct sna *sna = to_sna_from_pixmap(pixmap);
1706	struct sna_pixmap *priv = sna_pixmap(pixmap);
1707
1708	if (wedged(sna))
1709		goto out;
1710
1711	if ((priv->create & KGEM_CAN_CREATE_GTT) == 0)
1712		goto out;
1713
1714	assert_pixmap_damage(pixmap);
1715
1716	if (can_replace && priv->gpu_bo &&
1717	    (!kgem_bo_can_map(&sna->kgem, priv->gpu_bo) ||
1718	     __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) {
1719		if (priv->pinned)
1720			return false;
1721
1722		DBG(("%s: discard busy GPU bo\n", __FUNCTION__));
1723		sna_pixmap_free_gpu(sna, priv);
1724	}
1725
1726	if (priv->gpu_bo == NULL) {
1727		assert_pixmap_damage(pixmap);
1728		assert(priv->gpu_damage == NULL);
1729		sna_pixmap_alloc_gpu(sna, pixmap, priv, CREATE_GTT_MAP | CREATE_INACTIVE);
1730	}
1731
1732out:
1733	if (priv->gpu_bo == NULL)
1734		return false;
1735
1736	return (kgem_bo_can_map(&sna->kgem, priv->gpu_bo) &&
1737		!kgem_bo_is_busy(priv->gpu_bo));
1738}
1739
1740static inline bool gpu_bo_download(struct sna *sna,
1741				   struct sna_pixmap *priv,
1742				   int n, const BoxRec *box,
1743				   bool idle)
1744{
1745	char *src;
1746
1747	if (!USE_INPLACE)
1748		return false;
1749
1750	switch (priv->gpu_bo->tiling) {
1751	case I915_TILING_Y:
1752		return false;
1753	case I915_TILING_X:
1754		if (!sna->kgem.memcpy_from_tiled_x)
1755			return false;
1756	default:
1757		break;
1758	}
1759
1760	if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC))
1761		return false;
1762
1763	if (idle) {
1764		if (__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
1765			return false;
1766
1767		if (priv->cpu_bo && __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo))
1768			return false;
1769	}
1770
1771	src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
1772	if (src == NULL)
1773		return false;
1774
1775	kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC);
1776
1777	if (priv->cpu_bo)
1778		kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
1779	assert(has_coherent_ptr(sna, priv, MOVE_WRITE));
1780
1781	if (sigtrap_get())
1782		return false;
1783
1784	if (priv->gpu_bo->tiling) {
1785		int bpp = priv->pixmap->drawable.bitsPerPixel;
1786		void *dst = priv->pixmap->devPrivate.ptr;
1787		int dst_pitch = priv->pixmap->devKind;
1788
1789		DBG(("%s: download through a tiled CPU map\n", __FUNCTION__));
1790		do {
1791			DBG(("%s: box (%d, %d), (%d, %d)\n",
1792			     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
1793			memcpy_from_tiled_x(&sna->kgem, src, dst, bpp,
1794					    priv->gpu_bo->pitch, dst_pitch,
1795					    box->x1, box->y1,
1796					    box->x1, box->y1,
1797					    box->x2 - box->x1, box->y2 - box->y1);
1798			box++;
1799		} while (--n);
1800	} else {
1801		int bpp = priv->pixmap->drawable.bitsPerPixel;
1802		void *dst = priv->pixmap->devPrivate.ptr;
1803		int dst_pitch = priv->pixmap->devKind;
1804
1805		DBG(("%s: download through a linear CPU map\n", __FUNCTION__));
1806		do {
1807			DBG(("%s: box (%d, %d), (%d, %d)\n",
1808			     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
1809			memcpy_blt(src, dst, bpp,
1810				   priv->gpu_bo->pitch, dst_pitch,
1811				   box->x1, box->y1,
1812				   box->x1, box->y1,
1813				   box->x2 - box->x1, box->y2 - box->y1);
1814			box++;
1815		} while (--n);
1816	}
1817
1818	sigtrap_put();
1819	return true;
1820}
1821
1822static inline bool cpu_bo_download(struct sna *sna,
1823				   struct sna_pixmap *priv,
1824				   int n, const BoxRec *box)
1825{
1826	if (DBG_NO_CPU_DOWNLOAD)
1827		return false;
1828
1829	if (wedged(sna))
1830		return false;
1831
1832	if (priv->cpu_bo == NULL || !sna->kgem.can_blt_cpu)
1833		return false;
1834
1835	if (!kgem_bo_is_busy(priv->gpu_bo) && !kgem_bo_is_busy(priv->cpu_bo)) {
1836		/* Is it worth detiling? */
1837		assert(box[0].y1 < box[n-1].y2);
1838		if (kgem_bo_can_map(&sna->kgem, priv->gpu_bo) &&
1839		    (box[n-1].y2 - box[0].y1 - 1) * priv->gpu_bo->pitch < 4096) {
1840			DBG(("%s: no, tiny transfer (height=%d, pitch=%d) expect to read inplace\n",
1841			     __FUNCTION__, box[n-1].y2-box[0].y1, priv->gpu_bo->pitch));
1842			return false;
1843		}
1844	}
1845
1846	DBG(("%s: using GPU write to CPU bo for download from GPU\n", __FUNCTION__));
1847	return sna->render.copy_boxes(sna, GXcopy,
1848				      &priv->pixmap->drawable, priv->gpu_bo, 0, 0,
1849				      &priv->pixmap->drawable, priv->cpu_bo, 0, 0,
1850				      box, n, COPY_LAST);
1851}
1852
1853static void download_boxes(struct sna *sna,
1854			   struct sna_pixmap *priv,
1855			   int n, const BoxRec *box)
1856{
1857	bool ok;
1858
1859	DBG(("%s: nbox=%d\n", __FUNCTION__, n));
1860
1861	ok = gpu_bo_download(sna, priv, n, box, true);
1862	if (!ok)
1863		ok = cpu_bo_download(sna, priv, n, box);
1864	if (!ok)
1865		ok = gpu_bo_download(sna, priv, n, box, false);
1866	if (!ok) {
1867		if (priv->cpu_bo)
1868			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
1869		assert(priv->mapped == MAPPED_NONE);
1870		assert(has_coherent_ptr(sna, priv, MOVE_WRITE));
1871		sna_read_boxes(sna, priv->pixmap, priv->gpu_bo, box, n);
1872	}
1873}
1874
1875static inline bool use_cpu_bo_for_upload(struct sna *sna,
1876					 struct sna_pixmap *priv,
1877					 unsigned flags)
1878{
1879	if (DBG_NO_CPU_UPLOAD)
1880		return false;
1881
1882	if (wedged(sna))
1883		return false;
1884
1885	if (priv->cpu_bo == NULL)
1886		return false;
1887
1888	DBG(("%s? flags=%x, gpu busy?=%d, cpu busy?=%d\n", __FUNCTION__,
1889	     flags,
1890	     kgem_bo_is_busy(priv->gpu_bo),
1891	     kgem_bo_is_busy(priv->cpu_bo)));
1892
1893	if (!priv->cpu)
1894		return true;
1895
1896	if (flags & (MOVE_WRITE | MOVE_ASYNC_HINT))
1897		return true;
1898
1899	if (priv->gpu_bo->tiling)
1900		return true;
1901
1902	return kgem_bo_is_busy(priv->gpu_bo) || kgem_bo_is_busy(priv->cpu_bo);
1903}
1904
1905bool
1906sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags)
1907{
1908	struct sna_cow *cow = COW(priv->cow);
1909
1910	DBG(("%s: pixmap=%ld, handle=%d [refcnt=%d], cow refcnt=%d, flags=%x\n",
1911	     __FUNCTION__,
1912	     priv->pixmap->drawable.serialNumber,
1913	     priv->gpu_bo->handle,
1914	     priv->gpu_bo->refcnt,
1915	     cow->refcnt,
1916	     flags));
1917
1918	assert(priv->gpu_bo == cow->bo);
1919	assert(cow->refcnt);
1920
1921	if (flags && /* flags == 0 => force decouple */
1922	    (flags & MOVE_WRITE) == 0 &&
1923	    (((flags & __MOVE_FORCE) == 0) || IS_COW_OWNER(priv->cow)))
1924		return true;
1925
1926	if (!IS_COW_OWNER(priv->cow))
1927		list_del(&priv->cow_list);
1928
1929	if (!--cow->refcnt) {
1930		DBG(("%s: freeing cow\n", __FUNCTION__));
1931		assert(list_is_empty(&cow->list));
1932		free(cow);
1933	} else if (IS_COW_OWNER(priv->cow) && priv->pinned) {
1934		PixmapPtr pixmap = priv->pixmap;
1935		struct kgem_bo *bo;
1936		BoxRec box;
1937
1938		DBG(("%s: copying the Holy cow\n", __FUNCTION__));
1939
1940		box.x1 = box.y1 = 0;
1941		box.x2 = pixmap->drawable.width;
1942		box.y2 = pixmap->drawable.height;
1943
1944		bo = kgem_create_2d(&sna->kgem,
1945				    box.x2, box.y2,
1946				    pixmap->drawable.bitsPerPixel,
1947				    sna_pixmap_default_tiling(sna, pixmap),
1948				    0);
1949		if (bo == NULL) {
1950			cow->refcnt++;
1951			DBG(("%s: allocation failed\n", __FUNCTION__));
1952			return false;
1953		}
1954
1955		if (!sna->render.copy_boxes(sna, GXcopy,
1956					    &pixmap->drawable, priv->gpu_bo, 0, 0,
1957					    &pixmap->drawable, bo, 0, 0,
1958					    &box, 1, 0)) {
1959			DBG(("%s: copy failed\n", __FUNCTION__));
1960			kgem_bo_destroy(&sna->kgem, bo);
1961			cow->refcnt++;
1962			return false;
1963		}
1964
1965		assert(!list_is_empty(&cow->list));
1966		while (!list_is_empty(&cow->list)) {
1967			struct sna_pixmap *clone;
1968
1969			clone = list_first_entry(&cow->list,
1970						 struct sna_pixmap, cow_list);
1971			list_del(&clone->cow_list);
1972
1973			assert(clone->gpu_bo == cow->bo);
1974			sna_pixmap_unmap(clone->pixmap, clone);
1975			kgem_bo_destroy(&sna->kgem, clone->gpu_bo);
1976			clone->gpu_bo = kgem_bo_reference(bo);
1977		}
1978		cow->bo = bo;
1979		kgem_bo_destroy(&sna->kgem, bo);
1980	} else {
1981		struct kgem_bo *bo = NULL;
1982
1983		if (flags & MOVE_READ) {
1984			PixmapPtr pixmap = priv->pixmap;
1985			unsigned create, tiling;
1986			BoxRec box;
1987
1988			DBG(("%s: copying cow\n", __FUNCTION__));
1989
1990			box.x1 = box.y1 = 0;
1991			box.x2 = pixmap->drawable.width;
1992			box.y2 = pixmap->drawable.height;
1993
1994			if (flags & __MOVE_PRIME) {
1995				create = CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT;
1996				tiling = I915_TILING_NONE;
1997			} else {
1998				create = 0;
1999				tiling = sna_pixmap_default_tiling(sna, pixmap);
2000			}
2001
2002			bo = kgem_create_2d(&sna->kgem,
2003					    box.x2, box.y2,
2004					    pixmap->drawable.bitsPerPixel,
2005					    tiling, create);
2006			if (bo == NULL) {
2007				cow->refcnt++;
2008				DBG(("%s: allocation failed\n", __FUNCTION__));
2009				return false;
2010			}
2011
2012			if (!sna->render.copy_boxes(sna, GXcopy,
2013						    &pixmap->drawable, priv->gpu_bo, 0, 0,
2014						    &pixmap->drawable, bo, 0, 0,
2015						    &box, 1, 0)) {
2016				DBG(("%s: copy failed\n", __FUNCTION__));
2017				kgem_bo_destroy(&sna->kgem, bo);
2018				cow->refcnt++;
2019				return false;
2020			}
2021		}
2022
2023		assert(priv->gpu_bo);
2024		sna_pixmap_unmap(priv->pixmap, priv);
2025		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
2026		priv->gpu_bo = bo;
2027	}
2028
2029	priv->cow = NULL;
2030	return true;
2031}
2032
2033static bool
2034sna_pixmap_make_cow(struct sna *sna,
2035		    struct sna_pixmap *src_priv,
2036		    struct sna_pixmap *dst_priv)
2037{
2038	struct sna_cow *cow;
2039
2040	assert(src_priv->gpu_bo);
2041
2042	if (!USE_COW)
2043		return false;
2044
2045	if (src_priv->gpu_bo->proxy)
2046		return false;
2047
2048	DBG(("%s: make cow src=%ld, dst=%ld, handle=%d (already cow? src=%d, dst=%d)\n",
2049	     __FUNCTION__,
2050	     src_priv->pixmap->drawable.serialNumber,
2051	     dst_priv->pixmap->drawable.serialNumber,
2052	     src_priv->gpu_bo->handle,
2053	     src_priv->cow ? IS_COW_OWNER(src_priv->cow) ? 1 : -1 : 0,
2054	     dst_priv->cow ? IS_COW_OWNER(dst_priv->cow) ? 1 : -1 : 0));
2055
2056	if (dst_priv->pinned) {
2057		DBG(("%s: can't cow, dst_pinned=%x\n",
2058		     __FUNCTION__, dst_priv->pinned));
2059		return false;
2060	}
2061
2062	assert(dst_priv->move_to_gpu == NULL);
2063	assert(!dst_priv->flush);
2064	assert(list_is_empty(&dst_priv->cow_list));
2065
2066	cow = COW(src_priv->cow);
2067	if (cow == NULL) {
2068		cow = malloc(sizeof(*cow));
2069		if (cow == NULL)
2070			return false;
2071
2072		list_init(&cow->list);
2073
2074		cow->bo = src_priv->gpu_bo;
2075		cow->refcnt = 1;
2076
2077		DBG(("%s: moo! attaching source cow to pixmap=%ld, handle=%d\n",
2078		     __FUNCTION__,
2079		     src_priv->pixmap->drawable.serialNumber,
2080		     cow->bo->handle));
2081
2082		src_priv->cow = MAKE_COW_OWNER(cow);
2083		if (src_priv->flush & FLUSH_WRITE) {
2084			assert(!src_priv->shm);
2085			sna_add_flush_pixmap(sna, src_priv, src_priv->gpu_bo);
2086		}
2087	}
2088
2089	if (cow == COW(dst_priv->cow)) {
2090		assert(dst_priv->gpu_bo == cow->bo);
2091		return true;
2092	}
2093
2094	if (dst_priv->cow)
2095		sna_pixmap_undo_cow(sna, dst_priv, 0);
2096
2097	if (dst_priv->gpu_bo) {
2098		sna_pixmap_unmap(dst_priv->pixmap, dst_priv);
2099		kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo);
2100	}
2101	assert(!dst_priv->mapped);
2102	dst_priv->gpu_bo = kgem_bo_reference(cow->bo);
2103	dst_priv->cow = cow;
2104	list_add(&dst_priv->cow_list, &cow->list);
2105	cow->refcnt++;
2106
2107	DBG(("%s: moo! attaching clone to pixmap=%ld (source=%ld, handle=%d)\n",
2108	     __FUNCTION__,
2109	     dst_priv->pixmap->drawable.serialNumber,
2110	     src_priv->pixmap->drawable.serialNumber,
2111	     cow->bo->handle));
2112
2113	return true;
2114}
2115
2116static inline bool operate_inplace(struct sna_pixmap *priv, unsigned flags)
2117{
2118	if (!USE_INPLACE)
2119		return false;
2120
2121	if ((flags & MOVE_INPLACE_HINT) == 0) {
2122		DBG(("%s: no, inplace operation not suitable\n", __FUNCTION__));
2123		return false;
2124	}
2125
2126	assert((flags & MOVE_ASYNC_HINT) == 0 || (priv->create & KGEM_CAN_CREATE_LARGE));
2127
2128	if (priv->move_to_gpu && flags & MOVE_WRITE) {
2129		DBG(("%s: no, has pending move-to-gpu\n", __FUNCTION__));
2130		return false;
2131	}
2132
2133	if (priv->cow && flags & MOVE_WRITE) {
2134		DBG(("%s: no, has COW\n", __FUNCTION__));
2135		return false;
2136	}
2137
2138	if ((priv->create & KGEM_CAN_CREATE_GTT) == 0) {
2139		DBG(("%s: no, not accessible via GTT\n", __FUNCTION__));
2140		return false;
2141	}
2142
2143	if ((priv->gpu_damage == NULL || priv->cpu_damage) && flags & MOVE_READ) {
2144		DBG(("%s: no, has CPU damage and requires readback\n", __FUNCTION__));
2145		return false;
2146	}
2147
2148	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) {
2149		DBG(("%s: yes, CPU is busy\n", __FUNCTION__));
2150		return true;
2151	}
2152
2153	if (priv->create & KGEM_CAN_CREATE_LARGE) {
2154		DBG(("%s: large object, has GPU? %d\n",
2155		     __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0));
2156		return priv->gpu_bo != NULL;
2157	}
2158
2159	if (flags & MOVE_WRITE && priv->gpu_bo&&kgem_bo_is_busy(priv->gpu_bo)) {
2160		DBG(("%s: no, GPU is busy, so stage write\n", __FUNCTION__));
2161		return false;
2162	}
2163
2164	return true;
2165}
2166
2167bool
2168_sna_pixmap_move_to_cpu(PixmapPtr pixmap, unsigned int flags)
2169{
2170	struct sna *sna = to_sna_from_pixmap(pixmap);
2171	struct sna_pixmap *priv;
2172
2173	DBG(("%s(pixmap=%ld, %dx%d, flags=%x)\n", __FUNCTION__,
2174	     pixmap->drawable.serialNumber,
2175	     pixmap->drawable.width,
2176	     pixmap->drawable.height,
2177	     flags));
2178
2179	assert(flags & (MOVE_READ | MOVE_WRITE));
2180	assert_pixmap_damage(pixmap);
2181
2182	priv = sna_pixmap(pixmap);
2183	if (priv == NULL) {
2184		DBG(("%s: not attached\n", __FUNCTION__));
2185		return true;
2186	}
2187
2188	DBG(("%s: gpu_bo=%d, gpu_damage=%p, cpu_damage=%p, is-clear?=%d\n",
2189	     __FUNCTION__,
2190	     priv->gpu_bo ? priv->gpu_bo->handle : 0,
2191	     priv->gpu_damage, priv->cpu_damage, priv->clear));
2192
2193	assert(priv->gpu_damage == NULL || priv->gpu_bo);
2194
2195	if ((flags & MOVE_READ) == 0 && UNDO) {
2196		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
2197		if (priv->move_to_gpu)
2198			sna_pixmap_discard_shadow_damage(priv, NULL);
2199	}
2200
2201	if (kgem_bo_discard_cache(priv->gpu_bo, flags & MOVE_WRITE)) {
2202		assert(DAMAGE_IS_ALL(priv->cpu_damage));
2203		if (DAMAGE_IS_ALL(priv->gpu_damage)) {
2204			DBG(("%s: using magical upload buffer\n", __FUNCTION__));
2205			goto skip;
2206		}
2207
2208		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
2209		assert(priv->gpu_damage == NULL);
2210		assert(!priv->pinned);
2211		assert(!priv->mapped);
2212		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
2213		priv->gpu_bo = NULL;
2214	}
2215
2216	if (DAMAGE_IS_ALL(priv->cpu_damage)) {
2217		DBG(("%s: CPU all-damaged\n", __FUNCTION__));
2218		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage));
2219		assert(priv->gpu_damage == NULL || (flags & MOVE_WRITE) == 0);
2220		goto done;
2221	}
2222
2223	if (USE_INPLACE && (flags & MOVE_READ) == 0 && !(priv->cow || priv->move_to_gpu)) {
2224		assert(flags & MOVE_WRITE);
2225		DBG(("%s: no readback, discarding gpu damage [%d], pending clear[%d]\n",
2226		     __FUNCTION__, priv->gpu_damage != NULL, priv->clear));
2227
2228		if ((priv->gpu_bo || priv->create & KGEM_CAN_CREATE_GPU) &&
2229		    pixmap_inplace(sna, pixmap, priv, flags) &&
2230		    sna_pixmap_create_mappable_gpu(pixmap, true)) {
2231			void *ptr;
2232
2233			DBG(("%s: write inplace\n", __FUNCTION__));
2234			assert(!priv->shm);
2235			assert(priv->cow == NULL);
2236			assert(priv->move_to_gpu == NULL);
2237			assert(priv->gpu_bo->exec == NULL);
2238			assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL);
2239
2240			ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo);
2241			if (ptr == NULL)
2242				goto skip_inplace_map;
2243
2244			pixmap->devPrivate.ptr = ptr;
2245			pixmap->devKind = priv->gpu_bo->pitch;
2246			priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
2247			assert(has_coherent_ptr(sna, priv, flags));
2248
2249			assert(priv->gpu_bo->proxy == NULL);
2250			sna_damage_all(&priv->gpu_damage, pixmap);
2251			sna_damage_destroy(&priv->cpu_damage);
2252			priv->clear = false;
2253			list_del(&priv->flush_list);
2254
2255			assert(!priv->shm);
2256			assert(priv->cpu_bo == NULL || !priv->cpu_bo->flush);
2257			sna_pixmap_free_cpu(sna, priv, priv->cpu);
2258			priv->cpu &= priv->mapped == MAPPED_CPU;
2259
2260			assert_pixmap_damage(pixmap);
2261			return true;
2262		}
2263
2264skip_inplace_map:
2265		sna_damage_destroy(&priv->gpu_damage);
2266		priv->clear = false;
2267		if ((flags & MOVE_ASYNC_HINT) == 0 &&
2268		    priv->cpu_bo && !priv->cpu_bo->flush &&
2269		    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2270			DBG(("%s: discarding busy CPU bo\n", __FUNCTION__));
2271			assert(!priv->shm);
2272			assert(priv->gpu_bo == NULL || priv->gpu_damage == NULL);
2273
2274			sna_damage_destroy(&priv->cpu_damage);
2275			sna_pixmap_free_cpu(sna, priv, false);
2276
2277			assert(priv->mapped == MAPPED_NONE);
2278			if (!sna_pixmap_alloc_cpu(sna, pixmap, priv, 0))
2279				return false;
2280			assert(priv->mapped == MAPPED_NONE);
2281			assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2282
2283			goto mark_damage;
2284		}
2285	}
2286
2287	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2288
2289	if (operate_inplace(priv, flags) &&
2290	    pixmap_inplace(sna, pixmap, priv, flags) &&
2291	    sna_pixmap_create_mappable_gpu(pixmap, (flags & MOVE_READ) == 0)) {
2292		void *ptr;
2293
2294		DBG(("%s: try to operate inplace (GTT)\n", __FUNCTION__));
2295		assert(priv->gpu_bo);
2296		assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
2297		assert(!priv->move_to_gpu);
2298		assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2299		assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL);
2300		/* XXX only sync for writes? */
2301		kgem_bo_submit(&sna->kgem, priv->gpu_bo);
2302		assert(priv->gpu_bo->exec == NULL);
2303
2304		ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo);
2305		if (ptr != NULL) {
2306			pixmap->devPrivate.ptr = ptr;
2307			pixmap->devKind = priv->gpu_bo->pitch;
2308			priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
2309			assert(has_coherent_ptr(sna, priv, flags));
2310
2311			if (flags & MOVE_WRITE) {
2312				assert(priv->gpu_bo->proxy == NULL);
2313				sna_damage_all(&priv->gpu_damage, pixmap);
2314				sna_damage_destroy(&priv->cpu_damage);
2315				sna_pixmap_free_cpu(sna, priv, priv->cpu);
2316				list_del(&priv->flush_list);
2317				priv->clear = false;
2318			}
2319			priv->cpu &= priv->mapped == MAPPED_CPU;
2320
2321			assert_pixmap_damage(pixmap);
2322			DBG(("%s: operate inplace (GTT)\n", __FUNCTION__));
2323			return true;
2324		}
2325	}
2326
2327	sna_pixmap_unmap(pixmap, priv);
2328
2329	if (USE_INPLACE &&
2330	    (flags & MOVE_WRITE ? (void *)priv->gpu_bo : (void *)priv->gpu_damage) && priv->cpu_damage == NULL &&
2331	    priv->gpu_bo->tiling == I915_TILING_NONE &&
2332	    (flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE)) &&
2333	    (!priv->clear || !kgem_bo_is_busy(priv->gpu_bo)) &&
2334	    ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 ||
2335	     (!priv->cow && !priv->move_to_gpu && !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)))) {
2336		void *ptr;
2337
2338		DBG(("%s: try to operate inplace (CPU)\n", __FUNCTION__));
2339		assert(priv->gpu_bo);
2340		assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
2341		assert(priv->move_to_gpu == NULL || (flags & MOVE_WRITE) == 0);
2342		assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2343
2344		assert(!priv->mapped);
2345		assert(priv->gpu_bo->tiling == I915_TILING_NONE);
2346
2347		ptr = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
2348		if (ptr != NULL) {
2349			pixmap->devPrivate.ptr = ptr;
2350			pixmap->devKind = priv->gpu_bo->pitch;
2351			priv->mapped = MAPPED_CPU;
2352			assert(has_coherent_ptr(sna, priv, flags));
2353
2354			if (flags & MOVE_WRITE) {
2355				assert(priv->gpu_bo->proxy == NULL);
2356				sna_damage_all(&priv->gpu_damage, pixmap);
2357				sna_damage_destroy(&priv->cpu_damage);
2358				sna_pixmap_free_cpu(sna, priv, priv->cpu);
2359				list_del(&priv->flush_list);
2360				priv->clear = false;
2361				priv->cpu = true;
2362			}
2363
2364			assert(pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu));
2365			kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo,
2366					       FORCE_FULL_SYNC || flags & MOVE_WRITE);
2367			assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo));
2368			assert_pixmap_damage(pixmap);
2369			assert(has_coherent_ptr(sna, priv, flags));
2370			DBG(("%s: operate inplace (CPU)\n", __FUNCTION__));
2371			return true;
2372		}
2373	}
2374
2375	assert(priv->mapped == MAPPED_NONE);
2376	if (((flags & MOVE_READ) == 0 || priv->clear) &&
2377	    priv->cpu_bo && !priv->cpu_bo->flush &&
2378	    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2379		assert(!priv->shm);
2380		sna_pixmap_free_cpu(sna, priv, false);
2381	}
2382
2383	assert(priv->mapped == MAPPED_NONE);
2384	if (pixmap->devPrivate.ptr == NULL &&
2385	    !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags))
2386		return false;
2387	assert(priv->mapped == MAPPED_NONE);
2388	assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2389
2390	if (flags & MOVE_READ) {
2391		if (priv->clear) {
2392			DBG(("%s: applying clear [%08x] size=%dx%d, stride=%d (total=%d)\n",
2393			     __FUNCTION__, priv->clear_color, pixmap->drawable.width, pixmap->drawable.height,
2394			     pixmap->devKind, pixmap->devKind * pixmap->drawable.height));
2395
2396			if (priv->cpu_bo) {
2397				kgem_bo_undo(&sna->kgem, priv->cpu_bo);
2398				if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) &&
2399				    sna->kgem.can_blt_cpu &&
2400				    sna->render.fill_one(sna,
2401							  pixmap, priv->cpu_bo, priv->clear_color,
2402							  0, 0,
2403							  pixmap->drawable.width,
2404							  pixmap->drawable.height,
2405							  GXcopy))
2406					goto clear_done;
2407
2408				DBG(("%s: syncing CPU bo\n", __FUNCTION__));
2409				kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
2410				assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
2411			}
2412
2413			if (sigtrap_get() == 0) {
2414				assert(pixmap->devKind);
2415				sigtrap_assert_active();
2416				if (priv->clear_color == 0 ||
2417				    pixmap->drawable.bitsPerPixel == 8 ||
2418				    priv->clear_color == (1 << pixmap->drawable.depth) - 1) {
2419					memset(pixmap->devPrivate.ptr, priv->clear_color,
2420					       (size_t)pixmap->devKind * pixmap->drawable.height);
2421				} else {
2422					pixman_fill(pixmap->devPrivate.ptr,
2423						    pixmap->devKind/sizeof(uint32_t),
2424						    pixmap->drawable.bitsPerPixel,
2425						    0, 0,
2426						    pixmap->drawable.width,
2427						    pixmap->drawable.height,
2428						    priv->clear_color);
2429				}
2430				sigtrap_put();
2431			} else
2432				return false;
2433
2434clear_done:
2435			sna_damage_all(&priv->cpu_damage, pixmap);
2436			sna_pixmap_free_gpu(sna, priv);
2437			assert(priv->gpu_damage == NULL);
2438			assert(priv->clear == false);
2439		}
2440
2441		if (priv->gpu_damage) {
2442			const BoxRec *box;
2443			int n;
2444
2445			DBG(("%s: flushing GPU damage\n", __FUNCTION__));
2446			assert(priv->gpu_bo);
2447
2448			n = sna_damage_get_boxes(priv->gpu_damage, &box);
2449			if (n) {
2450				if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ)) {
2451					DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
2452					return false;
2453				}
2454
2455				download_boxes(sna, priv, n, box);
2456			}
2457
2458			__sna_damage_destroy(DAMAGE_PTR(priv->gpu_damage));
2459			priv->gpu_damage = NULL;
2460		}
2461	}
2462
2463	if (flags & MOVE_WRITE || priv->create & KGEM_CAN_CREATE_LARGE) {
2464mark_damage:
2465		DBG(("%s: marking as damaged\n", __FUNCTION__));
2466		sna_damage_all(&priv->cpu_damage, pixmap);
2467		sna_pixmap_free_gpu(sna, priv);
2468		assert(priv->gpu_damage == NULL);
2469		assert(priv->clear == false);
2470
2471		if (priv->flush) {
2472			assert(!priv->shm);
2473			sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
2474		}
2475	}
2476
2477done:
2478	if (flags & MOVE_WRITE) {
2479		assert(DAMAGE_IS_ALL(priv->cpu_damage));
2480		assert(priv->gpu_damage == NULL);
2481		assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
2482		if (priv->cow)
2483			sna_pixmap_undo_cow(sna, priv, 0);
2484		if (priv->gpu_bo && priv->gpu_bo->rq == NULL) {
2485			DBG(("%s: discarding idle GPU bo\n", __FUNCTION__));
2486			sna_pixmap_free_gpu(sna, priv);
2487		}
2488		if (priv->flush) {
2489			assert(!priv->shm);
2490			sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
2491		}
2492		priv->source_count = SOURCE_BIAS;
2493	}
2494
2495	if (priv->cpu_bo) {
2496		if ((flags & MOVE_ASYNC_HINT) == 0) {
2497			DBG(("%s: syncing CPU bo\n", __FUNCTION__));
2498			assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
2499			kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo,
2500					       FORCE_FULL_SYNC || flags & MOVE_WRITE);
2501			assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo));
2502		}
2503	}
2504skip:
2505	priv->cpu |= (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE;
2506	assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2507	assert(pixmap->devKind);
2508	assert_pixmap_damage(pixmap);
2509	assert(has_coherent_ptr(sna, sna_pixmap(pixmap), flags));
2510	return true;
2511}
2512
2513static bool
2514region_overlaps_damage(const RegionRec *region,
2515		       struct sna_damage *damage,
2516		       int dx, int dy)
2517{
2518	const BoxRec *re, *de;
2519
2520	DBG(("%s?\n", __FUNCTION__));
2521
2522	if (damage == NULL)
2523		return false;
2524
2525	if (DAMAGE_IS_ALL(damage))
2526		return true;
2527
2528	re = &region->extents;
2529	de = &DAMAGE_PTR(damage)->extents;
2530	DBG(("%s: region (%d, %d), (%d, %d), damage (%d, %d), (%d, %d)\n",
2531	     __FUNCTION__,
2532	     re->x1, re->y1, re->x2, re->y2,
2533	     de->x1, de->y1, de->x2, de->y2));
2534
2535	return (re->x1 + dx < de->x2 && re->x2 + dx > de->x1 &&
2536		re->y1 + dy < de->y2 && re->y2 + dy > de->y1);
2537}
2538
2539static inline bool region_inplace(struct sna *sna,
2540				  PixmapPtr pixmap,
2541				  RegionPtr region,
2542				  struct sna_pixmap *priv,
2543				  unsigned flags)
2544{
2545	assert_pixmap_damage(pixmap);
2546
2547	if (FORCE_INPLACE)
2548		return FORCE_INPLACE > 0;
2549
2550	if (wedged(sna) && !priv->pinned)
2551		return false;
2552
2553	if (priv->gpu_damage &&
2554	    (priv->clear || (flags & MOVE_READ) == 0) &&
2555	    kgem_bo_is_busy(priv->gpu_bo))
2556		return false;
2557
2558	if (flags & MOVE_READ &&
2559	    (priv->cpu ||
2560	     priv->gpu_damage == NULL ||
2561	     region_overlaps_damage(region, priv->cpu_damage, 0, 0))) {
2562		DBG(("%s: no, uncovered CPU damage pending\n", __FUNCTION__));
2563		return false;
2564	}
2565
2566	if (priv->mapped) {
2567		DBG(("%s: %s, already mapped, continuing\n", __FUNCTION__,
2568		     has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no"));
2569		return has_coherent_map(sna, priv->gpu_bo, flags);
2570	}
2571
2572	if (priv->flush) {
2573		DBG(("%s: yes, exported via dri, will flush\n", __FUNCTION__));
2574		return true;
2575	}
2576
2577	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
2578		DBG(("%s: yes, already wholly damaged on the GPU\n", __FUNCTION__));
2579		assert(priv->gpu_bo);
2580		return true;
2581	}
2582
2583	if (priv->cpu_bo && priv->cpu) {
2584		DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__));
2585		return false;
2586	}
2587
2588	DBG(("%s: (%dx%d), inplace? %d\n",
2589	     __FUNCTION__,
2590	     region->extents.x2 - region->extents.x1,
2591	     region->extents.y2 - region->extents.y1,
2592	     ((int)(region->extents.x2 - region->extents.x1) *
2593	      (int)(region->extents.y2 - region->extents.y1) *
2594	      pixmap->drawable.bitsPerPixel >> 12)
2595	     >= sna->kgem.half_cpu_cache_pages));
2596	return ((int)(region->extents.x2 - region->extents.x1) *
2597		(int)(region->extents.y2 - region->extents.y1) *
2598		pixmap->drawable.bitsPerPixel >> 12)
2599		>= sna->kgem.half_cpu_cache_pages;
2600}
2601
2602static bool cpu_clear_boxes(struct sna *sna,
2603			    PixmapPtr pixmap,
2604			    struct sna_pixmap *priv,
2605			    const BoxRec *box, int n)
2606{
2607	struct sna_fill_op fill;
2608
2609	if (!sna->kgem.can_blt_cpu)
2610		return false;
2611
2612	if (!sna_fill_init_blt(&fill, sna,
2613			       pixmap, priv->cpu_bo,
2614			       GXcopy, priv->clear_color,
2615			       FILL_BOXES)) {
2616		DBG(("%s: unsupported fill\n",
2617		     __FUNCTION__));
2618		return false;
2619	}
2620
2621	fill.boxes(sna, &fill, box, n);
2622	fill.done(sna, &fill);
2623	return true;
2624}
2625
2626bool
2627sna_drawable_move_region_to_cpu(DrawablePtr drawable,
2628				RegionPtr region,
2629				unsigned flags)
2630{
2631	PixmapPtr pixmap = get_drawable_pixmap(drawable);
2632	struct sna *sna = to_sna_from_pixmap(pixmap);
2633	struct sna_pixmap *priv;
2634	int16_t dx, dy;
2635
2636	DBG(("%s(pixmap=%ld (%dx%d), [(%d, %d), (%d, %d)], flags=%x)\n",
2637	     __FUNCTION__, pixmap->drawable.serialNumber,
2638	     pixmap->drawable.width, pixmap->drawable.height,
2639	     RegionExtents(region)->x1, RegionExtents(region)->y1,
2640	     RegionExtents(region)->x2, RegionExtents(region)->y2,
2641	     flags));
2642
2643	assert_pixmap_damage(pixmap);
2644	if (flags & MOVE_WRITE) {
2645		assert_drawable_contains_box(drawable, &region->extents);
2646	}
2647	assert(flags & (MOVE_WRITE | MOVE_READ));
2648
2649	if (box_empty(&region->extents))
2650		return true;
2651
2652	if (MIGRATE_ALL || DBG_NO_PARTIAL_MOVE_TO_CPU) {
2653		if (!region_subsumes_pixmap(region, pixmap))
2654			flags |= MOVE_READ;
2655		return _sna_pixmap_move_to_cpu(pixmap, flags);
2656	}
2657
2658	priv = sna_pixmap(pixmap);
2659	if (priv == NULL) {
2660		DBG(("%s: not attached to pixmap %ld (depth %d)\n",
2661		     __FUNCTION__, pixmap->drawable.serialNumber, pixmap->drawable.depth));
2662		return true;
2663	}
2664
2665	assert(priv->gpu_damage == NULL || priv->gpu_bo);
2666
2667	if (kgem_bo_discard_cache(priv->gpu_bo, flags & MOVE_WRITE)) {
2668		assert(DAMAGE_IS_ALL(priv->cpu_damage));
2669		if (DAMAGE_IS_ALL(priv->gpu_damage)) {
2670			DBG(("%s: using magical upload buffer\n", __FUNCTION__));
2671			goto skip;
2672		}
2673
2674		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
2675		assert(priv->gpu_damage == NULL);
2676		assert(!priv->pinned);
2677		assert(!priv->mapped);
2678		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
2679		priv->gpu_bo = NULL;
2680	}
2681
2682	if (sna_damage_is_all(&priv->cpu_damage,
2683			      pixmap->drawable.width,
2684			      pixmap->drawable.height)) {
2685		bool discard_gpu = priv->cpu;
2686
2687		DBG(("%s: pixmap=%ld all damaged on CPU\n",
2688		     __FUNCTION__, pixmap->drawable.serialNumber));
2689		assert(!priv->clear);
2690
2691		sna_damage_destroy(&priv->gpu_damage);
2692
2693		if ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 &&
2694		    priv->cpu_bo && !priv->cpu_bo->flush &&
2695		    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2696			DBG(("%s: active CPU bo replacing\n", __FUNCTION__));
2697			assert(!priv->shm);
2698			assert(!IS_STATIC_PTR(priv->ptr));
2699
2700			if (!region_subsumes_pixmap(region, pixmap)) {
2701				DBG(("%s: partial replacement\n", __FUNCTION__));
2702				if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
2703					RegionTranslate(region, dx, dy);
2704
2705				if (sna->kgem.has_llc && !priv->pinned &&
2706				    sna_pixmap_default_tiling(sna, pixmap) == I915_TILING_NONE) {
2707#ifdef DEBUG_MEMORY
2708					sna->debug_memory.cpu_bo_allocs--;
2709					sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
2710#endif
2711					DBG(("%s: promoting CPU bo to GPU bo\n", __FUNCTION__));
2712					if (priv->gpu_bo)
2713						sna_pixmap_free_gpu(sna, priv);
2714					priv->gpu_bo = priv->cpu_bo;
2715					priv->cpu_bo = NULL;
2716					priv->ptr = NULL;
2717					pixmap->devPrivate.ptr = NULL;
2718
2719					priv->gpu_damage = priv->cpu_damage;
2720					priv->cpu_damage = NULL;
2721
2722					sna_damage_subtract(&priv->gpu_damage, region);
2723					discard_gpu = false;
2724				} else {
2725					DBG(("%s: pushing surrounding damage to GPU bo\n", __FUNCTION__));
2726					sna_damage_subtract(&priv->cpu_damage, region);
2727					assert(priv->cpu_damage);
2728					if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) {
2729						sna_pixmap_free_cpu(sna, priv, false);
2730						if (priv->flush)
2731							sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
2732
2733						assert(priv->cpu_damage == NULL);
2734						sna_damage_all(&priv->gpu_damage, pixmap);
2735						sna_damage_subtract(&priv->gpu_damage, region);
2736						discard_gpu = false;
2737					}
2738				}
2739				sna_damage_add_to_pixmap(&priv->cpu_damage, region, pixmap);
2740				if (priv->flush) {
2741					assert(!priv->shm);
2742					sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
2743				}
2744
2745				if (dx | dy)
2746					RegionTranslate(region, -dx, -dy);
2747			} else
2748				sna_pixmap_free_cpu(sna, priv, false);
2749		}
2750
2751		if (flags & MOVE_WRITE && discard_gpu)
2752			sna_pixmap_free_gpu(sna, priv);
2753
2754		sna_pixmap_unmap(pixmap, priv);
2755		assert(priv->mapped == MAPPED_NONE);
2756		if (pixmap->devPrivate.ptr == NULL &&
2757		    !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags))
2758			return false;
2759		assert(priv->mapped == MAPPED_NONE);
2760		assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2761
2762		goto out;
2763	}
2764
2765	if (USE_INPLACE &&
2766	    (priv->create & KGEM_CAN_CREATE_LARGE ||
2767	     ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 &&
2768	      (priv->flush ||
2769	       (flags & MOVE_WHOLE_HINT && whole_pixmap_inplace(pixmap)) ||
2770	       box_inplace(pixmap, &region->extents))))) {
2771		DBG(("%s: marking for inplace hint (%d, %d)\n",
2772		     __FUNCTION__, priv->flush, box_inplace(pixmap, &region->extents)));
2773		flags |= MOVE_INPLACE_HINT;
2774	}
2775
2776	if (region_subsumes_pixmap(region, pixmap)) {
2777		DBG(("%s: region (%d, %d), (%d, %d) + (%d, %d) subsumes pixmap (%dx%d)\n",
2778		       __FUNCTION__,
2779		       region->extents.x1,
2780		       region->extents.y1,
2781		       region->extents.x2,
2782		       region->extents.y2,
2783		       get_drawable_dx(drawable), get_drawable_dy(drawable),
2784		       pixmap->drawable.width,
2785		       pixmap->drawable.height));
2786		return _sna_pixmap_move_to_cpu(pixmap, flags);
2787	}
2788
2789	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2790
2791	if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
2792		DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy));
2793		RegionTranslate(region, dx, dy);
2794	}
2795
2796	if (priv->move_to_gpu) {
2797		DBG(("%s: applying move-to-gpu override\n", __FUNCTION__));
2798		if ((flags & MOVE_READ) == 0)
2799			sna_pixmap_discard_shadow_damage(priv, region);
2800		if (!priv->move_to_gpu(sna, priv, MOVE_READ)) {
2801			DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
2802			return NULL;
2803		}
2804	}
2805
2806	if (operate_inplace(priv, flags) &&
2807	    region_inplace(sna, pixmap, region, priv, flags) &&
2808	    sna_pixmap_create_mappable_gpu(pixmap, false)) {
2809		void *ptr;
2810
2811		DBG(("%s: try to operate inplace\n", __FUNCTION__));
2812		assert(priv->gpu_bo);
2813		assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
2814		assert(priv->move_to_gpu == NULL || (flags & MOVE_WRITE) == 0);
2815		assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2816
2817		/* XXX only sync for writes? */
2818		kgem_bo_submit(&sna->kgem, priv->gpu_bo);
2819		assert(priv->gpu_bo->exec == NULL);
2820
2821		ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo);
2822		if (ptr != NULL) {
2823			pixmap->devPrivate.ptr = ptr;
2824			pixmap->devKind = priv->gpu_bo->pitch;
2825			priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
2826			assert(has_coherent_ptr(sna, priv, flags));
2827
2828			if (flags & MOVE_WRITE) {
2829				if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
2830					assert(!priv->clear);
2831					sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap);
2832					if (sna_damage_is_all(&priv->gpu_damage,
2833							      pixmap->drawable.width,
2834							      pixmap->drawable.height)) {
2835						DBG(("%s: replaced entire pixmap, destroying CPU shadow\n",
2836						     __FUNCTION__));
2837						sna_damage_destroy(&priv->cpu_damage);
2838						list_del(&priv->flush_list);
2839					} else
2840						sna_damage_subtract(&priv->cpu_damage,
2841								    region);
2842				}
2843				priv->clear = false;
2844			}
2845			priv->cpu &= priv->mapped == MAPPED_CPU;
2846			assert_pixmap_damage(pixmap);
2847			if (dx | dy)
2848				RegionTranslate(region, -dx, -dy);
2849			DBG(("%s: operate inplace\n", __FUNCTION__));
2850			return true;
2851		}
2852	}
2853
2854	if (priv->clear && flags & MOVE_WRITE) {
2855		DBG(("%s: pending clear, moving whole pixmap for partial write\n", __FUNCTION__));
2856demote_to_cpu:
2857		if (dx | dy)
2858			RegionTranslate(region, -dx, -dy);
2859		return _sna_pixmap_move_to_cpu(pixmap, flags | MOVE_READ);
2860	}
2861
2862	if (flags & MOVE_WHOLE_HINT) {
2863		DBG(("%s: region (%d, %d), (%d, %d) marked with WHOLE hint, pixmap %dx%d\n",
2864		       __FUNCTION__,
2865		       region->extents.x1,
2866		       region->extents.y1,
2867		       region->extents.x2,
2868		       region->extents.y2,
2869		       pixmap->drawable.width,
2870		       pixmap->drawable.height));
2871move_to_cpu:
2872		if ((flags & MOVE_READ) == 0)
2873			sna_damage_subtract(&priv->gpu_damage, region);
2874		goto demote_to_cpu;
2875	}
2876
2877	sna_pixmap_unmap(pixmap, priv);
2878
2879	if (USE_INPLACE &&
2880	    priv->gpu_damage &&
2881	    priv->gpu_bo->tiling == I915_TILING_NONE &&
2882	    ((priv->cow == NULL && priv->move_to_gpu == NULL) || (flags & MOVE_WRITE) == 0) &&
2883	    (DAMAGE_IS_ALL(priv->gpu_damage) ||
2884	     sna_damage_contains_box__no_reduce(priv->gpu_damage,
2885						&region->extents)) &&
2886	    kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE) &&
2887	    ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 ||
2888	     !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) {
2889		void *ptr;
2890
2891		DBG(("%s: try to operate inplace (CPU), read? %d, write? %d\n",
2892		     __FUNCTION__, !!(flags & MOVE_READ), !!(flags & MOVE_WRITE)));
2893		assert(priv->gpu_bo);
2894		assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2895		assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
2896		assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
2897
2898		ptr = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
2899		if (ptr != NULL) {
2900			pixmap->devPrivate.ptr = ptr;
2901			pixmap->devKind = priv->gpu_bo->pitch;
2902			priv->mapped = MAPPED_CPU;
2903			assert(has_coherent_ptr(sna, priv, flags));
2904
2905			if (flags & MOVE_WRITE) {
2906				if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
2907					assert(!priv->clear);
2908					sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap);
2909					if (sna_damage_is_all(&priv->gpu_damage,
2910							      pixmap->drawable.width,
2911							      pixmap->drawable.height)) {
2912						DBG(("%s: replaced entire pixmap, destroying CPU shadow\n",
2913						     __FUNCTION__));
2914						sna_damage_destroy(&priv->cpu_damage);
2915						list_del(&priv->flush_list);
2916					} else
2917						sna_damage_subtract(&priv->cpu_damage,
2918								    region);
2919				}
2920				priv->clear = false;
2921			}
2922			assert_pixmap_damage(pixmap);
2923
2924			kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo,
2925					       FORCE_FULL_SYNC || flags & MOVE_WRITE);
2926			priv->cpu = true;
2927
2928			assert_pixmap_map(pixmap, priv);
2929			assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo));
2930			if (dx | dy)
2931				RegionTranslate(region, -dx, -dy);
2932			DBG(("%s: operate inplace (CPU)\n", __FUNCTION__));
2933			return true;
2934		}
2935	}
2936
2937	if ((priv->clear || (flags & MOVE_READ) == 0) &&
2938	    priv->cpu_bo && !priv->cpu_bo->flush &&
2939	    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2940		sna_damage_subtract(&priv->cpu_damage, region);
2941		if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) {
2942			assert(priv->gpu_bo);
2943			sna_damage_all(&priv->gpu_damage, pixmap);
2944			sna_pixmap_free_cpu(sna, priv, false);
2945		}
2946	}
2947
2948	assert(priv->mapped == MAPPED_NONE);
2949	if (pixmap->devPrivate.ptr == NULL &&
2950	    !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags)) {
2951		DBG(("%s: CPU bo allocation failed, trying full move-to-cpu\n", __FUNCTION__));
2952		goto move_to_cpu;
2953	}
2954	assert(priv->mapped == MAPPED_NONE);
2955	assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2956
2957	if (priv->gpu_bo == NULL) {
2958		assert(priv->gpu_damage == NULL);
2959		goto done;
2960	}
2961
2962	assert(priv->gpu_bo->proxy == NULL);
2963
2964	if ((flags & MOVE_READ) == 0) {
2965		assert(flags & MOVE_WRITE);
2966		sna_damage_subtract(&priv->gpu_damage, region);
2967		priv->clear = false;
2968		goto done;
2969	}
2970
2971	if (priv->clear) {
2972		int n = region_num_rects(region);
2973		const BoxRec *box = region_rects(region);
2974
2975		assert(DAMAGE_IS_ALL(priv->gpu_damage));
2976		assert(priv->cpu_damage == NULL);
2977
2978		DBG(("%s: pending clear, doing partial fill\n", __FUNCTION__));
2979		if (priv->cpu_bo) {
2980			if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) &&
2981			    cpu_clear_boxes(sna, pixmap, priv, box, n))
2982				goto clear_done;
2983
2984			DBG(("%s: syncing CPU bo\n", __FUNCTION__));
2985			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
2986			assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
2987		}
2988
2989		if (sigtrap_get() == 0) {
2990			assert(pixmap->devKind);
2991			sigtrap_assert_active();
2992			do {
2993				pixman_fill(pixmap->devPrivate.ptr,
2994					    pixmap->devKind/sizeof(uint32_t),
2995					    pixmap->drawable.bitsPerPixel,
2996					    box->x1, box->y1,
2997					    box->x2 - box->x1,
2998					    box->y2 - box->y1,
2999					    priv->clear_color);
3000				box++;
3001			} while (--n);
3002			sigtrap_put();
3003		} else
3004			return false;
3005
3006clear_done:
3007		if (flags & MOVE_WRITE ||
3008		    region->extents.x2 - region->extents.x1 > 1 ||
3009		    region->extents.y2 - region->extents.y1 > 1) {
3010			sna_damage_subtract(&priv->gpu_damage, region);
3011			priv->clear = false;
3012		}
3013		goto done;
3014	}
3015
3016	if (priv->gpu_damage &&
3017	    (DAMAGE_IS_ALL(priv->gpu_damage) ||
3018	     sna_damage_overlaps_box(priv->gpu_damage, &region->extents))) {
3019		DBG(("%s: region (%dx%d) overlaps gpu damage\n",
3020		     __FUNCTION__,
3021		     region->extents.x2 - region->extents.x1,
3022		     region->extents.y2 - region->extents.y1));
3023		assert(priv->gpu_bo);
3024
3025		if (priv->cpu_damage == NULL) {
3026			if ((flags & MOVE_WRITE) == 0 &&
3027			    region->extents.x2 - region->extents.x1 == 1 &&
3028			    region->extents.y2 - region->extents.y1 == 1) {
3029				/*  Often associated with synchronisation, KISS */
3030				DBG(("%s: single pixel read\n", __FUNCTION__));
3031				sna_read_boxes(sna, pixmap, priv->gpu_bo,
3032					       &region->extents, 1);
3033				goto done;
3034			}
3035		} else {
3036			if (DAMAGE_IS_ALL(priv->cpu_damage) ||
3037			    sna_damage_contains_box__no_reduce(priv->cpu_damage,
3038							       &region->extents)) {
3039				assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_OUT);
3040				assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_IN);
3041
3042				DBG(("%s: region already in CPU damage\n",
3043				     __FUNCTION__));
3044				goto already_damaged;
3045			}
3046		}
3047
3048		if (sna_damage_contains_box(&priv->gpu_damage,
3049					    &region->extents) != PIXMAN_REGION_OUT) {
3050			RegionRec want, *r = region;
3051
3052			DBG(("%s: region (%dx%d) intersects gpu damage\n",
3053			     __FUNCTION__,
3054			     region->extents.x2 - region->extents.x1,
3055			     region->extents.y2 - region->extents.y1));
3056
3057			if ((flags & MOVE_WRITE) == 0 &&
3058			    region->extents.x2 - region->extents.x1 == 1 &&
3059			    region->extents.y2 - region->extents.y1 == 1) {
3060				sna_read_boxes(sna, pixmap, priv->gpu_bo,
3061					       &region->extents, 1);
3062				goto done;
3063			}
3064
3065			/* Expand the region to move 32x32 pixel blocks at a
3066			 * time, as we assume that we will continue writing
3067			 * afterwards and so aim to coallesce subsequent
3068			 * reads.
3069			 */
3070			if (flags & MOVE_WRITE) {
3071				int n = region_num_rects(region), i;
3072				const BoxRec *boxes = region_rects(region);
3073				BoxPtr blocks;
3074
3075				blocks = NULL;
3076				if (priv->cpu_damage == NULL)
3077					blocks = malloc(sizeof(BoxRec) * n);
3078				if (blocks) {
3079					for (i = 0; i < n; i++) {
3080						blocks[i].x1 = boxes[i].x1 & ~31;
3081						if (blocks[i].x1 < 0)
3082							blocks[i].x1 = 0;
3083
3084						blocks[i].x2 = (boxes[i].x2 + 31) & ~31;
3085						if (blocks[i].x2 > pixmap->drawable.width)
3086							blocks[i].x2 = pixmap->drawable.width;
3087
3088						blocks[i].y1 = boxes[i].y1 & ~31;
3089						if (blocks[i].y1 < 0)
3090							blocks[i].y1 = 0;
3091
3092						blocks[i].y2 = (boxes[i].y2 + 31) & ~31;
3093						if (blocks[i].y2 > pixmap->drawable.height)
3094							blocks[i].y2 = pixmap->drawable.height;
3095					}
3096					if (pixman_region_init_rects(&want, blocks, i))
3097						r = &want;
3098					free(blocks);
3099				}
3100			}
3101
3102			if (region_subsumes_damage(r, priv->gpu_damage)) {
3103				const BoxRec *box;
3104				int n;
3105
3106				DBG(("%s: region wholly contains damage\n",
3107				     __FUNCTION__));
3108
3109				n = sna_damage_get_boxes(priv->gpu_damage, &box);
3110				if (n)
3111					download_boxes(sna, priv, n, box);
3112
3113				sna_damage_destroy(&priv->gpu_damage);
3114			} else if (DAMAGE_IS_ALL(priv->gpu_damage) ||
3115				   sna_damage_contains_box__no_reduce(priv->gpu_damage,
3116								      &r->extents)) {
3117
3118				DBG(("%s: region wholly inside damage\n",
3119				     __FUNCTION__));
3120
3121				assert(sna_damage_contains_box(&priv->gpu_damage, &r->extents) == PIXMAN_REGION_IN);
3122				assert(sna_damage_contains_box(&priv->cpu_damage, &r->extents) == PIXMAN_REGION_OUT);
3123
3124				download_boxes(sna, priv,
3125					       region_num_rects(r),
3126					       region_rects(r));
3127				sna_damage_subtract(&priv->gpu_damage, r);
3128			} else {
3129				RegionRec need;
3130
3131				pixman_region_init(&need);
3132				if (sna_damage_intersect(priv->gpu_damage, r, &need)) {
3133					DBG(("%s: region intersects damage\n",
3134					     __FUNCTION__));
3135
3136					download_boxes(sna, priv,
3137						       region_num_rects(&need),
3138						       region_rects(&need));
3139					sna_damage_subtract(&priv->gpu_damage, r);
3140					RegionUninit(&need);
3141				}
3142			}
3143			if (r == &want)
3144				pixman_region_fini(&want);
3145		}
3146	}
3147
3148done:
3149	if ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE) {
3150		DBG(("%s: applying cpu damage\n", __FUNCTION__));
3151		assert(!DAMAGE_IS_ALL(priv->cpu_damage));
3152		assert_pixmap_contains_box(pixmap, RegionExtents(region));
3153		sna_damage_add_to_pixmap(&priv->cpu_damage, region, pixmap);
3154		sna_damage_reduce_all(&priv->cpu_damage, pixmap);
3155		if (DAMAGE_IS_ALL(priv->cpu_damage)) {
3156			DBG(("%s: replaced entire pixmap\n", __FUNCTION__));
3157			sna_pixmap_free_gpu(sna, priv);
3158		}
3159		if (priv->flush) {
3160			assert(!priv->shm);
3161			sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
3162		}
3163	}
3164
3165already_damaged:
3166	if (dx | dy)
3167		RegionTranslate(region, -dx, -dy);
3168
3169out:
3170	if (flags & MOVE_WRITE) {
3171		assert(!DAMAGE_IS_ALL(priv->gpu_damage));
3172		priv->source_count = SOURCE_BIAS;
3173		assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
3174		assert(priv->gpu_bo || priv->gpu_damage == NULL);
3175		assert(!priv->flush || !list_is_empty(&priv->flush_list));
3176		assert(!priv->clear);
3177	}
3178	if ((flags & MOVE_ASYNC_HINT) == 0 && priv->cpu_bo) {
3179		DBG(("%s: syncing cpu bo\n", __FUNCTION__));
3180		assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
3181		kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo,
3182				       FORCE_FULL_SYNC || flags & MOVE_WRITE);
3183		assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo));
3184	}
3185skip:
3186	priv->cpu |= (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE;
3187	assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
3188	assert(pixmap->devKind);
3189	assert_pixmap_damage(pixmap);
3190	assert(has_coherent_ptr(sna, priv, flags));
3191	return true;
3192}
3193
3194bool
3195sna_drawable_move_to_cpu(DrawablePtr drawable, unsigned flags)
3196{
3197	RegionRec region;
3198	PixmapPtr pixmap;
3199	int16_t dx, dy;
3200
3201	if (drawable->type == DRAWABLE_PIXMAP)
3202		return sna_pixmap_move_to_cpu((PixmapPtr)drawable, flags);
3203
3204	pixmap = get_window_pixmap((WindowPtr)drawable);
3205	get_drawable_deltas(drawable, pixmap, &dx, &dy);
3206
3207	DBG(("%s: (%d, %d)x(%d, %d) + (%d, %d), flags=%x\n",
3208	     __FUNCTION__,
3209	     drawable->x, drawable->y,
3210	     drawable->width, drawable->height,
3211	     dx, dy, flags));
3212
3213	region.extents.x1 = drawable->x + dx;
3214	region.extents.y1 = drawable->y + dy;
3215	region.extents.x2 = region.extents.x1 + drawable->width;
3216	region.extents.y2 = region.extents.y1 + drawable->height;
3217	region.data = NULL;
3218
3219	if (region.extents.x1 < 0)
3220		region.extents.x1 = 0;
3221	if (region.extents.y1 < 0)
3222		region.extents.y1 = 0;
3223	if (region.extents.x2 > pixmap->drawable.width)
3224		region.extents.x2 = pixmap->drawable.width;
3225	if (region.extents.y2 > pixmap->drawable.height)
3226		region.extents.y2 = pixmap->drawable.height;
3227
3228	if (box_empty(&region.extents))
3229		return true;
3230
3231	return sna_drawable_move_region_to_cpu(&pixmap->drawable, &region, flags);
3232}
3233
3234pure static bool alu_overwrites(uint8_t alu)
3235{
3236	switch (alu) {
3237	case GXclear:
3238	case GXcopy:
3239	case GXcopyInverted:
3240	case GXset:
3241		return true;
3242	default:
3243		return false;
3244	}
3245}
3246
3247inline static bool drawable_gc_inplace_hint(DrawablePtr draw, GCPtr gc)
3248{
3249	if (!alu_overwrites(gc->alu))
3250		return false;
3251
3252	if (!PM_IS_SOLID(draw, gc->planemask))
3253		return false;
3254
3255	if (gc->fillStyle == FillStippled)
3256		return false;
3257
3258	return true;
3259}
3260
3261inline static unsigned
3262drawable_gc_flags(DrawablePtr draw, GCPtr gc, bool partial)
3263{
3264	assert(sna_gc(gc)->changes == 0);
3265
3266	if (gc->fillStyle == FillStippled) {
3267		DBG(("%s: read due to fill %d\n",
3268		     __FUNCTION__, gc->fillStyle));
3269		return MOVE_READ | MOVE_WRITE;
3270	}
3271
3272	if (fb_gc(gc)->and | fb_gc(gc)->bgand) {
3273		DBG(("%s: read due to rrop %d:%x\n",
3274		     __FUNCTION__, gc->alu, (unsigned)fb_gc(gc)->and));
3275		return MOVE_READ | MOVE_WRITE;
3276	}
3277
3278	DBG(("%s: try operating on drawable inplace [hint? %d]\n",
3279	     __FUNCTION__, drawable_gc_inplace_hint(draw, gc)));
3280
3281	return (partial ? MOVE_READ : 0) | MOVE_WRITE | MOVE_INPLACE_HINT;
3282}
3283
3284static inline struct sna_pixmap *
3285sna_pixmap_mark_active(struct sna *sna, struct sna_pixmap *priv)
3286{
3287	assert(priv->gpu_bo);
3288	DBG(("%s: pixmap=%ld, handle=%u\n", __FUNCTION__,
3289	     priv->pixmap->drawable.serialNumber,
3290	     priv->gpu_bo->handle));
3291	return priv;
3292}
3293
3294inline static struct sna_pixmap *
3295__sna_pixmap_for_gpu(struct sna *sna, PixmapPtr pixmap, unsigned flags)
3296{
3297	struct sna_pixmap *priv;
3298
3299	assert(flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE));
3300	if ((flags & __MOVE_FORCE) == 0 && wedged(sna))
3301		return NULL;
3302
3303	priv = sna_pixmap(pixmap);
3304	if (priv == NULL) {
3305		DBG(("%s: not attached\n", __FUNCTION__));
3306		if ((flags & (__MOVE_DRI | __MOVE_SCANOUT)) == 0)
3307			return NULL;
3308
3309		if (pixmap->usage_hint == -1) {
3310			DBG(("%s: not promoting SHM Pixmap for DRI\n", __FUNCTION__));
3311			return NULL;
3312		}
3313
3314		DBG(("%s: forcing the creation on the GPU\n", __FUNCTION__));
3315
3316		priv = sna_pixmap_attach(pixmap);
3317		if (priv == NULL)
3318			return NULL;
3319
3320		sna_damage_all(&priv->cpu_damage, pixmap);
3321
3322		assert(priv->gpu_bo == NULL);
3323		assert(priv->gpu_damage == NULL);
3324	}
3325
3326	return priv;
3327}
3328
3329inline static void sna_pixmap_unclean(struct sna *sna,
3330				      struct sna_pixmap *priv,
3331				      unsigned flags)
3332{
3333	struct drm_i915_gem_busy busy;
3334
3335	assert(DAMAGE_IS_ALL(priv->gpu_damage));
3336	assert(priv->gpu_bo);
3337	assert(priv->gpu_bo->proxy == NULL);
3338	assert_pixmap_map(priv->pixmap, priv);
3339
3340	sna_damage_destroy(&priv->cpu_damage);
3341	list_del(&priv->flush_list);
3342
3343	if (flags & (__MOVE_DRI | __MOVE_SCANOUT))
3344		return;
3345
3346	if (!priv->flush || priv->gpu_bo->exec)
3347		return;
3348
3349	busy.handle = priv->gpu_bo->handle;
3350	busy.busy = 0;
3351	ioctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
3352
3353	DBG(("%s(pixmap=%ld): cleaning foreign bo handle=%u, busy=%x [ring=%d]\n",
3354	     __FUNCTION__,
3355	     priv->pixmap->drawable.serialNumber,
3356	     busy.handle, busy.busy, !!(busy.busy & (0xfffe << 16))));
3357
3358	if (busy.busy) {
3359		unsigned mode = KGEM_RENDER;
3360		if (busy.busy & (0xfffe << 16))
3361			mode = KGEM_BLT;
3362		kgem_bo_mark_busy(&sna->kgem, priv->gpu_bo, mode);
3363	} else
3364		__kgem_bo_clear_busy(priv->gpu_bo);
3365}
3366
3367struct sna_pixmap *
3368sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int flags)
3369{
3370	struct sna *sna = to_sna_from_pixmap(pixmap);
3371	struct sna_pixmap *priv;
3372	RegionRec i, r;
3373
3374	DBG(("%s: pixmap=%ld box=(%d, %d), (%d, %d), flags=%x\n",
3375	     __FUNCTION__, pixmap->drawable.serialNumber,
3376	     box->x1, box->y1, box->x2, box->y2, flags));
3377
3378	priv = __sna_pixmap_for_gpu(sna, pixmap, flags);
3379	if (priv == NULL)
3380		return NULL;
3381
3382	assert(box->x2 > box->x1 && box->y2 > box->y1);
3383	assert_pixmap_damage(pixmap);
3384	assert_pixmap_contains_box(pixmap, box);
3385	assert(priv->gpu_damage == NULL || priv->gpu_bo);
3386
3387	if ((flags & MOVE_READ) == 0)
3388		sna_damage_subtract_box(&priv->cpu_damage, box);
3389
3390	if (priv->move_to_gpu) {
3391		unsigned int hint;
3392
3393		DBG(("%s: applying move-to-gpu override\n", __FUNCTION__));
3394		hint = flags | MOVE_READ;
3395		if ((flags & MOVE_READ) == 0) {
3396			RegionRec region;
3397
3398			region.extents = *box;
3399			region.data = NULL;
3400			sna_pixmap_discard_shadow_damage(priv, &region);
3401			if (region_subsumes_pixmap(&region, pixmap))
3402				hint &= ~MOVE_READ;
3403		} else {
3404			if (priv->cpu_damage)
3405				hint |= MOVE_WRITE;
3406		}
3407		if (!priv->move_to_gpu(sna, priv, hint)) {
3408			DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
3409			return NULL;
3410		}
3411	}
3412
3413	if (priv->cow) {
3414		unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE);
3415
3416		assert(cow);
3417
3418		if ((flags & MOVE_READ) == 0) {
3419			if (priv->gpu_damage) {
3420				r.extents = *box;
3421				r.data = NULL;
3422				if (!region_subsumes_damage(&r, priv->gpu_damage))
3423					cow |= MOVE_READ | __MOVE_FORCE;
3424			}
3425		} else {
3426			if (priv->cpu_damage) {
3427				r.extents = *box;
3428				r.data = NULL;
3429				if (region_overlaps_damage(&r, priv->cpu_damage, 0, 0))
3430					cow |= MOVE_WRITE;
3431			}
3432		}
3433
3434		if (!sna_pixmap_undo_cow(sna, priv, cow))
3435			return NULL;
3436
3437		if (priv->gpu_bo == NULL)
3438			sna_damage_destroy(&priv->gpu_damage);
3439	}
3440
3441	if (sna_damage_is_all(&priv->gpu_damage,
3442			      pixmap->drawable.width,
3443			      pixmap->drawable.height)) {
3444		DBG(("%s: already all-damaged\n", __FUNCTION__));
3445		sna_pixmap_unclean(sna, priv, flags);
3446		goto done;
3447	}
3448
3449	if (kgem_bo_discard_cache(priv->gpu_bo, flags & (MOVE_WRITE | __MOVE_FORCE))) {
3450		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
3451		assert(DAMAGE_IS_ALL(priv->cpu_damage));
3452		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */
3453		assert(!priv->pinned);
3454		assert(!priv->mapped);
3455		sna_damage_destroy(&priv->gpu_damage);
3456		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
3457		priv->gpu_bo = NULL;
3458	}
3459
3460	sna_damage_reduce(&priv->cpu_damage);
3461	assert_pixmap_damage(pixmap);
3462
3463	if (priv->cpu_damage == NULL) {
3464		list_del(&priv->flush_list);
3465		return sna_pixmap_move_to_gpu(pixmap, MOVE_READ | flags);
3466	}
3467
3468	if (priv->gpu_bo == NULL) {
3469		assert(priv->gpu_damage == NULL);
3470
3471		if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU)
3472			sna_pixmap_alloc_gpu(sna, pixmap, priv, CREATE_INACTIVE);
3473
3474		if (priv->gpu_bo == NULL)
3475			return NULL;
3476
3477		DBG(("%s: created gpu bo\n", __FUNCTION__));
3478	}
3479
3480	if (priv->gpu_bo->proxy) {
3481		DBG(("%s: reusing cached upload\n", __FUNCTION__));
3482		assert((flags & MOVE_WRITE) == 0);
3483		assert(priv->gpu_damage == NULL);
3484		return priv;
3485	}
3486
3487	add_shm_flush(sna, priv);
3488
3489	assert(priv->cpu_damage);
3490	region_set(&r, box);
3491	if (MIGRATE_ALL || region_subsumes_damage(&r, priv->cpu_damage)) {
3492		bool ok = false;
3493		int n;
3494
3495		n = sna_damage_get_boxes(priv->cpu_damage, &box);
3496		assert(n);
3497		if (use_cpu_bo_for_upload(sna, priv, 0)) {
3498			DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__));
3499			ok = sna->render.copy_boxes(sna, GXcopy,
3500						    &pixmap->drawable, priv->cpu_bo, 0, 0,
3501						    &pixmap->drawable, priv->gpu_bo, 0, 0,
3502						    box, n, 0);
3503		}
3504		if (!ok) {
3505			sna_pixmap_unmap(pixmap, priv);
3506			if (pixmap->devPrivate.ptr == NULL)
3507				return NULL;
3508
3509			assert(pixmap->devKind);
3510			if (n == 1 && !priv->pinned &&
3511			    box->x1 <= 0 && box->y1 <= 0 &&
3512			    box->x2 >= pixmap->drawable.width &&
3513			    box->y2 >= pixmap->drawable.height) {
3514				ok = sna_replace(sna, pixmap,
3515						 pixmap->devPrivate.ptr,
3516						 pixmap->devKind);
3517			} else {
3518				ok = sna_write_boxes(sna, pixmap,
3519						     priv->gpu_bo, 0, 0,
3520						     pixmap->devPrivate.ptr,
3521						     pixmap->devKind,
3522						     0, 0,
3523						     box, n);
3524			}
3525			if (!ok)
3526				return NULL;
3527		}
3528
3529		sna_damage_destroy(&priv->cpu_damage);
3530	} else if (DAMAGE_IS_ALL(priv->cpu_damage) ||
3531		   sna_damage_contains_box__no_reduce(priv->cpu_damage, box)) {
3532		bool ok = false;
3533
3534		assert(sna_damage_contains_box(&priv->gpu_damage, box) == PIXMAN_REGION_OUT);
3535		assert(sna_damage_contains_box(&priv->cpu_damage, box) == PIXMAN_REGION_IN);
3536
3537		if (use_cpu_bo_for_upload(sna, priv, 0)) {
3538			DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__));
3539			ok = sna->render.copy_boxes(sna, GXcopy,
3540						    &pixmap->drawable, priv->cpu_bo, 0, 0,
3541						    &pixmap->drawable, priv->gpu_bo, 0, 0,
3542						    box, 1, 0);
3543		}
3544		if (!ok) {
3545			sna_pixmap_unmap(pixmap, priv);
3546			if (pixmap->devPrivate.ptr != NULL) {
3547				assert(pixmap->devKind);
3548				ok = sna_write_boxes(sna, pixmap,
3549						priv->gpu_bo, 0, 0,
3550						pixmap->devPrivate.ptr,
3551						pixmap->devKind,
3552						0, 0,
3553						box, 1);
3554			}
3555		}
3556		if (!ok)
3557			return NULL;
3558
3559		sna_damage_subtract(&priv->cpu_damage, &r);
3560	} else if (sna_damage_intersect(priv->cpu_damage, &r, &i)) {
3561		int n = region_num_rects(&i);
3562		bool ok;
3563
3564		box = region_rects(&i);
3565		ok = false;
3566		if (use_cpu_bo_for_upload(sna, priv, 0)) {
3567			DBG(("%s: using CPU bo for upload to GPU, %d boxes\n", __FUNCTION__, n));
3568			ok = sna->render.copy_boxes(sna, GXcopy,
3569						    &pixmap->drawable, priv->cpu_bo, 0, 0,
3570						    &pixmap->drawable, priv->gpu_bo, 0, 0,
3571						    box, n, 0);
3572		}
3573		if (!ok) {
3574			sna_pixmap_unmap(pixmap, priv);
3575			if (pixmap->devPrivate.ptr != NULL) {
3576				assert(pixmap->devKind);
3577				ok = sna_write_boxes(sna, pixmap,
3578						priv->gpu_bo, 0, 0,
3579						pixmap->devPrivate.ptr,
3580						pixmap->devKind,
3581						0, 0,
3582						box, n);
3583			}
3584		}
3585		if (!ok)
3586			return NULL;
3587
3588		sna_damage_subtract(&priv->cpu_damage, &r);
3589		RegionUninit(&i);
3590	}
3591
3592done:
3593	if (priv->cpu_damage == NULL && priv->flush)
3594		list_del(&priv->flush_list);
3595	if (flags & MOVE_WRITE) {
3596		priv->clear = false;
3597		if (!DAMAGE_IS_ALL(priv->gpu_damage) &&
3598		    priv->cpu_damage == NULL &&
3599		    (box_covers_pixmap(pixmap, &r.extents) ||
3600		     box_inplace(pixmap, &r.extents))) {
3601			DBG(("%s: large operation on undamaged, discarding CPU shadow\n",
3602			     __FUNCTION__));
3603			assert(priv->gpu_bo);
3604			assert(priv->gpu_bo->proxy == NULL);
3605			if (sna_pixmap_free_cpu(sna, priv, priv->cpu)) {
3606				DBG(("%s: large operation on undamaged, promoting to full GPU\n",
3607				     __FUNCTION__));
3608				sna_damage_all(&priv->gpu_damage, pixmap);
3609			}
3610		}
3611		if (DAMAGE_IS_ALL(priv->gpu_damage)) {
3612			sna_pixmap_free_cpu(sna, priv, priv->cpu);
3613			sna_damage_destroy(&priv->cpu_damage);
3614			list_del(&priv->flush_list);
3615		}
3616		priv->cpu = false;
3617	}
3618
3619	assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0);
3620	return sna_pixmap_mark_active(sna, priv);
3621}
3622
3623struct kgem_bo *
3624sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box,
3625		    struct sna_damage ***damage)
3626{
3627	PixmapPtr pixmap = get_drawable_pixmap(drawable);
3628	struct sna_pixmap *priv = sna_pixmap(pixmap);
3629	struct sna *sna;
3630	RegionRec region;
3631	int16_t dx, dy;
3632	int ret;
3633
3634	DBG(("%s pixmap=%ld, box=((%d, %d), (%d, %d)), flags=%x...\n",
3635	     __FUNCTION__,
3636	     pixmap->drawable.serialNumber,
3637	     box->x1, box->y1, box->x2, box->y2,
3638	     flags));
3639
3640	assert(box->x2 > box->x1 && box->y2 > box->y1);
3641	assert(pixmap->refcnt);
3642	assert_pixmap_damage(pixmap);
3643	assert_drawable_contains_box(drawable, box);
3644
3645	if (priv == NULL) {
3646		DBG(("%s: not attached\n", __FUNCTION__));
3647		return NULL;
3648	}
3649
3650	if (priv->cow) {
3651		unsigned cow = MOVE_WRITE | MOVE_READ | __MOVE_FORCE;
3652		assert(cow);
3653
3654		if (flags & IGNORE_DAMAGE) {
3655			if (priv->gpu_damage) {
3656				region.extents = *box;
3657				if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3658					region.extents.x1 += dx;
3659					region.extents.x2 += dx;
3660					region.extents.y1 += dy;
3661					region.extents.y2 += dy;
3662				}
3663				region.data = NULL;
3664				if (region_subsumes_damage(&region,
3665							   priv->gpu_damage))
3666					cow &= ~MOVE_READ;
3667			} else
3668				cow &= ~MOVE_READ;
3669		}
3670
3671		if (!sna_pixmap_undo_cow(to_sna_from_pixmap(pixmap), priv, cow))
3672			return NULL;
3673
3674		if (priv->gpu_bo == NULL)
3675			sna_damage_destroy(&priv->gpu_damage);
3676	}
3677
3678	if (kgem_bo_discard_cache(priv->gpu_bo, true)) {
3679		DBG(("%s: cached upload proxy, discard and revert to GPU\n", __FUNCTION__));
3680		assert(DAMAGE_IS_ALL(priv->cpu_damage));
3681		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */
3682		assert(!priv->pinned);
3683		assert(!priv->mapped);
3684		sna_damage_destroy(&priv->gpu_damage);
3685		kgem_bo_destroy(&to_sna_from_pixmap(pixmap)->kgem,
3686				priv->gpu_bo);
3687		priv->gpu_bo = NULL;
3688		goto use_cpu_bo;
3689	}
3690
3691	if (priv->flush) {
3692		DBG(("%s: exported target, set PREFER_GPU\n", __FUNCTION__));
3693		flags |= PREFER_GPU;
3694	}
3695	if (priv->shm) {
3696		DBG(("%s: shm target, discard PREFER_GPU\n", __FUNCTION__));
3697		flags &= ~PREFER_GPU;
3698	}
3699	if (priv->pinned) {
3700		DBG(("%s: pinned, never REPLACES\n", __FUNCTION__));
3701		flags &= ~REPLACES;
3702	}
3703	if (priv->cpu && (flags & (FORCE_GPU | IGNORE_DAMAGE)) == 0) {
3704		DBG(("%s: last on cpu and needs damage, discard PREFER_GPU\n", __FUNCTION__));
3705		flags &= ~PREFER_GPU;
3706	}
3707
3708	if ((flags & (PREFER_GPU | IGNORE_DAMAGE)) == IGNORE_DAMAGE) {
3709		if (priv->gpu_bo && (box_covers_pixmap(pixmap, box) || box_inplace(pixmap, box))) {
3710			DBG(("%s: not reading damage and large, set PREFER_GPU\n", __FUNCTION__));
3711			flags |= PREFER_GPU;
3712		}
3713	}
3714
3715	DBG(("%s: flush=%d, shm=%d, cpu=%d => flags=%x\n",
3716	     __FUNCTION__, priv->flush, priv->shm, priv->cpu, flags));
3717
3718	if ((flags & PREFER_GPU) == 0 &&
3719	    (flags & (REPLACES | IGNORE_DAMAGE) || !priv->gpu_damage || !kgem_bo_is_busy(priv->gpu_bo))) {
3720		DBG(("%s: try cpu as GPU bo is idle\n", __FUNCTION__));
3721		goto use_cpu_bo;
3722	}
3723
3724	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
3725		DBG(("%s: use GPU fast path (all-damaged)\n", __FUNCTION__));
3726		assert(priv->cpu_damage == NULL);
3727		assert(priv->gpu_bo);
3728		assert(priv->gpu_bo->proxy == NULL);
3729		goto use_gpu_bo;
3730	}
3731
3732	if (DAMAGE_IS_ALL(priv->cpu_damage)) {
3733		assert(priv->gpu_damage == NULL);
3734		if ((flags & FORCE_GPU) == 0 || priv->cpu_bo) {
3735			DBG(("%s: use CPU fast path (all-damaged), and not forced-gpu\n",
3736			     __FUNCTION__));
3737			goto use_cpu_bo;
3738		}
3739	}
3740
3741	DBG(("%s: gpu? %d, damaged? %d; cpu? %d, damaged? %d\n", __FUNCTION__,
3742	     priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->gpu_damage != NULL,
3743	     priv->cpu_bo ? priv->cpu_bo->handle : 0, priv->cpu_damage != NULL));
3744	if (priv->gpu_bo == NULL) {
3745		unsigned int move;
3746
3747		if ((flags & FORCE_GPU) == 0 &&
3748		    (priv->create & KGEM_CAN_CREATE_GPU) == 0) {
3749			DBG(("%s: untiled, will not force allocation\n",
3750			     __FUNCTION__));
3751			goto use_cpu_bo;
3752		}
3753
3754		if ((flags & IGNORE_DAMAGE) == 0) {
3755			if (priv->cpu_bo) {
3756				if (to_sna_from_pixmap(pixmap)->kgem.can_blt_cpu) {
3757					if (kgem_bo_is_busy(priv->cpu_bo)) {
3758						DBG(("%s: already using CPU bo, will not force allocation\n",
3759						     __FUNCTION__));
3760						goto use_cpu_bo;
3761					}
3762
3763					if ((flags & RENDER_GPU) == 0) {
3764						DBG(("%s: prefer cpu", __FUNCTION__));
3765						goto use_cpu_bo;
3766					}
3767				} else {
3768					if (kgem_bo_is_busy(priv->cpu_bo)) {
3769						DBG(("%s: CPU bo active, must force allocation\n",
3770						     __FUNCTION__));
3771						goto create_gpu_bo;
3772					}
3773				}
3774			}
3775
3776			if ((flags & FORCE_GPU) == 0 && priv->cpu_damage) {
3777				if ((flags & PREFER_GPU) == 0) {
3778					DBG(("%s: already damaged and prefer cpu",
3779					     __FUNCTION__));
3780					goto use_cpu_bo;
3781				}
3782
3783				if (!box_inplace(pixmap, box)) {
3784					DBG(("%s: damaged with a small operation, will not force allocation\n",
3785					     __FUNCTION__));
3786					goto use_cpu_bo;
3787				}
3788			}
3789		} else if (priv->cpu_damage) {
3790			region.extents = *box;
3791			if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3792				region.extents.x1 += dx;
3793				region.extents.x2 += dx;
3794				region.extents.y1 += dy;
3795				region.extents.y2 += dy;
3796			}
3797			region.data = NULL;
3798
3799			sna_damage_subtract(&priv->cpu_damage, &region);
3800			if (priv->cpu_damage == NULL) {
3801				list_del(&priv->flush_list);
3802				priv->cpu = false;
3803			}
3804		}
3805
3806create_gpu_bo:
3807		move = MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT;
3808		if (flags & FORCE_GPU)
3809			move |= __MOVE_FORCE;
3810		if (!sna_pixmap_move_to_gpu(pixmap, move))
3811			goto use_cpu_bo;
3812
3813		DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__));
3814		goto done;
3815	}
3816
3817
3818	region.extents = *box;
3819	if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3820		region.extents.x1 += dx;
3821		region.extents.x2 += dx;
3822		region.extents.y1 += dy;
3823		region.extents.y2 += dy;
3824	}
3825	region.data = NULL;
3826
3827	DBG(("%s extents (%d, %d), (%d, %d)\n", __FUNCTION__,
3828	     region.extents.x1, region.extents.y1,
3829	     region.extents.x2, region.extents.y2));
3830
3831	if (priv->gpu_damage) {
3832		assert(priv->gpu_bo);
3833		if (!priv->cpu_damage || flags & IGNORE_DAMAGE) {
3834			if (flags & REPLACES || box_covers_pixmap(pixmap, &region.extents)) {
3835				unsigned int move;
3836
3837				if (flags & IGNORE_DAMAGE)
3838					move = MOVE_WRITE;
3839				else
3840					move = MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT;
3841
3842				if (sna_pixmap_move_to_gpu(pixmap, move)) {
3843					sna_damage_all(&priv->gpu_damage,
3844						       pixmap);
3845					goto use_gpu_bo;
3846				}
3847			}
3848
3849			if (DAMAGE_IS_ALL(priv->gpu_damage) ||
3850			    sna_damage_contains_box__no_reduce(priv->gpu_damage,
3851							       &region.extents)) {
3852				DBG(("%s: region wholly contained within GPU damage\n",
3853				     __FUNCTION__));
3854				assert(sna_damage_contains_box(&priv->gpu_damage, &region.extents) == PIXMAN_REGION_IN);
3855				assert(sna_damage_contains_box(&priv->cpu_damage, &region.extents) == PIXMAN_REGION_OUT);
3856				goto use_gpu_bo;
3857			} else {
3858				DBG(("%s: partial GPU damage with no CPU damage, continuing to use GPU\n",
3859				     __FUNCTION__));
3860				goto move_to_gpu;
3861			}
3862		}
3863
3864		ret = sna_damage_contains_box(&priv->gpu_damage, &region.extents);
3865		if (ret == PIXMAN_REGION_IN) {
3866			DBG(("%s: region wholly contained within GPU damage\n",
3867			     __FUNCTION__));
3868			goto use_gpu_bo;
3869		}
3870
3871		if (ret != PIXMAN_REGION_OUT) {
3872			DBG(("%s: region partially contained within GPU damage\n",
3873			     __FUNCTION__));
3874			goto move_to_gpu;
3875		}
3876	}
3877
3878	if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_damage) {
3879		ret = sna_damage_contains_box(&priv->cpu_damage, &region.extents);
3880		if (ret == PIXMAN_REGION_IN) {
3881			DBG(("%s: region wholly contained within CPU damage\n",
3882			     __FUNCTION__));
3883			goto use_cpu_bo;
3884		}
3885
3886		if (box_inplace(pixmap, box)) {
3887			DBG(("%s: forcing inplace\n", __FUNCTION__));
3888			goto move_to_gpu;
3889		}
3890
3891		if (ret != PIXMAN_REGION_OUT) {
3892			DBG(("%s: region partially contained within CPU damage\n",
3893			     __FUNCTION__));
3894			goto use_cpu_bo;
3895		}
3896	}
3897
3898move_to_gpu:
3899	if (!sna_pixmap_move_area_to_gpu(pixmap, &region.extents,
3900					 flags & IGNORE_DAMAGE ? MOVE_WRITE : MOVE_READ | MOVE_WRITE)) {
3901		DBG(("%s: failed to move-to-gpu, fallback\n", __FUNCTION__));
3902		assert(priv->gpu_bo == NULL);
3903		goto use_cpu_bo;
3904	}
3905
3906done:
3907	assert(priv->move_to_gpu == NULL);
3908	assert(priv->gpu_bo != NULL);
3909	assert(priv->gpu_bo->refcnt);
3910	if (sna_damage_is_all(&priv->gpu_damage,
3911			      pixmap->drawable.width,
3912			      pixmap->drawable.height)) {
3913		sna_damage_destroy(&priv->cpu_damage);
3914		list_del(&priv->flush_list);
3915		*damage = NULL;
3916	} else
3917		*damage = &priv->gpu_damage;
3918
3919	DBG(("%s: using GPU bo with damage? %d\n",
3920	     __FUNCTION__, *damage != NULL));
3921	assert(*damage == NULL || !DAMAGE_IS_ALL(*damage));
3922	assert(priv->gpu_bo->proxy == NULL);
3923	assert(priv->clear == false);
3924	assert(priv->cpu == false);
3925	assert(!priv->shm);
3926	return priv->gpu_bo;
3927
3928use_gpu_bo:
3929	if (priv->move_to_gpu) {
3930		unsigned hint = MOVE_READ | MOVE_WRITE;
3931
3932		sna = to_sna_from_pixmap(pixmap);
3933
3934		DBG(("%s: applying move-to-gpu override\n", __FUNCTION__));
3935		if (flags & IGNORE_DAMAGE) {
3936			region.extents = *box;
3937			region.data = NULL;
3938			if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3939				region.extents.x1 += dx;
3940				region.extents.x2 += dx;
3941				region.extents.y1 += dy;
3942				region.extents.y2 += dy;
3943			}
3944			sna_pixmap_discard_shadow_damage(priv, &region);
3945			if (region_subsumes_pixmap(&region, pixmap)) {
3946				DBG(("%s: discarding move-to-gpu READ for subsumed pixmap\n", __FUNCTION__));
3947				hint = MOVE_WRITE;
3948			}
3949		}
3950
3951		if (!priv->move_to_gpu(sna, priv, hint)) {
3952			DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
3953			goto use_cpu_bo;
3954		}
3955	}
3956
3957	if (priv->shm) {
3958		assert(!priv->flush);
3959		list_move(&priv->flush_list, &sna->flush_pixmaps);
3960	}
3961
3962	DBG(("%s: using whole GPU bo\n", __FUNCTION__));
3963	assert(priv->gpu_bo != NULL);
3964	assert(priv->gpu_bo->refcnt);
3965	assert(priv->gpu_bo->proxy == NULL);
3966	assert(priv->gpu_damage);
3967	priv->cpu = false;
3968	priv->clear = false;
3969	*damage = NULL;
3970	return priv->gpu_bo;
3971
3972use_cpu_bo:
3973	if (!USE_CPU_BO || priv->cpu_bo == NULL) {
3974		if ((flags & FORCE_GPU) == 0) {
3975			DBG(("%s: no CPU bo, and GPU not forced\n", __FUNCTION__));
3976			return NULL;
3977		}
3978
3979		flags &= ~FORCE_GPU;
3980
3981		region.extents = *box;
3982		if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3983			region.extents.x1 += dx;
3984			region.extents.x2 += dx;
3985			region.extents.y1 += dy;
3986			region.extents.y2 += dy;
3987		}
3988		region.data = NULL;
3989
3990		if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, &region,
3991						     (flags & IGNORE_DAMAGE ? 0 : MOVE_READ) | MOVE_WRITE | MOVE_ASYNC_HINT) ||
3992		    priv->cpu_bo == NULL) {
3993			DBG(("%s: did not create CPU bo\n", __FUNCTION__));
3994cpu_fail:
3995			if (priv->gpu_bo)
3996				goto move_to_gpu;
3997
3998			return NULL;
3999		}
4000	}
4001
4002	assert(priv->cpu_bo->refcnt);
4003
4004	sna = to_sna_from_pixmap(pixmap);
4005	if ((flags & FORCE_GPU) == 0 &&
4006	    !__kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
4007		DBG(("%s: has CPU bo, but is idle and acceleration not forced\n",
4008		     __FUNCTION__));
4009		return NULL;
4010	}
4011
4012	region.extents = *box;
4013	if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
4014		region.extents.x1 += dx;
4015		region.extents.x2 += dx;
4016		region.extents.y1 += dy;
4017		region.extents.y2 += dy;
4018	}
4019	region.data = NULL;
4020
4021	if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) {
4022		DBG(("%s: both CPU and GPU are busy, prefer to use the GPU\n",
4023		     __FUNCTION__));
4024		goto move_to_gpu;
4025	}
4026
4027	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
4028
4029	if (flags & RENDER_GPU) {
4030		flags &= ~RENDER_GPU;
4031
4032		if ((flags & IGNORE_DAMAGE) == 0 && priv->gpu_damage) {
4033			DBG(("%s: prefer to use GPU bo for rendering whilst reading from GPU damage\n", __FUNCTION__));
4034
4035prefer_gpu_bo:
4036			if (priv->gpu_bo == NULL) {
4037				if ((flags & FORCE_GPU) == 0) {
4038					DBG(("%s: untiled, will not force allocation\n",
4039					     __FUNCTION__));
4040					return NULL;
4041				}
4042
4043				if (flags & IGNORE_DAMAGE) {
4044					sna_damage_subtract(&priv->cpu_damage, &region);
4045					if (priv->cpu_damage == NULL) {
4046						list_del(&priv->flush_list);
4047						priv->cpu = false;
4048					}
4049				}
4050
4051				if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE))
4052					return NULL;
4053
4054				sna_damage_all(&priv->gpu_damage, pixmap);
4055
4056				DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__));
4057				goto done;
4058			}
4059			goto move_to_gpu;
4060		}
4061
4062		if (!priv->shm) {
4063			if ((priv->cpu_damage == NULL || flags & IGNORE_DAMAGE)) {
4064				if (priv->gpu_bo && priv->gpu_bo->tiling) {
4065					DBG(("%s: prefer to use GPU bo for rendering large pixmaps\n", __FUNCTION__));
4066					goto prefer_gpu_bo;
4067				}
4068
4069				if (priv->cpu_bo->pitch >= 4096) {
4070					DBG(("%s: prefer to use GPU bo for rendering wide pixmaps\n", __FUNCTION__));
4071					goto prefer_gpu_bo;
4072				}
4073			}
4074
4075			if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_bo->snoop) {
4076				DBG(("%s: prefer to use GPU bo for reading from snooped target bo\n", __FUNCTION__));
4077				goto prefer_gpu_bo;
4078			}
4079
4080			if (!sna->kgem.can_blt_cpu) {
4081				DBG(("%s: can't render to CPU bo, try to use GPU bo\n", __FUNCTION__));
4082				goto prefer_gpu_bo;
4083			}
4084		}
4085	}
4086
4087	if (!sna->kgem.can_blt_cpu)
4088		goto cpu_fail;
4089
4090	if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, &region,
4091					     (flags & IGNORE_DAMAGE ? 0 : MOVE_READ) | MOVE_WRITE | MOVE_ASYNC_HINT)) {
4092		DBG(("%s: failed to move-to-cpu, fallback\n", __FUNCTION__));
4093		goto cpu_fail;
4094	}
4095
4096	if (priv->shm) {
4097		add_shm_flush(sna, priv);
4098		/* As we may have flushed and retired,, recheck for busy bo */
4099		if ((flags & FORCE_GPU) == 0 && !kgem_bo_is_busy(priv->cpu_bo))
4100			return NULL;
4101	}
4102	if (priv->flush) {
4103		assert(!priv->shm);
4104		sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
4105	}
4106
4107	if (sna_damage_is_all(&priv->cpu_damage,
4108			      pixmap->drawable.width,
4109			      pixmap->drawable.height)) {
4110		sna_damage_destroy(&priv->gpu_damage);
4111		*damage = NULL;
4112	} else {
4113		assert(!DAMAGE_IS_ALL(priv->cpu_damage));
4114		if (priv->cpu_damage &&
4115		    sna_damage_contains_box__no_reduce(priv->cpu_damage,
4116						       &region.extents)) {
4117			assert(sna_damage_contains_box(&priv->gpu_damage, &region.extents) == PIXMAN_REGION_OUT);
4118			assert(sna_damage_contains_box(&priv->cpu_damage, &region.extents) == PIXMAN_REGION_IN);
4119			*damage = NULL;
4120		} else
4121			*damage = &priv->cpu_damage;
4122	}
4123
4124	DBG(("%s: using CPU bo with damage? %d\n",
4125	     __FUNCTION__, *damage != NULL));
4126	assert(damage == NULL || !DAMAGE_IS_ALL(*damage));
4127	assert(priv->clear == false);
4128	priv->cpu = false;
4129	return priv->cpu_bo;
4130}
4131
4132PixmapPtr
4133sna_pixmap_create_upload(ScreenPtr screen,
4134			 int width, int height, int depth,
4135			 unsigned flags)
4136{
4137	struct sna *sna = to_sna_from_screen(screen);
4138	PixmapPtr pixmap;
4139	struct sna_pixmap *priv;
4140	void *ptr;
4141
4142	DBG(("%s(%d, %d, %d, flags=%x)\n", __FUNCTION__,
4143	     width, height, depth, flags));
4144	assert(width);
4145	assert(height);
4146
4147	if (depth < 8)
4148		return create_pixmap(sna, screen, width, height, depth,
4149				     CREATE_PIXMAP_USAGE_SCRATCH);
4150
4151	pixmap = create_pixmap_hdr(sna, screen,
4152				   width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH,
4153				   &priv);
4154	if (!pixmap)
4155		return NullPixmap;
4156
4157	priv->gpu_bo = kgem_create_buffer_2d(&sna->kgem,
4158					     width, height,
4159					     pixmap->drawable.bitsPerPixel,
4160					     flags, &ptr);
4161	if (!priv->gpu_bo) {
4162		free(priv);
4163		FreePixmap(pixmap);
4164		return NullPixmap;
4165	}
4166
4167	/* Marking both the shadow and the GPU bo is a little dubious,
4168	 * but will work so long as we always check before doing the
4169	 * transfer.
4170	 */
4171	sna_damage_all(&priv->gpu_damage, pixmap);
4172	sna_damage_all(&priv->cpu_damage, pixmap);
4173
4174	pixmap->devKind = priv->gpu_bo->pitch;
4175	pixmap->devPrivate.ptr = ptr;
4176	priv->ptr = MAKE_STATIC_PTR(ptr);
4177	priv->stride = priv->gpu_bo->pitch;
4178	priv->create = 0;
4179
4180	pixmap->usage_hint = 0;
4181	if (!kgem_buffer_is_inplace(priv->gpu_bo))
4182		pixmap->usage_hint = 1;
4183
4184	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
4185	     __FUNCTION__,
4186	     pixmap->drawable.serialNumber,
4187	     pixmap->drawable.width,
4188	     pixmap->drawable.height,
4189	     pixmap->usage_hint));
4190	return pixmap;
4191}
4192
4193static bool can_convert_to_gpu(struct sna_pixmap *priv, unsigned flags)
4194{
4195	assert(priv->gpu_bo == NULL);
4196
4197	if (priv->cpu_bo == NULL)
4198		return false;
4199
4200	if (priv->shm)
4201		return false;
4202
4203	/* Linear scanout have a restriction that their pitch must be
4204	 * 64 byte aligned. Force the creation of a proper GPU bo if
4205	 * this CPU bo is not suitable for scanout.
4206	 */
4207	if (priv->pixmap->usage_hint == SNA_CREATE_FB || flags & __MOVE_SCANOUT)
4208		if (priv->cpu_bo->pitch & 63)
4209			return false;
4210
4211	if (flags & __MOVE_PRIME)
4212		if (priv->cpu_bo->pitch & 255)
4213			return false;
4214
4215	return true;
4216}
4217
4218struct sna_pixmap *
4219sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
4220{
4221	struct sna *sna = to_sna_from_pixmap(pixmap);
4222	struct sna_pixmap *priv;
4223	const BoxRec *box;
4224	int n;
4225
4226	DBG(("%s(pixmap=%ld, usage=%d), flags=%x\n",
4227	     __FUNCTION__,
4228	     pixmap->drawable.serialNumber,
4229	     pixmap->usage_hint,
4230	     flags));
4231
4232	priv = __sna_pixmap_for_gpu(sna, pixmap, flags);
4233	if (priv == NULL)
4234		return NULL;
4235
4236	assert_pixmap_damage(pixmap);
4237
4238	if (priv->move_to_gpu &&
4239	    !priv->move_to_gpu(sna, priv, flags | ((priv->cpu_damage && (flags & MOVE_READ)) ? MOVE_WRITE : 0))) {
4240		DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
4241		return NULL;
4242	}
4243
4244	if ((flags & MOVE_READ) == 0 && UNDO)
4245		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
4246
4247	if (priv->cow) {
4248		unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE);
4249		assert(cow);
4250		if (flags & MOVE_READ && priv->cpu_damage)
4251			cow |= MOVE_WRITE;
4252		if (!sna_pixmap_undo_cow(sna, priv, cow))
4253			return NULL;
4254
4255		if (priv->gpu_bo == NULL)
4256			sna_damage_destroy(&priv->gpu_damage);
4257	}
4258
4259	if (sna_damage_is_all(&priv->gpu_damage,
4260			      pixmap->drawable.width,
4261			      pixmap->drawable.height)) {
4262		DBG(("%s: already all-damaged\n", __FUNCTION__));
4263		sna_pixmap_unclean(sna, priv, flags);
4264		goto active;
4265	}
4266
4267	if ((flags & MOVE_READ) == 0)
4268		sna_damage_destroy(&priv->cpu_damage);
4269
4270	sna_damage_reduce(&priv->cpu_damage);
4271	assert_pixmap_damage(pixmap);
4272	DBG(("%s: CPU damage? %d\n", __FUNCTION__, priv->cpu_damage != NULL));
4273	if (priv->gpu_bo == NULL ||
4274	    kgem_bo_discard_cache(priv->gpu_bo, flags & (MOVE_WRITE | __MOVE_FORCE))) {
4275		struct kgem_bo *proxy;
4276
4277		proxy = priv->gpu_bo;
4278		priv->gpu_bo = NULL;
4279
4280		DBG(("%s: creating GPU bo (%dx%d@%d), create=%x\n",
4281		     __FUNCTION__,
4282		     pixmap->drawable.width,
4283		     pixmap->drawable.height,
4284		     pixmap->drawable.bitsPerPixel,
4285		     priv->create));
4286		assert(!priv->mapped);
4287		assert(list_is_empty(&priv->flush_list));
4288
4289		if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU) {
4290			bool is_linear;
4291
4292			assert(pixmap->drawable.width > 0);
4293			assert(pixmap->drawable.height > 0);
4294			assert(pixmap->drawable.bitsPerPixel >= 8);
4295
4296			if (flags & __MOVE_PRIME) {
4297				assert((flags & __MOVE_TILED) == 0);
4298				is_linear = true;
4299			} else {
4300				is_linear = sna_pixmap_default_tiling(sna, pixmap) == I915_TILING_NONE;
4301				if (is_linear && flags & __MOVE_TILED) {
4302					DBG(("%s: not creating linear GPU bo\n",
4303					     __FUNCTION__));
4304					return NULL;
4305				}
4306			}
4307
4308			if (is_linear &&
4309			    can_convert_to_gpu(priv, flags) &&
4310			    kgem_bo_convert_to_gpu(&sna->kgem, priv->cpu_bo, flags)) {
4311				assert(!priv->mapped);
4312				assert(!IS_STATIC_PTR(priv->ptr));
4313#ifdef DEBUG_MEMORY
4314				sna->debug_memory.cpu_bo_allocs--;
4315				sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
4316#endif
4317				priv->gpu_bo = priv->cpu_bo;
4318				priv->cpu_bo = NULL;
4319				priv->ptr = NULL;
4320				pixmap->devPrivate.ptr = NULL;
4321				sna_damage_all(&priv->gpu_damage, pixmap);
4322				sna_damage_destroy(&priv->cpu_damage);
4323			} else {
4324				unsigned create = 0;
4325				if (flags & MOVE_INPLACE_HINT || (priv->cpu_damage && priv->cpu_bo == NULL))
4326					create = CREATE_GTT_MAP | CREATE_INACTIVE;
4327				if (flags & __MOVE_PRIME)
4328					create |= CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT;
4329
4330				sna_pixmap_alloc_gpu(sna, pixmap, priv, create);
4331			}
4332		}
4333
4334		if (priv->gpu_bo == NULL) {
4335			DBG(("%s: not creating GPU bo\n", __FUNCTION__));
4336			assert(priv->gpu_damage == NULL);
4337			priv->gpu_bo = proxy;
4338			if (proxy)
4339				sna_damage_all(&priv->cpu_damage, pixmap);
4340			return NULL;
4341		}
4342
4343		if (proxy) {
4344			DBG(("%s: promoting upload proxy handle=%d to GPU\n", __FUNCTION__, proxy->handle));
4345
4346			if (priv->cpu_damage &&
4347			    sna->render.copy_boxes(sna, GXcopy,
4348						   &pixmap->drawable, proxy, 0, 0,
4349						   &pixmap->drawable, priv->gpu_bo, 0, 0,
4350						   region_rects(DAMAGE_REGION(priv->cpu_damage)),
4351						   region_num_rects(DAMAGE_REGION(priv->cpu_damage)),
4352						   0))
4353				sna_damage_destroy(&priv->cpu_damage);
4354
4355			kgem_bo_destroy(&sna->kgem, proxy);
4356		}
4357
4358		if (flags & MOVE_WRITE && priv->cpu_damage == NULL) {
4359			/* Presume that we will only ever write to the GPU
4360			 * bo. Readbacks are expensive but fairly constant
4361			 * in cost for all sizes i.e. it is the act of
4362			 * synchronisation that takes the most time. This is
4363			 * mitigated by avoiding fallbacks in the first place.
4364			 */
4365			assert(priv->gpu_bo);
4366			assert(priv->gpu_bo->proxy == NULL);
4367			sna_damage_all(&priv->gpu_damage, pixmap);
4368			DBG(("%s: marking as all-damaged for GPU\n",
4369			     __FUNCTION__));
4370			goto active;
4371		}
4372	}
4373
4374	if (priv->gpu_bo->proxy) {
4375		DBG(("%s: reusing cached upload\n", __FUNCTION__));
4376		assert((flags & MOVE_WRITE) == 0);
4377		assert(priv->gpu_damage == NULL);
4378		return priv;
4379	}
4380
4381	if (priv->cpu_damage == NULL)
4382		goto done;
4383
4384	if (DAMAGE_IS_ALL(priv->cpu_damage) && priv->cpu_bo &&
4385	    !priv->pinned && !priv->shm &&
4386	    priv->gpu_bo->tiling == I915_TILING_NONE &&
4387	    kgem_bo_convert_to_gpu(&sna->kgem, priv->cpu_bo, flags)) {
4388		assert(!priv->mapped);
4389		assert(!IS_STATIC_PTR(priv->ptr));
4390#ifdef DEBUG_MEMORY
4391		sna->debug_memory.cpu_bo_allocs--;
4392		sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
4393#endif
4394		sna_pixmap_free_gpu(sna, priv);
4395		priv->gpu_bo = priv->cpu_bo;
4396		priv->cpu_bo = NULL;
4397		priv->ptr = NULL;
4398		pixmap->devPrivate.ptr = NULL;
4399		sna_damage_all(&priv->gpu_damage, pixmap);
4400		sna_damage_destroy(&priv->cpu_damage);
4401		goto done;
4402	}
4403
4404	add_shm_flush(sna, priv);
4405
4406	n = sna_damage_get_boxes(priv->cpu_damage, &box);
4407	assert(n);
4408	if (n) {
4409		bool ok;
4410
4411		assert_pixmap_contains_damage(pixmap, priv->cpu_damage);
4412		DBG(("%s: uploading %d damage boxes\n", __FUNCTION__, n));
4413
4414		ok = false;
4415		if (use_cpu_bo_for_upload(sna, priv, flags)) {
4416			DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__));
4417			ok = sna->render.copy_boxes(sna, GXcopy,
4418						    &pixmap->drawable, priv->cpu_bo, 0, 0,
4419						    &pixmap->drawable, priv->gpu_bo, 0, 0,
4420						    box, n, 0);
4421		}
4422		if (!ok) {
4423			sna_pixmap_unmap(pixmap, priv);
4424			if (pixmap->devPrivate.ptr == NULL)
4425				return NULL;
4426
4427			assert(pixmap->devKind);
4428			if (n == 1 && !priv->pinned &&
4429			    (box->x2 - box->x1) >= pixmap->drawable.width &&
4430			    (box->y2 - box->y1) >= pixmap->drawable.height) {
4431				ok = sna_replace(sna, pixmap,
4432						 pixmap->devPrivate.ptr,
4433						 pixmap->devKind);
4434			} else {
4435				ok = sna_write_boxes(sna, pixmap,
4436						     priv->gpu_bo, 0, 0,
4437						     pixmap->devPrivate.ptr,
4438						     pixmap->devKind,
4439						     0, 0,
4440						     box, n);
4441			}
4442			if (!ok)
4443				return NULL;
4444		}
4445	}
4446
4447	__sna_damage_destroy(DAMAGE_PTR(priv->cpu_damage));
4448	priv->cpu_damage = NULL;
4449
4450	/* For large bo, try to keep only a single copy around */
4451	if (priv->create & KGEM_CAN_CREATE_LARGE || flags & MOVE_SOURCE_HINT) {
4452		DBG(("%s: disposing of system copy for large/source\n",
4453		     __FUNCTION__));
4454		assert(!priv->shm);
4455		assert(priv->gpu_bo);
4456		assert(priv->gpu_bo->proxy == NULL);
4457		sna_damage_all(&priv->gpu_damage, pixmap);
4458		sna_pixmap_free_cpu(sna, priv,
4459				    (priv->create & KGEM_CAN_CREATE_LARGE) ? false : priv->cpu);
4460	}
4461done:
4462	list_del(&priv->flush_list);
4463
4464	sna_damage_reduce_all(&priv->gpu_damage, pixmap);
4465	if (DAMAGE_IS_ALL(priv->gpu_damage))
4466		sna_pixmap_free_cpu(sna, priv, priv->cpu);
4467
4468active:
4469	if (flags & MOVE_WRITE) {
4470		priv->clear = false;
4471		priv->cpu = false;
4472	}
4473	assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0);
4474	return sna_pixmap_mark_active(sna, priv);
4475}
4476
4477static bool must_check sna_validate_pixmap(DrawablePtr draw, PixmapPtr pixmap)
4478{
4479	DBG(("%s: target bpp=%d, source bpp=%d\n",
4480	     __FUNCTION__, draw->bitsPerPixel, pixmap->drawable.bitsPerPixel));
4481
4482	if (draw->bitsPerPixel == pixmap->drawable.bitsPerPixel &&
4483	    FbEvenTile(pixmap->drawable.width *
4484		       pixmap->drawable.bitsPerPixel)) {
4485		DBG(("%s: flushing pixmap\n", __FUNCTION__));
4486		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
4487			return false;
4488
4489		fbPadPixmap(pixmap);
4490	}
4491
4492	return true;
4493}
4494
4495static bool must_check sna_gc_move_to_cpu(GCPtr gc,
4496					  DrawablePtr drawable,
4497					  RegionPtr region)
4498{
4499	struct sna_gc *sgc = sna_gc(gc);
4500	long changes = sgc->changes;
4501
4502	DBG(("%s(%p) changes=%lx\n", __FUNCTION__, gc, changes));
4503	assert(drawable);
4504	assert(region);
4505
4506	assert(gc->ops == (GCOps *)&sna_gc_ops);
4507	gc->ops = (GCOps *)&sna_gc_ops__cpu;
4508
4509	assert(gc->funcs);
4510	sgc->old_funcs = gc->funcs;
4511	gc->funcs = (GCFuncs *)&sna_gc_funcs__cpu;
4512
4513	assert(gc->pCompositeClip);
4514	sgc->priv = gc->pCompositeClip;
4515	gc->pCompositeClip = region;
4516
4517#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0)
4518	if (gc->clientClipType == CT_PIXMAP) {
4519		PixmapPtr clip = gc->clientClip;
4520		gc->clientClip = region_from_bitmap(gc->pScreen, clip);
4521		gc->pScreen->DestroyPixmap(clip);
4522		gc->clientClipType = gc->clientClip ? CT_REGION : CT_NONE;
4523		changes |= GCClipMask;
4524	} else
4525		changes &= ~GCClipMask;
4526#else
4527	changes &= ~GCClipMask;
4528#endif
4529
4530	if (changes || drawable->serialNumber != (sgc->serial & DRAWABLE_SERIAL_BITS)) {
4531		long tmp = gc->serialNumber;
4532		gc->serialNumber = sgc->serial;
4533
4534		if (fb_gc(gc)->bpp != drawable->bitsPerPixel) {
4535			changes |= GCStipple | GCForeground | GCBackground | GCPlaneMask;
4536			fb_gc(gc)->bpp = drawable->bitsPerPixel;
4537		}
4538
4539		if (changes & GCTile && !gc->tileIsPixel) {
4540			DBG(("%s: flushing tile pixmap\n", __FUNCTION__));
4541			if (!sna_validate_pixmap(drawable, gc->tile.pixmap))
4542				return false;
4543		}
4544
4545		if (changes & GCStipple && gc->stipple) {
4546			DBG(("%s: flushing stipple pixmap\n", __FUNCTION__));
4547			if (!sna_validate_pixmap(drawable, gc->stipple))
4548				return false;
4549		}
4550
4551		fbValidateGC(gc, changes, drawable);
4552		gc->serialNumber = tmp;
4553	}
4554	sgc->changes = 0;
4555
4556	switch (gc->fillStyle) {
4557	case FillTiled:
4558		DBG(("%s: moving tile to cpu\n", __FUNCTION__));
4559		return sna_drawable_move_to_cpu(&gc->tile.pixmap->drawable, MOVE_READ);
4560	case FillStippled:
4561	case FillOpaqueStippled:
4562		DBG(("%s: moving stipple to cpu\n", __FUNCTION__));
4563		return sna_drawable_move_to_cpu(&gc->stipple->drawable, MOVE_READ);
4564	default:
4565		return true;
4566	}
4567}
4568
4569static void sna_gc_move_to_gpu(GCPtr gc)
4570{
4571	DBG(("%s(%p)\n", __FUNCTION__, gc));
4572
4573	assert(gc->ops == (GCOps *)&sna_gc_ops__cpu);
4574	assert(gc->funcs == (GCFuncs *)&sna_gc_funcs__cpu);
4575
4576	gc->ops = (GCOps *)&sna_gc_ops;
4577	gc->funcs = (GCFuncs *)sna_gc(gc)->old_funcs;
4578	assert(gc->funcs);
4579	gc->pCompositeClip = sna_gc(gc)->priv;
4580	assert(gc->pCompositeClip);
4581}
4582
4583static inline bool clip_box(BoxPtr box, GCPtr gc)
4584{
4585	const BoxRec *clip;
4586	bool clipped;
4587
4588	assert(gc->pCompositeClip);
4589	clip = &gc->pCompositeClip->extents;
4590
4591	clipped = !region_is_singular(gc->pCompositeClip);
4592	if (box->x1 < clip->x1)
4593		box->x1 = clip->x1, clipped = true;
4594	if (box->x2 > clip->x2)
4595		box->x2 = clip->x2, clipped = true;
4596
4597	if (box->y1 < clip->y1)
4598		box->y1 = clip->y1, clipped = true;
4599	if (box->y2 > clip->y2)
4600		box->y2 = clip->y2, clipped = true;
4601
4602	return clipped;
4603}
4604
4605static inline void translate_box(BoxPtr box, DrawablePtr d)
4606{
4607	box->x1 += d->x;
4608	box->x2 += d->x;
4609
4610	box->y1 += d->y;
4611	box->y2 += d->y;
4612}
4613
4614static inline bool trim_and_translate_box(BoxPtr box, DrawablePtr d, GCPtr gc)
4615{
4616	translate_box(box, d);
4617	return clip_box(box, gc);
4618}
4619
4620static inline bool box32_clip(Box32Rec *box, GCPtr gc)
4621{
4622	bool clipped = !region_is_singular(gc->pCompositeClip);
4623	const BoxRec *clip = &gc->pCompositeClip->extents;
4624
4625	if (box->x1 < clip->x1)
4626		box->x1 = clip->x1, clipped = true;
4627	if (box->x2 > clip->x2)
4628		box->x2 = clip->x2, clipped = true;
4629
4630	if (box->y1 < clip->y1)
4631		box->y1 = clip->y1, clipped = true;
4632	if (box->y2 > clip->y2)
4633		box->y2 = clip->y2, clipped = true;
4634
4635	return clipped;
4636}
4637
4638static inline void box32_translate(Box32Rec *box, DrawablePtr d)
4639{
4640	box->x1 += d->x;
4641	box->x2 += d->x;
4642
4643	box->y1 += d->y;
4644	box->y2 += d->y;
4645}
4646
4647static inline bool box32_trim_and_translate(Box32Rec *box, DrawablePtr d, GCPtr gc)
4648{
4649	box32_translate(box, d);
4650	return box32_clip(box, gc);
4651}
4652
4653static inline void box_add_xy(BoxPtr box, int16_t x, int16_t y)
4654{
4655	if (box->x1 > x)
4656		box->x1 = x;
4657	else if (box->x2 < x)
4658		box->x2 = x;
4659
4660	if (box->y1 > y)
4661		box->y1 = y;
4662	else if (box->y2 < y)
4663		box->y2 = y;
4664}
4665
4666static inline void box_add_pt(BoxPtr box, const DDXPointRec *pt)
4667{
4668	box_add_xy(box, pt->x, pt->y);
4669}
4670
4671static inline bool box32_to_box16(const Box32Rec *b32, BoxRec *b16)
4672{
4673	b16->x1 = b32->x1;
4674	b16->y1 = b32->y1;
4675	b16->x2 = b32->x2;
4676	b16->y2 = b32->y2;
4677
4678	return b16->x2 > b16->x1 && b16->y2 > b16->y1;
4679}
4680
4681static inline void box32_add_rect(Box32Rec *box, const xRectangle *r)
4682{
4683	int32_t v;
4684
4685	v = r->x;
4686	if (box->x1 > v)
4687		box->x1 = v;
4688	v += r->width;
4689	if (box->x2 < v)
4690		box->x2 = v;
4691
4692	v = r->y;
4693	if (box->y1 > v)
4694		box->y1 = v;
4695	v += r->height;
4696	if (box->y2 < v)
4697		box->y2 = v;
4698}
4699
4700static bool
4701can_create_upload_tiled_x(struct sna *sna,
4702			  PixmapPtr pixmap,
4703			  struct sna_pixmap *priv,
4704			  bool replaces)
4705{
4706	if (priv->shm || (priv->cpu && !replaces))
4707		return false;
4708
4709	if ((priv->create & KGEM_CAN_CREATE_GPU) == 0)
4710		return false;
4711
4712	if (sna->kgem.has_llc)
4713		return true;
4714
4715	if (!sna->kgem.has_wc_mmap && sna_pixmap_default_tiling(sna, pixmap))
4716		return false;
4717
4718	return true;
4719}
4720
4721static bool
4722create_upload_tiled_x(struct sna *sna,
4723		      PixmapPtr pixmap,
4724		      struct sna_pixmap *priv,
4725		      bool replaces)
4726{
4727	unsigned create;
4728
4729	if (!can_create_upload_tiled_x(sna, pixmap, priv, replaces))
4730		return false;
4731
4732	assert(priv->gpu_bo == NULL);
4733	assert(priv->gpu_damage == NULL);
4734
4735	if (sna->kgem.has_llc)
4736		create = CREATE_CPU_MAP | CREATE_INACTIVE;
4737	else if (sna->kgem.has_wc_mmap)
4738		create = CREATE_GTT_MAP | CREATE_INACTIVE;
4739	else
4740		create = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_CACHED;
4741
4742	return sna_pixmap_alloc_gpu(sna, pixmap, priv, create);
4743}
4744
4745static bool can_upload__tiled_x(struct kgem *kgem, struct kgem_bo *bo)
4746{
4747	return kgem_bo_can_map__cpu(kgem, bo, true) || kgem->has_wc_mmap;
4748}
4749
4750static bool
4751try_upload__tiled_x(PixmapPtr pixmap, RegionRec *region,
4752		    int x, int y, int w, int  h, char *bits, int stride)
4753{
4754	struct sna *sna = to_sna_from_pixmap(pixmap);
4755	struct sna_pixmap *priv = sna_pixmap(pixmap);
4756	const BoxRec *box;
4757	uint8_t *dst;
4758	int n;
4759
4760	if (!can_upload__tiled_x(&sna->kgem, priv->gpu_bo)) {
4761		DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__));
4762		return false;
4763	}
4764
4765	if (!sna_pixmap_move_area_to_gpu(pixmap, &region->extents,
4766					 MOVE_WRITE | (region->data ? MOVE_READ : 0)))
4767		return false;
4768
4769	if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 &&
4770	    __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
4771		return false;
4772
4773	if (kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true)) {
4774		dst = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
4775		if (dst == NULL)
4776			return false;
4777
4778		kgem_bo_sync__cpu(&sna->kgem, priv->gpu_bo);
4779	} else {
4780		dst = kgem_bo_map__wc(&sna->kgem, priv->gpu_bo);
4781		if (dst == NULL)
4782			return false;
4783
4784		kgem_bo_sync__gtt(&sna->kgem, priv->gpu_bo);
4785	}
4786
4787	box = region_rects(region);
4788	n = region_num_rects(region);
4789
4790	DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n));
4791
4792	if (sigtrap_get())
4793		return false;
4794
4795	if (priv->gpu_bo->tiling) {
4796		do {
4797			DBG(("%s: copy tiled box (%d, %d)->(%d, %d)x(%d, %d)\n",
4798			     __FUNCTION__,
4799			     box->x1 - x, box->y1 - y,
4800			     box->x1, box->y1,
4801			     box->x2 - box->x1, box->y2 - box->y1));
4802
4803			assert(box->x2 > box->x1);
4804			assert(box->y2 > box->y1);
4805
4806			assert(box->x1 >= 0);
4807			assert(box->y1 >= 0);
4808			assert(box->x2 <= pixmap->drawable.width);
4809			assert(box->y2 <= pixmap->drawable.height);
4810
4811			assert(box->x1 - x >= 0);
4812			assert(box->y1 - y >= 0);
4813			assert(box->x2 - x <= w);
4814			assert(box->y2 - y <= h);
4815
4816			memcpy_to_tiled_x(&sna->kgem, bits, dst,
4817					  pixmap->drawable.bitsPerPixel,
4818					  stride, priv->gpu_bo->pitch,
4819					  box->x1 - x, box->y1 - y,
4820					  box->x1, box->y1,
4821					  box->x2 - box->x1, box->y2 - box->y1);
4822			box++;
4823		} while (--n);
4824	} else {
4825		do {
4826			DBG(("%s: copy lined box (%d, %d)->(%d, %d)x(%d, %d)\n",
4827			     __FUNCTION__,
4828			     box->x1 - x, box->y1 - y,
4829			     box->x1, box->y1,
4830			     box->x2 - box->x1, box->y2 - box->y1));
4831
4832			assert(box->x2 > box->x1);
4833			assert(box->y2 > box->y1);
4834
4835			assert(box->x1 >= 0);
4836			assert(box->y1 >= 0);
4837			assert(box->x2 <= pixmap->drawable.width);
4838			assert(box->y2 <= pixmap->drawable.height);
4839
4840			assert(box->x1 - x >= 0);
4841			assert(box->y1 - y >= 0);
4842			assert(box->x2 - x <= w);
4843			assert(box->y2 - y <= h);
4844
4845			memcpy_blt(bits, dst,
4846				   pixmap->drawable.bitsPerPixel,
4847				   stride, priv->gpu_bo->pitch,
4848				   box->x1 - x, box->y1 - y,
4849				   box->x1, box->y1,
4850				   box->x2 - box->x1, box->y2 - box->y1);
4851			box++;
4852		} while (--n);
4853
4854		if (!priv->shm) {
4855			pixmap->devPrivate.ptr = dst;
4856			pixmap->devKind = priv->gpu_bo->pitch;
4857			if (dst == MAP(priv->gpu_bo->map__cpu)) {
4858				priv->mapped = MAPPED_CPU;
4859				priv->cpu = true;
4860			} else
4861				priv->mapped = MAPPED_GTT;
4862			assert_pixmap_map(pixmap, priv);
4863		}
4864	}
4865
4866	sigtrap_put();
4867	return true;
4868}
4869
4870static bool
4871try_upload__inplace(PixmapPtr pixmap, RegionRec *region,
4872		    int x, int y, int w, int  h, char *bits, int stride)
4873{
4874	struct sna *sna = to_sna_from_pixmap(pixmap);
4875	struct sna_pixmap *priv = sna_pixmap(pixmap);
4876	bool ignore_cpu = false;
4877	bool replaces;
4878	const BoxRec *box;
4879	uint8_t *dst;
4880	int n;
4881
4882	if (!USE_INPLACE)
4883		return false;
4884
4885	assert(priv);
4886
4887	if (priv->shm && priv->gpu_damage == NULL)
4888		return false;
4889
4890	replaces = region_subsumes_pixmap(region, pixmap);
4891
4892	DBG(("%s: bo? %d, can map? %d, replaces? %d\n", __FUNCTION__,
4893	     priv->gpu_bo != NULL,
4894	     priv->gpu_bo ? kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true) : 0,
4895	     replaces));
4896
4897	if (kgem_bo_discard_cache(priv->gpu_bo, true)) {
4898		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
4899		assert(DAMAGE_IS_ALL(priv->cpu_damage));
4900		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */
4901		assert(!priv->pinned);
4902		assert(!priv->mapped);
4903		sna_damage_destroy(&priv->gpu_damage);
4904		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
4905		priv->gpu_bo = NULL;
4906	}
4907
4908	if (priv->gpu_bo && replaces) {
4909		if (UNDO) kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
4910		if (can_create_upload_tiled_x(sna, pixmap, priv, true) &&
4911		    (priv->cow ||
4912		     __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo) ||
4913		     !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))) {
4914			DBG(("%s: discarding unusable target bo (busy? %d, mappable? %d)\n", __FUNCTION__,
4915			     kgem_bo_is_busy(priv->gpu_bo),
4916			     kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true)));
4917			sna_pixmap_free_gpu(sna, priv);
4918			ignore_cpu = true;
4919		}
4920	}
4921	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
4922
4923	if (priv->cow ||
4924	    (priv->move_to_gpu && !sna_pixmap_discard_shadow_damage(priv, replaces ? NULL : region))) {
4925		DBG(("%s: no, has pending COW? %d or move-to-gpu? %d\n",
4926		     __FUNCTION__, priv->cow != NULL, priv->move_to_gpu != NULL));
4927		return false;
4928	}
4929
4930	if (priv->gpu_damage &&
4931	    region_subsumes_damage(region, priv->gpu_damage)) {
4932		if (UNDO) kgem_bo_undo(&sna->kgem, priv->gpu_bo);
4933		if (can_create_upload_tiled_x(sna, pixmap, priv, priv->cpu_damage == NULL) &&
4934		    (__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo) ||
4935		     !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))) {
4936			DBG(("%s: discarding unusable partial target bo (busy? %d, mappable? %d)\n", __FUNCTION__,
4937			     kgem_bo_is_busy(priv->gpu_bo),
4938			     kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true)));
4939			sna_pixmap_free_gpu(sna, priv);
4940			ignore_cpu = priv->cpu_damage == NULL;
4941			if (priv->ptr)
4942				sna_damage_all(&priv->cpu_damage, pixmap);
4943		}
4944	}
4945
4946	if (priv->gpu_bo == NULL &&
4947	    !create_upload_tiled_x(sna, pixmap, priv, ignore_cpu))
4948		return false;
4949
4950	DBG(("%s: tiling=%d\n", __FUNCTION__, priv->gpu_bo->tiling));
4951	switch (priv->gpu_bo->tiling) {
4952	case I915_TILING_Y:
4953		break;
4954	case I915_TILING_X:
4955		if (!sna->kgem.memcpy_to_tiled_x)
4956			break;
4957	default:
4958		if (try_upload__tiled_x(pixmap, region, x, y, w, h, bits, stride))
4959			goto done;
4960		break;
4961	}
4962
4963	if (priv->gpu_damage == NULL && !box_inplace(pixmap, &region->extents)) {
4964		DBG(("%s: no, too small to bother with using the GTT\n", __FUNCTION__));
4965		return false;
4966	}
4967
4968	if (!kgem_bo_can_map(&sna->kgem, priv->gpu_bo)) {
4969		DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__));
4970		return false;
4971	}
4972
4973	if (!sna_pixmap_move_area_to_gpu(pixmap, &region->extents,
4974					 MOVE_WRITE | (region->data ? MOVE_READ : 0)))
4975		return false;
4976
4977	if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 &&
4978	    __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
4979		return false;
4980
4981	dst = kgem_bo_map(&sna->kgem, priv->gpu_bo);
4982	if (dst == NULL)
4983		return false;
4984
4985	pixmap->devPrivate.ptr = dst;
4986	pixmap->devKind = priv->gpu_bo->pitch;
4987	priv->mapped = dst == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
4988	priv->cpu &= priv->mapped == MAPPED_CPU;
4989	assert(has_coherent_ptr(sna, priv, MOVE_WRITE));
4990
4991	box = region_rects(region);
4992	n = region_num_rects(region);
4993
4994	DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n));
4995
4996	if (sigtrap_get())
4997		return false;
4998
4999	do {
5000		DBG(("%s: copy lined box (%d, %d)->(%d, %d)x(%d, %d)\n",
5001		     __FUNCTION__,
5002		     box->x1 - x, box->y1 - y,
5003		     box->x1, box->y1,
5004		     box->x2 - box->x1, box->y2 - box->y1));
5005
5006		assert(box->x2 > box->x1);
5007		assert(box->y2 > box->y1);
5008
5009		assert(box->x1 >= 0);
5010		assert(box->y1 >= 0);
5011		assert(box->x2 <= pixmap->drawable.width);
5012		assert(box->y2 <= pixmap->drawable.height);
5013
5014		assert(box->x1 - x >= 0);
5015		assert(box->y1 - y >= 0);
5016		assert(box->x2 - x <= w);
5017		assert(box->y2 - y <= h);
5018
5019		memcpy_blt(bits, dst,
5020			   pixmap->drawable.bitsPerPixel,
5021			   stride, priv->gpu_bo->pitch,
5022			   box->x1 - x, box->y1 - y,
5023			   box->x1, box->y1,
5024			   box->x2 - box->x1, box->y2 - box->y1);
5025		box++;
5026	} while (--n);
5027
5028	sigtrap_put();
5029
5030done:
5031	if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
5032		if (replaces) {
5033			sna_damage_all(&priv->gpu_damage, pixmap);
5034		} else {
5035			sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap);
5036			sna_damage_reduce_all(&priv->gpu_damage, pixmap);
5037		}
5038		if (DAMAGE_IS_ALL(priv->gpu_damage))
5039			sna_damage_destroy(&priv->cpu_damage);
5040		else
5041			sna_damage_subtract(&priv->cpu_damage, region);
5042
5043		if (priv->cpu_damage == NULL) {
5044			list_del(&priv->flush_list);
5045			sna_damage_all(&priv->gpu_damage, pixmap);
5046		}
5047
5048		add_shm_flush(sna, priv);
5049	}
5050
5051	assert(!priv->clear);
5052	return true;
5053}
5054
5055static bool
5056try_upload__blt(PixmapPtr pixmap, RegionRec *region,
5057		int x, int y, int w, int  h, char *bits, int stride)
5058{
5059	struct sna *sna = to_sna_from_pixmap(pixmap);
5060	struct sna_pixmap *priv;
5061	struct kgem_bo *src_bo;
5062	bool ok;
5063
5064	if (!sna->kgem.has_userptr || !USE_USERPTR_UPLOADS)
5065		return false;
5066
5067	priv = sna_pixmap(pixmap);
5068	assert(priv);
5069	assert(priv->gpu_bo);
5070	assert(priv->gpu_bo->proxy == NULL);
5071
5072	if (priv->cpu_damage &&
5073	    (DAMAGE_IS_ALL(priv->cpu_damage) ||
5074	     sna_damage_contains_box__no_reduce(priv->cpu_damage,
5075						&region->extents)) &&
5076	    !box_inplace(pixmap, &region->extents)) {
5077		DBG(("%s: no, damage on CPU and too small\n", __FUNCTION__));
5078		return false;
5079	}
5080
5081	src_bo = kgem_create_map(&sna->kgem, bits, stride * h, true);
5082	if (src_bo == NULL)
5083		return false;
5084
5085	src_bo->pitch = stride;
5086	kgem_bo_mark_unreusable(src_bo);
5087
5088	if (!sna_pixmap_move_area_to_gpu(pixmap, &region->extents,
5089					 MOVE_WRITE | MOVE_ASYNC_HINT | (region->data ? MOVE_READ : 0))) {
5090		kgem_bo_destroy(&sna->kgem, src_bo);
5091		return false;
5092	}
5093
5094	DBG(("%s: upload(%d, %d, %d, %d) x %d through a temporary map\n",
5095	     __FUNCTION__, x, y, w, h, region_num_rects(region)));
5096
5097	if (sigtrap_get() == 0) {
5098		ok = sna->render.copy_boxes(sna, GXcopy,
5099					    &pixmap->drawable, src_bo, -x, -y,
5100					    &pixmap->drawable, priv->gpu_bo, 0, 0,
5101					    region_rects(region),
5102					    region_num_rects(region),
5103					    COPY_LAST);
5104		sigtrap_put();
5105	} else
5106		ok = false;
5107
5108	kgem_bo_sync__cpu(&sna->kgem, src_bo);
5109	assert(src_bo->rq == NULL);
5110	kgem_bo_destroy(&sna->kgem, src_bo);
5111
5112	if (!ok) {
5113		DBG(("%s: copy failed!\n", __FUNCTION__));
5114		return false;
5115	}
5116
5117	if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
5118		assert(!priv->clear);
5119		if (region_subsumes_drawable(region, &pixmap->drawable)) {
5120			sna_damage_all(&priv->gpu_damage, pixmap);
5121		} else {
5122			sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap);
5123			sna_damage_reduce_all(&priv->gpu_damage, pixmap);
5124		}
5125		if (DAMAGE_IS_ALL(priv->gpu_damage))
5126			sna_damage_destroy(&priv->cpu_damage);
5127		else
5128			sna_damage_subtract(&priv->cpu_damage, region);
5129		if (priv->cpu_damage == NULL) {
5130			list_del(&priv->flush_list);
5131			if (sna_pixmap_free_cpu(sna, priv, priv->cpu))
5132				sna_damage_all(&priv->gpu_damage, pixmap);
5133		}
5134	}
5135	priv->cpu = false;
5136	priv->clear = false;
5137
5138	return true;
5139}
5140
5141static bool ignore_cpu_damage(struct sna *sna, struct sna_pixmap *priv, const RegionRec *region)
5142{
5143	if (region_subsumes_pixmap(region, priv->pixmap))
5144		return true;
5145
5146	if (priv->cpu_damage != NULL) {
5147		if (DAMAGE_IS_ALL(priv->cpu_damage))
5148			return false;
5149
5150		if (!box_inplace(priv->pixmap, &region->extents))
5151			return false;
5152
5153		if (sna_damage_contains_box__no_reduce(priv->cpu_damage, &region->extents))
5154			return false;
5155	}
5156
5157	return priv->gpu_bo == NULL || !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo);
5158
5159}
5160
5161static bool
5162try_upload__fast(PixmapPtr pixmap, RegionRec *region,
5163		 int x, int y, int w, int  h, char *bits, int stride)
5164{
5165	struct sna *sna = to_sna_from_pixmap(pixmap);
5166	struct sna_pixmap *priv;
5167
5168	if (wedged(sna))
5169		return false;
5170
5171	priv = sna_pixmap(pixmap);
5172	if (priv == NULL)
5173		return false;
5174
5175	if (ignore_cpu_damage(sna, priv, region)) {
5176		DBG(("%s: ignore existing cpu damage (if any)\n", __FUNCTION__));
5177		if (try_upload__inplace(pixmap, region, x, y, w, h, bits, stride))
5178			return true;
5179	}
5180
5181	if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL || priv->cpu) {
5182		DBG(("%s: no, no gpu damage\n", __FUNCTION__));
5183		return false;
5184	}
5185
5186	assert(priv->gpu_bo);
5187	assert(priv->gpu_bo->proxy == NULL);
5188
5189	if (try_upload__blt(pixmap, region, x, y, w, h, bits, stride))
5190		return true;
5191
5192	if (try_upload__inplace(pixmap, region, x, y, w, h, bits, stride))
5193		return true;
5194
5195	return false;
5196}
5197
5198static bool
5199sna_put_zpixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
5200		    int x, int y, int w, int  h, char *bits, int stride)
5201{
5202	PixmapPtr pixmap = get_drawable_pixmap(drawable);
5203	unsigned int hint;
5204	const BoxRec *box;
5205	int16_t dx, dy;
5206	int n;
5207
5208	assert_pixmap_contains_box(pixmap, RegionExtents(region));
5209
5210	if (gc->alu != GXcopy)
5211		return false;
5212
5213	if (drawable->depth < 8)
5214		return false;
5215
5216	get_drawable_deltas(drawable, pixmap, &dx, &dy);
5217	x += dx + drawable->x;
5218	y += dy + drawable->y;
5219	assert(region->extents.x1 >= x);
5220	assert(region->extents.y1 >= y);
5221	assert(region->extents.x2 <= x + w);
5222	assert(region->extents.y2 <= y + h);
5223
5224	if (try_upload__fast(pixmap, region, x, y, w, h, bits, stride))
5225		return true;
5226
5227	hint = MOVE_WRITE;
5228	if (region_is_unclipped(region, pixmap->drawable.width, h) &&
5229	    (h+1)*stride > 65536) {
5230		DBG(("%s: segmented, unclipped large upload (%d bytes), marking WHOLE_HINT\n",
5231		     __FUNCTION__, h*stride));
5232		hint |= MOVE_WHOLE_HINT;
5233	}
5234
5235	if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, region, hint))
5236		return false;
5237
5238	if (sigtrap_get())
5239		return false;
5240
5241	/* Region is pre-clipped and translated into pixmap space */
5242	box = region_rects(region);
5243	n = region_num_rects(region);
5244	DBG(("%s: upload(%d, %d, %d, %d) x %d boxes\n", __FUNCTION__, x, y, w, h, n));
5245	do {
5246		DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n",
5247		     __FUNCTION__,
5248		     box->x1 - x, box->y1 - y,
5249		     box->x1, box->y1,
5250		     box->x2 - box->x1, box->y2 - box->y1));
5251
5252		assert(box->x2 > box->x1);
5253		assert(box->y2 > box->y1);
5254
5255		assert(box->x1 >= 0);
5256		assert(box->y1 >= 0);
5257		assert(box->x2 <= pixmap->drawable.width);
5258		assert(box->y2 <= pixmap->drawable.height);
5259
5260		assert(box->x1 - x >= 0);
5261		assert(box->y1 - y >= 0);
5262		assert(box->x2 - x <= w);
5263		assert(box->y2 - y <= h);
5264
5265		assert(has_coherent_ptr(to_sna_from_pixmap(pixmap), sna_pixmap(pixmap), MOVE_WRITE));
5266		assert(pixmap->devKind);
5267		memcpy_blt(bits, pixmap->devPrivate.ptr,
5268			   pixmap->drawable.bitsPerPixel,
5269			   stride, pixmap->devKind,
5270			   box->x1 - x, box->y1 - y,
5271			   box->x1, box->y1,
5272			   box->x2 - box->x1, box->y2 - box->y1);
5273		box++;
5274	} while (--n);
5275
5276	sigtrap_put();
5277	assert_pixmap_damage(pixmap);
5278	return true;
5279}
5280
5281static inline uint8_t byte_reverse(uint8_t b)
5282{
5283	return ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
5284}
5285
5286static inline uint8_t blt_depth(int depth)
5287{
5288	switch (depth) {
5289	case 8: return 0;
5290	case 15: return 0x2;
5291	case 16: return 0x1;
5292	default: return 0x3;
5293	}
5294}
5295
5296inline static void blt_done(struct sna *sna)
5297{
5298	sna->blt_state.fill_bo = 0;
5299	if (sna->kgem.nbatch && __kgem_ring_empty(&sna->kgem)) {
5300		DBG(("%s: flushing BLT operation on empty ring\n",
5301		     __FUNCTION__));
5302		_kgem_submit(&sna->kgem);
5303	}
5304}
5305
5306static bool
5307sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
5308		     int x, int y, int w, int  h, char *bits)
5309{
5310	PixmapPtr pixmap = get_drawable_pixmap(drawable);
5311	struct sna *sna = to_sna_from_pixmap(pixmap);
5312	struct sna_damage **damage;
5313	struct kgem_bo *bo;
5314	const BoxRec *box;
5315	int16_t dx, dy;
5316	int n;
5317	uint8_t rop = copy_ROP[gc->alu];
5318
5319	bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU,
5320				 &region->extents, &damage);
5321	if (bo == NULL)
5322		return false;
5323
5324	if (bo->tiling == I915_TILING_Y) {
5325		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
5326		assert(bo == __sna_pixmap_get_bo(pixmap));
5327		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
5328		if (bo == NULL) {
5329			DBG(("%s: fallback -- unable to change tiling\n",
5330			     __FUNCTION__));
5331			return false;
5332		}
5333	}
5334
5335	if (!kgem_bo_can_blt(&sna->kgem, bo))
5336		return false;
5337
5338	assert_pixmap_contains_box(pixmap, RegionExtents(region));
5339	if (damage)
5340		sna_damage_add_to_pixmap(damage, region, pixmap);
5341	assert_pixmap_damage(pixmap);
5342
5343	DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h));
5344
5345	get_drawable_deltas(drawable, pixmap, &dx, &dy);
5346	x += dx + drawable->x;
5347	y += dy + drawable->y;
5348
5349	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
5350	assert(kgem_bo_can_blt(&sna->kgem, bo));
5351	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
5352
5353	/* Region is pre-clipped and translated into pixmap space */
5354	box = region_rects(region);
5355	n = region_num_rects(region);
5356	do {
5357		int bx1 = (box->x1 - x) & ~7;
5358		int bx2 = (box->x2 - x + 7) & ~7;
5359		int bw = (bx2 - bx1)/8;
5360		int bh = box->y2 - box->y1;
5361		int bstride = ALIGN(bw, 2);
5362		struct kgem_bo *upload;
5363		void *ptr;
5364
5365		if (!kgem_check_batch(&sna->kgem, 10) ||
5366		    !kgem_check_bo_fenced(&sna->kgem, bo) ||
5367		    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
5368			kgem_submit(&sna->kgem);
5369			if (!kgem_check_bo_fenced(&sna->kgem, bo))
5370				return false;
5371			_kgem_set_mode(&sna->kgem, KGEM_BLT);
5372		}
5373		kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
5374
5375		upload = kgem_create_buffer(&sna->kgem,
5376					    bstride*bh,
5377					    KGEM_BUFFER_WRITE_INPLACE,
5378					    &ptr);
5379		if (!upload)
5380			break;
5381
5382
5383		if (sigtrap_get() == 0) {
5384			int src_stride = BitmapBytePad(w);
5385			uint8_t *dst = ptr;
5386			uint8_t *src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8;
5387			uint32_t *b;
5388
5389			bstride -= bw;
5390			src_stride -= bw;
5391
5392			do {
5393				int i = bw;
5394				assert(src >= (uint8_t *)bits);
5395				do {
5396					*dst++ = byte_reverse(*src++);
5397				} while (--i);
5398				assert(src <= (uint8_t *)bits + BitmapBytePad(w) * h);
5399				assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload));
5400				dst += bstride;
5401				src += src_stride;
5402			} while (--bh);
5403
5404			assert(sna->kgem.mode == KGEM_BLT);
5405			if (sna->kgem.gen >= 0100) {
5406				b = sna->kgem.batch + sna->kgem.nbatch;
5407				b[0] = XY_MONO_SRC_COPY | 3 << 20 | 8;
5408				b[0] |= ((box->x1 - x) & 7) << 17;
5409				b[1] = bo->pitch;
5410				if (bo->tiling) {
5411					b[0] |= BLT_DST_TILED;
5412					b[1] >>= 2;
5413				}
5414				b[1] |= blt_depth(drawable->depth) << 24;
5415				b[1] |= rop << 16;
5416				b[2] = box->y1 << 16 | box->x1;
5417				b[3] = box->y2 << 16 | box->x2;
5418				*(uint64_t *)(b+4) =
5419					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
5420							I915_GEM_DOMAIN_RENDER << 16 |
5421							I915_GEM_DOMAIN_RENDER |
5422							KGEM_RELOC_FENCED,
5423							0);
5424				*(uint64_t *)(b+6) =
5425					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
5426							I915_GEM_DOMAIN_RENDER << 16 |
5427							KGEM_RELOC_FENCED,
5428							0);
5429				b[8] = gc->bgPixel;
5430				b[9] = gc->fgPixel;
5431
5432				sna->kgem.nbatch += 10;
5433			} else {
5434				b = sna->kgem.batch + sna->kgem.nbatch;
5435				b[0] = XY_MONO_SRC_COPY | 3 << 20 | 6;
5436				b[0] |= ((box->x1 - x) & 7) << 17;
5437				b[1] = bo->pitch;
5438				if (sna->kgem.gen >= 040 && bo->tiling) {
5439					b[0] |= BLT_DST_TILED;
5440					b[1] >>= 2;
5441				}
5442				b[1] |= blt_depth(drawable->depth) << 24;
5443				b[1] |= rop << 16;
5444				b[2] = box->y1 << 16 | box->x1;
5445				b[3] = box->y2 << 16 | box->x2;
5446				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
5447						I915_GEM_DOMAIN_RENDER << 16 |
5448						I915_GEM_DOMAIN_RENDER |
5449						KGEM_RELOC_FENCED,
5450						0);
5451				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
5452						I915_GEM_DOMAIN_RENDER << 16 |
5453						KGEM_RELOC_FENCED,
5454						0);
5455				b[6] = gc->bgPixel;
5456				b[7] = gc->fgPixel;
5457
5458				sna->kgem.nbatch += 8;
5459			}
5460			sigtrap_put();
5461		}
5462		kgem_bo_destroy(&sna->kgem, upload);
5463
5464		box++;
5465	} while (--n);
5466
5467	blt_done(sna);
5468	return true;
5469}
5470
5471static bool
5472sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
5473		     int x, int y, int w, int  h, int left,char *bits)
5474{
5475	PixmapPtr pixmap = get_drawable_pixmap(drawable);
5476	struct sna *sna = to_sna_from_pixmap(pixmap);
5477	struct sna_damage **damage;
5478	struct kgem_bo *bo;
5479	int16_t dx, dy;
5480	unsigned i, skip;
5481
5482	if (gc->alu != GXcopy)
5483		return false;
5484
5485	bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU,
5486				 &region->extents, &damage);
5487	if (bo == NULL)
5488		return false;
5489
5490	if (bo->tiling == I915_TILING_Y) {
5491		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
5492		assert(bo == __sna_pixmap_get_bo(pixmap));
5493		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
5494		if (bo == NULL) {
5495			DBG(("%s: fallback -- unable to change tiling\n",
5496			     __FUNCTION__));
5497			return false;
5498		}
5499	}
5500
5501	if (!kgem_bo_can_blt(&sna->kgem, bo))
5502		return false;
5503
5504	assert_pixmap_contains_box(pixmap, RegionExtents(region));
5505	if (damage)
5506		sna_damage_add_to_pixmap(damage, region, pixmap);
5507	assert_pixmap_damage(pixmap);
5508
5509	DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h));
5510
5511	get_drawable_deltas(drawable, pixmap, &dx, &dy);
5512	x += dx + drawable->x;
5513	y += dy + drawable->y;
5514
5515	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
5516	assert(kgem_bo_can_blt(&sna->kgem, bo));
5517	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
5518
5519	skip = h * BitmapBytePad(w + left);
5520	for (i = 1 << (gc->depth-1); i; i >>= 1, bits += skip) {
5521		const BoxRec *box = region_rects(region);
5522		int n = region_num_rects(region);
5523
5524		if ((gc->planemask & i) == 0)
5525			continue;
5526
5527		/* Region is pre-clipped and translated into pixmap space */
5528		do {
5529			int bx1 = (box->x1 - x) & ~7;
5530			int bx2 = (box->x2 - x + 7) & ~7;
5531			int bw = (bx2 - bx1)/8;
5532			int bh = box->y2 - box->y1;
5533			int bstride = ALIGN(bw, 2);
5534			struct kgem_bo *upload;
5535			void *ptr;
5536
5537			if (!kgem_check_batch(&sna->kgem, 14) ||
5538			    !kgem_check_bo_fenced(&sna->kgem, bo) ||
5539			    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
5540				kgem_submit(&sna->kgem);
5541				if (!kgem_check_bo_fenced(&sna->kgem, bo))
5542					return false;
5543				_kgem_set_mode(&sna->kgem, KGEM_BLT);
5544			}
5545			kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
5546
5547			upload = kgem_create_buffer(&sna->kgem,
5548						    bstride*bh,
5549						    KGEM_BUFFER_WRITE_INPLACE,
5550						    &ptr);
5551			if (!upload)
5552				break;
5553
5554			if (sigtrap_get() == 0) {
5555				int src_stride = BitmapBytePad(w);
5556				uint8_t *src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8;
5557				uint8_t *dst = ptr;
5558				uint32_t *b;
5559
5560				bstride -= bw;
5561				src_stride -= bw;
5562				do {
5563					int j = bw;
5564					assert(src >= (uint8_t *)bits);
5565					do {
5566						*dst++ = byte_reverse(*src++);
5567					} while (--j);
5568					assert(src <= (uint8_t *)bits + BitmapBytePad(w) * h);
5569					assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload));
5570					dst += bstride;
5571					src += src_stride;
5572				} while (--bh);
5573
5574				assert(sna->kgem.mode == KGEM_BLT);
5575				if (sna->kgem.gen >= 0100) {
5576					assert(sna->kgem.mode == KGEM_BLT);
5577					b = sna->kgem.batch + sna->kgem.nbatch;
5578					b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20 | 12;
5579					b[0] |= ((box->x1 - x) & 7) << 17;
5580					b[1] = bo->pitch;
5581					if (bo->tiling) {
5582						b[0] |= BLT_DST_TILED;
5583						b[1] >>= 2;
5584					}
5585					b[1] |= 1 << 31; /* solid pattern */
5586					b[1] |= blt_depth(drawable->depth) << 24;
5587					b[1] |= 0xce << 16; /* S or (D and !P) */
5588					b[2] = box->y1 << 16 | box->x1;
5589					b[3] = box->y2 << 16 | box->x2;
5590					*(uint64_t *)(b+4) =
5591						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
5592								I915_GEM_DOMAIN_RENDER << 16 |
5593								I915_GEM_DOMAIN_RENDER |
5594								KGEM_RELOC_FENCED,
5595								0);
5596					*(uint64_t *)(b+6) =
5597						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
5598								I915_GEM_DOMAIN_RENDER << 16 |
5599								KGEM_RELOC_FENCED,
5600								0);
5601					b[8] = 0;
5602					b[9] = i;
5603					b[10] = i;
5604					b[11] = i;
5605					b[12] = -1;
5606					b[13] = -1;
5607					sna->kgem.nbatch += 14;
5608				} else {
5609					b = sna->kgem.batch + sna->kgem.nbatch;
5610					b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20 | 10;
5611					b[0] |= ((box->x1 - x) & 7) << 17;
5612					b[1] = bo->pitch;
5613					if (sna->kgem.gen >= 040 && bo->tiling) {
5614						b[0] |= BLT_DST_TILED;
5615						b[1] >>= 2;
5616					}
5617					b[1] |= 1 << 31; /* solid pattern */
5618					b[1] |= blt_depth(drawable->depth) << 24;
5619					b[1] |= 0xce << 16; /* S or (D and !P) */
5620					b[2] = box->y1 << 16 | box->x1;
5621					b[3] = box->y2 << 16 | box->x2;
5622					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
5623							I915_GEM_DOMAIN_RENDER << 16 |
5624							I915_GEM_DOMAIN_RENDER |
5625							KGEM_RELOC_FENCED,
5626							0);
5627					b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
5628							I915_GEM_DOMAIN_RENDER << 16 |
5629							KGEM_RELOC_FENCED,
5630							0);
5631					b[6] = 0;
5632					b[7] = i;
5633					b[8] = i;
5634					b[9] = i;
5635					b[10] = -1;
5636					b[11] = -1;
5637					sna->kgem.nbatch += 12;
5638				}
5639				sigtrap_put();
5640			}
5641			kgem_bo_destroy(&sna->kgem, upload);
5642
5643			box++;
5644		} while (--n);
5645	}
5646
5647	blt_done(sna);
5648	return true;
5649}
5650
5651static void
5652sna_put_image(DrawablePtr drawable, GCPtr gc, int depth,
5653	      int x, int y, int w, int h, int left, int format,
5654	      char *bits)
5655{
5656	PixmapPtr pixmap = get_drawable_pixmap(drawable);
5657	struct sna *sna = to_sna_from_pixmap(pixmap);
5658	struct sna_pixmap *priv = sna_pixmap(pixmap);
5659	RegionRec region;
5660	int16_t dx, dy;
5661
5662	DBG(("%s((%d, %d)x(%d, %d), depth=%d, format=%d)\n",
5663	     __FUNCTION__, x, y, w, h, depth, format));
5664
5665	if (w == 0 || h == 0)
5666		return;
5667
5668	region.extents.x1 = x + drawable->x;
5669	region.extents.y1 = y + drawable->y;
5670	region.extents.x2 = region.extents.x1 + w;
5671	region.extents.y2 = region.extents.y1 + h;
5672	region.data = NULL;
5673
5674	if (!region_is_singular(gc->pCompositeClip) ||
5675	    gc->pCompositeClip->extents.x1 > region.extents.x1 ||
5676	    gc->pCompositeClip->extents.y1 > region.extents.y1 ||
5677	    gc->pCompositeClip->extents.x2 < region.extents.x2 ||
5678	    gc->pCompositeClip->extents.y2 < region.extents.y2) {
5679		if (!RegionIntersect(&region, &region, gc->pCompositeClip) ||
5680		    box_empty(&region.extents))
5681			return;
5682	}
5683
5684	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
5685		RegionTranslate(&region, dx, dy);
5686
5687	if (priv == NULL) {
5688		DBG(("%s: fallback -- unattached(%d, %d, %d, %d)\n",
5689		     __FUNCTION__, x, y, w, h));
5690		goto fallback;
5691	}
5692
5693	if (FORCE_FALLBACK)
5694		goto fallback;
5695
5696	if (wedged(sna))
5697		goto fallback;
5698
5699	if (!ACCEL_PUT_IMAGE)
5700		goto fallback;
5701
5702	switch (format) {
5703	case ZPixmap:
5704		if (!PM_IS_SOLID(drawable, gc->planemask))
5705			goto fallback;
5706
5707		if (sna_put_zpixmap_blt(drawable, gc, &region,
5708					x, y, w, h,
5709					bits, PixmapBytePad(w, depth)))
5710			return;
5711		break;
5712
5713	case XYBitmap:
5714		if (!PM_IS_SOLID(drawable, gc->planemask))
5715			goto fallback;
5716
5717		if (sna_put_xybitmap_blt(drawable, gc, &region,
5718					 x, y, w, h,
5719					 bits))
5720			return;
5721		break;
5722
5723	case XYPixmap:
5724		if (sna_put_xypixmap_blt(drawable, gc, &region,
5725					 x, y, w, h, left,
5726					 bits))
5727			return;
5728		break;
5729
5730	default:
5731		return;
5732	}
5733
5734fallback:
5735	DBG(("%s: fallback\n", __FUNCTION__));
5736	RegionTranslate(&region, -dx, -dy);
5737
5738	if (!sna_gc_move_to_cpu(gc, drawable, &region))
5739		goto out;
5740	if (!sna_drawable_move_region_to_cpu(drawable, &region,
5741					      format == XYPixmap ?
5742					      MOVE_READ | MOVE_WRITE :
5743					      drawable_gc_flags(drawable, gc, false)))
5744		goto out;
5745
5746	if (sigtrap_get() == 0) {
5747		DBG(("%s: fbPutImage(%d, %d, %d, %d)\n",
5748		     __FUNCTION__, x, y, w, h));
5749		fbPutImage(drawable, gc, depth, x, y, w, h, left, format, bits);
5750		FALLBACK_FLUSH(drawable);
5751		sigtrap_put();
5752	}
5753out:
5754	sna_gc_move_to_gpu(gc);
5755	RegionUninit(&region);
5756}
5757
5758static bool
5759source_contains_region(struct sna_damage *damage,
5760		       const RegionRec *region, int16_t dx, int16_t dy)
5761{
5762	BoxRec box;
5763
5764	if (DAMAGE_IS_ALL(damage))
5765		return true;
5766
5767	if (damage == NULL)
5768		return false;
5769
5770	box = region->extents;
5771	box.x1 += dx;
5772	box.x2 += dx;
5773	box.y1 += dy;
5774	box.y2 += dy;
5775	return sna_damage_contains_box__no_reduce(damage, &box);
5776}
5777
5778static bool
5779move_to_gpu(PixmapPtr pixmap, struct sna_pixmap *priv,
5780	    RegionRec *region, int16_t dx, int16_t dy,
5781	    uint8_t alu, bool dst_is_gpu)
5782{
5783	int w = region->extents.x2 - region->extents.x1;
5784	int h = region->extents.y2 - region->extents.y1;
5785	int count;
5786
5787	assert_pixmap_map(pixmap, priv);
5788	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
5789		assert(priv->gpu_bo);
5790		return true;
5791	}
5792
5793	if (dst_is_gpu && priv->cpu_bo && priv->cpu_damage) {
5794		DBG(("%s: can use CPU bo? cpu_damage=%d, gpu_damage=%d, cpu hint=%d\n",
5795		     __FUNCTION__,
5796		     priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0,
5797		     priv->gpu_damage ? DAMAGE_IS_ALL(priv->gpu_damage) ? -1 : 1 : 0,
5798		     priv->cpu));
5799		if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL)
5800			return false;
5801
5802		if (priv->cpu &&
5803		    source_contains_region(priv->cpu_damage, region, dx, dy))
5804			return false;
5805	}
5806
5807	if (priv->gpu_bo) {
5808		DBG(("%s: has gpu bo (cpu damage?=%d, cpu=%d, gpu tiling=%d)\n",
5809		     __FUNCTION__,
5810		     priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0,
5811		     priv->cpu, priv->gpu_bo->tiling));
5812
5813		if (priv->cpu_damage == NULL)
5814			return true;
5815
5816		if (alu != GXcopy)
5817			return true;
5818
5819		if (!priv->cpu)
5820			return true;
5821
5822		if (priv->gpu_bo->tiling)
5823			return true;
5824
5825		RegionTranslate(region, dx, dy);
5826		count = region_subsumes_damage(region, priv->cpu_damage);
5827		RegionTranslate(region, -dx, -dy);
5828		if (count)
5829			return true;
5830	} else {
5831		if ((priv->create & KGEM_CAN_CREATE_GPU) == 0)
5832			return false;
5833		if (priv->shm)
5834			return false;
5835	}
5836
5837	count = priv->source_count++;
5838	if (priv->cpu_bo) {
5839		if (priv->cpu_bo->flush && count > SOURCE_BIAS)
5840			return true;
5841
5842		if (sna_pixmap_default_tiling(to_sna_from_pixmap(pixmap), pixmap) == I915_TILING_NONE)
5843			return false;
5844
5845		if (priv->cpu)
5846			return false;
5847
5848		return count > SOURCE_BIAS;
5849	} else {
5850		if (w == pixmap->drawable.width && h == pixmap->drawable.height)
5851			return count > SOURCE_BIAS;
5852
5853		return count * w*h >= (SOURCE_BIAS+2) * (int)pixmap->drawable.width * pixmap->drawable.height;
5854	}
5855}
5856
5857static const BoxRec *
5858reorder_boxes(const BoxRec *box, int n, int dx, int dy)
5859{
5860	const BoxRec *next, *base;
5861	BoxRec *new;
5862
5863	DBG(("%s x %d dx=%d, dy=%d\n", __FUNCTION__, n, dx, dy));
5864
5865	if (dy <= 0 && dx <= 0) {
5866		BoxRec *tmp;
5867
5868		new = malloc(sizeof(BoxRec) * n);
5869		if (new == NULL)
5870			return NULL;
5871
5872		tmp = new;
5873		next = box + n;
5874		do {
5875			*tmp++ = *--next;
5876		} while (next != box);
5877	} else if (dy < 0) {
5878		new = malloc(sizeof(BoxRec) * n);
5879		if (new == NULL)
5880			return NULL;
5881
5882		base = next = box + n - 1;
5883		while (base >= box) {
5884			const BoxRec *tmp;
5885
5886			while (next >= box && base->y1 == next->y1)
5887				next--;
5888			tmp = next + 1;
5889			while (tmp <= base)
5890				*new++ = *tmp++;
5891			base = next;
5892		}
5893		new -= n;
5894	} else {
5895		new = malloc(sizeof(BoxRec) * n);
5896		if (!new)
5897			return NULL;
5898
5899		base = next = box;
5900		while (base < box + n) {
5901			const BoxRec *tmp;
5902
5903			while (next < box + n && next->y1 == base->y1)
5904				next++;
5905			tmp = next;
5906			while (tmp != base)
5907				*new++ = *--tmp;
5908			base = next;
5909		}
5910		new -= n;
5911	}
5912
5913	return new;
5914}
5915
5916static void
5917sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
5918		    RegionPtr region,int dx, int dy,
5919		    Pixel bitplane, void *closure)
5920{
5921	PixmapPtr pixmap = get_drawable_pixmap(src);
5922	struct sna *sna = to_sna_from_pixmap(pixmap);
5923	struct sna_pixmap *priv = sna_pixmap(pixmap);
5924	const BoxRec *box = region_rects(region);
5925	int n = region_num_rects(region);
5926	int alu = gc ? gc->alu : GXcopy;
5927	int16_t tx, ty, sx, sy;
5928
5929	assert(pixmap == get_drawable_pixmap(dst));
5930
5931	assert(region_num_rects(region));
5932	if (((dx | dy) == 0 && alu == GXcopy))
5933		return;
5934
5935	if (n > 1 && (dx | dy) < 0) {
5936		box = reorder_boxes(box, n, dx, dy);
5937		if (box == NULL)
5938			return;
5939	}
5940
5941	DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d, pix.size=%dx%d)\n",
5942	     __FUNCTION__, n,
5943	     region->extents.x1, region->extents.y1,
5944	     region->extents.x2, region->extents.y2,
5945	     dx, dy, alu,
5946	     pixmap->drawable.width, pixmap->drawable.height));
5947
5948	get_drawable_deltas(dst, pixmap, &tx, &ty);
5949	get_drawable_deltas(src, pixmap, &sx, &sy);
5950	sx += dx;
5951	sy += dy;
5952
5953	if (priv == NULL || DAMAGE_IS_ALL(priv->cpu_damage)) {
5954		DBG(("%s: unattached, or all damaged on CPU\n", __FUNCTION__));
5955		goto fallback;
5956	}
5957
5958	if (priv->gpu_damage || (priv->cpu_damage == NULL && priv->gpu_bo)) {
5959		assert(priv->gpu_bo);
5960
5961		if (alu == GXcopy && priv->clear)
5962			goto free_boxes;
5963
5964		assert(priv->gpu_bo->proxy == NULL);
5965		if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT)) {
5966			DBG(("%s: fallback - not a pure copy and failed to move dst to GPU\n",
5967			     __FUNCTION__));
5968			goto fallback;
5969		}
5970		assert(priv->cpu_damage == NULL);
5971
5972		if (!sna->render.copy_boxes(sna, alu,
5973					    &pixmap->drawable, priv->gpu_bo, sx, sy,
5974					    &pixmap->drawable, priv->gpu_bo, tx, ty,
5975					    box, n, small_copy(region))) {
5976			DBG(("%s: fallback - accelerated copy boxes failed\n",
5977			     __FUNCTION__));
5978			goto fallback;
5979		}
5980
5981		if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
5982			assert(!priv->clear);
5983			if (sna_pixmap_free_cpu(sna, priv, false)) {
5984				sna_damage_all(&priv->gpu_damage, pixmap);
5985			} else {
5986				RegionTranslate(region, tx, ty);
5987				sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap);
5988			}
5989		}
5990		assert_pixmap_damage(pixmap);
5991	} else {
5992fallback:
5993		DBG(("%s: fallback\n", __FUNCTION__));
5994		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE))
5995			goto free_boxes;
5996
5997		if (alu == GXcopy && pixmap->drawable.bitsPerPixel >= 8) {
5998			assert(pixmap->devKind);
5999			if (sigtrap_get() == 0) {
6000				FbBits *dst_bits, *src_bits;
6001				int stride = pixmap->devKind;
6002				int bpp = pixmap->drawable.bitsPerPixel;
6003				int i;
6004
6005				dst_bits = (FbBits *)
6006					((char *)pixmap->devPrivate.ptr +
6007					 ty * stride + tx * bpp / 8);
6008				src_bits = (FbBits *)
6009					((char *)pixmap->devPrivate.ptr +
6010					 sy * stride + sx * bpp / 8);
6011
6012				for (i = 0; i < n; i++)
6013					memmove_box(src_bits, dst_bits,
6014						    bpp, stride, box+i,
6015						    dx, dy);
6016				sigtrap_put();
6017			}
6018		} else {
6019			if (gc && !sna_gc_move_to_cpu(gc, dst, region))
6020				goto out;
6021
6022			if (sigtrap_get() == 0) {
6023				miCopyRegion(src, dst, gc,
6024					     region, dx, dy,
6025					     fbCopyNtoN, 0, NULL);
6026				sigtrap_put();
6027			}
6028
6029			if (gc)
6030out:
6031				sna_gc_move_to_gpu(gc);
6032		}
6033	}
6034
6035free_boxes:
6036	if (box != region_rects(region))
6037		free((void *)box);
6038}
6039
6040static inline bool
6041sna_pixmap_is_gpu(PixmapPtr pixmap)
6042{
6043	struct sna_pixmap *priv = sna_pixmap(pixmap);
6044
6045	if (priv == NULL || priv->clear)
6046		return false;
6047
6048	if (DAMAGE_IS_ALL(priv->gpu_damage) ||
6049	    (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo) && !priv->gpu_bo->proxy))
6050		return true;
6051
6052	return priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo);
6053}
6054
6055static int
6056copy_prefer_gpu(struct sna *sna,
6057		struct sna_pixmap *dst_priv,
6058		struct sna_pixmap *src_priv,
6059		RegionRec *region,
6060		int16_t dx, int16_t dy)
6061{
6062	assert(dst_priv);
6063
6064	if (wedged(sna) && !dst_priv->pinned)
6065		return 0;
6066
6067	if (src_priv == NULL) {
6068		DBG(("%s: source unattached, use cpu\n", __FUNCTION__));
6069		return 0;
6070	}
6071
6072	if (src_priv->clear) {
6073		DBG(("%s: source is clear, don't force use of GPU\n", __FUNCTION__));
6074		return 0;
6075	}
6076
6077	if (src_priv->gpu_damage &&
6078	    !source_contains_region(src_priv->cpu_damage, region, dx, dy)) {
6079		DBG(("%s: source has gpu damage, force gpu? %d\n",
6080		     __FUNCTION__, src_priv->cpu_damage == NULL));
6081		assert(src_priv->gpu_bo);
6082		return src_priv->cpu_damage ? PREFER_GPU : PREFER_GPU | FORCE_GPU;
6083	}
6084
6085	if (src_priv->cpu_bo && kgem_bo_is_busy(src_priv->cpu_bo)) {
6086		DBG(("%s: source has busy CPU bo, force gpu\n", __FUNCTION__));
6087		return PREFER_GPU | FORCE_GPU;
6088	}
6089
6090	if (source_contains_region(src_priv->cpu_damage, region, dx, dy))
6091		return src_priv->cpu_bo && kgem_is_idle(&sna->kgem);
6092
6093	DBG(("%s: source has GPU bo? %d\n",
6094	     __FUNCTION__, src_priv->gpu_bo != NULL));
6095	return src_priv->gpu_bo != NULL;
6096}
6097
6098static bool use_shm_bo(struct sna *sna,
6099		       struct kgem_bo *bo,
6100		       struct sna_pixmap *priv,
6101		       int alu, bool replaces)
6102{
6103	if (priv == NULL || priv->cpu_bo == NULL) {
6104		DBG(("%s: no, not attached\n", __FUNCTION__));
6105		return false;
6106	}
6107
6108	if (!priv->shm && !priv->cpu) {
6109		DBG(("%s: yes, ordinary CPU bo\n", __FUNCTION__));
6110		return true;
6111	}
6112
6113	if (alu != GXcopy) {
6114		DBG(("%s: yes, complex alu=%d\n", __FUNCTION__, alu));
6115		return true;
6116	}
6117
6118	if (!replaces && __kgem_bo_is_busy(&sna->kgem, bo)) {
6119		DBG(("%s: yes, dst is busy\n", __FUNCTION__));
6120		return true;
6121	}
6122
6123	if (priv->cpu_bo->needs_flush &&
6124	    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
6125		DBG(("%s: yes, src is busy\n", __FUNCTION__));
6126		return true;
6127	}
6128
6129	return false;
6130}
6131
6132static bool
6133sna_damage_contains_box__no_reduce__offset(struct sna_damage *damage,
6134					   const BoxRec *extents,
6135					   int16_t dx, int16_t dy)
6136{
6137	BoxRec _extents;
6138
6139	if (dx | dy) {
6140		_extents.x1 = extents->x1 + dx;
6141		_extents.x2 = extents->x2 + dx;
6142		_extents.y1 = extents->y1 + dy;
6143		_extents.y2 = extents->y2 + dy;
6144		extents = &_extents;
6145	}
6146
6147	return sna_damage_contains_box__no_reduce(damage, extents);
6148}
6149
6150static bool
6151sna_copy_boxes__inplace(struct sna *sna, RegionPtr region, int alu,
6152			PixmapPtr src_pixmap, struct sna_pixmap *src_priv,
6153			int dx, int dy,
6154			PixmapPtr dst_pixmap, struct sna_pixmap *dst_priv,
6155			bool replaces)
6156{
6157	const BoxRec *box;
6158	char *ptr;
6159	int n;
6160
6161	assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel);
6162
6163	if (alu != GXcopy) {
6164		DBG(("%s - no, complex alu [%d]\n", __FUNCTION__, alu));
6165		return false;
6166	}
6167
6168	if (!USE_INPLACE) {
6169		DBG(("%s - no, compile time disabled\n", __FUNCTION__));
6170		return false;
6171	}
6172
6173	if (dst_priv == src_priv) {
6174		DBG(("%s - no, dst == src\n", __FUNCTION__));
6175		return false;
6176	}
6177
6178	if (src_priv == NULL || src_priv->gpu_bo == NULL) {
6179		if (dst_priv && dst_priv->gpu_bo)
6180			goto upload_inplace;
6181
6182		DBG(("%s - no, no src or dst GPU bo\n", __FUNCTION__));
6183		return false;
6184	}
6185
6186	switch (src_priv->gpu_bo->tiling) {
6187	case I915_TILING_Y:
6188		DBG(("%s - no, bad src tiling [Y]\n", __FUNCTION__));
6189		return false;
6190	case I915_TILING_X:
6191		if (!sna->kgem.memcpy_from_tiled_x) {
6192			DBG(("%s - no, bad src tiling [X]\n", __FUNCTION__));
6193			return false;
6194		}
6195	default:
6196		break;
6197	}
6198
6199	if (src_priv->move_to_gpu && !src_priv->move_to_gpu(sna, src_priv, MOVE_READ)) {
6200		DBG(("%s - no, pending src move-to-gpu failed\n", __FUNCTION__));
6201		return false;
6202	}
6203
6204	if (!kgem_bo_can_map__cpu(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC)) {
6205		DBG(("%s - no, cannot map src for reads into the CPU\n", __FUNCTION__));
6206		return false;
6207	}
6208
6209	if (src_priv->gpu_damage == NULL ||
6210	    !(DAMAGE_IS_ALL(src_priv->gpu_damage) ||
6211	      sna_damage_contains_box__no_reduce__offset(src_priv->gpu_damage,
6212							 &region->extents,
6213							 dx, dy))) {
6214		DBG(("%s - no, src is not damaged on the GPU\n", __FUNCTION__));
6215		return false;
6216	}
6217
6218	assert(sna_damage_contains_box__offset(&src_priv->gpu_damage, &region->extents, dx, dy) == PIXMAN_REGION_IN);
6219	assert(sna_damage_contains_box__offset(&src_priv->cpu_damage, &region->extents, dx, dy) == PIXMAN_REGION_OUT);
6220
6221	ptr = kgem_bo_map__cpu(&sna->kgem, src_priv->gpu_bo);
6222	if (ptr == NULL) {
6223		DBG(("%s - no, map failed\n", __FUNCTION__));
6224		return false;
6225	}
6226
6227	if (dst_priv &&
6228	    !sna_drawable_move_region_to_cpu(&dst_pixmap->drawable,
6229					     region, MOVE_WRITE | MOVE_INPLACE_HINT)) {
6230		DBG(("%s - no, dst sync failed\n", __FUNCTION__));
6231		return false;
6232	}
6233
6234	kgem_bo_sync__cpu_full(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC);
6235
6236	if (sigtrap_get())
6237		return false;
6238
6239	box = region_rects(region);
6240	n = region_num_rects(region);
6241	if (src_priv->gpu_bo->tiling) {
6242		DBG(("%s: copy from a tiled CPU map\n", __FUNCTION__));
6243		assert(dst_pixmap->devKind);
6244		do {
6245			memcpy_from_tiled_x(&sna->kgem, ptr, dst_pixmap->devPrivate.ptr,
6246					    src_pixmap->drawable.bitsPerPixel,
6247					    src_priv->gpu_bo->pitch,
6248					    dst_pixmap->devKind,
6249					    box->x1 + dx, box->y1 + dy,
6250					    box->x1, box->y1,
6251					    box->x2 - box->x1, box->y2 - box->y1);
6252			box++;
6253		} while (--n);
6254	} else {
6255		DBG(("%s: copy from a linear CPU map\n", __FUNCTION__));
6256		assert(dst_pixmap->devKind);
6257		do {
6258			memcpy_blt(ptr, dst_pixmap->devPrivate.ptr,
6259				   src_pixmap->drawable.bitsPerPixel,
6260				   src_priv->gpu_bo->pitch,
6261				   dst_pixmap->devKind,
6262				   box->x1 + dx, box->y1 + dy,
6263				   box->x1, box->y1,
6264				   box->x2 - box->x1, box->y2 - box->y1);
6265			box++;
6266		} while (--n);
6267
6268		if (!src_priv->shm) {
6269			assert(ptr == MAP(src_priv->gpu_bo->map__cpu));
6270			src_pixmap->devPrivate.ptr = ptr;
6271			src_pixmap->devKind = src_priv->gpu_bo->pitch;
6272			src_priv->mapped = MAPPED_CPU;
6273			assert_pixmap_map(src_pixmap, src_priv);
6274			src_priv->cpu = true;
6275		}
6276	}
6277
6278	sigtrap_put();
6279
6280	return true;
6281
6282upload_inplace:
6283	switch (dst_priv->gpu_bo->tiling) {
6284	case I915_TILING_Y:
6285		DBG(("%s - no, bad dst tiling [Y]\n", __FUNCTION__));
6286		return false;
6287	case I915_TILING_X:
6288		if (!sna->kgem.memcpy_to_tiled_x) {
6289			DBG(("%s - no, bad dst tiling [X]\n", __FUNCTION__));
6290			return false;
6291		}
6292	default:
6293		break;
6294	}
6295
6296	if (dst_priv->move_to_gpu) {
6297		DBG(("%s - no, pending dst move-to-gpu\n", __FUNCTION__));
6298		return false;
6299	}
6300
6301	if (!can_upload__tiled_x(&sna->kgem, dst_priv->gpu_bo) ||
6302	    __kgem_bo_is_busy(&sna->kgem, dst_priv->gpu_bo)) {
6303		if (replaces && !dst_priv->pinned) {
6304			unsigned create;
6305			struct kgem_bo *bo;
6306
6307			create = CREATE_CPU_MAP | CREATE_INACTIVE;
6308			if (dst_priv->gpu_bo->scanout)
6309				create |= CREATE_SCANOUT;
6310
6311			bo = kgem_create_2d(&sna->kgem,
6312					    dst_pixmap->drawable.width,
6313					    dst_pixmap->drawable.height,
6314					    dst_pixmap->drawable.bitsPerPixel,
6315					    dst_priv->gpu_bo->tiling,
6316					    create);
6317			if (bo == NULL)
6318				return false;
6319
6320			sna_pixmap_unmap(dst_pixmap, dst_priv);
6321			kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo);
6322			dst_priv->gpu_bo = bo;
6323		} else {
6324			DBG(("%s - no, dst is busy\n", __FUNCTION__));
6325			return false;
6326		}
6327
6328		if (!can_upload__tiled_x(&sna->kgem, dst_priv->gpu_bo)) {
6329			DBG(("%s - no, cannot map dst for reads into the CPU\n", __FUNCTION__));
6330			return false;
6331		}
6332	}
6333
6334	if (src_priv &&
6335	    !sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
6336					     region, MOVE_READ)) {
6337		DBG(("%s - no, src sync failed\n", __FUNCTION__));
6338		return false;
6339	}
6340
6341	if (kgem_bo_can_map__cpu(&sna->kgem, dst_priv->gpu_bo, true)) {
6342		ptr = kgem_bo_map__cpu(&sna->kgem, dst_priv->gpu_bo);
6343		if (ptr == NULL) {
6344			DBG(("%s - no, map failed\n", __FUNCTION__));
6345			return false;
6346		}
6347
6348		kgem_bo_sync__cpu(&sna->kgem, dst_priv->gpu_bo);
6349	} else {
6350		ptr = kgem_bo_map__wc(&sna->kgem, dst_priv->gpu_bo);
6351		if (ptr == NULL) {
6352			DBG(("%s - no, map failed\n", __FUNCTION__));
6353			return false;
6354		}
6355
6356		kgem_bo_sync__gtt(&sna->kgem, dst_priv->gpu_bo);
6357	}
6358
6359	if (!DAMAGE_IS_ALL(dst_priv->gpu_damage)) {
6360		assert(!dst_priv->clear);
6361		sna_damage_add_to_pixmap(&dst_priv->gpu_damage, region, dst_pixmap);
6362		if (sna_damage_is_all(&dst_priv->gpu_damage,
6363				      dst_pixmap->drawable.width,
6364				      dst_pixmap->drawable.height)) {
6365			DBG(("%s: replaced entire pixmap, destroying CPU shadow\n",
6366			     __FUNCTION__));
6367			sna_damage_destroy(&dst_priv->cpu_damage);
6368			list_del(&dst_priv->flush_list);
6369		} else
6370			sna_damage_subtract(&dst_priv->cpu_damage,
6371					    region);
6372	}
6373	dst_priv->clear = false;
6374
6375	assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
6376
6377	if (sigtrap_get())
6378		return false;
6379
6380	box = region_rects(region);
6381	n = region_num_rects(region);
6382	if (dst_priv->gpu_bo->tiling) {
6383		DBG(("%s: copy to a tiled CPU map\n", __FUNCTION__));
6384		assert(dst_priv->gpu_bo->tiling == I915_TILING_X);
6385		assert(src_pixmap->devKind);
6386		do {
6387			memcpy_to_tiled_x(&sna->kgem, src_pixmap->devPrivate.ptr, ptr,
6388					  src_pixmap->drawable.bitsPerPixel,
6389					  src_pixmap->devKind,
6390					  dst_priv->gpu_bo->pitch,
6391					  box->x1 + dx, box->y1 + dy,
6392					  box->x1, box->y1,
6393					  box->x2 - box->x1, box->y2 - box->y1);
6394			box++;
6395		} while (--n);
6396	} else {
6397		DBG(("%s: copy to a linear CPU map\n", __FUNCTION__));
6398		assert(src_pixmap->devKind);
6399		do {
6400			memcpy_blt(src_pixmap->devPrivate.ptr, ptr,
6401				   src_pixmap->drawable.bitsPerPixel,
6402				   src_pixmap->devKind,
6403				   dst_priv->gpu_bo->pitch,
6404				   box->x1 + dx, box->y1 + dy,
6405				   box->x1, box->y1,
6406				   box->x2 - box->x1, box->y2 - box->y1);
6407			box++;
6408		} while (--n);
6409
6410		if (!dst_priv->shm) {
6411			dst_pixmap->devPrivate.ptr = ptr;
6412			dst_pixmap->devKind = dst_priv->gpu_bo->pitch;
6413			if (ptr == MAP(dst_priv->gpu_bo->map__cpu)) {
6414				dst_priv->mapped = MAPPED_CPU;
6415				dst_priv->cpu = true;
6416			} else
6417				dst_priv->mapped = MAPPED_GTT;
6418			assert_pixmap_map(dst_pixmap, dst_priv);
6419		}
6420	}
6421
6422	sigtrap_put();
6423
6424	return true;
6425}
6426
6427static void discard_cpu_damage(struct sna *sna, struct sna_pixmap *priv)
6428{
6429	if (priv->cpu_damage == NULL && !priv->shm)
6430		return;
6431
6432	DBG(("%s: discarding existing CPU damage\n", __FUNCTION__));
6433
6434	if (kgem_bo_discard_cache(priv->gpu_bo, true)) {
6435		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
6436		assert(DAMAGE_IS_ALL(priv->cpu_damage));
6437		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */
6438		assert(!priv->pinned);
6439		assert(!priv->mapped);
6440		sna_damage_destroy(&priv->gpu_damage);
6441		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
6442		priv->gpu_bo = NULL;
6443	}
6444
6445	sna_damage_destroy(&priv->cpu_damage);
6446	list_del(&priv->flush_list);
6447
6448	if (priv->gpu_bo && sna_pixmap_free_cpu(sna, priv, priv->cpu))
6449		sna_damage_all(&priv->gpu_damage, priv->pixmap);
6450	priv->cpu = false;
6451}
6452
6453static void
6454sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
6455	       RegionPtr region, int dx, int dy,
6456	       Pixel bitplane, void *closure)
6457{
6458	PixmapPtr src_pixmap = get_drawable_pixmap(src);
6459	struct sna_pixmap *src_priv = sna_pixmap(src_pixmap);
6460	PixmapPtr dst_pixmap = get_drawable_pixmap(dst);
6461	struct sna_pixmap *dst_priv = sna_pixmap(dst_pixmap);
6462	struct sna *sna = to_sna_from_pixmap(src_pixmap);
6463	struct sna_damage **damage;
6464	struct kgem_bo *bo;
6465	int16_t src_dx, src_dy;
6466	int16_t dst_dx, dst_dy;
6467	const BoxRec *box = region_rects(region);
6468	int n = region_num_rects(region);
6469	int alu = gc->alu;
6470	int stride, bpp;
6471	char *bits;
6472	bool replaces;
6473
6474	assert(region_num_rects(region));
6475
6476	if (src_priv &&
6477	    src_priv->gpu_bo == NULL &&
6478	    src_priv->cpu_bo == NULL &&
6479	    src_priv->ptr == NULL) {
6480		/* Rare but still happens, nothing to copy */
6481		DBG(("%s: src pixmap=%ld is empty\n",
6482		     __FUNCTION__, src_pixmap->drawable.serialNumber));
6483		return;
6484	}
6485
6486	if (src_pixmap == dst_pixmap)
6487		return sna_self_copy_boxes(src, dst, gc,
6488					   region, dx, dy,
6489					   bitplane, closure);
6490
6491	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",
6492	     __FUNCTION__, n,
6493	     box[0].x1, box[0].y1, box[0].x2, box[0].y2,
6494	     src_pixmap->drawable.serialNumber, dx, dy,
6495	     dst_pixmap->drawable.serialNumber, get_drawable_dx(dst), get_drawable_dy(dst),
6496	     alu,
6497	     src_pixmap->drawable.width, src_pixmap->drawable.height,
6498	     dst_pixmap->drawable.width, dst_pixmap->drawable.height));
6499
6500	assert_pixmap_damage(dst_pixmap);
6501	assert_pixmap_damage(src_pixmap);
6502
6503	bpp = dst_pixmap->drawable.bitsPerPixel;
6504
6505	if (get_drawable_deltas(dst, dst_pixmap, &dst_dx, &dst_dy))
6506		RegionTranslate(region, dst_dx, dst_dy);
6507	get_drawable_deltas(src, src_pixmap, &src_dx, &src_dy);
6508	src_dx += dx - dst_dx;
6509	src_dy += dy - dst_dy;
6510
6511	assert_pixmap_contains_box(dst_pixmap, RegionExtents(region));
6512	assert_pixmap_contains_box_with_offset(src_pixmap,
6513					       RegionExtents(region),
6514					       src_dx, src_dy);
6515
6516	replaces = n == 1 &&
6517		alu_overwrites(alu) &&
6518		box->x1 <= 0 &&
6519		box->y1 <= 0 &&
6520		box->x2 >= dst_pixmap->drawable.width &&
6521		box->y2 >= dst_pixmap->drawable.height;
6522
6523	DBG(("%s: dst=(priv=%p, gpu_bo=%d, cpu_bo=%d), src=(priv=%p, gpu_bo=%d, cpu_bo=%d), replaces=%d\n",
6524	     __FUNCTION__,
6525	     dst_priv,
6526	     dst_priv && dst_priv->gpu_bo ? dst_priv->gpu_bo->handle : 0,
6527	     dst_priv && dst_priv->cpu_bo ? dst_priv->cpu_bo->handle : 0,
6528	     src_priv,
6529	     src_priv && src_priv->gpu_bo ? src_priv->gpu_bo->handle : 0,
6530	     src_priv && src_priv->cpu_bo ? src_priv->cpu_bo->handle : 0,
6531	     replaces));
6532
6533	if (dst_priv == NULL) {
6534		DBG(("%s: unattached dst failed, fallback\n", __FUNCTION__));
6535		goto fallback;
6536	}
6537
6538	if (alu == GXcopy &&
6539	    src_priv && src_priv->cow &&
6540	    COW(src_priv->cow) == COW(dst_priv->cow)) {
6541		if ((dx | dy) == 0) {
6542			DBG(("%s: ignoring cow for no op\n",
6543			     __FUNCTION__));
6544			return;
6545		} else if (IS_COW_OWNER(dst_priv->cow)) {
6546			/* XXX hack for firefox -- subsequent uses of src will be corrupt! */
6547			DBG(("%s: ignoring cow reference for cousin copy\n",
6548			     __FUNCTION__));
6549			assert(src_priv->cpu_damage == NULL);
6550			assert(dst_priv->move_to_gpu == NULL);
6551			bo = dst_priv->gpu_bo;
6552			damage = NULL;
6553		} else
6554			goto discard_cow;
6555	} else {
6556		unsigned hint;
6557discard_cow:
6558		hint = copy_prefer_gpu(sna, dst_priv, src_priv, region, src_dx, src_dy);
6559		if (replaces) {
6560			discard_cpu_damage(sna, dst_priv);
6561			hint |= REPLACES | IGNORE_DAMAGE;
6562		} else if (alu_overwrites(alu)) {
6563			if (region->data == NULL)
6564				hint |= IGNORE_DAMAGE;
6565			if (dst_priv->cpu_damage &&
6566			    region_subsumes_damage(region,
6567						   dst_priv->cpu_damage))
6568				discard_cpu_damage(sna, dst_priv);
6569		}
6570		bo = sna_drawable_use_bo(&dst_pixmap->drawable, hint,
6571					 &region->extents, &damage);
6572	}
6573	if (bo) {
6574		if (alu == GXset || alu == GXclear || (src_priv && src_priv->clear)) {
6575			uint32_t color;
6576
6577			if (alu == GXset)
6578				color = (1 << dst_pixmap->drawable.depth) - 1;
6579			else if (alu == GXclear)
6580				color = 0;
6581			else
6582				color = src_priv->clear_color;
6583			DBG(("%s: applying src clear [%08x] to dst\n",
6584			     __FUNCTION__, src_priv->clear_color));
6585
6586			if (n == 1) {
6587				if (replaces && UNDO)
6588					kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
6589
6590				if (!sna->render.fill_one(sna,
6591							  dst_pixmap, bo, color,
6592							  box->x1, box->y1,
6593							  box->x2, box->y2,
6594							  alu)) {
6595					DBG(("%s: unsupported fill\n",
6596					     __FUNCTION__));
6597					goto fallback;
6598				}
6599
6600				if (replaces && bo == dst_priv->gpu_bo) {
6601					DBG(("%s: marking dst handle=%d as all clear [%08x]\n",
6602					     __FUNCTION__,
6603					     dst_priv->gpu_bo->handle,
6604					     src_priv->clear_color));
6605					dst_priv->clear = true;
6606					dst_priv->clear_color = color;
6607					sna_damage_all(&dst_priv->gpu_damage, dst_pixmap);
6608					sna_damage_destroy(&dst_priv->cpu_damage);
6609					list_del(&dst_priv->flush_list);
6610					return;
6611				}
6612			} else {
6613				struct sna_fill_op fill;
6614
6615				if (!sna_fill_init_blt(&fill, sna,
6616						       dst_pixmap, bo,
6617						       alu, color,
6618						       FILL_BOXES)) {
6619					DBG(("%s: unsupported fill\n",
6620					     __FUNCTION__));
6621					goto fallback;
6622				}
6623
6624				fill.boxes(sna, &fill, box, n);
6625				fill.done(sna, &fill);
6626			}
6627
6628			if (damage)
6629				sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6630			return;
6631		}
6632
6633		if (src_priv &&
6634		    move_to_gpu(src_pixmap, src_priv, region, src_dx, src_dy, alu, bo == dst_priv->gpu_bo) &&
6635		    sna_pixmap_move_to_gpu(src_pixmap, MOVE_READ | MOVE_ASYNC_HINT)) {
6636			DBG(("%s: move whole src_pixmap to GPU and copy\n",
6637			     __FUNCTION__));
6638			if (replaces && UNDO)
6639				kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
6640
6641			if (replaces &&
6642			    src_pixmap->drawable.width == dst_pixmap->drawable.width &&
6643			    src_pixmap->drawable.height == dst_pixmap->drawable.height) {
6644				assert(src_pixmap->drawable.depth == dst_pixmap->drawable.depth);
6645				assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel);
6646				if (sna_pixmap_make_cow(sna, src_priv, dst_priv)) {
6647					assert(dst_priv->gpu_bo == src_priv->gpu_bo);
6648					sna_damage_all(&dst_priv->gpu_damage, dst_pixmap);
6649					sna_damage_destroy(&dst_priv->cpu_damage);
6650					list_del(&dst_priv->flush_list);
6651					add_shm_flush(sna, dst_priv);
6652					return;
6653				}
6654			}
6655			if (!sna->render.copy_boxes(sna, alu,
6656						    &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy,
6657						    &dst_pixmap->drawable, bo, 0, 0,
6658						    box, n, small_copy(region))) {
6659				DBG(("%s: fallback - accelerated copy boxes failed\n",
6660				     __FUNCTION__));
6661				goto fallback;
6662			}
6663
6664			if (damage)
6665				sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6666			return;
6667		}
6668
6669		if (src_priv &&
6670		    region_overlaps_damage(region, src_priv->gpu_damage,
6671					   src_dx, src_dy)) {
6672			BoxRec area;
6673
6674			DBG(("%s: region overlaps GPU damage, upload and copy\n",
6675			     __FUNCTION__));
6676
6677			area = region->extents;
6678			area.x1 += src_dx;
6679			area.x2 += src_dx;
6680			area.y1 += src_dy;
6681			area.y2 += src_dy;
6682
6683			if (!sna_pixmap_move_area_to_gpu(src_pixmap, &area,
6684							 MOVE_READ | MOVE_ASYNC_HINT)) {
6685				DBG(("%s: move-to-gpu(src) failed, fallback\n", __FUNCTION__));
6686				goto fallback;
6687			}
6688
6689			if (replaces && UNDO)
6690				kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
6691
6692			if (!sna->render.copy_boxes(sna, alu,
6693						    &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy,
6694						    &dst_pixmap->drawable, bo, 0, 0,
6695						    box, n, small_copy(region))) {
6696				DBG(("%s: fallback - accelerated copy boxes failed\n",
6697				     __FUNCTION__));
6698				goto fallback;
6699			}
6700
6701			if (damage)
6702				sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6703			return;
6704		}
6705
6706		if (bo != dst_priv->gpu_bo)
6707			goto fallback;
6708
6709		if (use_shm_bo(sna, bo, src_priv, alu, replaces && !dst_priv->pinned)) {
6710			bool ret;
6711
6712			DBG(("%s: region overlaps CPU damage, copy from CPU bo (shm? %d)\n",
6713			     __FUNCTION__, src_priv->shm));
6714
6715			assert(bo != dst_priv->cpu_bo);
6716
6717			RegionTranslate(region, src_dx, src_dy);
6718			ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
6719							      region,
6720							      MOVE_READ | MOVE_ASYNC_HINT);
6721			RegionTranslate(region, -src_dx, -src_dy);
6722			if (!ret) {
6723				DBG(("%s: move-to-cpu(src) failed, fallback\n", __FUNCTION__));
6724				goto fallback;
6725			}
6726
6727			if (replaces && UNDO)
6728				kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
6729
6730			add_shm_flush(sna, src_priv);
6731
6732			if (!sna->render.copy_boxes(sna, alu,
6733						    &src_pixmap->drawable, src_priv->cpu_bo, src_dx, src_dy,
6734						    &dst_pixmap->drawable, bo, 0, 0,
6735						    box, n, small_copy(region) | (src_priv->shm ? COPY_LAST : 0))) {
6736				DBG(("%s: fallback - accelerated copy boxes failed\n",
6737				     __FUNCTION__));
6738				goto fallback;
6739			}
6740
6741			if (damage)
6742				sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6743			return;
6744		}
6745
6746		if (src_priv) {
6747			bool ret;
6748
6749			RegionTranslate(region, src_dx, src_dy);
6750			ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
6751							      region, MOVE_READ);
6752			RegionTranslate(region, -src_dx, -src_dy);
6753			if (!ret) {
6754				DBG(("%s: move-to-cpu(src) failed, fallback\n", __FUNCTION__));
6755				goto fallback;
6756			}
6757
6758			assert(!src_priv->mapped);
6759			if (src_pixmap->devPrivate.ptr == NULL)
6760				/* uninitialised!*/
6761				return;
6762		}
6763
6764		if (USE_USERPTR_UPLOADS &&
6765		    sna->kgem.has_userptr &&
6766		    (alu != GXcopy ||
6767		     (box_inplace(src_pixmap, &region->extents) &&
6768		      __kgem_bo_is_busy(&sna->kgem, bo)))) {
6769			struct kgem_bo *src_bo;
6770			bool ok = false;
6771
6772			DBG(("%s: upload through a temporary map\n",
6773			     __FUNCTION__));
6774
6775			assert(src_pixmap->devKind);
6776			src_bo = kgem_create_map(&sna->kgem,
6777						 src_pixmap->devPrivate.ptr,
6778						 src_pixmap->devKind * src_pixmap->drawable.height,
6779						 true);
6780			if (src_bo) {
6781				src_bo->pitch = src_pixmap->devKind;
6782				kgem_bo_mark_unreusable(src_bo);
6783
6784				ok = sna->render.copy_boxes(sna, alu,
6785							    &src_pixmap->drawable, src_bo, src_dx, src_dy,
6786							    &dst_pixmap->drawable, bo, 0, 0,
6787							    box, n, small_copy(region) |  COPY_LAST);
6788				kgem_bo_sync__cpu(&sna->kgem, src_bo);
6789				assert(src_bo->rq == NULL);
6790				kgem_bo_destroy(&sna->kgem, src_bo);
6791			}
6792
6793			if (ok) {
6794				if (damage)
6795					sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6796				return;
6797			}
6798		}
6799
6800		if (alu != GXcopy) {
6801			PixmapPtr tmp;
6802			struct kgem_bo *src_bo;
6803			int i;
6804
6805			assert(src_pixmap->drawable.depth != 1);
6806
6807			DBG(("%s: creating temporary source upload for non-copy alu [%d]\n",
6808			     __FUNCTION__, alu));
6809
6810			tmp = sna_pixmap_create_upload(src->pScreen,
6811						       region->extents.x2 - region->extents.x1,
6812						       region->extents.y2 - region->extents.y1,
6813						       src->depth,
6814						       KGEM_BUFFER_WRITE_INPLACE);
6815			if (tmp == NullPixmap)
6816				return;
6817
6818			src_bo = __sna_pixmap_get_bo(tmp);
6819			assert(src_bo != NULL);
6820
6821			dx = -region->extents.x1;
6822			dy = -region->extents.y1;
6823			for (i = 0; i < n; i++) {
6824				assert(box[i].x1 + src_dx >= 0);
6825				assert(box[i].y1 + src_dy >= 0);
6826				assert(box[i].x2 + src_dx <= src_pixmap->drawable.width);
6827				assert(box[i].y2 + src_dy <= src_pixmap->drawable.height);
6828
6829				assert(box[i].x1 + dx >= 0);
6830				assert(box[i].y1 + dy >= 0);
6831				assert(box[i].x2 + dx <= tmp->drawable.width);
6832				assert(box[i].y2 + dy <= tmp->drawable.height);
6833
6834				assert(has_coherent_ptr(sna, sna_pixmap(src_pixmap), MOVE_READ));
6835				assert(has_coherent_ptr(sna, sna_pixmap(tmp), MOVE_WRITE));
6836				assert(src_pixmap->devKind);
6837				assert(tmp->devKind);
6838				memcpy_blt(src_pixmap->devPrivate.ptr,
6839					   tmp->devPrivate.ptr,
6840					   src_pixmap->drawable.bitsPerPixel,
6841					   src_pixmap->devKind,
6842					   tmp->devKind,
6843					   box[i].x1 + src_dx,
6844					   box[i].y1 + src_dy,
6845					   box[i].x1 + dx,
6846					   box[i].y1 + dy,
6847					   box[i].x2 - box[i].x1,
6848					   box[i].y2 - box[i].y1);
6849			}
6850
6851			if (n == 1 &&
6852			    tmp->drawable.width == src_pixmap->drawable.width &&
6853			    tmp->drawable.height == src_pixmap->drawable.height) {
6854				DBG(("%s: caching upload for src bo\n",
6855				     __FUNCTION__));
6856				assert(src_priv->gpu_damage == NULL);
6857				assert(src_priv->gpu_bo == NULL);
6858				kgem_proxy_bo_attach(src_bo, &src_priv->gpu_bo);
6859			}
6860
6861			if (!sna->render.copy_boxes(sna, alu,
6862						    &tmp->drawable, src_bo, dx, dy,
6863						    &dst_pixmap->drawable, bo, 0, 0,
6864						    box, n, 0)) {
6865				DBG(("%s: fallback - accelerated copy boxes failed\n",
6866				     __FUNCTION__));
6867				tmp->drawable.pScreen->DestroyPixmap(tmp);
6868				goto fallback;
6869			}
6870			tmp->drawable.pScreen->DestroyPixmap(tmp);
6871
6872			if (damage)
6873				sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6874			return;
6875		} else {
6876			DBG(("%s: dst is on the GPU, src is on the CPU, uploading into dst\n",
6877			     __FUNCTION__));
6878
6879			assert(src_pixmap->devKind);
6880			if (!dst_priv->pinned && replaces) {
6881				stride = src_pixmap->devKind;
6882				bits = src_pixmap->devPrivate.ptr;
6883				bits += (src_dy + box->y1) * stride + (src_dx + box->x1) * bpp / 8;
6884
6885				if (!sna_replace(sna, dst_pixmap, bits, stride)) {
6886					DBG(("%s: replace failed, fallback\n", __FUNCTION__));
6887					goto fallback;
6888				}
6889			} else {
6890				assert(!DAMAGE_IS_ALL(dst_priv->cpu_damage));
6891				if (!sna_write_boxes(sna, dst_pixmap,
6892						     dst_priv->gpu_bo, 0, 0,
6893						     src_pixmap->devPrivate.ptr,
6894						     src_pixmap->devKind,
6895						     src_dx, src_dy,
6896						     box, n)) {
6897					DBG(("%s: write failed, fallback\n", __FUNCTION__));
6898					goto fallback;
6899				}
6900			}
6901
6902			assert(dst_priv->clear == false);
6903			dst_priv->cpu = false;
6904			if (damage) {
6905				assert(!dst_priv->clear);
6906				assert(dst_priv->gpu_bo);
6907				assert(dst_priv->gpu_bo->proxy == NULL);
6908				assert(*damage == dst_priv->gpu_damage);
6909				if (replaces) {
6910					sna_damage_destroy(&dst_priv->cpu_damage);
6911					sna_damage_all(&dst_priv->gpu_damage, dst_pixmap);
6912					list_del(&dst_priv->flush_list);
6913				} else
6914					sna_damage_add(&dst_priv->gpu_damage,
6915						       region);
6916				assert_pixmap_damage(dst_pixmap);
6917			}
6918		}
6919
6920		return;
6921	}
6922
6923fallback:
6924	if (alu == GXcopy && src_priv && src_priv->clear) {
6925		DBG(("%s: copying clear [%08x]\n",
6926		     __FUNCTION__, src_priv->clear_color));
6927
6928		if (dst_priv) {
6929			if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable,
6930							     region,
6931							     MOVE_WRITE | MOVE_INPLACE_HINT))
6932				return;
6933		}
6934
6935		if (sigtrap_get() == 0) {
6936			assert(dst_pixmap->devPrivate.ptr);
6937			assert(dst_pixmap->devKind);
6938			sigtrap_assert_active();
6939			do {
6940				pixman_fill(dst_pixmap->devPrivate.ptr,
6941					    dst_pixmap->devKind/sizeof(uint32_t),
6942					    dst_pixmap->drawable.bitsPerPixel,
6943					    box->x1, box->y1,
6944					    box->x2 - box->x1,
6945					    box->y2 - box->y1,
6946					    src_priv->clear_color);
6947				box++;
6948			} while (--n);
6949			sigtrap_put();
6950		}
6951	} else if (!sna_copy_boxes__inplace(sna, region, alu,
6952					    src_pixmap, src_priv,
6953					    src_dx, src_dy,
6954					    dst_pixmap, dst_priv,
6955					    replaces)) {
6956		FbBits *dst_bits, *src_bits;
6957		int dst_stride, src_stride;
6958
6959		DBG(("%s: fallback -- src=(%d, %d), dst=(%d, %d)\n",
6960		     __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy));
6961		if (src_priv) {
6962			unsigned mode;
6963
6964			RegionTranslate(region, src_dx, src_dy);
6965
6966			assert_pixmap_contains_box(src_pixmap,
6967						   RegionExtents(region));
6968
6969			mode = MOVE_READ;
6970			if (!sna->kgem.can_blt_cpu ||
6971			    (src_priv->cpu_bo == NULL &&
6972			     (src_priv->create & KGEM_CAN_CREATE_CPU) == 0))
6973				mode |= MOVE_INPLACE_HINT;
6974
6975			if (!sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
6976							     region, mode))
6977				return;
6978
6979			RegionTranslate(region, -src_dx, -src_dy);
6980		}
6981		assert(src_priv == sna_pixmap(src_pixmap));
6982
6983		if (dst_priv) {
6984			unsigned mode;
6985
6986			if (alu_overwrites(alu))
6987				mode = MOVE_WRITE | MOVE_INPLACE_HINT;
6988			else
6989				mode = MOVE_WRITE | MOVE_READ;
6990			if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable,
6991							     region, mode))
6992				return;
6993		}
6994		assert(dst_priv == sna_pixmap(dst_pixmap));
6995
6996		assert(dst_pixmap->devKind);
6997		assert(src_pixmap->devKind);
6998		dst_stride = dst_pixmap->devKind;
6999		src_stride = src_pixmap->devKind;
7000
7001		if (alu == GXcopy && bpp >= 8) {
7002			dst_bits = (FbBits *)dst_pixmap->devPrivate.ptr;
7003			src_bits = (FbBits *)
7004				((char *)src_pixmap->devPrivate.ptr +
7005				 src_dy * src_stride + src_dx * bpp / 8);
7006
7007			if (sigtrap_get() == 0) {
7008				do {
7009					DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n",
7010					     __FUNCTION__,
7011					     box->x1, box->y1,
7012					     box->x2 - box->x1,
7013					     box->y2 - box->y1,
7014					     src_dx, src_dy,
7015					     src_stride, dst_stride));
7016
7017					assert(box->x1 >= 0);
7018					assert(box->y1 >= 0);
7019					assert(box->x2 <= dst_pixmap->drawable.width);
7020					assert(box->y2 <= dst_pixmap->drawable.height);
7021
7022					assert(box->x1 + src_dx >= 0);
7023					assert(box->y1 + src_dy >= 0);
7024					assert(box->x2 + src_dx <= src_pixmap->drawable.width);
7025					assert(box->y2 + src_dy <= src_pixmap->drawable.height);
7026					assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
7027					assert(has_coherent_ptr(sna, dst_priv, MOVE_WRITE));
7028					assert(src_stride);
7029					assert(dst_stride);
7030					memcpy_blt(src_bits, dst_bits, bpp,
7031						   src_stride, dst_stride,
7032						   box->x1, box->y1,
7033						   box->x1, box->y1,
7034						   box->x2 - box->x1,
7035						   box->y2 - box->y1);
7036					box++;
7037				} while (--n);
7038				sigtrap_put();
7039			}
7040		} else {
7041			DBG(("%s: fallback -- miCopyRegion\n", __FUNCTION__));
7042
7043			RegionTranslate(region, -dst_dx, -dst_dy);
7044
7045			if (sna_gc_move_to_cpu(gc, dst, region) &&
7046			    sigtrap_get() == 0) {
7047				miCopyRegion(src, dst, gc,
7048					     region, dx, dy,
7049					     fbCopyNtoN, 0, NULL);
7050				sigtrap_put();
7051			}
7052
7053			sna_gc_move_to_gpu(gc);
7054		}
7055	}
7056}
7057
7058typedef void (*sna_copy_func)(DrawablePtr src, DrawablePtr dst, GCPtr gc,
7059			      RegionPtr region, int dx, int dy,
7060			      Pixel bitPlane, void *closure);
7061
7062static inline bool box_equal(const BoxRec *a, const BoxRec *b)
7063{
7064	return *(const uint64_t *)a == *(const uint64_t *)b;
7065}
7066
7067static inline bool has_clip(GCPtr gc)
7068{
7069#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0)
7070	return gc->clientClipType != CT_NONE;
7071#else
7072	return gc->clientClip != NULL;
7073#endif
7074}
7075
7076static RegionPtr
7077sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc,
7078	    int sx, int sy,
7079	    int width, int height,
7080	    int dx, int dy,
7081	    sna_copy_func copy, Pixel bitPlane, void *closure)
7082{
7083	RegionPtr clip;
7084	RegionRec region;
7085	BoxRec src_extents;
7086	bool expose;
7087
7088	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n",
7089	     __FUNCTION__, sx, sy, dx, dy, width, height));
7090
7091	/* Short cut for unmapped windows */
7092	if (dst->type == DRAWABLE_WINDOW && !((WindowPtr)dst)->realized) {
7093		DBG(("%s: unmapped/unrealized dst (pixmap=%ld)\n",
7094		     __FUNCTION__, get_window_pixmap((WindowPtr)dst)));
7095		return NULL;
7096	}
7097
7098	SourceValidate(src, sx, sy, width, height, gc->subWindowMode);
7099
7100	sx += src->x;
7101	sy += src->y;
7102
7103	dx += dst->x;
7104	dy += dst->y;
7105
7106	DBG(("%s: after drawable: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n",
7107	     __FUNCTION__, sx, sy, dx, dy, width, height));
7108
7109	region.extents.x1 = dx;
7110	region.extents.y1 = dy;
7111	region.extents.x2 = bound(dx, width);
7112	region.extents.y2 = bound(dy, height);
7113	region.data = NULL;
7114
7115	DBG(("%s: dst extents (%d, %d), (%d, %d), dst clip extents (%d, %d), (%d, %d), dst size=%dx%d\n", __FUNCTION__,
7116	     region.extents.x1, region.extents.y1,
7117	     region.extents.x2, region.extents.y2,
7118	     gc->pCompositeClip->extents.x1, gc->pCompositeClip->extents.y1,
7119	     gc->pCompositeClip->extents.x2, gc->pCompositeClip->extents.y2,
7120	     dst->width, dst->height));
7121
7122	if (!box_intersect(&region.extents, &gc->pCompositeClip->extents)) {
7123		DBG(("%s: dst clipped out\n", __FUNCTION__));
7124		return NULL;
7125	}
7126
7127	DBG(("%s: clipped dst extents (%d, %d), (%d, %d)\n", __FUNCTION__,
7128	     region.extents.x1, region.extents.y1,
7129	     region.extents.x2, region.extents.y2));
7130	assert_drawable_contains_box(dst, &region.extents);
7131
7132	region.extents.x1 = clamp(region.extents.x1, sx - dx);
7133	region.extents.x2 = clamp(region.extents.x2, sx - dx);
7134	region.extents.y1 = clamp(region.extents.y1, sy - dy);
7135	region.extents.y2 = clamp(region.extents.y2, sy - dy);
7136
7137	src_extents = region.extents;
7138	expose = true;
7139
7140	DBG(("%s: unclipped src extents (%d, %d), (%d, %d)\n", __FUNCTION__,
7141	     region.extents.x1, region.extents.y1,
7142	     region.extents.x2, region.extents.y2));
7143
7144	if (region.extents.x1 < src->x)
7145		region.extents.x1 = src->x;
7146	if (region.extents.y1 < src->y)
7147		region.extents.y1 = src->y;
7148	if (region.extents.x2 > src->x + (int) src->width)
7149		region.extents.x2 = src->x + (int) src->width;
7150	if (region.extents.y2 > src->y + (int) src->height)
7151		region.extents.y2 = src->y + (int) src->height;
7152
7153	DBG(("%s: clipped src extents (%d, %d), (%d, %d)\n", __FUNCTION__,
7154	     region.extents.x1, region.extents.y1,
7155	     region.extents.x2, region.extents.y2));
7156	if (box_empty(&region.extents)) {
7157		DBG(("%s: src clipped out\n", __FUNCTION__));
7158		return NULL;
7159	}
7160
7161	/* Compute source clip region */
7162	if (src->type == DRAWABLE_PIXMAP) {
7163		if (src == dst && !has_clip(gc)) {
7164			DBG(("%s: pixmap -- using gc clip\n", __FUNCTION__));
7165			clip = gc->pCompositeClip;
7166		} else {
7167			DBG(("%s: pixmap -- no source clipping\n", __FUNCTION__));
7168			expose = false;
7169			clip = NULL;
7170		}
7171	} else {
7172		WindowPtr w = (WindowPtr)src;
7173		if (gc->subWindowMode == IncludeInferiors) {
7174			DBG(("%s: window -- include inferiors\n", __FUNCTION__));
7175
7176			if (w->winSize.data)
7177				RegionIntersect(&region, &region, &w->winSize);
7178			else
7179				box_intersect(&region.extents, &w->winSize.extents);
7180			clip = &w->borderClip;
7181		} else {
7182			DBG(("%s: window -- clip by children\n", __FUNCTION__));
7183			clip = &w->clipList;
7184		}
7185	}
7186	if (clip != NULL) {
7187		if (clip->data == NULL) {
7188			box_intersect(&region.extents, &clip->extents);
7189			if (box_equal(&src_extents, &region.extents))
7190				expose = false;
7191		} else
7192			RegionIntersect(&region, &region, clip);
7193	}
7194	DBG(("%s: src extents (%d, %d), (%d, %d) x %d\n", __FUNCTION__,
7195	     region.extents.x1, region.extents.y1,
7196	     region.extents.x2, region.extents.y2,
7197	     region_num_rects(&region)));
7198
7199	RegionTranslate(&region, dx-sx, dy-sy);
7200	if (gc->pCompositeClip->data)
7201		RegionIntersect(&region, &region, gc->pCompositeClip);
7202	DBG(("%s: copy region (%d, %d), (%d, %d) x %d + (%d, %d)\n",
7203	     __FUNCTION__,
7204	     region.extents.x1, region.extents.y1,
7205	     region.extents.x2, region.extents.y2,
7206	     region_num_rects(&region),
7207	     sx-dx, sy-dy));
7208
7209	if (!box_empty(&region.extents))
7210		copy(src, dst, gc, &region, sx-dx, sy-dy, bitPlane, closure);
7211	assert(gc->pCompositeClip != &region);
7212	RegionUninit(&region);
7213
7214	/* Pixmap sources generate a NoExposed (we return NULL to do this) */
7215	clip = NULL;
7216	if (expose && gc->fExpose)
7217		clip = miHandleExposures(src, dst, gc,
7218					 sx - src->x, sy - src->y,
7219					 width, height,
7220					 dx - dst->x, dy - dst->y,
7221					 (unsigned long) bitPlane);
7222	return clip;
7223}
7224
7225static void
7226sna_fallback_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
7227			RegionPtr region, int dx, int dy,
7228			Pixel bitplane, void *closure)
7229{
7230	DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d\n",
7231	     __FUNCTION__, region_num_rects(region),
7232	     region->extents.x1, region->extents.y1,
7233	     region->extents.x2, region->extents.y2,
7234	     dx, dy, gc->alu));
7235
7236	if (!sna_gc_move_to_cpu(gc, dst, region))
7237		goto out;
7238
7239	RegionTranslate(region, dx, dy);
7240	if (!sna_drawable_move_region_to_cpu(src, region, MOVE_READ))
7241		goto out;
7242	RegionTranslate(region, -dx, -dy);
7243
7244	if (src == dst ||
7245	    get_drawable_pixmap(src) == get_drawable_pixmap(dst)) {
7246		DBG(("%s: self-copy\n", __FUNCTION__));
7247		if (!sna_drawable_move_to_cpu(dst, MOVE_WRITE | MOVE_READ))
7248			goto out;
7249	} else {
7250		if (!sna_drawable_move_region_to_cpu(dst, region,
7251						     drawable_gc_flags(dst, gc, false)))
7252			goto out;
7253	}
7254
7255	if (sigtrap_get() == 0) {
7256		miCopyRegion(src, dst, gc,
7257			     region, dx, dy,
7258			     fbCopyNtoN, 0, NULL);
7259		FALLBACK_FLUSH(dst);
7260		sigtrap_put();
7261	}
7262out:
7263	sna_gc_move_to_gpu(gc);
7264}
7265
7266static RegionPtr
7267sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
7268	      int src_x, int src_y,
7269	      int width, int height,
7270	      int dst_x, int dst_y)
7271{
7272	struct sna *sna = to_sna_from_drawable(dst);
7273	sna_copy_func copy;
7274
7275	if (gc->planemask == 0)
7276		return NULL;
7277
7278	if (sna->ignore_copy_area)
7279		return NULL;
7280
7281	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",
7282	     __FUNCTION__,
7283	     get_drawable_pixmap(src)->drawable.serialNumber,
7284	     src_x, src_y, width, height, src->x, src->y,
7285	     get_drawable_pixmap(dst)->drawable.serialNumber,
7286	     dst_x, dst_y, dst->x, dst->y,
7287	     gc->alu, gc->planemask, gc->depth));
7288
7289	if (FORCE_FALLBACK || !ACCEL_COPY_AREA || wedged(sna) ||
7290	    !PM_IS_SOLID(dst, gc->planemask) || gc->depth < 8) {
7291		DBG(("%s: fallback copy\n", __FUNCTION__));
7292		copy = sna_fallback_copy_boxes;
7293	} else if (src == dst) {
7294		DBG(("%s: self copy\n", __FUNCTION__));
7295		copy = sna_self_copy_boxes;
7296	} else {
7297		DBG(("%s: normal copy\n", __FUNCTION__));
7298		copy = sna_copy_boxes;
7299	}
7300
7301	return sna_do_copy(src, dst, gc,
7302			   src_x, src_y,
7303			   width, height,
7304			   dst_x, dst_y,
7305			   copy, 0, NULL);
7306}
7307
7308const BoxRec *
7309__find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y)
7310{
7311	assert(end - begin > 1);
7312	do {
7313		const BoxRec *mid = begin + (end - begin) / 2;
7314		if (mid->y2 > y)
7315			end = mid;
7316		else
7317			begin = mid;
7318	} while (end > begin + 1);
7319	if (begin->y2 > y)
7320		return begin;
7321	else
7322		return end;
7323}
7324
7325struct sna_fill_spans {
7326	struct sna *sna;
7327	PixmapPtr pixmap;
7328	RegionRec region;
7329	unsigned flags;
7330	uint32_t phase;
7331	struct kgem_bo *bo;
7332	struct sna_damage **damage;
7333	int16_t dx, dy;
7334	void *op;
7335};
7336
7337static void
7338sna_poly_point__cpu(DrawablePtr drawable, GCPtr gc,
7339		    int mode, int n, DDXPointPtr pt)
7340{
7341	fbPolyPoint(drawable, gc, mode, n, pt, -1);
7342}
7343
7344static void
7345sna_poly_point__fill(DrawablePtr drawable, GCPtr gc,
7346		     int mode, int n, DDXPointPtr pt)
7347{
7348	struct sna_fill_spans *data = sna_gc(gc)->priv;
7349	struct sna_fill_op *op = data->op;
7350	BoxRec box[512];
7351	DDXPointRec last;
7352
7353	DBG(("%s: count=%d\n", __FUNCTION__, n));
7354	if (n == 0)
7355		return;
7356
7357	last.x = drawable->x + data->dx;
7358	last.y = drawable->y + data->dy;
7359	if (op->points && mode != CoordModePrevious) {
7360		op->points(data->sna, op, last.x, last.y, pt, n);
7361	} else do {
7362		BoxRec *b = box;
7363		unsigned nbox = n;
7364		if (nbox > ARRAY_SIZE(box))
7365			nbox = ARRAY_SIZE(box);
7366		n -= nbox;
7367		do {
7368			*(DDXPointRec *)b = *pt++;
7369
7370			b->x1 += last.x;
7371			b->y1 += last.y;
7372			if (mode == CoordModePrevious)
7373				last = *(DDXPointRec *)b;
7374
7375			b->x2 = b->x1 + 1;
7376			b->y2 = b->y1 + 1;
7377			b++;
7378		} while (--nbox);
7379		op->boxes(data->sna, op, box, b - box);
7380	} while (n);
7381}
7382
7383static void
7384sna_poly_point__gpu(DrawablePtr drawable, GCPtr gc,
7385		     int mode, int n, DDXPointPtr pt)
7386{
7387	struct sna_fill_spans *data = sna_gc(gc)->priv;
7388	struct sna_fill_op fill;
7389	BoxRec box[512];
7390	DDXPointRec last;
7391
7392	if (!sna_fill_init_blt(&fill,
7393			       data->sna, data->pixmap,
7394			       data->bo, gc->alu, gc->fgPixel,
7395			       FILL_POINTS))
7396		return;
7397
7398	DBG(("%s: count=%d\n", __FUNCTION__, n));
7399
7400	last.x = drawable->x;
7401	last.y = drawable->y;
7402	while (n) {
7403		BoxRec *b = box;
7404		unsigned nbox = n;
7405		if (nbox > ARRAY_SIZE(box))
7406			nbox = ARRAY_SIZE(box);
7407		n -= nbox;
7408		do {
7409			*(DDXPointRec *)b = *pt++;
7410
7411			b->x1 += last.x;
7412			b->y1 += last.y;
7413			if (mode == CoordModePrevious)
7414				last = *(DDXPointRec *)b;
7415
7416			if (RegionContainsPoint(&data->region,
7417						b->x1, b->y1, NULL)) {
7418				b->x1 += data->dx;
7419				b->y1 += data->dy;
7420				b->x2 = b->x1 + 1;
7421				b->y2 = b->y1 + 1;
7422				b++;
7423			}
7424		} while (--nbox);
7425		if (b != box)
7426			fill.boxes(data->sna, &fill, box, b - box);
7427	}
7428	fill.done(data->sna, &fill);
7429}
7430
7431static void
7432sna_poly_point__fill_clip_extents(DrawablePtr drawable, GCPtr gc,
7433				  int mode, int n, DDXPointPtr pt)
7434{
7435	struct sna_fill_spans *data = sna_gc(gc)->priv;
7436	struct sna_fill_op *op = data->op;
7437	const BoxRec *extents = &data->region.extents;
7438	BoxRec box[512], *b = box;
7439	const BoxRec *const last_box = b + ARRAY_SIZE(box);
7440	DDXPointRec last;
7441
7442	DBG(("%s: count=%d\n", __FUNCTION__, n));
7443
7444	last.x = drawable->x + data->dx;
7445	last.y = drawable->y + data->dy;
7446	while (n--) {
7447		*(DDXPointRec *)b = *pt++;
7448
7449		b->x1 += last.x;
7450		b->y1 += last.y;
7451		if (mode == CoordModePrevious)
7452			last = *(DDXPointRec *)b;
7453
7454		if (b->x1 >= extents->x1 && b->x1 < extents->x2 &&
7455		    b->y1 >= extents->y1 && b->y1 < extents->y2) {
7456			b->x2 = b->x1 + 1;
7457			b->y2 = b->y1 + 1;
7458			if (++b == last_box) {
7459				op->boxes(data->sna, op, box, last_box - box);
7460				b = box;
7461			}
7462		}
7463	}
7464	if (b != box)
7465		op->boxes(data->sna, op, box, b - box);
7466}
7467
7468static void
7469sna_poly_point__fill_clip_boxes(DrawablePtr drawable, GCPtr gc,
7470				int mode, int n, DDXPointPtr pt)
7471{
7472	struct sna_fill_spans *data = sna_gc(gc)->priv;
7473	struct sna_fill_op *op = data->op;
7474	RegionRec *clip = &data->region;
7475	BoxRec box[512], *b = box;
7476	const BoxRec *const last_box = b + ARRAY_SIZE(box);
7477	DDXPointRec last;
7478
7479	DBG(("%s: count=%d\n", __FUNCTION__, n));
7480
7481	last.x = drawable->x + data->dx;
7482	last.y = drawable->y + data->dy;
7483	while (n--) {
7484		*(DDXPointRec *)b = *pt++;
7485
7486		b->x1 += last.x;
7487		b->y1 += last.y;
7488		if (mode == CoordModePrevious)
7489			last = *(DDXPointRec *)b;
7490
7491		if (RegionContainsPoint(clip, b->x1, b->y1, NULL)) {
7492			b->x2 = b->x1 + 1;
7493			b->y2 = b->y1 + 1;
7494			if (++b == last_box) {
7495				op->boxes(data->sna, op, box, last_box - box);
7496				b = box;
7497			}
7498		}
7499	}
7500	if (b != box)
7501		op->boxes(data->sna, op, box, b - box);
7502}
7503
7504static void
7505sna_poly_point__dash(DrawablePtr drawable, GCPtr gc,
7506		     int mode, int n, DDXPointPtr pt)
7507{
7508	struct sna_fill_spans *data = sna_gc(gc)->priv;
7509	if (data->phase == gc->fgPixel)
7510		sna_poly_point__fill(drawable, gc, mode, n, pt);
7511}
7512
7513static void
7514sna_poly_point__dash_clip_extents(DrawablePtr drawable, GCPtr gc,
7515				  int mode, int n, DDXPointPtr pt)
7516{
7517	struct sna_fill_spans *data = sna_gc(gc)->priv;
7518	if (data->phase == gc->fgPixel)
7519		sna_poly_point__fill_clip_extents(drawable, gc, mode, n, pt);
7520}
7521
7522static void
7523sna_poly_point__dash_clip_boxes(DrawablePtr drawable, GCPtr gc,
7524				  int mode, int n, DDXPointPtr pt)
7525{
7526	struct sna_fill_spans *data = sna_gc(gc)->priv;
7527	if (data->phase == gc->fgPixel)
7528		sna_poly_point__fill_clip_boxes(drawable, gc, mode, n, pt);
7529}
7530
7531static void
7532sna_fill_spans__fill(DrawablePtr drawable,
7533		     GCPtr gc, int n,
7534		     DDXPointPtr pt, int *width, int sorted)
7535{
7536	struct sna_fill_spans *data = sna_gc(gc)->priv;
7537	struct sna_fill_op *op = data->op;
7538	BoxRec box[512];
7539
7540	DBG(("%s: alu=%d, fg=%08lx, count=%d\n",
7541	     __FUNCTION__, gc->alu, gc->fgPixel, n));
7542
7543	while (n) {
7544		BoxRec *b = box;
7545		int nbox = n;
7546		if (nbox > ARRAY_SIZE(box))
7547			nbox = ARRAY_SIZE(box);
7548		n -= nbox;
7549		do {
7550			*(DDXPointRec *)b = *pt++;
7551			b->x2 = b->x1 + (int)*width++;
7552			b->y2 = b->y1 + 1;
7553			DBG(("%s: (%d, %d), (%d, %d)\n",
7554			     __FUNCTION__, b->x1, b->y1, b->x2, b->y2));
7555			assert(b->x1 >= drawable->x);
7556			assert(b->x2 <= drawable->x + drawable->width);
7557			assert(b->y1 >= drawable->y);
7558			assert(b->y2 <= drawable->y + drawable->height);
7559			if (b->x2 > b->x1) {
7560				if (b != box &&
7561				    b->y1 == b[-1].y2 &&
7562				    b->x1 == b[-1].x1 &&
7563				    b->x2 == b[-1].x2)
7564					b[-1].y2 = b->y2;
7565				else
7566					b++;
7567			}
7568		} while (--nbox);
7569		if (b != box)
7570			op->boxes(data->sna, op, box, b - box);
7571	}
7572}
7573
7574static void
7575sna_fill_spans__dash(DrawablePtr drawable,
7576		     GCPtr gc, int n,
7577		     DDXPointPtr pt, int *width, int sorted)
7578{
7579	struct sna_fill_spans *data = sna_gc(gc)->priv;
7580	if (data->phase == gc->fgPixel)
7581		sna_fill_spans__fill(drawable, gc, n, pt, width, sorted);
7582}
7583
7584static void
7585sna_fill_spans__fill_offset(DrawablePtr drawable,
7586			    GCPtr gc, int n,
7587			    DDXPointPtr pt, int *width, int sorted)
7588{
7589	struct sna_fill_spans *data = sna_gc(gc)->priv;
7590	struct sna_fill_op *op = data->op;
7591	BoxRec box[512];
7592
7593	DBG(("%s: alu=%d, fg=%08lx\n", __FUNCTION__, gc->alu, gc->fgPixel));
7594
7595	while (n) {
7596		BoxRec *b = box;
7597		int nbox = n;
7598		if (nbox > ARRAY_SIZE(box))
7599			nbox = ARRAY_SIZE(box);
7600		n -= nbox;
7601		do {
7602			*(DDXPointRec *)b = *pt++;
7603			b->x1 += data->dx;
7604			b->y1 += data->dy;
7605			b->x2 = b->x1 + (int)*width++;
7606			b->y2 = b->y1 + 1;
7607			if (b->x2 > b->x1)
7608				b++;
7609		} while (--nbox);
7610		if (b != box)
7611			op->boxes(data->sna, op, box, b - box);
7612	}
7613}
7614
7615static void
7616sna_fill_spans__dash_offset(DrawablePtr drawable,
7617			    GCPtr gc, int n,
7618			    DDXPointPtr pt, int *width, int sorted)
7619{
7620	struct sna_fill_spans *data = sna_gc(gc)->priv;
7621	if (data->phase == gc->fgPixel)
7622		sna_fill_spans__fill_offset(drawable, gc, n, pt, width, sorted);
7623}
7624
7625static void
7626sna_fill_spans__fill_clip_extents(DrawablePtr drawable,
7627				  GCPtr gc, int n,
7628				  DDXPointPtr pt, int *width, int sorted)
7629{
7630	struct sna_fill_spans *data = sna_gc(gc)->priv;
7631	struct sna_fill_op *op = data->op;
7632	const BoxRec *extents = &data->region.extents;
7633	BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box);
7634
7635	DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n",
7636	     __FUNCTION__, gc->alu, gc->fgPixel, n,
7637	     extents->x1, extents->y1,
7638	     extents->x2, extents->y2));
7639
7640	while (n--) {
7641		DBG(("%s: [%d] pt=(%d, %d), width=%d\n",
7642		     __FUNCTION__, n, pt->x, pt->y, *width));
7643		*(DDXPointRec *)b = *pt++;
7644		b->x2 = b->x1 + (int)*width++;
7645		b->y2 = b->y1 + 1;
7646		if (box_intersect(b, extents)) {
7647			DBG(("%s: [%d] clipped=(%d, %d), (%d, %d)\n",
7648			     __FUNCTION__, n, b->x1, b->y1, b->x2, b->y2));
7649			if (data->dx|data->dy) {
7650				b->x1 += data->dx; b->x2 += data->dx;
7651				b->y1 += data->dy; b->y2 += data->dy;
7652			}
7653			if (b != box &&
7654			    b->y1 == b[-1].y2 &&
7655			    b->x1 == b[-1].x1 &&
7656			    b->x2 == b[-1].x2) {
7657				b[-1].y2 = b->y2;
7658			} else if (++b == last_box) {
7659				op->boxes(data->sna, op, box, last_box - box);
7660				b = box;
7661			}
7662		}
7663	}
7664	if (b != box)
7665		op->boxes(data->sna, op, box, b - box);
7666}
7667
7668static void
7669sna_fill_spans__dash_clip_extents(DrawablePtr drawable,
7670				  GCPtr gc, int n,
7671				  DDXPointPtr pt, int *width, int sorted)
7672{
7673	struct sna_fill_spans *data = sna_gc(gc)->priv;
7674	if (data->phase == gc->fgPixel)
7675		sna_fill_spans__fill_clip_extents(drawable, gc, n, pt, width, sorted);
7676}
7677
7678static void
7679sna_fill_spans__fill_clip_boxes(DrawablePtr drawable,
7680				GCPtr gc, int n,
7681				DDXPointPtr pt, int *width, int sorted)
7682{
7683	struct sna_fill_spans *data = sna_gc(gc)->priv;
7684	struct sna_fill_op *op = data->op;
7685	BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box);
7686	const BoxRec * const clip_start = RegionBoxptr(&data->region);
7687	const BoxRec * const clip_end = clip_start + data->region.data->numRects;
7688
7689	DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n",
7690	     __FUNCTION__, gc->alu, gc->fgPixel, n,
7691	     data->region.extents.x1, data->region.extents.y1,
7692	     data->region.extents.x2, data->region.extents.y2));
7693
7694	while (n--) {
7695		int16_t X1 = pt->x;
7696		int16_t y = pt->y;
7697		int16_t X2 = X1 + (int)*width;
7698		const BoxRec *c;
7699
7700		pt++;
7701		width++;
7702
7703		if (y < data->region.extents.y1 || data->region.extents.y2 <= y)
7704			continue;
7705
7706		if (X1 < data->region.extents.x1)
7707			X1 = data->region.extents.x1;
7708
7709		if (X2 > data->region.extents.x2)
7710			X2 = data->region.extents.x2;
7711
7712		if (X1 >= X2)
7713			continue;
7714
7715		c = find_clip_box_for_y(clip_start, clip_end, y);
7716		while (c != clip_end) {
7717			if (y + 1 <= c->y1 || X2 <= c->x1)
7718				break;
7719
7720			if (X1 >= c->x2) {
7721				c++;
7722				continue;
7723			}
7724
7725			b->x1 = c->x1;
7726			b->x2 = c->x2;
7727			c++;
7728
7729			if (b->x1 < X1)
7730				b->x1 = X1;
7731			if (b->x2 > X2)
7732				b->x2 = X2;
7733			if (b->x2 <= b->x1)
7734				continue;
7735
7736			b->x1 += data->dx;
7737			b->x2 += data->dx;
7738			b->y1 = y + data->dy;
7739			b->y2 = b->y1 + 1;
7740			if (++b == last_box) {
7741				op->boxes(data->sna, op, box, last_box - box);
7742				b = box;
7743			}
7744		}
7745	}
7746	if (b != box)
7747		op->boxes(data->sna, op, box, b - box);
7748}
7749
7750static void
7751sna_fill_spans__dash_clip_boxes(DrawablePtr drawable,
7752				GCPtr gc, int n,
7753				DDXPointPtr pt, int *width, int sorted)
7754{
7755	struct sna_fill_spans *data = sna_gc(gc)->priv;
7756	if (data->phase == gc->fgPixel)
7757		sna_fill_spans__fill_clip_boxes(drawable, gc, n, pt, width, sorted);
7758}
7759
7760static bool
7761sna_fill_spans_blt(DrawablePtr drawable,
7762		   struct kgem_bo *bo, struct sna_damage **damage,
7763		   GCPtr gc, uint32_t pixel,
7764		   int n, DDXPointPtr pt, int *width, int sorted,
7765		   const BoxRec *extents, unsigned clipped)
7766{
7767	PixmapPtr pixmap = get_drawable_pixmap(drawable);
7768	struct sna *sna = to_sna_from_pixmap(pixmap);
7769	int16_t dx, dy;
7770	struct sna_fill_op fill;
7771	BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box);
7772	static void * const jump[] = {
7773		&&no_damage,
7774		&&damage,
7775		&&no_damage_clipped,
7776		&&damage_clipped,
7777	};
7778	unsigned v;
7779
7780	DBG(("%s: alu=%d, fg=%08lx, damge=%p, clipped?=%d\n",
7781	     __FUNCTION__, gc->alu, gc->fgPixel, damage, clipped));
7782
7783	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_SPANS))
7784		return false;
7785
7786	get_drawable_deltas(drawable, pixmap, &dx, &dy);
7787
7788	v = (damage != NULL) | clipped;
7789	goto *jump[v];
7790
7791no_damage:
7792	if (dx|dy) {
7793		do {
7794			int nbox = n;
7795			if (nbox > last_box - box)
7796				nbox = last_box - box;
7797			n -= nbox;
7798			do {
7799				*(DDXPointRec *)b = *pt++;
7800				b->x1 += dx;
7801				b->y1 += dy;
7802				b->x2 = b->x1 + (int)*width++;
7803				b->y2 = b->y1 + 1;
7804				b++;
7805			} while (--nbox);
7806			fill.boxes(sna, &fill, box, b - box);
7807			b = box;
7808		} while (n);
7809	} else {
7810		do {
7811			int nbox = n;
7812			if (nbox > last_box - box)
7813				nbox = last_box - box;
7814			n -= nbox;
7815			do {
7816				*(DDXPointRec *)b = *pt++;
7817				b->x2 = b->x1 + (int)*width++;
7818				b->y2 = b->y1 + 1;
7819				b++;
7820			} while (--nbox);
7821			fill.boxes(sna, &fill, box, b - box);
7822			b = box;
7823		} while (n);
7824	}
7825	goto done;
7826
7827damage:
7828	do {
7829		*(DDXPointRec *)b = *pt++;
7830		b->x1 += dx;
7831		b->y1 += dy;
7832		b->x2 = b->x1 + (int)*width++;
7833		b->y2 = b->y1 + 1;
7834
7835		if (++b == last_box) {
7836			assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0);
7837			fill.boxes(sna, &fill, box, last_box - box);
7838			sna_damage_add_boxes(damage, box, last_box - box, 0, 0);
7839			b = box;
7840		}
7841	} while (--n);
7842	if (b != box) {
7843		assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
7844		fill.boxes(sna, &fill, box, b - box);
7845		sna_damage_add_boxes(damage, box, b - box, 0, 0);
7846	}
7847	goto done;
7848
7849no_damage_clipped:
7850	{
7851		RegionRec clip;
7852
7853		region_set(&clip, extents);
7854		if (!region_maybe_clip(&clip, gc->pCompositeClip))
7855			return true;
7856
7857		assert(dx + clip.extents.x1 >= 0);
7858		assert(dy + clip.extents.y1 >= 0);
7859		assert(dx + clip.extents.x2 <= pixmap->drawable.width);
7860		assert(dy + clip.extents.y2 <= pixmap->drawable.height);
7861
7862		DBG(("%s: clip %d x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n",
7863		     __FUNCTION__,
7864		     region_num_rects(&clip),
7865		     clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2,
7866		     n, pt->x, pt->y));
7867
7868		if (clip.data == NULL) {
7869			do {
7870				*(DDXPointRec *)b = *pt++;
7871				b->x2 = b->x1 + (int)*width++;
7872				b->y2 = b->y1 + 1;
7873
7874				if (box_intersect(b, &clip.extents)) {
7875					if (dx|dy) {
7876						b->x1 += dx; b->x2 += dx;
7877						b->y1 += dy; b->y2 += dy;
7878					}
7879					if (++b == last_box) {
7880						fill.boxes(sna, &fill, box, last_box - box);
7881						b = box;
7882					}
7883				}
7884			} while (--n);
7885		} else {
7886			const BoxRec * const clip_start = RegionBoxptr(&clip);
7887			const BoxRec * const clip_end = clip_start + clip.data->numRects;
7888			do {
7889				int16_t X1 = pt->x;
7890				int16_t y = pt->y;
7891				int16_t X2 = X1 + (int)*width;
7892				const BoxRec *c;
7893
7894				pt++;
7895				width++;
7896
7897				if (y < extents->y1 || extents->y2 <= y)
7898					continue;
7899
7900				if (X1 < extents->x1)
7901					X1 = extents->x1;
7902
7903				if (X2 > extents->x2)
7904					X2 = extents->x2;
7905
7906				if (X1 >= X2)
7907					continue;
7908
7909				c = find_clip_box_for_y(clip_start,
7910							clip_end,
7911							y);
7912				while (c != clip_end) {
7913					if (y + 1 <= c->y1 || X2 <= c->x1)
7914						break;
7915
7916					if (X1 >= c->x2) {
7917						c++;
7918						continue;
7919					}
7920
7921					b->x1 = c->x1;
7922					b->x2 = c->x2;
7923					c++;
7924
7925					if (b->x1 < X1)
7926						b->x1 = X1;
7927					if (b->x2 > X2)
7928						b->x2 = X2;
7929					if (b->x2 <= b->x1)
7930						continue;
7931
7932					b->x1 += dx;
7933					b->x2 += dx;
7934					b->y1 = y + dy;
7935					b->y2 = b->y1 + 1;
7936					if (++b == last_box) {
7937						fill.boxes(sna, &fill, box, last_box - box);
7938						b = box;
7939					}
7940				}
7941			} while (--n);
7942			RegionUninit(&clip);
7943		}
7944		if (b != box)
7945			fill.boxes(sna, &fill, box, b - box);
7946		goto done;
7947	}
7948
7949damage_clipped:
7950	{
7951		RegionRec clip;
7952
7953		region_set(&clip, extents);
7954		if (!region_maybe_clip(&clip, gc->pCompositeClip))
7955			return true;
7956
7957		assert(dx + clip.extents.x1 >= 0);
7958		assert(dy + clip.extents.y1 >= 0);
7959		assert(dx + clip.extents.x2 <= pixmap->drawable.width);
7960		assert(dy + clip.extents.y2 <= pixmap->drawable.height);
7961
7962		DBG(("%s: clip %d x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n",
7963		     __FUNCTION__,
7964		     region_num_rects(&clip),
7965		     clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2,
7966		     n, pt->x, pt->y));
7967
7968		if (clip.data == NULL) {
7969			do {
7970				*(DDXPointRec *)b = *pt++;
7971				b->x2 = b->x1 + (int)*width++;
7972				b->y2 = b->y1 + 1;
7973
7974				if (box_intersect(b, &clip.extents)) {
7975					b->x1 += dx;
7976					b->x2 += dx;
7977					b->y1 += dy;
7978					b->y2 += dy;
7979					if (++b == last_box) {
7980						assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
7981						fill.boxes(sna, &fill, box, last_box - box);
7982						sna_damage_add_boxes(damage, box, b - box, 0, 0);
7983						b = box;
7984					}
7985				}
7986			} while (--n);
7987		} else {
7988			const BoxRec * const clip_start = RegionBoxptr(&clip);
7989			const BoxRec * const clip_end = clip_start + clip.data->numRects;
7990			do {
7991				int16_t X1 = pt->x;
7992				int16_t y = pt->y;
7993				int16_t X2 = X1 + (int)*width;
7994				const BoxRec *c;
7995
7996				pt++;
7997				width++;
7998
7999				if (y < extents->y1 || extents->y2 <= y)
8000					continue;
8001
8002				if (X1 < extents->x1)
8003					X1 = extents->x1;
8004
8005				if (X2 > extents->x2)
8006					X2 = extents->x2;
8007
8008				if (X1 >= X2)
8009					continue;
8010
8011				c = find_clip_box_for_y(clip_start,
8012							clip_end,
8013							y);
8014				while (c != clip_end) {
8015					if (y + 1 <= c->y1 || X2 <= c->x1)
8016						break;
8017
8018					if (X1 >= c->x2) {
8019						c++;
8020						continue;
8021					}
8022
8023					b->x1 = c->x1;
8024					b->x2 = c->x2;
8025					c++;
8026
8027					if (b->x1 < X1)
8028						b->x1 = X1;
8029					if (b->x2 > X2)
8030						b->x2 = X2;
8031					if (b->x2 <= b->x1)
8032						continue;
8033
8034					b->x1 += dx;
8035					b->x2 += dx;
8036					b->y1 = y + dy;
8037					b->y2 = b->y1 + 1;
8038					if (++b == last_box) {
8039						assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0);
8040						fill.boxes(sna, &fill, box, last_box - box);
8041						sna_damage_add_boxes(damage, box, last_box - box, 0, 0);
8042						b = box;
8043					}
8044				}
8045			} while (--n);
8046			RegionUninit(&clip);
8047		}
8048		if (b != box) {
8049			assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
8050			fill.boxes(sna, &fill, box, b - box);
8051			sna_damage_add_boxes(damage, box, b - box, 0, 0);
8052		}
8053		goto done;
8054	}
8055
8056done:
8057	fill.done(sna, &fill);
8058	assert_pixmap_damage(pixmap);
8059	return true;
8060}
8061
8062static bool
8063sna_poly_fill_rect_tiled_blt(DrawablePtr drawable,
8064			     struct kgem_bo *bo,
8065			     struct sna_damage **damage,
8066			     GCPtr gc, int n, xRectangle *rect,
8067			     const BoxRec *extents, unsigned clipped);
8068
8069static bool
8070sna_poly_fill_rect_stippled_blt(DrawablePtr drawable,
8071				struct kgem_bo *bo,
8072				struct sna_damage **damage,
8073				GCPtr gc, int n, xRectangle *rect,
8074				const BoxRec *extents, unsigned clipped);
8075
8076static inline bool
8077gc_is_solid(GCPtr gc, uint32_t *color)
8078{
8079	assert(FbFullMask(gc->depth) == (FbFullMask(gc->depth) & gc->planemask));
8080
8081	if (gc->alu == GXclear) {
8082		*color = 0;
8083		return true;
8084	}
8085	if (gc->alu == GXset) {
8086		*color = (1 << gc->depth) - 1;
8087		return true;
8088	}
8089
8090	if (gc->fillStyle == FillSolid ||
8091	    (gc->fillStyle == FillTiled && gc->tileIsPixel) ||
8092	    (gc->fillStyle == FillOpaqueStippled && gc->bgPixel == gc->fgPixel)) {
8093		*color = gc->fillStyle == FillTiled ? gc->tile.pixel : gc->fgPixel;
8094		return true;
8095	}
8096
8097	return false;
8098}
8099
8100static void
8101sna_fill_spans__gpu(DrawablePtr drawable, GCPtr gc, int n,
8102		    DDXPointPtr pt, int *width, int sorted)
8103{
8104	struct sna_fill_spans *data = sna_gc(gc)->priv;
8105	uint32_t color;
8106
8107	DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n",
8108	     __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted));
8109
8110	assert(PM_IS_SOLID(drawable, gc->planemask));
8111	if (n == 0)
8112		return;
8113
8114	/* The mi routines do not attempt to keep the spans it generates
8115	 * within the clip, so we must run them through the clipper.
8116	 */
8117
8118	if (gc_is_solid(gc, &color)) {
8119		sna_fill_spans_blt(drawable,
8120				   data->bo, NULL,
8121				   gc, color, n, pt, width, sorted,
8122				   &data->region.extents, 2);
8123	} else {
8124		/* Try converting these to a set of rectangles instead */
8125		xRectangle *rect;
8126		int i;
8127
8128		DBG(("%s: converting to rectagnles\n", __FUNCTION__));
8129
8130		rect = malloc (n * sizeof (xRectangle));
8131		if (rect == NULL)
8132			return;
8133
8134		for (i = 0; i < n; i++) {
8135			rect[i].x = pt[i].x - drawable->x;
8136			rect[i].width = width[i];
8137			rect[i].y = pt[i].y - drawable->y;
8138			rect[i].height = 1;
8139		}
8140
8141		if (gc->fillStyle == FillTiled) {
8142			(void)sna_poly_fill_rect_tiled_blt(drawable,
8143							   data->bo, NULL,
8144							   gc, n, rect,
8145							   &data->region.extents, 2);
8146		} else {
8147			(void)sna_poly_fill_rect_stippled_blt(drawable,
8148							      data->bo, NULL,
8149							      gc, n, rect,
8150							      &data->region.extents, 2);
8151		}
8152		free (rect);
8153	}
8154}
8155
8156static unsigned
8157sna_spans_extents(DrawablePtr drawable, GCPtr gc,
8158		  int n, DDXPointPtr pt, int *width,
8159		  BoxPtr out)
8160{
8161	BoxRec box;
8162	bool clipped = false;
8163
8164	if (n == 0)
8165		return 0;
8166
8167	box.x1 = pt->x;
8168	box.x2 = box.x1 + *width;
8169	box.y2 = box.y1 = pt->y;
8170
8171	while (--n) {
8172		pt++;
8173		width++;
8174		if (box.x1 > pt->x)
8175			box.x1 = pt->x;
8176		if (box.x2 < pt->x + *width)
8177			box.x2 = pt->x + *width;
8178
8179		if (box.y1 > pt->y)
8180			box.y1 = pt->y;
8181		else if (box.y2 < pt->y)
8182			box.y2 = pt->y;
8183	}
8184	box.y2++;
8185
8186	if (gc)
8187		clipped = clip_box(&box, gc);
8188	if (box_empty(&box))
8189		return 0;
8190
8191	*out = box;
8192	return 1 | clipped << 1;
8193}
8194
8195static void
8196sna_fill_spans(DrawablePtr drawable, GCPtr gc, int n,
8197	       DDXPointPtr pt, int *width, int sorted)
8198{
8199	PixmapPtr pixmap = get_drawable_pixmap(drawable);
8200	struct sna *sna = to_sna_from_pixmap(pixmap);
8201	struct sna_damage **damage;
8202	struct kgem_bo *bo;
8203	RegionRec region;
8204	unsigned flags;
8205	uint32_t color;
8206
8207	DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n",
8208	     __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted));
8209
8210	flags = sna_spans_extents(drawable, gc, n, pt, width, &region.extents);
8211	if (flags == 0)
8212		return;
8213
8214	DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__,
8215	     region.extents.x1, region.extents.y1,
8216	     region.extents.x2, region.extents.y2));
8217
8218	if (FORCE_FALLBACK)
8219		goto fallback;
8220
8221	if (!ACCEL_FILL_SPANS)
8222		goto fallback;
8223
8224	if (wedged(sna)) {
8225		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
8226		goto fallback;
8227	}
8228
8229	DBG(("%s: fillStyle=%x [%d], mask=%lx [%d]\n", __FUNCTION__,
8230	     gc->fillStyle, gc->fillStyle == FillSolid,
8231	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask)));
8232	if (!PM_IS_SOLID(drawable, gc->planemask))
8233		goto fallback;
8234
8235	bo = sna_drawable_use_bo(drawable, PREFER_GPU,
8236				 &region.extents, &damage);
8237	if (bo) {
8238		if (gc_is_solid(gc, &color)) {
8239			DBG(("%s: trying solid fill [alu=%d, pixel=%08lx] blt paths\n",
8240			     __FUNCTION__, gc->alu, gc->fgPixel));
8241
8242			sna_fill_spans_blt(drawable,
8243					   bo, damage,
8244					   gc, color, n, pt, width, sorted,
8245					   &region.extents, flags & IS_CLIPPED);
8246		} else {
8247			/* Try converting these to a set of rectangles instead */
8248			xRectangle *rect;
8249			int i;
8250
8251			DBG(("%s: converting to rectagnles\n", __FUNCTION__));
8252
8253			rect = malloc (n * sizeof (xRectangle));
8254			if (rect == NULL)
8255				return;
8256
8257			for (i = 0; i < n; i++) {
8258				rect[i].x = pt[i].x - drawable->x;
8259				rect[i].width = width[i];
8260				rect[i].y = pt[i].y - drawable->y;
8261				rect[i].height = 1;
8262			}
8263
8264			if (gc->fillStyle == FillTiled) {
8265				i = sna_poly_fill_rect_tiled_blt(drawable,
8266								 bo, damage,
8267								 gc, n, rect,
8268								 &region.extents, flags & IS_CLIPPED);
8269			} else {
8270				i = sna_poly_fill_rect_stippled_blt(drawable,
8271								    bo, damage,
8272								    gc, n, rect,
8273								    &region.extents, flags & IS_CLIPPED);
8274			}
8275			free (rect);
8276
8277			if (i)
8278				return;
8279		}
8280	}
8281
8282fallback:
8283	DBG(("%s: fallback\n", __FUNCTION__));
8284	region.data = NULL;
8285	if (!region_maybe_clip(&region, gc->pCompositeClip))
8286		return;
8287
8288	if (!sna_gc_move_to_cpu(gc, drawable, &region))
8289		goto out;
8290	if (!sna_drawable_move_region_to_cpu(drawable, &region,
8291					     drawable_gc_flags(drawable, gc, n > 1)))
8292		goto out;
8293
8294	if (sigtrap_get() == 0) {
8295		DBG(("%s: fbFillSpans\n", __FUNCTION__));
8296		fbFillSpans(drawable, gc, n, pt, width, sorted);
8297		FALLBACK_FLUSH(drawable);
8298		sigtrap_put();
8299	}
8300out:
8301	sna_gc_move_to_gpu(gc);
8302	RegionUninit(&region);
8303}
8304
8305static void
8306sna_set_spans(DrawablePtr drawable, GCPtr gc, char *src,
8307	      DDXPointPtr pt, int *width, int n, int sorted)
8308{
8309	RegionRec region;
8310
8311	if (sna_spans_extents(drawable, gc, n, pt, width, &region.extents) == 0)
8312		return;
8313
8314	DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__,
8315	     region.extents.x1, region.extents.y1,
8316	     region.extents.x2, region.extents.y2));
8317
8318	if (FORCE_FALLBACK)
8319		goto fallback;
8320
8321	if (!ACCEL_SET_SPANS)
8322		goto fallback;
8323
8324fallback:
8325	region.data = NULL;
8326	if (!region_maybe_clip(&region, gc->pCompositeClip))
8327		return;
8328
8329	if (!sna_gc_move_to_cpu(gc, drawable, &region))
8330		goto out;
8331	if (!sna_drawable_move_region_to_cpu(drawable, &region,
8332					     drawable_gc_flags(drawable, gc, n > 1)))
8333		goto out;
8334
8335	if (sigtrap_get() == 0) {
8336		DBG(("%s: fbSetSpans\n", __FUNCTION__));
8337		fbSetSpans(drawable, gc, src, pt, width, n, sorted);
8338		FALLBACK_FLUSH(drawable);
8339		sigtrap_put();
8340	}
8341out:
8342	sna_gc_move_to_gpu(gc);
8343	RegionUninit(&region);
8344}
8345
8346struct sna_copy_plane {
8347	struct sna_damage **damage;
8348	struct kgem_bo *bo;
8349};
8350
8351static void
8352sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
8353		    RegionRec *region, int sx, int sy,
8354		    Pixel bitplane, void *closure)
8355{
8356	PixmapPtr pixmap = get_drawable_pixmap(drawable);
8357	struct sna *sna = to_sna_from_pixmap(pixmap);
8358	struct sna_copy_plane *arg = closure;
8359	PixmapPtr bitmap = (PixmapPtr)_bitmap;
8360	uint32_t br00, br13;
8361	int16_t dx, dy;
8362	const BoxRec *box;
8363	int n;
8364
8365	DBG(("%s: plane=%x (%d,%d),(%d,%d)xld\n",
8366	     __FUNCTION__, (unsigned)bitplane,
8367	     region->extents.x1, region->extents.y1,
8368	     region->extents.x2, region->extents.y2,
8369	     region_num_rects(region)));
8370
8371	box = region_rects(region);
8372	n = region_num_rects(region);
8373	assert(n);
8374
8375	get_drawable_deltas(drawable, pixmap, &dx, &dy);
8376	assert_pixmap_contains_boxes(pixmap, box, n, dx, dy);
8377
8378	br00 = 3 << 20;
8379	br13 = arg->bo->pitch;
8380	if (sna->kgem.gen >= 040 && arg->bo->tiling) {
8381		br00 |= BLT_DST_TILED;
8382		br13 >>= 2;
8383	}
8384	br13 |= blt_depth(drawable->depth) << 24;
8385	br13 |= copy_ROP[gc->alu] << 16;
8386	DBG(("%s: target-depth=%d, alu=%d, bg=%08x, fg=%08x\n",
8387	     __FUNCTION__, drawable->depth, gc->alu, gc->bgPixel, gc->fgPixel));
8388
8389	kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo);
8390	assert(kgem_bo_can_blt(&sna->kgem, arg->bo));
8391	do {
8392		int bx1 = (box->x1 + sx) & ~7;
8393		int bx2 = (box->x2 + sx + 7) & ~7;
8394		int bw = (bx2 - bx1)/8;
8395		int bh = box->y2 - box->y1;
8396		int bstride = ALIGN(bw, 2);
8397		int src_stride;
8398		uint8_t *dst, *src;
8399		uint32_t *b;
8400
8401		DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n",
8402		     __FUNCTION__,
8403		     box->x1, box->y1,
8404		     box->x2, box->y2,
8405		     sx, sy, bx1, bx2));
8406
8407		src_stride = bstride*bh;
8408		assert(src_stride > 0);
8409		if (src_stride <= 128) {
8410			src_stride = ALIGN(src_stride, 8) / 4;
8411			assert(src_stride <= 32);
8412			if (!kgem_check_batch(&sna->kgem, 8+src_stride) ||
8413			    !kgem_check_bo_fenced(&sna->kgem, arg->bo) ||
8414			    !kgem_check_reloc(&sna->kgem, 1)) {
8415				kgem_submit(&sna->kgem);
8416				if (!kgem_check_bo_fenced(&sna->kgem, arg->bo))
8417					return; /* XXX fallback? */
8418				_kgem_set_mode(&sna->kgem, KGEM_BLT);
8419			}
8420			kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo);
8421
8422			assert(sna->kgem.mode == KGEM_BLT);
8423			if (sna->kgem.gen >= 0100) {
8424				b = sna->kgem.batch + sna->kgem.nbatch;
8425				b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00;
8426				b[0] |= ((box->x1 + sx) & 7) << 17;
8427				b[1] = br13;
8428				b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8429				b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8430				*(uint64_t *)(b+4) =
8431					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8432							 I915_GEM_DOMAIN_RENDER << 16 |
8433							 I915_GEM_DOMAIN_RENDER |
8434							 KGEM_RELOC_FENCED,
8435							 0);
8436				b[6] = gc->bgPixel;
8437				b[7] = gc->fgPixel;
8438
8439				dst = (uint8_t *)&b[8];
8440				sna->kgem.nbatch += 8 + src_stride;
8441			} else {
8442				b = sna->kgem.batch + sna->kgem.nbatch;
8443				b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
8444				b[0] |= ((box->x1 + sx) & 7) << 17;
8445				b[1] = br13;
8446				b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8447				b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8448				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8449						      I915_GEM_DOMAIN_RENDER << 16 |
8450						      I915_GEM_DOMAIN_RENDER |
8451						      KGEM_RELOC_FENCED,
8452						      0);
8453				b[5] = gc->bgPixel;
8454				b[6] = gc->fgPixel;
8455
8456				dst = (uint8_t *)&b[7];
8457				sna->kgem.nbatch += 7 + src_stride;
8458			}
8459
8460			assert(bitmap->devKind);
8461			src_stride = bitmap->devKind;
8462			src = bitmap->devPrivate.ptr;
8463			src += (box->y1 + sy) * src_stride + bx1/8;
8464			src_stride -= bstride;
8465			do {
8466				int i = bstride;
8467				assert(src >= (uint8_t *)bitmap->devPrivate.ptr);
8468				do {
8469					*dst++ = byte_reverse(*src++);
8470					*dst++ = byte_reverse(*src++);
8471					i -= 2;
8472				} while (i);
8473				assert(src <= (uint8_t *)bitmap->devPrivate.ptr + bitmap->devKind * bitmap->drawable.height);
8474				src += src_stride;
8475			} while (--bh);
8476		} else {
8477			struct kgem_bo *upload;
8478			void *ptr;
8479
8480			if (!kgem_check_batch(&sna->kgem, 10) ||
8481			    !kgem_check_bo_fenced(&sna->kgem, arg->bo) ||
8482			    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
8483				kgem_submit(&sna->kgem);
8484				if (!kgem_check_bo_fenced(&sna->kgem, arg->bo))
8485					return; /* XXX fallback? */
8486				_kgem_set_mode(&sna->kgem, KGEM_BLT);
8487			}
8488			kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo);
8489
8490			upload = kgem_create_buffer(&sna->kgem,
8491						    bstride*bh,
8492						    KGEM_BUFFER_WRITE_INPLACE,
8493						    &ptr);
8494			if (!upload)
8495				break;
8496
8497			if (sigtrap_get() == 0) {
8498				assert(sna->kgem.mode == KGEM_BLT);
8499				b = sna->kgem.batch + sna->kgem.nbatch;
8500				if (sna->kgem.gen >= 0100) {
8501					b[0] = XY_MONO_SRC_COPY | br00 | 8;
8502					b[0] |= ((box->x1 + sx) & 7) << 17;
8503					b[1] = br13;
8504					b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8505					b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8506					*(uint64_t *)(b+4) =
8507						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8508								I915_GEM_DOMAIN_RENDER << 16 |
8509								I915_GEM_DOMAIN_RENDER |
8510								KGEM_RELOC_FENCED,
8511								0);
8512					*(uint64_t *)(b+6) =
8513						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
8514								I915_GEM_DOMAIN_RENDER << 16 |
8515								KGEM_RELOC_FENCED,
8516								0);
8517					b[8] = gc->bgPixel;
8518					b[9] = gc->fgPixel;
8519
8520					sna->kgem.nbatch += 10;
8521				} else {
8522					b[0] = XY_MONO_SRC_COPY | br00 | 6;
8523					b[0] |= ((box->x1 + sx) & 7) << 17;
8524					b[1] = br13;
8525					b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8526					b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8527					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8528							I915_GEM_DOMAIN_RENDER << 16 |
8529							I915_GEM_DOMAIN_RENDER |
8530							KGEM_RELOC_FENCED,
8531							0);
8532					b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
8533							I915_GEM_DOMAIN_RENDER << 16 |
8534							KGEM_RELOC_FENCED,
8535							0);
8536					b[6] = gc->bgPixel;
8537					b[7] = gc->fgPixel;
8538
8539					sna->kgem.nbatch += 8;
8540				}
8541
8542				dst = ptr;
8543				assert(bitmap->devKind);
8544				src_stride = bitmap->devKind;
8545				src = bitmap->devPrivate.ptr;
8546				src += (box->y1 + sy) * src_stride + bx1/8;
8547				src_stride -= bstride;
8548				do {
8549					int i = bstride;
8550					assert(src >= (uint8_t *)bitmap->devPrivate.ptr);
8551					do {
8552						*dst++ = byte_reverse(*src++);
8553						*dst++ = byte_reverse(*src++);
8554						i -= 2;
8555					} while (i);
8556					assert(src <= (uint8_t *)bitmap->devPrivate.ptr + bitmap->devKind * bitmap->drawable.height);
8557					assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload));
8558					src += src_stride;
8559				} while (--bh);
8560
8561				sigtrap_put();
8562			}
8563
8564			kgem_bo_destroy(&sna->kgem, upload);
8565		}
8566
8567		box++;
8568	} while (--n);
8569
8570	if (arg->damage) {
8571		RegionTranslate(region, dx, dy);
8572		sna_damage_add_to_pixmap(arg->damage, region, pixmap);
8573	}
8574	assert_pixmap_damage(pixmap);
8575	blt_done(sna);
8576}
8577
8578static void
8579sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc,
8580		   RegionPtr region, int sx, int sy,
8581		   Pixel bitplane, void *closure)
8582{
8583	PixmapPtr dst_pixmap = get_drawable_pixmap(drawable);
8584	PixmapPtr src_pixmap = get_drawable_pixmap(source);
8585	struct sna *sna = to_sna_from_pixmap(dst_pixmap);
8586	struct sna_copy_plane *arg = closure;
8587	int16_t dx, dy;
8588	int bit = ffs(bitplane) - 1;
8589	uint32_t br00, br13;
8590	const BoxRec *box = region_rects(region);
8591	int n = region_num_rects(region);
8592
8593	DBG(("%s: plane=%x [%d] x%d\n", __FUNCTION__,
8594	     (unsigned)bitplane, bit, n));
8595
8596	if (n == 0)
8597		return;
8598
8599	if (get_drawable_deltas(source, src_pixmap, &dx, &dy))
8600		sx += dx, sy += dy;
8601
8602	get_drawable_deltas(drawable, dst_pixmap, &dx, &dy);
8603	assert_pixmap_contains_boxes(dst_pixmap, box, n, dx, dy);
8604
8605	br00 = XY_MONO_SRC_COPY | 3 << 20;
8606	br13 = arg->bo->pitch;
8607	if (sna->kgem.gen >= 040 && arg->bo->tiling) {
8608		br00 |= BLT_DST_TILED;
8609		br13 >>= 2;
8610	}
8611	br13 |= blt_depth(drawable->depth) << 24;
8612	br13 |= copy_ROP[gc->alu] << 16;
8613
8614	kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo);
8615	assert(kgem_bo_can_blt(&sna->kgem, arg->bo));
8616	do {
8617		int bx1 = (box->x1 + sx) & ~7;
8618		int bx2 = (box->x2 + sx + 7) & ~7;
8619		int bw = (bx2 - bx1)/8;
8620		int bh = box->y2 - box->y1;
8621		int bstride = ALIGN(bw, 2);
8622		struct kgem_bo *upload;
8623		void *ptr;
8624
8625		DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n",
8626		     __FUNCTION__,
8627		     box->x1, box->y1,
8628		     box->x2, box->y2,
8629		     sx, sy, bx1, bx2));
8630
8631		if (!kgem_check_batch(&sna->kgem, 10) ||
8632		    !kgem_check_bo_fenced(&sna->kgem, arg->bo) ||
8633		    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
8634			kgem_submit(&sna->kgem);
8635			if (!kgem_check_bo_fenced(&sna->kgem, arg->bo))
8636				return; /* XXX fallback? */
8637			_kgem_set_mode(&sna->kgem, KGEM_BLT);
8638		}
8639		kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo);
8640
8641		upload = kgem_create_buffer(&sna->kgem,
8642					    bstride*bh,
8643					    KGEM_BUFFER_WRITE_INPLACE,
8644					    &ptr);
8645		if (!upload)
8646			break;
8647
8648		if (sigtrap_get() == 0) {
8649			uint32_t *b;
8650
8651			assert(src_pixmap->devKind);
8652			switch (source->bitsPerPixel) {
8653			case 32:
8654				{
8655					uint32_t *src = src_pixmap->devPrivate.ptr;
8656					int src_stride = src_pixmap->devKind/sizeof(uint32_t);
8657					uint8_t *dst = ptr;
8658
8659					src += (box->y1 + sy) * src_stride;
8660					src += bx1;
8661
8662					src_stride -= bw * 8;
8663					bstride -= bw;
8664
8665					do {
8666						int i = bw;
8667						do {
8668							uint8_t v = 0;
8669
8670							v |= ((*src++ >> bit) & 1) << 7;
8671							v |= ((*src++ >> bit) & 1) << 6;
8672							v |= ((*src++ >> bit) & 1) << 5;
8673							v |= ((*src++ >> bit) & 1) << 4;
8674							v |= ((*src++ >> bit) & 1) << 3;
8675							v |= ((*src++ >> bit) & 1) << 2;
8676							v |= ((*src++ >> bit) & 1) << 1;
8677							v |= ((*src++ >> bit) & 1) << 0;
8678
8679							*dst++ = v;
8680						} while (--i);
8681						dst += bstride;
8682						src += src_stride;
8683					} while (--bh);
8684					break;
8685				}
8686			case 16:
8687				{
8688					uint16_t *src = src_pixmap->devPrivate.ptr;
8689					int src_stride = src_pixmap->devKind/sizeof(uint16_t);
8690					uint8_t *dst = ptr;
8691
8692					src += (box->y1 + sy) * src_stride;
8693					src += bx1;
8694
8695					src_stride -= bw * 8;
8696					bstride -= bw;
8697
8698					do {
8699						int i = bw;
8700						do {
8701							uint8_t v = 0;
8702
8703							v |= ((*src++ >> bit) & 1) << 7;
8704							v |= ((*src++ >> bit) & 1) << 6;
8705							v |= ((*src++ >> bit) & 1) << 5;
8706							v |= ((*src++ >> bit) & 1) << 4;
8707							v |= ((*src++ >> bit) & 1) << 3;
8708							v |= ((*src++ >> bit) & 1) << 2;
8709							v |= ((*src++ >> bit) & 1) << 1;
8710							v |= ((*src++ >> bit) & 1) << 0;
8711
8712							*dst++ = v;
8713						} while (--i);
8714						dst += bstride;
8715						src += src_stride;
8716					} while (--bh);
8717					break;
8718				}
8719			default:
8720				assert(0);
8721			case 8:
8722				{
8723					uint8_t *src = src_pixmap->devPrivate.ptr;
8724					int src_stride = src_pixmap->devKind/sizeof(uint8_t);
8725					uint8_t *dst = ptr;
8726
8727					src += (box->y1 + sy) * src_stride;
8728					src += bx1;
8729
8730					src_stride -= bw * 8;
8731					bstride -= bw;
8732
8733					do {
8734						int i = bw;
8735						do {
8736							uint8_t v = 0;
8737
8738							v |= ((*src++ >> bit) & 1) << 7;
8739							v |= ((*src++ >> bit) & 1) << 6;
8740							v |= ((*src++ >> bit) & 1) << 5;
8741							v |= ((*src++ >> bit) & 1) << 4;
8742							v |= ((*src++ >> bit) & 1) << 3;
8743							v |= ((*src++ >> bit) & 1) << 2;
8744							v |= ((*src++ >> bit) & 1) << 1;
8745							v |= ((*src++ >> bit) & 1) << 0;
8746
8747							*dst++ = v;
8748						} while (--i);
8749						dst += bstride;
8750						src += src_stride;
8751					} while (--bh);
8752					break;
8753				}
8754			}
8755
8756			kgem_bcs_set_tiling(&sna->kgem, upload, arg->bo);
8757
8758			assert(sna->kgem.mode == KGEM_BLT);
8759			b = sna->kgem.batch + sna->kgem.nbatch;
8760			if (sna->kgem.gen >= 0100) {
8761				b[0] = br00 | ((box->x1 + sx) & 7) << 17 | 8;
8762				b[1] = br13;
8763				b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8764				b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8765				*(uint64_t *)(b+4) =
8766					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8767							I915_GEM_DOMAIN_RENDER << 16 |
8768							I915_GEM_DOMAIN_RENDER |
8769							KGEM_RELOC_FENCED,
8770							0);
8771				*(uint64_t *)(b+6) =
8772					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
8773							I915_GEM_DOMAIN_RENDER << 16 |
8774							KGEM_RELOC_FENCED,
8775							0);
8776				b[8] = gc->bgPixel;
8777				b[9] = gc->fgPixel;
8778
8779				sna->kgem.nbatch += 10;
8780			} else {
8781				b[0] = br00 | ((box->x1 + sx) & 7) << 17 | 6;
8782				b[1] = br13;
8783				b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8784				b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8785				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8786						I915_GEM_DOMAIN_RENDER << 16 |
8787						I915_GEM_DOMAIN_RENDER |
8788						KGEM_RELOC_FENCED,
8789						0);
8790				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
8791						I915_GEM_DOMAIN_RENDER << 16 |
8792						KGEM_RELOC_FENCED,
8793						0);
8794				b[6] = gc->bgPixel;
8795				b[7] = gc->fgPixel;
8796
8797				sna->kgem.nbatch += 8;
8798			}
8799			sigtrap_put();
8800		}
8801		kgem_bo_destroy(&sna->kgem, upload);
8802
8803		box++;
8804	} while (--n);
8805
8806	if (arg->damage) {
8807		RegionTranslate(region, dx, dy);
8808		sna_damage_add_to_pixmap(arg->damage, region, dst_pixmap);
8809	}
8810	assert_pixmap_damage(dst_pixmap);
8811	blt_done(sna);
8812}
8813
8814static RegionPtr
8815sna_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc,
8816	       int src_x, int src_y,
8817	       int w, int h,
8818	       int dst_x, int dst_y,
8819	       unsigned long bit)
8820{
8821	PixmapPtr pixmap = get_drawable_pixmap(dst);
8822	struct sna *sna = to_sna_from_pixmap(pixmap);
8823	RegionRec region, *ret = NULL;
8824	struct sna_copy_plane arg;
8825
8826	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=%dx%d\n", __FUNCTION__,
8827	     src_x, src_y, dst_x, dst_y, w, h));
8828
8829	if (gc->planemask == 0)
8830		goto empty;
8831
8832	if (src->bitsPerPixel == 1 && (bit&1) == 0)
8833		goto empty;
8834
8835	region.extents.x1 = dst_x + dst->x;
8836	region.extents.y1 = dst_y + dst->y;
8837	region.extents.x2 = region.extents.x1 + w;
8838	region.extents.y2 = region.extents.y1 + h;
8839	region.data = NULL;
8840	RegionIntersect(&region, &region, gc->pCompositeClip);
8841
8842	DBG(("%s: dst extents (%d, %d), (%d, %d)\n",
8843	     __FUNCTION__,
8844	     region.extents.x1, region.extents.y1,
8845	     region.extents.x2, region.extents.y2));
8846
8847	{
8848		RegionRec clip;
8849
8850		clip.extents.x1 = src->x - (src->x + src_x) + (dst->x + dst_x);
8851		clip.extents.y1 = src->y - (src->y + src_y) + (dst->y + dst_y);
8852		clip.extents.x2 = clip.extents.x1 + src->width;
8853		clip.extents.y2 = clip.extents.y1 + src->height;
8854		clip.data = NULL;
8855
8856		DBG(("%s: src extents (%d, %d), (%d, %d)\n",
8857		     __FUNCTION__,
8858		     clip.extents.x1, clip.extents.y1,
8859		     clip.extents.x2, clip.extents.y2));
8860
8861		RegionIntersect(&region, &region, &clip);
8862	}
8863	DBG(("%s: dst^src extents (%d, %d), (%d, %d)\n",
8864	     __FUNCTION__,
8865	     region.extents.x1, region.extents.y1,
8866	     region.extents.x2, region.extents.y2));
8867	if (box_empty(&region.extents))
8868		goto empty;
8869
8870	RegionTranslate(&region,
8871			src_x - dst_x - dst->x + src->x,
8872			src_y - dst_y - dst->y + src->y);
8873
8874	if (!sna_drawable_move_region_to_cpu(src, &region, MOVE_READ))
8875		goto out;
8876
8877	RegionTranslate(&region,
8878			-(src_x - dst_x - dst->x + src->x),
8879			-(src_y - dst_y - dst->y + src->y));
8880
8881	if (FORCE_FALLBACK)
8882		goto fallback;
8883
8884	if (!ACCEL_COPY_PLANE)
8885		goto fallback;
8886
8887	if (wedged(sna))
8888		goto fallback;
8889
8890	if (!PM_IS_SOLID(dst, gc->planemask))
8891		goto fallback;
8892
8893	arg.bo = sna_drawable_use_bo(dst, PREFER_GPU,
8894				     &region.extents, &arg.damage);
8895	if (arg.bo) {
8896		if (arg.bo->tiling == I915_TILING_Y) {
8897			assert(arg.bo == __sna_pixmap_get_bo(pixmap));
8898			arg.bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
8899			if (arg.bo == NULL) {
8900				DBG(("%s: fallback -- unable to change tiling\n",
8901				     __FUNCTION__));
8902				goto fallback;
8903			}
8904		}
8905
8906		if (!kgem_bo_can_blt(&sna->kgem, arg.bo))
8907			return false;
8908
8909		RegionUninit(&region);
8910		return sna_do_copy(src, dst, gc,
8911				   src_x, src_y,
8912				   w, h,
8913				   dst_x, dst_y,
8914				   src->depth == 1 ? sna_copy_bitmap_blt : sna_copy_plane_blt,
8915				   (Pixel)bit, &arg);
8916	}
8917
8918fallback:
8919	DBG(("%s: fallback\n", __FUNCTION__));
8920	if (!sna_gc_move_to_cpu(gc, dst, &region))
8921		goto out;
8922	if (!sna_drawable_move_region_to_cpu(dst, &region,
8923					     drawable_gc_flags(dst, gc, false)))
8924		goto out;
8925
8926	if (sigtrap_get() == 0) {
8927		DBG(("%s: fbCopyPlane(%d, %d, %d, %d, %d,%d) %x\n",
8928		     __FUNCTION__, src_x, src_y, w, h, dst_x, dst_y, (unsigned)bit));
8929		ret = miDoCopy(src, dst, gc,
8930			       src_x, src_y, w, h, dst_x, dst_y,
8931			       src->bitsPerPixel > 1 ? fbCopyNto1 : fbCopy1toN,
8932			       bit, 0);
8933		FALLBACK_FLUSH(dst);
8934		sigtrap_put();
8935	}
8936out:
8937	sna_gc_move_to_gpu(gc);
8938	RegionUninit(&region);
8939	return ret;
8940empty:
8941	return miHandleExposures(src, dst, gc,
8942				 src_x, src_y,
8943				 w, h,
8944				 dst_x, dst_y, bit);
8945}
8946
8947static bool
8948sna_poly_point_blt(DrawablePtr drawable,
8949		   struct kgem_bo *bo,
8950		   struct sna_damage **damage,
8951		   GCPtr gc, int mode, int n, DDXPointPtr pt,
8952		   bool clipped)
8953{
8954	PixmapPtr pixmap = get_drawable_pixmap(drawable);
8955	struct sna *sna = to_sna_from_pixmap(pixmap);
8956	BoxRec box[512], *b = box, * const last_box = box + ARRAY_SIZE(box);
8957	struct sna_fill_op fill;
8958	DDXPointRec last;
8959	int16_t dx, dy;
8960
8961	DBG(("%s: alu=%d, pixel=%08lx, clipped?=%d\n",
8962	     __FUNCTION__, gc->alu, gc->fgPixel, clipped));
8963
8964	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_POINTS))
8965		return false;
8966
8967	get_drawable_deltas(drawable, pixmap, &dx, &dy);
8968
8969	last.x = drawable->x;
8970	last.y = drawable->y;
8971
8972	if (!clipped) {
8973		last.x += dx;
8974		last.y += dy;
8975
8976		assert_pixmap_contains_points(pixmap, pt, n, last.x, last.y);
8977		sna_damage_add_points(damage, pt, n, last.x, last.y);
8978		if (fill.points && mode != CoordModePrevious) {
8979			fill.points(sna, &fill, last.x, last.y, pt, n);
8980		} else {
8981			do {
8982				unsigned nbox = n;
8983				if (nbox > ARRAY_SIZE(box))
8984					nbox = ARRAY_SIZE(box);
8985				n -= nbox;
8986				do {
8987					*(DDXPointRec *)b = *pt++;
8988
8989					b->x1 += last.x;
8990					b->y1 += last.y;
8991					if (mode == CoordModePrevious)
8992						last = *(DDXPointRec *)b;
8993
8994					b->x2 = b->x1 + 1;
8995					b->y2 = b->y1 + 1;
8996					b++;
8997				} while (--nbox);
8998				fill.boxes(sna, &fill, box, b - box);
8999				b = box;
9000			} while (n);
9001		}
9002	} else {
9003		RegionPtr clip = gc->pCompositeClip;
9004
9005		while (n--) {
9006			int x, y;
9007
9008			x = pt->x;
9009			y = pt->y;
9010			pt++;
9011			if (mode == CoordModePrevious) {
9012				x += last.x;
9013				y += last.y;
9014				last.x = x;
9015				last.y = y;
9016			} else {
9017				x += drawable->x;
9018				y += drawable->y;
9019			}
9020
9021			if (RegionContainsPoint(clip, x, y, NULL)) {
9022				b->x1 = x + dx;
9023				b->y1 = y + dy;
9024				b->x2 = b->x1 + 1;
9025				b->y2 = b->y1 + 1;
9026				if (++b == last_box){
9027					assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0);
9028					fill.boxes(sna, &fill, box, last_box - box);
9029					if (damage)
9030						sna_damage_add_boxes(damage, box, last_box-box, 0, 0);
9031					b = box;
9032				}
9033			}
9034		}
9035		if (b != box){
9036			assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
9037			fill.boxes(sna, &fill, box, b - box);
9038			if (damage)
9039				sna_damage_add_boxes(damage, box, b-box, 0, 0);
9040		}
9041	}
9042	fill.done(sna, &fill);
9043	assert_pixmap_damage(pixmap);
9044	return true;
9045}
9046
9047static unsigned
9048sna_poly_point_extents(DrawablePtr drawable, GCPtr gc,
9049		       int mode, int n, DDXPointPtr pt, BoxPtr out)
9050{
9051	BoxRec box;
9052	bool clipped;
9053
9054	if (n == 0)
9055		return 0;
9056
9057	box.x2 = box.x1 = pt->x;
9058	box.y2 = box.y1 = pt->y;
9059	if (mode == CoordModePrevious) {
9060		DDXPointRec last = *pt++;
9061		while (--n) {
9062			last.x += pt->x;
9063			last.y += pt->y;
9064			pt++;
9065			box_add_xy(&box, last.x, last.y);
9066		}
9067	} else {
9068		while (--n)
9069			box_add_pt(&box, ++pt);
9070	}
9071	box.x2++;
9072	box.y2++;
9073
9074	clipped = trim_and_translate_box(&box, drawable, gc);
9075	if (box_empty(&box))
9076		return 0;
9077
9078	*out = box;
9079	return 1 | clipped << 1;
9080}
9081
9082static void
9083sna_poly_point(DrawablePtr drawable, GCPtr gc,
9084	       int mode, int n, DDXPointPtr pt)
9085{
9086	PixmapPtr pixmap = get_drawable_pixmap(drawable);
9087	struct sna *sna = to_sna_from_pixmap(pixmap);
9088	RegionRec region;
9089	unsigned flags;
9090
9091	DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d)\n",
9092	     __FUNCTION__, mode, n, pt[0].x, pt[0].y));
9093
9094	flags = sna_poly_point_extents(drawable, gc, mode, n, pt, &region.extents);
9095	if (flags == 0)
9096		return;
9097
9098	DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
9099	     region.extents.x1, region.extents.y1,
9100	     region.extents.x2, region.extents.y2,
9101	     flags));
9102
9103	if (FORCE_FALLBACK)
9104		goto fallback;
9105
9106	if (!ACCEL_POLY_POINT)
9107		goto fallback;
9108
9109	if (wedged(sna)) {
9110		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
9111		goto fallback;
9112	}
9113
9114	if (PM_IS_SOLID(drawable, gc->planemask)) {
9115		struct sna_damage **damage;
9116		struct kgem_bo *bo;
9117
9118		DBG(("%s: trying solid fill [%08lx] blt paths\n",
9119		     __FUNCTION__, gc->fgPixel));
9120
9121		if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU,
9122					      &region.extents, &damage)) &&
9123		    sna_poly_point_blt(drawable, bo, damage,
9124				       gc, mode, n, pt, flags & IS_CLIPPED))
9125			return;
9126	}
9127
9128fallback:
9129	DBG(("%s: fallback\n", __FUNCTION__));
9130	region.data = NULL;
9131	if (!region_maybe_clip(&region, gc->pCompositeClip))
9132		return;
9133
9134	if (!sna_gc_move_to_cpu(gc, drawable, &region))
9135		goto out;
9136	if (!sna_drawable_move_region_to_cpu(drawable, &region,
9137					     MOVE_READ | MOVE_WRITE))
9138		goto out;
9139
9140	if (sigtrap_get() == 0) {
9141		DBG(("%s: fbPolyPoint\n", __FUNCTION__));
9142		fbPolyPoint(drawable, gc, mode, n, pt, flags);
9143		FALLBACK_FLUSH(drawable);
9144		sigtrap_put();
9145	}
9146out:
9147	sna_gc_move_to_gpu(gc);
9148	RegionUninit(&region);
9149}
9150
9151static bool
9152sna_poly_zero_line_blt(DrawablePtr drawable,
9153		       struct kgem_bo *bo,
9154		       struct sna_damage **damage,
9155		       GCPtr gc, int mode, const int _n, const DDXPointRec * const _pt,
9156		       const BoxRec *extents, unsigned clipped)
9157{
9158	static void * const _jump[] = {
9159		&&no_damage,
9160		&&damage,
9161
9162		&&no_damage_offset,
9163		&&damage_offset,
9164	};
9165
9166	PixmapPtr pixmap = get_drawable_pixmap(drawable);
9167	struct sna *sna = to_sna_from_pixmap(pixmap);
9168	int x2, y2, xstart, ystart, oc2;
9169	unsigned int bias = miGetZeroLineBias(drawable->pScreen);
9170	bool degenerate = true;
9171	struct sna_fill_op fill;
9172	RegionRec clip;
9173	BoxRec box[512], *b, * const last_box = box + ARRAY_SIZE(box);
9174	const BoxRec *last_extents;
9175	int16_t dx, dy;
9176	void *jump, *ret;
9177
9178	DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n",
9179	     __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage));
9180	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_SPANS))
9181		return false;
9182
9183	get_drawable_deltas(drawable, pixmap, &dx, &dy);
9184
9185	region_set(&clip, extents);
9186	if (clipped) {
9187		if (!region_maybe_clip(&clip, gc->pCompositeClip))
9188			return true;
9189	}
9190
9191	jump = _jump[(damage != NULL) | !!(dx|dy) << 1];
9192	DBG(("%s: [clipped=%x] extents=(%d, %d), (%d, %d), delta=(%d, %d), damage=%p\n",
9193	     __FUNCTION__, clipped,
9194	     clip.extents.x1, clip.extents.y1,
9195	     clip.extents.x2, clip.extents.y2,
9196	     dx, dy, damage));
9197
9198	extents = region_rects(&clip);
9199	last_extents = extents + region_num_rects(&clip);
9200
9201	b = box;
9202	do {
9203		int n = _n;
9204		const DDXPointRec *pt = _pt;
9205
9206		xstart = pt->x + drawable->x;
9207		ystart = pt->y + drawable->y;
9208
9209		x2 = xstart;
9210		y2 = ystart;
9211		oc2 = 0;
9212		OUTCODES(oc2, x2, y2, extents);
9213
9214		while (--n) {
9215			int16_t sdx, sdy;
9216			int adx, ady, length;
9217			int e, e1, e2, e3;
9218			int x1 = x2, x;
9219			int y1 = y2, y;
9220			int oc1 = oc2;
9221			int octant;
9222
9223			++pt;
9224
9225			x2 = pt->x;
9226			y2 = pt->y;
9227			if (mode == CoordModePrevious) {
9228				x2 += x1;
9229				y2 += y1;
9230			} else {
9231				x2 += drawable->x;
9232				y2 += drawable->y;
9233			}
9234			DBG(("%s: segment (%d, %d) to (%d, %d)\n",
9235			     __FUNCTION__, x1, y1, x2, y2));
9236			if (x2 == x1 && y2 == y1)
9237				continue;
9238
9239			degenerate = false;
9240
9241			oc2 = 0;
9242			OUTCODES(oc2, x2, y2, extents);
9243			if (oc1 & oc2)
9244				continue;
9245
9246			CalcLineDeltas(x1, y1, x2, y2,
9247				       adx, ady, sdx, sdy,
9248				       1, 1, octant);
9249
9250			DBG(("%s: adx=(%d, %d), sdx=(%d, %d), oc1=%x, oc2=%x\n",
9251			     __FUNCTION__, adx, ady, sdx, sdy, oc1, oc2));
9252			if (adx == 0 || ady == 0) {
9253				if (x1 <= x2) {
9254					b->x1 = x1;
9255					b->x2 = x2;
9256				} else {
9257					b->x1 = x2;
9258					b->x2 = x1;
9259				}
9260				if (y1 <= y2) {
9261					b->y1 = y1;
9262					b->y2 = y2;
9263				} else {
9264					b->y1 = y2;
9265					b->y2 = y1;
9266				}
9267				b->x2++;
9268				b->y2++;
9269				if (oc1 | oc2) {
9270					bool intersects;
9271
9272					intersects = box_intersect(b, extents);
9273					assert(intersects);
9274				}
9275				if (++b == last_box) {
9276					ret = &&rectangle_continue;
9277					goto *jump;
9278rectangle_continue:
9279					b = box;
9280				}
9281			} else if (adx >= ady) {
9282				int x2_clipped = x2, y2_clipped = y2;
9283				bool dirty;
9284
9285				/* X-major segment */
9286				e1 = ady << 1;
9287				e2 = e1 - (adx << 1);
9288				e  = e1 - adx;
9289				length = adx;
9290
9291				FIXUP_ERROR(e, octant, bias);
9292
9293				x = x1;
9294				y = y1;
9295
9296				if (oc1 | oc2) {
9297					int pt1_clipped, pt2_clipped;
9298
9299					if (miZeroClipLine(extents->x1, extents->y1,
9300							   extents->x2-1, extents->y2-1,
9301							   &x, &y, &x2_clipped, &y2_clipped,
9302							   adx, ady,
9303							   &pt1_clipped, &pt2_clipped,
9304							   octant, bias, oc1, oc2) == -1)
9305						continue;
9306
9307					length = abs(x2_clipped - x);
9308					if (length == 0)
9309						continue;
9310
9311					if (pt1_clipped) {
9312						int clipdx = abs(x - x1);
9313						int clipdy = abs(y - y1);
9314						e += clipdy * e2 + (clipdx - clipdy) * e1;
9315					}
9316				}
9317
9318				e3 = e2 - e1;
9319				e  = e - e1;
9320
9321				b->x1 = x;
9322				b->y1 = y;
9323				dirty = false;
9324				while (length--) {
9325					e += e1;
9326					dirty = true;
9327					if (e >= 0) {
9328						e += e3;
9329
9330						if (sdx < 0) {
9331							b->x2 = b->x1 + 1;
9332							b->x1 = x;
9333						} else
9334							b->x2 = x + 1;
9335						b->y2 = b->y1 + 1;
9336
9337						if (++b == last_box) {
9338							ret = &&X_continue;
9339							goto *jump;
9340X_continue:
9341							b = box;
9342						}
9343
9344						b->x1 = x + sdx;
9345						b->y1 = y += sdy;
9346						dirty = false;
9347					}
9348					x += sdx;
9349				}
9350				if (dirty) {
9351					x -= sdx;
9352					if (sdx < 0) {
9353						b->x2 = b->x1 + 1;
9354						b->x1 = x;
9355					} else
9356						b->x2 = x + 1;
9357					b->y2 = b->y1 + 1;
9358
9359					if (++b == last_box) {
9360						ret = &&X2_continue;
9361						goto *jump;
9362X2_continue:
9363						b = box;
9364					}
9365				}
9366			} else {
9367				int x2_clipped = x2, y2_clipped = y2;
9368				bool dirty;
9369
9370				/* Y-major segment */
9371				e1 = adx << 1;
9372				e2 = e1 - (ady << 1);
9373				e  = e1 - ady;
9374				length  = ady;
9375
9376				SetYMajorOctant(octant);
9377				FIXUP_ERROR(e, octant, bias);
9378
9379				x = x1;
9380				y = y1;
9381
9382				if (oc1 | oc2) {
9383					int pt1_clipped, pt2_clipped;
9384
9385					if (miZeroClipLine(extents->x1, extents->y1,
9386							   extents->x2-1, extents->y2-1,
9387							   &x, &y, &x2_clipped, &y2_clipped,
9388							   adx, ady,
9389							   &pt1_clipped, &pt2_clipped,
9390							   octant, bias, oc1, oc2) == -1)
9391						continue;
9392
9393					length = abs(y2_clipped - y);
9394					if (length == 0)
9395						continue;
9396
9397					if (pt1_clipped) {
9398						int clipdx = abs(x - x1);
9399						int clipdy = abs(y - y1);
9400						e += clipdx * e2 + (clipdy - clipdx) * e1;
9401					}
9402				}
9403
9404				e3 = e2 - e1;
9405				e  = e - e1;
9406
9407				b->x1 = x;
9408				b->y1 = y;
9409				dirty = false;
9410				while (length--) {
9411					e += e1;
9412					dirty = true;
9413					if (e >= 0) {
9414						e += e3;
9415
9416						if (sdy < 0) {
9417							b->y2 = b->y1 + 1;
9418							b->y1 = y;
9419						} else
9420							b->y2 = y + 1;
9421						b->x2 = x + 1;
9422
9423						if (++b == last_box) {
9424							ret = &&Y_continue;
9425							goto *jump;
9426Y_continue:
9427							b = box;
9428						}
9429
9430						b->x1 = x += sdx;
9431						b->y1 = y + sdy;
9432						dirty = false;
9433					}
9434					y += sdy;
9435				}
9436
9437				if (dirty) {
9438					y -= sdy;
9439					if (sdy < 0) {
9440						b->y2 = b->y1 + 1;
9441						b->y1 = y;
9442					} else
9443						b->y2 = y + 1;
9444					b->x2 = x + 1;
9445
9446					if (++b == last_box) {
9447						ret = &&Y2_continue;
9448						goto *jump;
9449Y2_continue:
9450						b = box;
9451					}
9452				}
9453			}
9454		}
9455
9456#if 0
9457		/* Only do the CapNotLast check on the last segment
9458		 * and only if the endpoint wasn't clipped.  And then, if the last
9459		 * point is the same as the first point, do not draw it, unless the
9460		 * line is degenerate
9461		 */
9462		if (!pt2_clipped &&
9463		    gc->capStyle != CapNotLast &&
9464		    !(xstart == x2 && ystart == y2 && !degenerate))
9465		{
9466			b->x2 = x2;
9467			b->y2 = y2;
9468			if (b->x2 < b->x1) {
9469				int16_t t = b->x1;
9470				b->x1 = b->x2;
9471				b->x2 = t;
9472			}
9473			if (b->y2 < b->y1) {
9474				int16_t t = b->y1;
9475				b->y1 = b->y2;
9476				b->y2 = t;
9477			}
9478			b->x2++;
9479			b->y2++;
9480			b++;
9481		}
9482#endif
9483	} while (++extents != last_extents);
9484
9485	if (b != box) {
9486		ret = &&done;
9487		goto *jump;
9488	}
9489
9490done:
9491	fill.done(sna, &fill);
9492	assert_pixmap_damage(pixmap);
9493	RegionUninit(&clip);
9494	return true;
9495
9496damage:
9497	assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
9498	sna_damage_add_boxes(damage, box, b-box, 0, 0);
9499no_damage:
9500	fill.boxes(sna, &fill, box, b-box);
9501	goto *ret;
9502
9503no_damage_offset:
9504	{
9505		BoxRec *bb = box;
9506		do {
9507			bb->x1 += dx;
9508			bb->x2 += dx;
9509			bb->y1 += dy;
9510			bb->y2 += dy;
9511		} while (++bb != b);
9512		assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
9513		fill.boxes(sna, &fill, box, b - box);
9514	}
9515	goto *ret;
9516
9517damage_offset:
9518	{
9519		BoxRec *bb = box;
9520		do {
9521			bb->x1 += dx;
9522			bb->x2 += dx;
9523			bb->y1 += dy;
9524			bb->y2 += dy;
9525		} while (++bb != b);
9526		assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
9527		fill.boxes(sna, &fill, box, b - box);
9528		sna_damage_add_boxes(damage, box, b - box, 0, 0);
9529	}
9530	goto *ret;
9531}
9532
9533static bool
9534sna_poly_line_blt(DrawablePtr drawable,
9535		  struct kgem_bo *bo,
9536		  struct sna_damage **damage,
9537		  GCPtr gc, uint32_t pixel,
9538		  int mode, int n, DDXPointPtr pt,
9539		  const BoxRec *extents, bool clipped)
9540{
9541	PixmapPtr pixmap = get_drawable_pixmap(drawable);
9542	struct sna *sna = to_sna_from_pixmap(pixmap);
9543	BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes);
9544	struct sna_fill_op fill;
9545	DDXPointRec last;
9546	int16_t dx, dy;
9547
9548	DBG(("%s: alu=%d, fg=%08x, clipped=%d\n", __FUNCTION__, gc->alu, (unsigned)pixel, clipped));
9549
9550	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_BOXES))
9551		return false;
9552
9553	get_drawable_deltas(drawable, pixmap, &dx, &dy);
9554
9555	if (!clipped) {
9556		dx += drawable->x;
9557		dy += drawable->y;
9558
9559		last.x = pt->x + dx;
9560		last.y = pt->y + dy;
9561		pt++;
9562
9563		while (--n) {
9564			DDXPointRec p;
9565
9566			p = *pt++;
9567			if (mode == CoordModePrevious) {
9568				p.x += last.x;
9569				p.y += last.y;
9570			} else {
9571				p.x += dx;
9572				p.y += dy;
9573			}
9574			DBG(("%s: line (%d, %d) -> (%d, %d)\n", __FUNCTION__, last.x, last.y, p.x, p.y));
9575
9576			if (last.x == p.x) {
9577				b->x1 = last.x;
9578				b->x2 = last.x + 1;
9579			} else if (last.x < p.x) {
9580				b->x1 = last.x;
9581				b->x2 = p.x;
9582			} else {
9583				b->x1 = p.x;
9584				b->x2 = last.x;
9585			}
9586
9587			if (last.y == p.y) {
9588				b->y1 = last.y;
9589				b->y2 = last.y + 1;
9590			} else if (last.y < p.y) {
9591				b->y1 = last.y;
9592				b->y2 = p.y;
9593			} else {
9594				b->y1 = p.y;
9595				b->y2 = last.y;
9596			}
9597			b->y2 += last.x == p.x && last.y != p.y;
9598			b->x2 += last.y == p.y && last.x != p.x;
9599			DBG(("%s: blt (%d, %d), (%d, %d)\n",
9600			     __FUNCTION__,
9601			     b->x1, b->y1, b->x2, b->y2));
9602
9603			if (++b == last_box) {
9604				assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0);
9605				fill.boxes(sna, &fill, boxes, last_box - boxes);
9606				if (damage)
9607					sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0);
9608				b = boxes;
9609			}
9610
9611			last = p;
9612		}
9613	} else {
9614		RegionRec clip;
9615
9616		region_set(&clip, extents);
9617		if (!region_maybe_clip(&clip, gc->pCompositeClip))
9618			return true;
9619
9620		last.x = pt->x + drawable->x;
9621		last.y = pt->y + drawable->y;
9622		pt++;
9623
9624		if (clip.data == NULL) {
9625			while (--n) {
9626				DDXPointRec p;
9627
9628				p = *pt++;
9629				if (mode == CoordModePrevious) {
9630					p.x += last.x;
9631					p.y += last.y;
9632				} else {
9633					p.x += drawable->x;
9634					p.y += drawable->y;
9635				}
9636				if (last.x == p.x) {
9637					b->x1 = last.x;
9638					b->x2 = last.x + 1;
9639				} else if (last.x < p.x) {
9640					b->x1 = last.x;
9641					b->x2 = p.x;
9642				} else {
9643					b->x1 = p.x;
9644					b->x2 = last.x;
9645				}
9646				if (last.y == p.y) {
9647					b->y1 = last.y;
9648					b->y2 = last.y + 1;
9649				} else if (last.y < p.y) {
9650					b->y1 = last.y;
9651					b->y2 = p.y;
9652				} else {
9653					b->y1 = p.y;
9654					b->y2 = last.y;
9655				}
9656				b->y2 += last.x == p.x && last.y != p.y;
9657				b->x2 += last.y == p.y && last.x != p.x;
9658				DBG(("%s: blt (%d, %d), (%d, %d)\n",
9659				     __FUNCTION__,
9660				     b->x1, b->y1, b->x2, b->y2));
9661				if (box_intersect(b, &clip.extents)) {
9662					b->x1 += dx;
9663					b->x2 += dx;
9664					b->y1 += dy;
9665					b->y2 += dy;
9666					if (++b == last_box) {
9667						assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0);
9668						fill.boxes(sna, &fill, boxes, last_box - boxes);
9669						if (damage)
9670							sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0);
9671						b = boxes;
9672					}
9673				}
9674
9675				last = p;
9676			}
9677		} else {
9678			const BoxRec * const clip_start = RegionBoxptr(&clip);
9679			const BoxRec * const clip_end = clip_start + clip.data->numRects;
9680			const BoxRec *c;
9681
9682			while (--n) {
9683				DDXPointRec p;
9684				BoxRec box;
9685
9686				p = *pt++;
9687				if (mode == CoordModePrevious) {
9688					p.x += last.x;
9689					p.y += last.y;
9690				} else {
9691					p.x += drawable->x;
9692					p.y += drawable->y;
9693				}
9694				if (last.x == p.x) {
9695					box.x1 = last.x;
9696					box.x2 = last.x + 1;
9697				} else if (last.x < p.x) {
9698					box.x1 = last.x;
9699					box.x2 = p.x;
9700				} else {
9701					box.x1 = p.x;
9702					box.x2 = last.x;
9703				}
9704				if (last.y == p.y) {
9705					box.y1 = last.y;
9706					box.y2 = last.y + 1;
9707				} else if (last.y < p.y) {
9708					box.y1 = last.y;
9709					box.y2 = p.y;
9710				} else {
9711					box.y1 = p.y;
9712					box.y2 = last.y;
9713				}
9714				b->y2 += last.x == p.x && last.y != p.y;
9715				b->x2 += last.y == p.y && last.x != p.x;
9716				DBG(("%s: blt (%d, %d), (%d, %d)\n",
9717				     __FUNCTION__,
9718				     box.x1, box.y1, box.x2, box.y2));
9719
9720				c = find_clip_box_for_y(clip_start,
9721							clip_end,
9722							box.y1);
9723				while (c != clip_end) {
9724					if (box.y2 <= c->y1)
9725						break;
9726
9727					*b = box;
9728					if (box_intersect(b, c++)) {
9729						b->x1 += dx;
9730						b->x2 += dx;
9731						b->y1 += dy;
9732						b->y2 += dy;
9733						if (++b == last_box) {
9734							assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0);
9735							fill.boxes(sna, &fill, boxes, last_box-boxes);
9736							if (damage)
9737								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
9738							b = boxes;
9739						}
9740					}
9741				}
9742
9743				last = p;
9744			}
9745		}
9746		RegionUninit(&clip);
9747	}
9748	if (b != boxes) {
9749		assert_pixmap_contains_boxes(pixmap, boxes, b-boxes, 0, 0);
9750		fill.boxes(sna, &fill, boxes, b - boxes);
9751		if (damage)
9752			sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0);
9753	}
9754	fill.done(sna, &fill);
9755	assert_pixmap_damage(pixmap);
9756	return true;
9757}
9758
9759static unsigned
9760sna_poly_line_extents(DrawablePtr drawable, GCPtr gc,
9761		      int mode, int n, DDXPointPtr pt,
9762		      BoxPtr out)
9763{
9764	BoxRec box;
9765	bool clip, blt = true;
9766
9767	if (n == 0)
9768		return 0;
9769
9770	box.x2 = box.x1 = pt->x;
9771	box.y2 = box.y1 = pt->y;
9772	if (mode == CoordModePrevious) {
9773		int x = box.x1;
9774		int y = box.y1;
9775		while (--n) {
9776			pt++;
9777			x += pt->x;
9778			y += pt->y;
9779			if (blt)
9780				blt &= pt->x == 0 || pt->y == 0;
9781			box_add_xy(&box, x, y);
9782		}
9783	} else {
9784		int x = box.x1;
9785		int y = box.y1;
9786		while (--n) {
9787			pt++;
9788			if (blt) {
9789				blt &= pt->x == x || pt->y == y;
9790				x = pt->x;
9791				y = pt->y;
9792			}
9793			box_add_pt(&box, pt);
9794		}
9795	}
9796	box.x2++;
9797	box.y2++;
9798
9799	if (gc->lineWidth) {
9800		int extra = gc->lineWidth >> 1;
9801		if (n > 1) {
9802			if (gc->joinStyle == JoinMiter)
9803				extra = 6 * gc->lineWidth;
9804			else if (gc->capStyle == CapProjecting)
9805				extra = gc->lineWidth;
9806		}
9807		if (extra) {
9808			box.x1 -= extra;
9809			box.x2 += extra;
9810			box.y1 -= extra;
9811			box.y2 += extra;
9812		}
9813	}
9814
9815	clip = trim_and_translate_box(&box, drawable, gc);
9816	if (box_empty(&box))
9817		return 0;
9818
9819	*out = box;
9820	return 1 | blt << 2 | clip << 1;
9821}
9822
9823inline static int
9824_use_line_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags)
9825{
9826	uint32_t ignored;
9827
9828	if (USE_SPANS)
9829		return USE_SPANS > 0;
9830
9831	if (flags & RECTILINEAR)
9832		return PREFER_GPU;
9833
9834	if (gc->lineStyle != LineSolid && gc->lineWidth == 0)
9835		return 0;
9836
9837	if (gc_is_solid(gc, &ignored))
9838		return PREFER_GPU;
9839
9840	return !drawable_gc_inplace_hint(drawable, gc);
9841}
9842
9843inline static int
9844use_line_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags)
9845{
9846	int ret = _use_line_spans(drawable, gc, extents, flags);
9847	DBG(("%s? %d\n", __FUNCTION__, ret));
9848	return ret;
9849}
9850
9851static void
9852sna_poly_line(DrawablePtr drawable, GCPtr gc,
9853	      int mode, int n, DDXPointPtr pt)
9854{
9855	struct sna_pixmap *priv;
9856	struct sna_fill_spans data;
9857	uint32_t color;
9858
9859	DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d), lineWidth=%d\n",
9860	     __FUNCTION__, mode, n, pt[0].x, pt[0].y, gc->lineWidth));
9861
9862	data.flags = sna_poly_line_extents(drawable, gc, mode, n, pt,
9863					   &data.region.extents);
9864	if (data.flags == 0)
9865		return;
9866
9867	DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
9868	     data.region.extents.x1, data.region.extents.y1,
9869	     data.region.extents.x2, data.region.extents.y2,
9870	     data.flags));
9871
9872	data.region.data = NULL;
9873
9874	if (FORCE_FALLBACK)
9875		goto fallback;
9876
9877	if (!ACCEL_POLY_LINE)
9878		goto fallback;
9879
9880	data.pixmap = get_drawable_pixmap(drawable);
9881	data.sna = to_sna_from_pixmap(data.pixmap);
9882	if (wedged(data.sna)) {
9883		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
9884		goto fallback;
9885	}
9886
9887	DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lx [%d], rectlinear=%d\n",
9888	     __FUNCTION__,
9889	     gc->fillStyle, gc->fillStyle == FillSolid,
9890	     gc->lineStyle, gc->lineStyle == LineSolid,
9891	     gc->lineWidth,
9892	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask),
9893	     data.flags & RECTILINEAR));
9894
9895	if (!PM_IS_SOLID(drawable, gc->planemask))
9896		goto fallback;
9897
9898	priv = sna_pixmap(data.pixmap);
9899	if (!priv) {
9900		DBG(("%s: not attached to pixmap %ld\n",
9901		     __FUNCTION__, data.pixmap->drawable.serialNumber));
9902		goto fallback;
9903	}
9904
9905	if (gc->lineStyle != LineSolid) {
9906		DBG(("%s: lineStyle, %d, is not solid\n",
9907		     __FUNCTION__, gc->lineStyle));
9908		goto spans_fallback;
9909	}
9910	if (!(gc->lineWidth == 0 ||
9911	      (gc->lineWidth == 1 && (n == 1 || gc->alu == GXcopy)))) {
9912		DBG(("%s: non-zero lineWidth %d\n",
9913		     __FUNCTION__, gc->lineWidth));
9914		goto spans_fallback;
9915	}
9916
9917	data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
9918				      &data.region.extents,
9919				      &data.damage);
9920	if (data.bo == NULL)
9921		goto fallback;
9922
9923	if (gc_is_solid(gc, &color)) {
9924		DBG(("%s: trying solid fill [%08x]\n",
9925		     __FUNCTION__, (unsigned)color));
9926		if (data.flags & RECTILINEAR) {
9927			if (sna_poly_line_blt(drawable,
9928					      data.bo, data.damage,
9929					      gc, color, mode, n, pt,
9930					      &data.region.extents,
9931					      data.flags & IS_CLIPPED))
9932				return;
9933		} else { /* !rectilinear */
9934			if (sna_poly_zero_line_blt(drawable,
9935						   data.bo, data.damage,
9936						   gc, mode, n, pt,
9937						   &data.region.extents,
9938						   data.flags & IS_CLIPPED))
9939				return;
9940
9941		}
9942	} else if (data.flags & RECTILINEAR) {
9943		/* Try converting these to a set of rectangles instead */
9944		DDXPointRec p1, p2;
9945		xRectangle *rect;
9946		int i;
9947
9948		DBG(("%s: converting to rectagnles\n", __FUNCTION__));
9949
9950		rect = malloc (n * sizeof (xRectangle));
9951		if (rect == NULL)
9952			return;
9953
9954		p1 = pt[0];
9955		for (i = 1; i < n; i++) {
9956			if (mode == CoordModePrevious) {
9957				p2.x = p1.x + pt[i].x;
9958				p2.y = p1.y + pt[i].y;
9959			} else
9960				p2 = pt[i];
9961			if (p1.x < p2.x) {
9962				rect[i].x = p1.x;
9963				rect[i].width = p2.x - p1.x + 1;
9964			} else if (p1.x > p2.x) {
9965				rect[i].x = p2.x;
9966				rect[i].width = p1.x - p2.x + 1;
9967			} else {
9968				rect[i].x = p1.x;
9969				rect[i].width = 1;
9970			}
9971			if (p1.y < p2.y) {
9972				rect[i].y = p1.y;
9973				rect[i].height = p2.y - p1.y + 1;
9974			} else if (p1.y > p2.y) {
9975				rect[i].y = p2.y;
9976				rect[i].height = p1.y - p2.y + 1;
9977			} else {
9978				rect[i].y = p1.y;
9979				rect[i].height = 1;
9980			}
9981
9982			/* don't paint last pixel */
9983			if (gc->capStyle == CapNotLast) {
9984				if (p1.x == p2.x)
9985					rect[i].height--;
9986				else
9987					rect[i].width--;
9988			}
9989			p1 = p2;
9990		}
9991
9992		if (gc->fillStyle == FillTiled) {
9993			i = sna_poly_fill_rect_tiled_blt(drawable,
9994							 data.bo, data.damage,
9995							 gc, n - 1, rect + 1,
9996							 &data.region.extents,
9997							 data.flags & IS_CLIPPED);
9998		} else {
9999			i = sna_poly_fill_rect_stippled_blt(drawable,
10000							    data.bo, data.damage,
10001							    gc, n - 1, rect + 1,
10002							    &data.region.extents,
10003							    data.flags & IS_CLIPPED);
10004		}
10005		free (rect);
10006
10007		if (i)
10008			return;
10009	}
10010
10011spans_fallback:
10012	if ((data.bo = sna_drawable_use_bo(drawable,
10013					   use_line_spans(drawable, gc, &data.region.extents, data.flags),
10014					   &data.region.extents, &data.damage))) {
10015		DBG(("%s: converting line into spans\n", __FUNCTION__));
10016		get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy);
10017		sna_gc(gc)->priv = &data;
10018
10019		if (gc->lineWidth == 0 && gc_is_solid(gc, &color)) {
10020			struct sna_fill_op fill;
10021
10022			if (gc->lineStyle == LineSolid) {
10023				if (!sna_fill_init_blt(&fill,
10024						       data.sna, data.pixmap,
10025						       data.bo, gc->alu, color,
10026						       FILL_POINTS | FILL_SPANS))
10027					goto fallback;
10028
10029				data.op = &fill;
10030
10031				if ((data.flags & IS_CLIPPED) == 0) {
10032					if (data.dx | data.dy)
10033						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
10034					else
10035						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
10036					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill;
10037				} else {
10038					if (!region_maybe_clip(&data.region,
10039							       gc->pCompositeClip))
10040						return;
10041
10042					if (region_is_singular(&data.region)) {
10043						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
10044						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents;
10045					} else {
10046						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
10047						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes;
10048					}
10049				}
10050				assert(gc->miTranslate);
10051
10052				gc->ops = &sna_gc_ops__tmp;
10053				DBG(("%s: miZeroLine (solid fill)\n", __FUNCTION__));
10054				miZeroLine(drawable, gc, mode, n, pt);
10055				fill.done(data.sna, &fill);
10056			} else {
10057				data.op = &fill;
10058
10059				if ((data.flags & IS_CLIPPED) == 0) {
10060					if (data.dx | data.dy)
10061						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_offset;
10062					else
10063						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash;
10064					sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash;
10065				} else {
10066					if (!region_maybe_clip(&data.region,
10067							       gc->pCompositeClip))
10068						return;
10069
10070					if (region_is_singular(&data.region)) {
10071						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_extents;
10072						sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_extents;
10073					} else {
10074						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_boxes;
10075						sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_boxes;
10076					}
10077				}
10078				assert(gc->miTranslate);
10079
10080				DBG(("%s: miZeroLine (solid dash, clipped? %d (complex? %d)), fg pass [%08x]\n",
10081				     __FUNCTION__,
10082				     !!(data.flags & IS_CLIPPED), data.flags & IS_CLIPPED && !region_is_singular(&data.region),
10083				     gc->fgPixel));
10084
10085				if (!sna_fill_init_blt(&fill,
10086						       data.sna, data.pixmap,
10087						       data.bo, gc->alu, color,
10088						       FILL_POINTS | FILL_SPANS))
10089					goto fallback;
10090
10091				gc->ops = &sna_gc_ops__tmp;
10092				data.phase = gc->fgPixel;
10093				miZeroDashLine(drawable, gc, mode, n, pt);
10094				fill.done(data.sna, &fill);
10095
10096				DBG(("%s: miZeroLine (solid dash, clipped? %d (complex? %d)), bg pass [%08x]\n",
10097				     __FUNCTION__,
10098				     !!(data.flags & IS_CLIPPED), data.flags & IS_CLIPPED && !region_is_singular(&data.region),
10099				     gc->bgPixel));
10100
10101				if (sna_fill_init_blt(&fill,
10102						      data.sna, data.pixmap,
10103						      data.bo, gc->alu,
10104						      gc->bgPixel,
10105						      FILL_POINTS | FILL_SPANS)) {
10106					data.phase = gc->bgPixel;
10107					miZeroDashLine(drawable, gc, mode, n, pt);
10108					fill.done(data.sna, &fill);
10109				}
10110			}
10111		} else {
10112			/* Note that the WideDash functions alternate
10113			 * between filling using fgPixel and bgPixel
10114			 * so we need to reset state between FillSpans and
10115			 * cannot use the fill fast paths.
10116			 */
10117			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
10118			sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu;
10119			sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu;
10120			gc->ops = &sna_gc_ops__tmp;
10121
10122			switch (gc->lineStyle) {
10123			default:
10124				assert(0);
10125			case LineSolid:
10126				if (gc->lineWidth == 0) {
10127					DBG(("%s: miZeroLine\n", __FUNCTION__));
10128					miZeroLine(drawable, gc, mode, n, pt);
10129				} else {
10130					DBG(("%s: miWideLine\n", __FUNCTION__));
10131					miWideLine(drawable, gc, mode, n, pt);
10132				}
10133				break;
10134			case LineOnOffDash:
10135			case LineDoubleDash:
10136				if (gc->lineWidth == 0) {
10137					DBG(("%s: miZeroDashLine\n", __FUNCTION__));
10138					miZeroDashLine(drawable, gc, mode, n, pt);
10139				} else {
10140					DBG(("%s: miWideDash\n", __FUNCTION__));
10141					miWideDash(drawable, gc, mode, n, pt);
10142				}
10143				break;
10144			}
10145		}
10146
10147		gc->ops = (GCOps *)&sna_gc_ops;
10148		if (data.damage) {
10149			if (data.dx | data.dy)
10150				pixman_region_translate(&data.region, data.dx, data.dy);
10151			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
10152			sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap);
10153			assert_pixmap_damage(data.pixmap);
10154		}
10155		RegionUninit(&data.region);
10156		return;
10157	}
10158
10159fallback:
10160	DBG(("%s: fallback\n", __FUNCTION__));
10161	if (!region_maybe_clip(&data.region, gc->pCompositeClip))
10162		return;
10163
10164	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
10165		goto out;
10166	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
10167					     drawable_gc_flags(drawable, gc,
10168							       !(data.flags & RECTILINEAR && n == 2))))
10169		goto out;
10170
10171	if (sigtrap_get() == 0) {
10172		DBG(("%s: fbPolyLine\n", __FUNCTION__));
10173		fbPolyLine(drawable, gc, mode, n, pt);
10174		FALLBACK_FLUSH(drawable);
10175		sigtrap_put();
10176	}
10177out:
10178	sna_gc_move_to_gpu(gc);
10179	RegionUninit(&data.region);
10180}
10181
10182static inline bool box_from_seg(BoxPtr b, const xSegment *seg, GCPtr gc)
10183{
10184	if (seg->x1 == seg->x2) {
10185		if (seg->y1 > seg->y2) {
10186			b->y2 = seg->y1 + 1;
10187			b->y1 = seg->y2 + 1;
10188			if (gc->capStyle != CapNotLast)
10189				b->y1--;
10190		} else {
10191			b->y1 = seg->y1;
10192			b->y2 = seg->y2;
10193			if (gc->capStyle != CapNotLast)
10194				b->y2++;
10195		}
10196		if (b->y1 >= b->y2)
10197			return false;
10198
10199		b->x1 = seg->x1;
10200		b->x2 = seg->x1 + 1;
10201	} else {
10202		if (seg->x1 > seg->x2) {
10203			b->x2 = seg->x1 + 1;
10204			b->x1 = seg->x2 + 1;
10205			if (gc->capStyle != CapNotLast)
10206				b->x1--;
10207		} else {
10208			b->x1 = seg->x1;
10209			b->x2 = seg->x2;
10210			if (gc->capStyle != CapNotLast)
10211				b->x2++;
10212		}
10213		if (b->x1 >= b->x2)
10214			return false;
10215
10216		b->y1 = seg->y1;
10217		b->y2 = seg->y1 + 1;
10218	}
10219
10220	DBG(("%s: seg=(%d,%d),(%d,%d); box=(%d,%d),(%d,%d)\n",
10221	     __FUNCTION__,
10222	     seg->x1, seg->y1, seg->x2, seg->y2,
10223	     b->x1, b->y1, b->x2, b->y2));
10224	return true;
10225}
10226
10227static bool
10228sna_poly_segment_blt(DrawablePtr drawable,
10229		     struct kgem_bo *bo,
10230		     struct sna_damage **damage,
10231		     GCPtr gc, uint32_t pixel,
10232		     int n, xSegment *seg,
10233		     const BoxRec *extents, unsigned clipped)
10234{
10235	PixmapPtr pixmap = get_drawable_pixmap(drawable);
10236	struct sna *sna = to_sna_from_pixmap(pixmap);
10237	BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes);
10238	struct sna_fill_op fill;
10239	int16_t dx, dy;
10240
10241	DBG(("%s: n=%d, alu=%d, fg=%08lx, clipped=%d\n",
10242	     __FUNCTION__, n, gc->alu, gc->fgPixel, clipped));
10243
10244	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_SPANS))
10245		return false;
10246
10247	get_drawable_deltas(drawable, pixmap, &dx, &dy);
10248
10249	if (!clipped) {
10250		dx += drawable->x;
10251		dy += drawable->y;
10252		if (dx|dy) {
10253			do {
10254				unsigned nbox = n;
10255				if (nbox > ARRAY_SIZE(boxes))
10256					nbox = ARRAY_SIZE(boxes);
10257				n -= nbox;
10258				do {
10259					if (box_from_seg(b, seg++, gc)) {
10260						assert(!box_empty(b));
10261						b->x1 += dx;
10262						b->x2 += dx;
10263						b->y1 += dy;
10264						b->y2 += dy;
10265						assert(!box_empty(b));
10266						b++;
10267					}
10268				} while (--nbox);
10269
10270				if (b != boxes) {
10271					fill.boxes(sna, &fill, boxes, b-boxes);
10272					if (damage)
10273						sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
10274					b = boxes;
10275				}
10276			} while (n);
10277		} else {
10278			do {
10279				unsigned nbox = n;
10280				if (nbox > ARRAY_SIZE(boxes))
10281					nbox = ARRAY_SIZE(boxes);
10282				n -= nbox;
10283				do {
10284					if (box_from_seg(b, seg++, gc)) {
10285						assert(!box_empty(b));
10286						b++;
10287					}
10288				} while (--nbox);
10289
10290				if (b != boxes) {
10291					fill.boxes(sna, &fill, boxes, b-boxes);
10292					if (damage)
10293						sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
10294					b = boxes;
10295				}
10296			} while (n);
10297		}
10298	} else {
10299		RegionRec clip;
10300
10301		region_set(&clip, extents);
10302		if (!region_maybe_clip(&clip, gc->pCompositeClip))
10303			goto done;
10304
10305		if (clip.data) {
10306			const BoxRec * const clip_start = RegionBoxptr(&clip);
10307			const BoxRec * const clip_end = clip_start + clip.data->numRects;
10308			const BoxRec *c;
10309			do {
10310				BoxRec box;
10311
10312				if (!box_from_seg(&box, seg++, gc))
10313					continue;
10314
10315				assert(!box_empty(&box));
10316				box.x1 += drawable->x;
10317				box.x2 += drawable->x;
10318				box.y1 += drawable->y;
10319				box.y2 += drawable->y;
10320				c = find_clip_box_for_y(clip_start,
10321							clip_end,
10322							box.y1);
10323				while (c != clip_end) {
10324					if (box.y2 <= c->y1)
10325						break;
10326
10327					*b = box;
10328					if (box_intersect(b, c++)) {
10329						b->x1 += dx;
10330						b->x2 += dx;
10331						b->y1 += dy;
10332						b->y2 += dy;
10333						assert(!box_empty(b));
10334						if (++b == last_box) {
10335							fill.boxes(sna, &fill, boxes, last_box-boxes);
10336							if (damage)
10337								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
10338							b = boxes;
10339						}
10340					}
10341				}
10342			} while (--n);
10343		} else {
10344			do {
10345				if (!box_from_seg(b, seg++, gc))
10346					continue;
10347
10348				assert(!box_empty(b));
10349				b->x1 += drawable->x;
10350				b->x2 += drawable->x;
10351				b->y1 += drawable->y;
10352				b->y2 += drawable->y;
10353				if (box_intersect(b, &clip.extents)) {
10354					b->x1 += dx;
10355					b->x2 += dx;
10356					b->y1 += dy;
10357					b->y2 += dy;
10358					assert(!box_empty(b));
10359					if (++b == last_box) {
10360						fill.boxes(sna, &fill, boxes, last_box-boxes);
10361						if (damage)
10362							sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
10363						b = boxes;
10364					}
10365				}
10366			} while (--n);
10367		}
10368		RegionUninit(&clip);
10369	}
10370	if (b != boxes) {
10371		fill.boxes(sna, &fill, boxes, b - boxes);
10372		if (damage)
10373			sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0);
10374	}
10375done:
10376	fill.done(sna, &fill);
10377	assert_pixmap_damage(pixmap);
10378	return true;
10379}
10380
10381static bool
10382sna_poly_zero_segment_blt(DrawablePtr drawable,
10383			  struct kgem_bo *bo,
10384			  struct sna_damage **damage,
10385			  GCPtr gc, const int _n, const xSegment *_s,
10386			  const BoxRec *extents, unsigned clipped)
10387{
10388	static void * const _jump[] = {
10389		&&no_damage,
10390		&&damage,
10391
10392		&&no_damage_offset,
10393		&&damage_offset,
10394	};
10395
10396	PixmapPtr pixmap = get_drawable_pixmap(drawable);
10397	struct sna *sna = to_sna_from_pixmap(pixmap);
10398	unsigned int bias = miGetZeroLineBias(drawable->pScreen);
10399	struct sna_fill_op fill;
10400	RegionRec clip;
10401	const BoxRec *last_extents;
10402	BoxRec box[512], *b;
10403	BoxRec *const last_box = box + ARRAY_SIZE(box);
10404	int16_t dx, dy;
10405	void *jump, *ret;
10406
10407	DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n",
10408	     __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage));
10409	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_BOXES))
10410		return false;
10411
10412	get_drawable_deltas(drawable, pixmap, &dx, &dy);
10413
10414	region_set(&clip, extents);
10415	if (clipped) {
10416		if (!region_maybe_clip(&clip, gc->pCompositeClip))
10417			return true;
10418	}
10419	DBG(("%s: [clipped] extents=(%d, %d), (%d, %d), delta=(%d, %d)\n",
10420	     __FUNCTION__,
10421	     clip.extents.x1, clip.extents.y1,
10422	     clip.extents.x2, clip.extents.y2,
10423	     dx, dy));
10424
10425	jump = _jump[(damage != NULL) | !!(dx|dy) << 1];
10426
10427	b = box;
10428	extents = region_rects(&clip);
10429	last_extents = extents + region_num_rects(&clip);
10430	do {
10431		int n = _n;
10432		const xSegment *s = _s;
10433		do {
10434			int16_t sdx, sdy;
10435			int adx, ady, length;
10436			int e, e1, e2, e3;
10437			int x1, x2;
10438			int y1, y2;
10439			int oc1, oc2;
10440			int octant;
10441
10442			x1 = s->x1 + drawable->x;
10443			y1 = s->y1 + drawable->y;
10444			x2 = s->x2 + drawable->x;
10445			y2 = s->y2 + drawable->y;
10446			s++;
10447
10448			DBG(("%s: segment (%d, %d) to (%d, %d)\n",
10449			     __FUNCTION__, x1, y1, x2, y2));
10450			if (x2 == x1 && y2 == y1)
10451				continue;
10452
10453			oc1 = 0;
10454			OUTCODES(oc1, x1, y1, extents);
10455			oc2 = 0;
10456			OUTCODES(oc2, x2, y2, extents);
10457			if (oc1 & oc2)
10458				continue;
10459
10460			CalcLineDeltas(x1, y1, x2, y2,
10461				       adx, ady, sdx, sdy,
10462				       1, 1, octant);
10463
10464			DBG(("%s: adx=(%d, %d), sdx=(%d, %d)\n",
10465			     __FUNCTION__, adx, ady, sdx, sdy));
10466			if (adx == 0 || ady == 0) {
10467				if (x1 <= x2) {
10468					b->x1 = x1;
10469					b->x2 = x2;
10470				} else {
10471					b->x1 = x2;
10472					b->x2 = x1;
10473				}
10474				if (y1 <= y2) {
10475					b->y1 = y1;
10476					b->y2 = y2;
10477				} else {
10478					b->y1 = y2;
10479					b->y2 = y1;
10480				}
10481				b->x2++;
10482				b->y2++;
10483
10484				if ((oc1 | oc2) && !box_intersect(b, extents))
10485					continue;
10486
10487				assert(!box_empty(b));
10488				if (++b == last_box) {
10489					ret = &&rectangle_continue;
10490					goto *jump;
10491rectangle_continue:
10492					b = box;
10493				}
10494			} else if (adx >= ady) {
10495				bool dirty;
10496
10497				/* X-major segment */
10498				e1 = ady << 1;
10499				e2 = e1 - (adx << 1);
10500				e  = e1 - adx;
10501				length = adx;	/* don't draw endpoint in main loop */
10502
10503				FIXUP_ERROR(e, octant, bias);
10504
10505				if (oc1 | oc2) {
10506					int pt1_clipped, pt2_clipped;
10507					int x = x1, y = y1;
10508
10509					if (miZeroClipLine(extents->x1, extents->y1,
10510							   extents->x2-1, extents->y2-1,
10511							   &x1, &y1, &x2, &y2,
10512							   adx, ady,
10513							   &pt1_clipped, &pt2_clipped,
10514							   octant, bias, oc1, oc2) == -1)
10515						continue;
10516
10517					length = abs(x2 - x1);
10518					if (length == 0)
10519						continue;
10520
10521					if (pt1_clipped) {
10522						int clipdx = abs(x1 - x);
10523						int clipdy = abs(y1 - y);
10524						e += clipdy * e2 + (clipdx - clipdy) * e1;
10525					}
10526				}
10527				e3 = e2 - e1;
10528				e  = e - e1;
10529
10530				b->x1 = x1;
10531				b->y1 = y1;
10532				dirty = false;
10533				while (length--) {
10534					dirty = true;
10535					e += e1;
10536					if (e >= 0) {
10537						e += e3;
10538
10539						if (sdx < 0) {
10540							b->x2 = b->x1 + 1;
10541							b->x1 = x1;
10542						} else
10543							b->x2 = x1 + 1;
10544						b->y2 = b->y1 + 1;
10545
10546						DBG(("%s: horizontal step: (%d, %d), box: (%d, %d), (%d, %d)\n",
10547						     __FUNCTION__, x1, y1,
10548						     b->x1, b->y1, b->x2, b->y2));
10549
10550						assert(!box_empty(b));
10551						if (++b == last_box) {
10552							ret = &&X_continue;
10553							goto *jump;
10554X_continue:
10555							b = box;
10556						}
10557
10558						b->x1 = x1 + sdx;
10559						b->y1 = y1 += sdy;
10560						dirty = false;
10561					}
10562					x1 += sdx;
10563				}
10564				if (dirty) {
10565					x1 -= sdx;
10566					DBG(("%s: horizontal tail: (%d, %d)\n",
10567					     __FUNCTION__, x1, y1));
10568					if (sdx < 0) {
10569						b->x2 = b->x1 + 1;
10570						b->x1 = x1;
10571					} else
10572						b->x2 = x1 + 1;
10573					b->y2 = b->y1 + 1;
10574
10575					assert(!box_empty(b));
10576					if (++b == last_box) {
10577						ret = &&X2_continue;
10578						goto *jump;
10579X2_continue:
10580						b = box;
10581					}
10582				}
10583			} else {
10584				bool dirty;
10585
10586				/* Y-major segment */
10587				e1 = adx << 1;
10588				e2 = e1 - (ady << 1);
10589				e  = e1 - ady;
10590				length  = ady;	/* don't draw endpoint in main loop */
10591
10592				SetYMajorOctant(octant);
10593				FIXUP_ERROR(e, octant, bias);
10594
10595				if (oc1 | oc2) {
10596					int pt1_clipped, pt2_clipped;
10597					int x = x1, y = y1;
10598
10599					if (miZeroClipLine(extents->x1, extents->y1,
10600							   extents->x2-1, extents->y2-1,
10601							   &x1, &y1, &x2, &y2,
10602							   adx, ady,
10603							   &pt1_clipped, &pt2_clipped,
10604							   octant, bias, oc1, oc2) == -1)
10605						continue;
10606
10607					length = abs(y2 - y1);
10608					if (length == 0)
10609						continue;
10610
10611					if (pt1_clipped) {
10612						int clipdx = abs(x1 - x);
10613						int clipdy = abs(y1 - y);
10614						e += clipdx * e2 + (clipdy - clipdx) * e1;
10615					}
10616				}
10617
10618				e3 = e2 - e1;
10619				e  = e - e1;
10620
10621				b->x1 = x1;
10622				b->y1 = y1;
10623				dirty = false;
10624				while (length--) {
10625					e += e1;
10626					dirty = true;
10627					if (e >= 0) {
10628						e += e3;
10629
10630						if (sdy < 0) {
10631							b->y2 = b->y1 + 1;
10632							b->y1 = y1;
10633						} else
10634							b->y2 = y1 + 1;
10635						b->x2 = x1 + 1;
10636
10637						assert(!box_empty(b));
10638						if (++b == last_box) {
10639							ret = &&Y_continue;
10640							goto *jump;
10641Y_continue:
10642							b = box;
10643						}
10644
10645						b->x1 = x1 += sdx;
10646						b->y1 = y1 + sdy;
10647						dirty = false;
10648					}
10649					y1 += sdy;
10650				}
10651
10652				if (dirty) {
10653					y1 -= sdy;
10654					if (sdy < 0) {
10655						b->y2 = b->y1 + 1;
10656						b->y1 = y1;
10657					} else
10658						b->y2 = y1 + 1;
10659					b->x2 = x1 + 1;
10660
10661					assert(!box_empty(b));
10662					if (++b == last_box) {
10663						ret = &&Y2_continue;
10664						goto *jump;
10665Y2_continue:
10666						b = box;
10667					}
10668				}
10669			}
10670		} while (--n);
10671	} while (++extents != last_extents);
10672
10673	if (b != box) {
10674		ret = &&done;
10675		goto *jump;
10676	}
10677
10678done:
10679	fill.done(sna, &fill);
10680	assert_pixmap_damage(pixmap);
10681	RegionUninit(&clip);
10682	return true;
10683
10684damage:
10685	sna_damage_add_boxes(damage, box, b-box, 0, 0);
10686no_damage:
10687	fill.boxes(sna, &fill, box, b-box);
10688	goto *ret;
10689
10690no_damage_offset:
10691	{
10692		BoxRec *bb = box;
10693		do {
10694			bb->x1 += dx;
10695			bb->x2 += dx;
10696			bb->y1 += dy;
10697			bb->y2 += dy;
10698		} while (++bb != b);
10699		fill.boxes(sna, &fill, box, b - box);
10700	}
10701	goto *ret;
10702
10703damage_offset:
10704	{
10705		BoxRec *bb = box;
10706		do {
10707			bb->x1 += dx;
10708			bb->x2 += dx;
10709			bb->y1 += dy;
10710			bb->y2 += dy;
10711		} while (++bb != b);
10712		fill.boxes(sna, &fill, box, b - box);
10713		sna_damage_add_boxes(damage, box, b - box, 0, 0);
10714	}
10715	goto *ret;
10716}
10717
10718static unsigned
10719sna_poly_segment_extents(DrawablePtr drawable, GCPtr gc,
10720			 int n, xSegment *seg,
10721			 BoxPtr out)
10722{
10723	BoxRec box;
10724	bool clipped, can_blit;
10725
10726	if (n == 0)
10727		return 0;
10728
10729	if (seg->x2 >= seg->x1) {
10730		box.x1 = seg->x1;
10731		box.x2 = seg->x2;
10732	} else {
10733		box.x2 = seg->x1;
10734		box.x1 = seg->x2;
10735	}
10736
10737	if (seg->y2 >= seg->y1) {
10738		box.y1 = seg->y1;
10739		box.y2 = seg->y2;
10740	} else {
10741		box.y2 = seg->y1;
10742		box.y1 = seg->y2;
10743	}
10744
10745	can_blit = seg->x1 == seg->x2 || seg->y1 == seg->y2;
10746	while (--n) {
10747		seg++;
10748		if (seg->x2 > seg->x1) {
10749			if (seg->x1 < box.x1) box.x1 = seg->x1;
10750			if (seg->x2 > box.x2) box.x2 = seg->x2;
10751		} else {
10752			if (seg->x2 < box.x1) box.x1 = seg->x2;
10753			if (seg->x1 > box.x2) box.x2 = seg->x1;
10754		}
10755
10756		if (seg->y2 > seg->y1) {
10757			if (seg->y1 < box.y1) box.y1 = seg->y1;
10758			if (seg->y2 > box.y2) box.y2 = seg->y2;
10759		} else {
10760			if (seg->y2 < box.y1) box.y1 = seg->y2;
10761			if (seg->y1 > box.y2) box.y2 = seg->y1;
10762		}
10763
10764		if (can_blit && !(seg->x1 == seg->x2 || seg->y1 == seg->y2))
10765			can_blit = false;
10766	}
10767
10768	box.x2++;
10769	box.y2++;
10770
10771	if (gc->lineWidth) {
10772		int extra = gc->lineWidth;
10773		if (gc->capStyle != CapProjecting)
10774			extra >>= 1;
10775		if (extra) {
10776			box.x1 -= extra;
10777			box.x2 += extra;
10778			box.y1 -= extra;
10779			box.y2 += extra;
10780		}
10781	}
10782
10783	DBG(("%s: unclipped, untranslated extents (%d, %d), (%d, %d)\n",
10784	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
10785
10786	clipped = trim_and_translate_box(&box, drawable, gc);
10787	if (box_empty(&box))
10788		return 0;
10789
10790	*out = box;
10791	return 1 | clipped << 1 | can_blit << 2;
10792}
10793
10794static void
10795sna_poly_segment(DrawablePtr drawable, GCPtr gc, int n, xSegment *seg)
10796{
10797	struct sna_pixmap *priv;
10798	struct sna_fill_spans data;
10799	uint32_t color;
10800
10801	DBG(("%s(n=%d, first=((%d, %d), (%d, %d)), lineWidth=%d\n",
10802	     __FUNCTION__,
10803	     n, seg->x1, seg->y1, seg->x2, seg->y2,
10804	     gc->lineWidth));
10805
10806	data.flags = sna_poly_segment_extents(drawable, gc, n, seg,
10807					      &data.region.extents);
10808	if (data.flags == 0)
10809		return;
10810
10811	DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__,
10812	     data.region.extents.x1, data.region.extents.y1,
10813	     data.region.extents.x2, data.region.extents.y2));
10814
10815	data.region.data = NULL;
10816
10817	if (FORCE_FALLBACK)
10818		goto fallback;
10819
10820	if (!ACCEL_POLY_SEGMENT)
10821		goto fallback;
10822
10823	data.pixmap = get_drawable_pixmap(drawable);
10824	data.sna = to_sna_from_pixmap(data.pixmap);
10825	priv = sna_pixmap(data.pixmap);
10826	if (priv == NULL) {
10827		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
10828		goto fallback;
10829	}
10830
10831	if (wedged(data.sna)) {
10832		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
10833		goto fallback;
10834	}
10835
10836	DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lu [%d], rectlinear=%d\n",
10837	     __FUNCTION__,
10838	     gc->fillStyle, gc->fillStyle == FillSolid,
10839	     gc->lineStyle, gc->lineStyle == LineSolid,
10840	     gc->lineWidth,
10841	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask),
10842	     data.flags & RECTILINEAR));
10843	if (!PM_IS_SOLID(drawable, gc->planemask))
10844		goto fallback;
10845
10846	if (gc->lineStyle != LineSolid || gc->lineWidth > 1)
10847		goto spans_fallback;
10848
10849	data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
10850				      &data.region.extents,
10851				      &data.damage);
10852	if (data.bo == NULL)
10853		goto fallback;
10854
10855	if (gc_is_solid(gc, &color)) {
10856		DBG(("%s: trying blt solid fill [%08x, flags=%x] paths\n",
10857		     __FUNCTION__, (unsigned)color, data.flags));
10858
10859		if (data.flags & RECTILINEAR) {
10860			if (sna_poly_segment_blt(drawable,
10861						 data.bo, data.damage,
10862						 gc, color, n, seg,
10863						 &data.region.extents,
10864						 data.flags & IS_CLIPPED))
10865				return;
10866		} else {
10867			if (sna_poly_zero_segment_blt(drawable,
10868						      data.bo, data.damage,
10869						      gc, n, seg,
10870						      &data.region.extents,
10871						      data.flags & IS_CLIPPED))
10872				return;
10873		}
10874	} else if (data.flags & RECTILINEAR) {
10875		/* Try converting these to a set of rectangles instead */
10876		xRectangle *rect;
10877		int i;
10878
10879		DBG(("%s: converting to rectangles\n", __FUNCTION__));
10880
10881		rect = malloc (n * sizeof (xRectangle));
10882		if (rect == NULL)
10883			return;
10884
10885		for (i = 0; i < n; i++) {
10886			if (seg[i].x1 < seg[i].x2) {
10887				rect[i].x = seg[i].x1;
10888				rect[i].width = seg[i].x2 - seg[i].x1 + 1;
10889			} else if (seg[i].x1 > seg[i].x2) {
10890				rect[i].x = seg[i].x2;
10891				rect[i].width = seg[i].x1 - seg[i].x2 + 1;
10892			} else {
10893				rect[i].x = seg[i].x1;
10894				rect[i].width = 1;
10895			}
10896			if (seg[i].y1 < seg[i].y2) {
10897				rect[i].y = seg[i].y1;
10898				rect[i].height = seg[i].y2 - seg[i].y1 + 1;
10899			} else if (seg[i].y1 > seg[i].y2) {
10900				rect[i].y = seg[i].y2;
10901				rect[i].height = seg[i].y1 - seg[i].y2 + 1;
10902			} else {
10903				rect[i].y = seg[i].y1;
10904				rect[i].height = 1;
10905			}
10906
10907			/* don't paint last pixel */
10908			if (gc->capStyle == CapNotLast) {
10909				if (seg[i].x1 == seg[i].x2)
10910					rect[i].height--;
10911				else
10912					rect[i].width--;
10913			}
10914		}
10915
10916		if (gc->fillStyle == FillTiled) {
10917			i = sna_poly_fill_rect_tiled_blt(drawable,
10918							 data.bo, data.damage,
10919							 gc, n, rect,
10920							 &data.region.extents,
10921							 data.flags);
10922		} else {
10923			i = sna_poly_fill_rect_stippled_blt(drawable,
10924							    data.bo, data.damage,
10925							    gc, n, rect,
10926							    &data.region.extents,
10927							    data.flags);
10928		}
10929		free (rect);
10930
10931		if (i)
10932			return;
10933	}
10934
10935spans_fallback:
10936	if ((data.bo = sna_drawable_use_bo(drawable,
10937					   use_line_spans(drawable, gc, &data.region.extents, data.flags),
10938					   &data.region.extents,
10939					   &data.damage))) {
10940		void (*line)(DrawablePtr, GCPtr, int, int, DDXPointPtr);
10941		int i;
10942
10943		DBG(("%s: converting segments into spans\n", __FUNCTION__));
10944
10945		switch (gc->lineStyle) {
10946		default:
10947		case LineSolid:
10948			if (gc->lineWidth == 0)
10949				line = miZeroLine;
10950			else
10951				line = miWideLine;
10952			break;
10953		case LineOnOffDash:
10954		case LineDoubleDash:
10955			if (gc->lineWidth == 0)
10956				line = miZeroDashLine;
10957			else
10958				line = miWideDash;
10959			break;
10960		}
10961
10962		get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy);
10963		sna_gc(gc)->priv = &data;
10964
10965		if (gc->lineWidth == 0 &&
10966		    gc->lineStyle == LineSolid &&
10967		    gc_is_solid(gc, &color)) {
10968			struct sna_fill_op fill;
10969
10970			if (!sna_fill_init_blt(&fill,
10971					       data.sna, data.pixmap,
10972					       data.bo, gc->alu, color,
10973					       FILL_POINTS | FILL_SPANS))
10974				goto fallback;
10975
10976			data.op = &fill;
10977
10978			if ((data.flags & IS_CLIPPED) == 0) {
10979				if (data.dx | data.dy)
10980					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
10981				else
10982					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
10983				sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill;
10984			} else {
10985				if (!region_maybe_clip(&data.region,
10986						       gc->pCompositeClip))
10987					return;
10988
10989				if (region_is_singular(&data.region)) {
10990					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
10991					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents;
10992				} else {
10993					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
10994					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes;
10995				}
10996			}
10997			assert(gc->miTranslate);
10998			gc->ops = &sna_gc_ops__tmp;
10999			for (i = 0; i < n; i++)
11000				line(drawable, gc, CoordModeOrigin, 2,
11001				     (DDXPointPtr)&seg[i]);
11002
11003			fill.done(data.sna, &fill);
11004		} else {
11005			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
11006			sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu;
11007			sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu;
11008			gc->ops = &sna_gc_ops__tmp;
11009
11010			for (i = 0; i < n; i++)
11011				line(drawable, gc, CoordModeOrigin, 2,
11012				     (DDXPointPtr)&seg[i]);
11013		}
11014
11015		gc->ops = (GCOps *)&sna_gc_ops;
11016		if (data.damage) {
11017			if (data.dx | data.dy)
11018				pixman_region_translate(&data.region, data.dx, data.dy);
11019			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
11020			sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap);
11021		}
11022		assert_pixmap_damage(data.pixmap);
11023		RegionUninit(&data.region);
11024		return;
11025	}
11026
11027fallback:
11028	DBG(("%s: fallback\n", __FUNCTION__));
11029	if (!region_maybe_clip(&data.region, gc->pCompositeClip))
11030		return;
11031
11032	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
11033		goto out;
11034	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
11035					     drawable_gc_flags(drawable, gc,
11036							       !(data.flags & RECTILINEAR && n == 1))))
11037		goto out;
11038
11039	if (sigtrap_get() == 0) {
11040		DBG(("%s: fbPolySegment\n", __FUNCTION__));
11041		fbPolySegment(drawable, gc, n, seg);
11042		FALLBACK_FLUSH(drawable);
11043		sigtrap_put();
11044	}
11045out:
11046	sna_gc_move_to_gpu(gc);
11047	RegionUninit(&data.region);
11048}
11049
11050static unsigned
11051sna_poly_rectangle_extents(DrawablePtr drawable, GCPtr gc,
11052			   int n, xRectangle *r,
11053			   BoxPtr out)
11054{
11055	Box32Rec box;
11056	int extra = gc->lineWidth >> 1;
11057	bool clipped;
11058	bool zero = false;
11059
11060	if (n == 0)
11061		return 0;
11062
11063	box.x1 = r->x;
11064	box.y1 = r->y;
11065	box.x2 = box.x1 + r->width;
11066	box.y2 = box.y1 + r->height;
11067	zero |= (r->width | r->height) == 0;
11068
11069	while (--n) {
11070		r++;
11071		zero |= (r->width | r->height) == 0;
11072		box32_add_rect(&box, r);
11073	}
11074
11075	box.x2++;
11076	box.y2++;
11077
11078	if (extra) {
11079		box.x1 -= extra;
11080		box.x2 += extra;
11081		box.y1 -= extra;
11082		box.y2 += extra;
11083		zero = !zero;
11084	} else
11085		zero = true;
11086
11087	DBG(("%s: unclipped original extents: (%d, %d), (%d, %d)\n",
11088	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
11089	clipped = box32_trim_and_translate(&box, drawable, gc);
11090	if (!box32_to_box16(&box, out))
11091		return 0;
11092
11093	DBG(("%s: extents: (%d, %d), (%d, %d), clipped? %d\n",
11094	     __FUNCTION__, out->x1, out->y1, out->x2, out->y2, clipped));
11095	return 1 | clipped << 1 | zero << 2;
11096}
11097
11098static bool
11099sna_poly_rectangle_blt(DrawablePtr drawable,
11100		       struct kgem_bo *bo,
11101		       struct sna_damage **damage,
11102		       GCPtr gc, int n, xRectangle *r,
11103		       const BoxRec *extents, unsigned clipped)
11104{
11105	PixmapPtr pixmap = get_drawable_pixmap(drawable);
11106	struct sna *sna = to_sna_from_pixmap(pixmap);
11107	struct sna_fill_op fill;
11108	BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes);
11109	int16_t dx, dy;
11110	static void * const jump[] = {
11111		&&wide,
11112		&&zero,
11113		&&wide_clipped,
11114		&&zero_clipped,
11115	};
11116
11117	DBG(("%s: n=%d, alu=%d, width=%d, fg=%08lx, damge=%p, clipped?=%d\n",
11118	     __FUNCTION__, n, gc->alu, gc->lineWidth, gc->fgPixel, damage, clipped));
11119	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_BOXES))
11120		return false;
11121
11122	get_drawable_deltas(drawable, pixmap, &dx, &dy);
11123
11124	goto *jump[(gc->lineWidth <= 1) | clipped];
11125
11126zero:
11127	dx += drawable->x;
11128	dy += drawable->y;
11129
11130	do {
11131		xRectangle rr = *r++;
11132
11133		if ((rr.width | rr.height) == 0)
11134			continue; /* XXX -> PolyLine */
11135
11136		DBG(("%s - zero : r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__,
11137		     n, rr.x, rr.y, rr.width, rr.height));
11138		rr.x += dx;
11139		rr.y += dy;
11140
11141		if (b+4 > last_box) {
11142			fill.boxes(sna, &fill, boxes, b-boxes);
11143			if (damage)
11144				sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
11145			b = boxes;
11146		}
11147
11148		if (rr.width <= 1 || rr.height <= 1) {
11149			b->x1 = rr.x;
11150			b->y1 = rr.y;
11151			b->x2 = rr.x + rr.width + (rr.height != 0);
11152			b->y2 = rr.y + rr.height + (rr.width != 0);
11153			DBG(("%s: blt (%d, %d), (%d, %d)\n",
11154			     __FUNCTION__,
11155			     b->x1, b->y1, b->x2,b->y2));
11156			b++;
11157		} else {
11158			b[0].x1 = rr.x;
11159			b[0].y1 = rr.y;
11160			b[0].x2 = rr.x + rr.width + 1;
11161			b[0].y2 = rr.y + 1;
11162
11163			b[1] = b[0];
11164			b[1].y1 += rr.height;
11165			b[1].y2 += rr.height;
11166
11167			b[2].y1 = rr.y + 1;
11168			b[2].y2 = rr.y + rr.height;
11169			b[2].x1 = rr.x;
11170			b[2].x2 = rr.x + 1;
11171
11172			b[3] = b[2];
11173			b[3].x1 += rr.width;
11174			b[3].x2 += rr.width;
11175
11176			b += 4;
11177		}
11178	} while (--n);
11179	goto done;
11180
11181zero_clipped:
11182	{
11183		RegionRec clip;
11184		BoxRec box[4];
11185		int count;
11186
11187		region_set(&clip, extents);
11188		if (!region_maybe_clip(&clip, gc->pCompositeClip))
11189			goto done;
11190
11191		if (clip.data) {
11192			const BoxRec * const clip_start = RegionBoxptr(&clip);
11193			const BoxRec * const clip_end = clip_start + clip.data->numRects;
11194			const BoxRec *c;
11195			do {
11196				xRectangle rr = *r++;
11197
11198				DBG(("%s - zero, clipped complex: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__,
11199				     n, rr.x, rr.y, rr.width, rr.height));
11200
11201				if ((rr.width | rr.height) == 0)
11202					continue; /* XXX -> PolyLine */
11203
11204				rr.x += drawable->x;
11205				rr.y += drawable->y;
11206
11207				if (rr.width <= 1 || rr.height <= 1) {
11208					box[0].x1 = rr.x;
11209					box[0].y1 = rr.y;
11210					box[0].x2 = rr.x + rr.width + (rr.height != 0);
11211					box[0].y2 = rr.y + rr.height + (rr.width != 0);
11212					count = 1;
11213				} else {
11214					box[0].x1 = rr.x;
11215					box[0].y1 = rr.y;
11216					box[0].x2 = rr.x + rr.width + 1;
11217					box[0].y2 = rr.y + 1;
11218
11219					box[1] = box[0];
11220					box[1].y1 += rr.height;
11221					box[1].y2 += rr.height;
11222
11223					box[2].y1 = rr.y + 1;
11224					box[2].y2 = rr.y + rr.height;
11225					box[2].x1 = rr.x;
11226					box[2].x2 = rr.x + 1;
11227
11228					box[3] = box[2];
11229					box[3].x1 += rr.width;
11230					box[3].x2 += rr.width;
11231					count = 4;
11232				}
11233
11234				while (count--) {
11235					c = find_clip_box_for_y(clip_start,
11236								clip_end,
11237								box[count].y1);
11238					while (c != clip_end) {
11239						if (box[count].y2 <= c->y1)
11240							break;
11241
11242						*b = box[count];
11243						if (box_intersect(b, c++)) {
11244							b->x1 += dx;
11245							b->x2 += dx;
11246							b->y1 += dy;
11247							b->y2 += dy;
11248							if (++b == last_box) {
11249								fill.boxes(sna, &fill, boxes, last_box-boxes);
11250								if (damage)
11251									sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11252								b = boxes;
11253							}
11254						}
11255
11256					}
11257				}
11258			} while (--n);
11259		} else {
11260			do {
11261				xRectangle rr = *r++;
11262				DBG(("%s - zero, clip: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__,
11263				     n, rr.x, rr.y, rr.width, rr.height));
11264
11265				if ((rr.width | rr.height) == 0)
11266					continue; /* XXX -> PolyLine */
11267
11268				rr.x += drawable->x;
11269				rr.y += drawable->y;
11270
11271				if (rr.width <= 1 || rr.height <= 1) {
11272					box[0].x1 = rr.x;
11273					box[0].y1 = rr.y;
11274					box[0].x2 = rr.x + rr.width + (rr.height != 0);
11275					box[0].y2 = rr.y + rr.height + (rr.width != 0);
11276					count = 1;
11277				} else {
11278					box[0].x1 = rr.x;
11279					box[0].y1 = rr.y;
11280					box[0].x2 = rr.x + rr.width + 1;
11281					box[0].y2 = rr.y + 1;
11282
11283					box[1] = box[0];
11284					box[1].y1 += rr.height;
11285					box[1].y2 += rr.height;
11286
11287					box[2].y1 = rr.y + 1;
11288					box[2].y2 = rr.y + rr.height;
11289					box[2].x1 = rr.x;
11290					box[2].x2 = rr.x + 1;
11291
11292					box[3] = box[2];
11293					box[3].x1 += rr.width;
11294					box[3].x2 += rr.width;
11295					count = 4;
11296				}
11297
11298				while (count--) {
11299					*b = box[count];
11300					if (box_intersect(b, &clip.extents)) {
11301						b->x1 += dx;
11302						b->x2 += dx;
11303						b->y1 += dy;
11304						b->y2 += dy;
11305						if (++b == last_box) {
11306							fill.boxes(sna, &fill, boxes, last_box-boxes);
11307							if (damage)
11308								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11309							b = boxes;
11310						}
11311					}
11312
11313				}
11314			} while (--n);
11315		}
11316		RegionUninit(&clip);
11317	}
11318	goto done;
11319
11320wide_clipped:
11321	{
11322		RegionRec clip;
11323		BoxRec box[4];
11324		int16_t offset2 = gc->lineWidth;
11325		int16_t offset1 = offset2 >> 1;
11326		int16_t offset3 = offset2 - offset1;
11327
11328		region_set(&clip, extents);
11329		if (!region_maybe_clip(&clip, gc->pCompositeClip))
11330			goto done;
11331
11332		DBG(("%s: wide clipped: extents=((%d, %d), (%d, %d))\n",
11333		     __FUNCTION__,
11334		     clip.extents.x1, clip.extents.y1,
11335		     clip.extents.x2, clip.extents.y2));
11336
11337		if (clip.data) {
11338			const BoxRec * const clip_start = RegionBoxptr(&clip);
11339			const BoxRec * const clip_end = clip_start + clip.data->numRects;
11340			const BoxRec *c;
11341			do {
11342				xRectangle rr = *r++;
11343				int count;
11344
11345				if ((rr.width | rr.height) == 0)
11346					continue; /* XXX -> PolyLine */
11347
11348				rr.x += drawable->x;
11349				rr.y += drawable->y;
11350
11351				if (rr.height <= offset2 || rr.width <= offset2) {
11352					if (rr.height == 0) {
11353						box[0].x1 = rr.x;
11354						box[0].x2 = rr.x + rr.width;
11355					} else {
11356						box[0].x1 = rr.x - offset1;
11357						box[0].x2 = rr.x + rr.width + offset3;
11358					}
11359					if (rr.width == 0) {
11360						box[0].y1 = rr.y;
11361						box[0].y2 = rr.y + rr.height;
11362					} else {
11363						box[0].y1 = rr.y - offset1;
11364						box[0].y2 = rr.y + rr.height + offset3;
11365					}
11366					count = 1;
11367				} else {
11368					box[0].x1 = rr.x - offset1;
11369					box[0].x2 = box[0].x1 + rr.width + offset2;
11370					box[0].y1 = rr.y - offset1;
11371					box[0].y2 = box[0].y1 + offset2;
11372
11373					box[1].x1 = rr.x - offset1;
11374					box[1].x2 = box[1].x1 + offset2;
11375					box[1].y1 = rr.y + offset3;
11376					box[1].y2 = rr.y + rr.height - offset1;
11377
11378					box[2] = box[1];
11379					box[2].x1 += rr.width;
11380					box[2].x2 += rr.width;
11381
11382					box[3] = box[0];
11383					box[3].y1 += rr.height;
11384					box[3].y2 += rr.height;
11385					count = 4;
11386				}
11387
11388				while (count--) {
11389					c = find_clip_box_for_y(clip_start,
11390								clip_end,
11391								box[count].y1);
11392					while (c != clip_end) {
11393						if (box[count].y2 <= c->y1)
11394							break;
11395
11396						*b = box[count];
11397						if (box_intersect(b, c++)) {
11398							b->x1 += dx;
11399							b->x2 += dx;
11400							b->y1 += dy;
11401							b->y2 += dy;
11402							if (++b == last_box) {
11403								fill.boxes(sna, &fill, boxes, last_box-boxes);
11404								if (damage)
11405									sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11406								b = boxes;
11407							}
11408						}
11409					}
11410				}
11411			} while (--n);
11412		} else {
11413			DBG(("%s: singular clip offset1=%d, offset2=%d, offset3=%d\n",
11414			     __FUNCTION__, offset1, offset2, offset3));
11415			do {
11416				xRectangle rr = *r++;
11417				int count;
11418				rr.x += drawable->x;
11419				rr.y += drawable->y;
11420
11421				DBG(("%s: r=(%d, %d)x(%d, %d)\n",
11422				     __FUNCTION__, rr.x, rr.y, rr.width, rr.height));
11423				if (rr.height <= offset2 || rr.width <= offset2) {
11424					if (rr.height == 0) {
11425						box[0].x1 = rr.x;
11426						box[0].x2 = rr.x + rr.width;
11427					} else {
11428						box[0].x1 = rr.x - offset1;
11429						box[0].x2 = box[0].x1 + rr.width + offset2;
11430					}
11431					if (rr.width == 0) {
11432						box[0].y1 = rr.y;
11433						box[0].y2 = rr.y + rr.height;
11434					} else {
11435						box[0].y1 = rr.y - offset1;
11436						box[0].y2 = box[0].y1 + rr.height + offset2;
11437					}
11438					count = 1;
11439				} else {
11440					box[0].x1 = rr.x - offset1;
11441					box[0].x2 = box[0].x1 + rr.width + offset2;
11442					box[0].y1 = rr.y - offset1;
11443					box[0].y2 = box[0].y1 + offset2;
11444					DBG(("%s: box[0]=(%d, %d), (%d, %d)\n",
11445					     __FUNCTION__,
11446					     box[0].x1, box[0].y1,
11447					     box[0].x2, box[0].y2));
11448
11449					box[1].x1 = rr.x - offset1;
11450					box[1].x2 = box[1].x1 + offset2;
11451					box[1].y1 = rr.y + offset3;
11452					box[1].y2 = rr.y + rr.height - offset1;
11453					DBG(("%s: box[1]=(%d, %d), (%d, %d)\n",
11454					     __FUNCTION__,
11455					     box[1].x1, box[1].y1,
11456					     box[1].x2, box[1].y2));
11457
11458					box[2] = box[1];
11459					box[2].x1 += rr.width;
11460					box[2].x2 += rr.width;
11461					DBG(("%s: box[2]=(%d, %d), (%d, %d)\n",
11462					     __FUNCTION__,
11463					     box[2].x1, box[2].y1,
11464					     box[2].x2, box[2].y2));
11465
11466					box[3] = box[0];
11467					box[3].y1 += rr.height;
11468					box[3].y2 += rr.height;
11469					DBG(("%s: box[3]=(%d, %d), (%d, %d)\n",
11470					     __FUNCTION__,
11471					     box[3].x1, box[3].y1,
11472					     box[3].x2, box[3].y2));
11473
11474					count = 4;
11475				}
11476
11477				while (count--) {
11478					*b = box[count];
11479					if (box_intersect(b, &clip.extents)) {
11480						b->x1 += dx;
11481						b->x2 += dx;
11482						b->y1 += dy;
11483						b->y2 += dy;
11484						if (++b == last_box) {
11485							fill.boxes(sna, &fill, boxes, last_box-boxes);
11486							if (damage)
11487								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11488							b = boxes;
11489						}
11490					}
11491				}
11492			} while (--n);
11493		}
11494		RegionUninit(&clip);
11495	}
11496	goto done;
11497
11498wide:
11499	{
11500		int offset2 = gc->lineWidth;
11501		int offset1 = offset2 >> 1;
11502		int offset3 = offset2 - offset1;
11503
11504		dx += drawable->x;
11505		dy += drawable->y;
11506
11507		do {
11508			xRectangle rr = *r++;
11509
11510			if ((rr.width | rr.height) == 0)
11511				continue; /* XXX -> PolyLine */
11512
11513			rr.x += dx;
11514			rr.y += dy;
11515
11516			if (b+4 > last_box) {
11517				fill.boxes(sna, &fill, boxes, last_box-boxes);
11518				if (damage)
11519					sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11520				b = boxes;
11521			}
11522
11523			if (rr.height <= offset2 || rr.width <= offset2) {
11524				if (rr.height == 0) {
11525					b->x1 = rr.x;
11526					b->x2 = rr.x + rr.width;
11527				} else {
11528					b->x1 = rr.x - offset1;
11529					b->x2 = rr.x + rr.width + offset3;
11530				}
11531				if (rr.width == 0) {
11532					b->y1 = rr.y;
11533					b->y2 = rr.y + rr.height;
11534				} else {
11535					b->y1 = rr.y - offset1;
11536					b->y2 = rr.y + rr.height + offset3;
11537				}
11538				b++;
11539			} else {
11540				b[0].x1 = rr.x - offset1;
11541				b[0].x2 = b[0].x1 + rr.width + offset2;
11542				b[0].y1 = rr.y - offset1;
11543				b[0].y2 = b[0].y1 + offset2;
11544
11545				b[1].x1 = rr.x - offset1;
11546				b[1].x2 = b[1].x1 + offset2;
11547				b[1].y1 = rr.y + offset3;
11548				b[1].y2 = rr.y + rr.height - offset1;
11549
11550				b[2] = b[1];
11551				b[2].x1 += rr.width;
11552				b[2].x2 += rr.width;
11553
11554				b[3] = b[0];
11555				b[3].y1 += rr.height;
11556				b[3].y2 += rr.height;
11557				b += 4;
11558			}
11559		} while (--n);
11560	}
11561	goto done;
11562
11563done:
11564	if (b != boxes) {
11565		fill.boxes(sna, &fill, boxes, b-boxes);
11566		if (damage)
11567			sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
11568	}
11569	fill.done(sna, &fill);
11570	assert_pixmap_damage(pixmap);
11571	return true;
11572}
11573
11574static void
11575sna_poly_rectangle(DrawablePtr drawable, GCPtr gc, int n, xRectangle *r)
11576{
11577	PixmapPtr pixmap = get_drawable_pixmap(drawable);
11578	struct sna *sna = to_sna_from_pixmap(pixmap);
11579	struct sna_damage **damage;
11580	struct kgem_bo *bo;
11581	RegionRec region;
11582	unsigned flags;
11583
11584	DBG(("%s(n=%d, first=((%d, %d)x(%d, %d)), lineWidth=%d\n",
11585	     __FUNCTION__,
11586	     n, r->x, r->y, r->width, r->height,
11587	     gc->lineWidth));
11588
11589	flags = sna_poly_rectangle_extents(drawable, gc, n, r, &region.extents);
11590	if (flags == 0)
11591		return;
11592
11593	DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
11594	     region.extents.x1, region.extents.y1,
11595	     region.extents.x2, region.extents.y2,
11596	     flags));
11597
11598	if (FORCE_FALLBACK)
11599		goto fallback;
11600
11601	if (!ACCEL_POLY_RECTANGLE)
11602		goto fallback;
11603
11604	if (wedged(sna)) {
11605		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
11606		goto fallback;
11607	}
11608
11609	DBG(("%s: fill=%d [%d], line=%d [%d], join=%d [%d], mask=%lu [%d]\n",
11610	     __FUNCTION__,
11611	     gc->fillStyle, gc->fillStyle == FillSolid,
11612	     gc->lineStyle, gc->lineStyle == LineSolid,
11613	     gc->joinStyle, gc->joinStyle == JoinMiter,
11614	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask)));
11615
11616	if (!PM_IS_SOLID(drawable, gc->planemask))
11617		goto fallback;
11618
11619	if (flags & RECTILINEAR && gc->fillStyle == FillSolid && gc->lineStyle == LineSolid && gc->joinStyle == JoinMiter) {
11620		DBG(("%s: trying blt solid fill [%08lx] paths\n",
11621		     __FUNCTION__, gc->fgPixel));
11622		if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU,
11623					      &region.extents, &damage)) &&
11624		    sna_poly_rectangle_blt(drawable, bo, damage,
11625					   gc, n, r, &region.extents, flags&2))
11626			return;
11627	} else {
11628		/* Not a trivial outline, but we still maybe able to break it
11629		 * down into simpler operations that we can accelerate.
11630		 */
11631		if (sna_drawable_use_bo(drawable, PREFER_GPU,
11632					&region.extents, &damage)) {
11633			miPolyRectangle(drawable, gc, n, r);
11634			return;
11635		}
11636	}
11637
11638fallback:
11639	DBG(("%s: fallback, clip=%dx[(%d, %d), (%d, %d)]\n", __FUNCTION__,
11640	     region_num_rects(gc->pCompositeClip),
11641	     gc->pCompositeClip->extents.x1, gc->pCompositeClip->extents.y1,
11642	     gc->pCompositeClip->extents.x2, gc->pCompositeClip->extents.y2));
11643
11644	region.data = NULL;
11645	if (!region_maybe_clip(&region, gc->pCompositeClip))
11646		return;
11647
11648	DBG(("%s: CPU region=%dx[(%d, %d), (%d, %d)]\n", __FUNCTION__,
11649	     region_num_rects(&region),
11650	     region.extents.x1, region.extents.y1,
11651	     region.extents.x2, region.extents.y2));
11652	if (!sna_gc_move_to_cpu(gc, drawable, &region))
11653		goto out;
11654	if (!sna_drawable_move_region_to_cpu(drawable, &region,
11655					     drawable_gc_flags(drawable, gc, true)))
11656		goto out;
11657
11658	if (sigtrap_get() == 0) {
11659		DBG(("%s: miPolyRectangle\n", __FUNCTION__));
11660		miPolyRectangle(drawable, gc, n, r);
11661		FALLBACK_FLUSH(drawable);
11662		sigtrap_put();
11663	}
11664out:
11665	sna_gc_move_to_gpu(gc);
11666	RegionUninit(&region);
11667}
11668
11669static unsigned
11670sna_poly_arc_extents(DrawablePtr drawable, GCPtr gc,
11671		     int n, xArc *arc,
11672		     BoxPtr out)
11673{
11674	BoxRec box;
11675	bool clipped;
11676	int v;
11677
11678	if (n == 0)
11679		return 0;
11680
11681	box.x1 = arc->x;
11682	box.x2 = bound(box.x1, arc->width);
11683	box.y1 = arc->y;
11684	box.y2 = bound(box.y1, arc->height);
11685
11686	while (--n) {
11687		arc++;
11688		if (box.x1 > arc->x)
11689			box.x1 = arc->x;
11690		v = bound(arc->x, arc->width);
11691		if (box.x2 < v)
11692			box.x2 = v;
11693		if (box.y1 > arc->y)
11694			box.y1 = arc->y;
11695		v = bound(arc->y, arc->height);
11696		if (box.y2 < v)
11697			box.y2 = v;
11698	}
11699
11700	v = gc->lineWidth >> 1;
11701	if (v) {
11702		box.x1 -= v;
11703		box.x2 += v;
11704		box.y1 -= v;
11705		box.y2 += v;
11706	}
11707
11708	box.x2++;
11709	box.y2++;
11710
11711	clipped = trim_and_translate_box(&box, drawable, gc);
11712	if (box_empty(&box))
11713		return 0;
11714
11715	*out = box;
11716	return 1 | clipped << 1;
11717}
11718
11719static void
11720sna_poly_arc(DrawablePtr drawable, GCPtr gc, int n, xArc *arc)
11721{
11722	struct sna_fill_spans data;
11723	struct sna_pixmap *priv;
11724
11725	DBG(("%s(n=%d, lineWidth=%d\n", __FUNCTION__, n, gc->lineWidth));
11726
11727	data.flags = sna_poly_arc_extents(drawable, gc, n, arc,
11728					  &data.region.extents);
11729	if (data.flags == 0)
11730		return;
11731
11732	DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
11733	     data.region.extents.x1, data.region.extents.y1,
11734	     data.region.extents.x2, data.region.extents.y2,
11735	     data.flags));
11736
11737	data.region.data = NULL;
11738
11739	if (FORCE_FALLBACK)
11740		goto fallback;
11741
11742	if (!ACCEL_POLY_ARC)
11743		goto fallback;
11744
11745	data.pixmap = get_drawable_pixmap(drawable);
11746	data.sna = to_sna_from_pixmap(data.pixmap);
11747	priv = sna_pixmap(data.pixmap);
11748	if (priv == NULL) {
11749		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
11750		goto fallback;
11751	}
11752
11753	if (wedged(data.sna)) {
11754		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
11755		goto fallback;
11756	}
11757
11758	if (!PM_IS_SOLID(drawable, gc->planemask))
11759		goto fallback;
11760
11761	if ((data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
11762					   &data.region.extents, &data.damage))) {
11763		uint32_t color;
11764
11765		DBG(("%s: converting arcs into spans\n", __FUNCTION__));
11766		get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy);
11767
11768		if (gc_is_solid(gc, &color)) {
11769			sna_gc(gc)->priv = &data;
11770
11771			assert(gc->miTranslate);
11772			if (gc->lineStyle == LineSolid) {
11773				struct sna_fill_op fill;
11774
11775				if (!sna_fill_init_blt(&fill,
11776						       data.sna, data.pixmap,
11777						       data.bo, gc->alu, color,
11778						       FILL_POINTS | FILL_SPANS))
11779					goto fallback;
11780
11781				if ((data.flags & IS_CLIPPED) == 0) {
11782					if (data.dx | data.dy)
11783						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
11784					else
11785						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
11786					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill;
11787				} else {
11788					if (!region_maybe_clip(&data.region,
11789							       gc->pCompositeClip))
11790						return;
11791
11792					if (region_is_singular(&data.region)) {
11793						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
11794						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents;
11795					} else {
11796						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
11797						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes;
11798					}
11799				}
11800
11801				data.op = &fill;
11802				gc->ops = &sna_gc_ops__tmp;
11803				if (gc->lineWidth == 0)
11804					miZeroPolyArc(drawable, gc, n, arc);
11805				else
11806					miPolyArc(drawable, gc, n, arc);
11807				gc->ops = (GCOps *)&sna_gc_ops;
11808
11809				fill.done(data.sna, &fill);
11810			} else {
11811				if (!region_maybe_clip(&data.region,
11812						       gc->pCompositeClip))
11813					return;
11814
11815				sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
11816				sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu;
11817
11818				gc->ops = &sna_gc_ops__tmp;
11819				if (gc->lineWidth == 0)
11820					miZeroPolyArc(drawable, gc, n, arc);
11821				else
11822					miPolyArc(drawable, gc, n, arc);
11823				gc->ops = (GCOps *)&sna_gc_ops;
11824			}
11825
11826			if (data.damage) {
11827				if (data.dx | data.dy)
11828					pixman_region_translate(&data.region, data.dx, data.dy);
11829				assert_pixmap_contains_box(data.pixmap, &data.region.extents);
11830				sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap);
11831			}
11832			assert_pixmap_damage(data.pixmap);
11833			RegionUninit(&data.region);
11834			return;
11835		}
11836
11837		/* XXX still around 10x slower for x11perf -ellipse */
11838		if (gc->lineWidth == 0)
11839			miZeroPolyArc(drawable, gc, n, arc);
11840		else
11841			miPolyArc(drawable, gc, n, arc);
11842		return;
11843	}
11844
11845fallback:
11846	DBG(("%s -- fallback\n", __FUNCTION__));
11847	if (!region_maybe_clip(&data.region, gc->pCompositeClip))
11848		return;
11849
11850	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
11851		goto out;
11852	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
11853					     drawable_gc_flags(drawable, gc, true)))
11854		goto out;
11855
11856	if (sigtrap_get() == 0) {
11857		DBG(("%s -- fbPolyArc\n", __FUNCTION__));
11858		fbPolyArc(drawable, gc, n, arc);
11859		FALLBACK_FLUSH(drawable);
11860		sigtrap_put();
11861	}
11862out:
11863	sna_gc_move_to_gpu(gc);
11864	RegionUninit(&data.region);
11865}
11866
11867static bool
11868sna_poly_fill_rect_blt(DrawablePtr drawable,
11869		       struct kgem_bo *bo,
11870		       struct sna_damage **damage,
11871		       GCPtr gc, uint32_t pixel,
11872		       int n, const xRectangle *rect,
11873		       const BoxRec *extents,
11874		       unsigned flags)
11875{
11876	PixmapPtr pixmap = get_drawable_pixmap(drawable);
11877	struct sna *sna = to_sna_from_pixmap(pixmap);
11878	struct sna_fill_op fill;
11879	BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes);
11880	int16_t dx, dy;
11881
11882	DBG(("%s pixmap=%ld x %d [(%d, %d)x(%d, %d)...]+(%d,%d), clipped?=%d\n",
11883	     __FUNCTION__, pixmap->drawable.serialNumber, n,
11884	     rect->x, rect->y, rect->width, rect->height,
11885	     drawable->x, drawable->y,
11886	     flags&2));
11887
11888	if (n == 1 && region_is_singular(gc->pCompositeClip)) {
11889		BoxRec r;
11890		bool success = true;
11891
11892		r.x1 = rect->x + drawable->x;
11893		r.y1 = rect->y + drawable->y;
11894		r.x2 = bound(r.x1, rect->width);
11895		r.y2 = bound(r.y1, rect->height);
11896		if (box_intersect(&r, &gc->pCompositeClip->extents)) {
11897			if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
11898				r.x1 += dx; r.y1 += dy;
11899				r.x2 += dx; r.y2 += dy;
11900			}
11901			DBG(("%s: using fill_one() fast path: (%d, %d), (%d, %d). alu=%d, pixel=%08x, damage?=%d\n",
11902			     __FUNCTION__, r.x1, r.y1, r.x2, r.y2, gc->alu, pixel, damage != NULL));
11903
11904			assert_pixmap_contains_box(pixmap, &r);
11905			if (sna->render.fill_one(sna, pixmap, bo, pixel,
11906						 r.x1, r.y1, r.x2, r.y2,
11907						 gc->alu)) {
11908				if (r.x2 - r.x1 == pixmap->drawable.width &&
11909				    r.y2 - r.y1 == pixmap->drawable.height) {
11910					if (damage) {
11911						sna_damage_all(damage, pixmap);
11912						damage = NULL;
11913					}
11914					if (flags & OVERWRITES) {
11915						struct sna_pixmap *priv = sna_pixmap(pixmap);
11916						if (bo == priv->gpu_bo) {
11917							assert(damage == NULL || damage == &priv->gpu_damage);
11918							assert(priv->gpu_bo->proxy == NULL);
11919							sna_damage_destroy(&priv->cpu_damage);
11920							list_del(&priv->flush_list);
11921							priv->clear = true;
11922							priv->clear_color = gc->alu == GXcopyInverted ? ~pixel & ((1 << gc->depth) - 1) : pixel;
11923
11924							DBG(("%s: pixmap=%ld, marking clear [%08x]\n",
11925							     __FUNCTION__, pixmap->drawable.serialNumber, priv->clear_color));
11926						}
11927					}
11928				}
11929				if (damage)
11930					sna_damage_add_box(damage, &r);
11931				assert_pixmap_damage(pixmap);
11932			} else
11933				success = false;
11934		}
11935
11936		return success;
11937	}
11938
11939	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_BOXES)) {
11940		DBG(("%s: unsupported blt\n", __FUNCTION__));
11941		return false;
11942	}
11943
11944	get_drawable_deltas(drawable, pixmap, &dx, &dy);
11945	if ((flags & IS_CLIPPED) == 0) {
11946		dx += drawable->x;
11947		dy += drawable->y;
11948
11949		sna_damage_add_rectangles(damage, rect, n, dx, dy);
11950		if (dx|dy) {
11951			do {
11952				unsigned nbox = n;
11953				if (nbox > ARRAY_SIZE(boxes))
11954					nbox = ARRAY_SIZE(boxes);
11955				n -= nbox;
11956				while (nbox >= 2) {
11957					b[0].x1 = rect[0].x + dx;
11958					b[0].y1 = rect[0].y + dy;
11959					b[0].x2 = b[0].x1 + rect[0].width;
11960					b[0].y2 = b[0].y1 + rect[0].height;
11961
11962					b[1].x1 = rect[1].x + dx;
11963					b[1].y1 = rect[1].y + dy;
11964					b[1].x2 = b[1].x1 + rect[1].width;
11965					b[1].y2 = b[1].y1 + rect[1].height;
11966
11967					b += 2;
11968					rect += 2;
11969					nbox -= 2;
11970				}
11971				if (nbox) {
11972					b->x1 = rect->x + dx;
11973					b->y1 = rect->y + dy;
11974					b->x2 = b->x1 + rect->width;
11975					b->y2 = b->y1 + rect->height;
11976					b++;
11977					rect++;
11978				}
11979				fill.boxes(sna, &fill, boxes, b-boxes);
11980				b = boxes;
11981			} while (n);
11982		} else {
11983			do {
11984				unsigned nbox = n;
11985				if (nbox > ARRAY_SIZE(boxes))
11986					nbox = ARRAY_SIZE(boxes);
11987				n -= nbox;
11988				while (nbox >= 2) {
11989					b[0].x1 = rect[0].x;
11990					b[0].y1 = rect[0].y;
11991					b[0].x2 = b[0].x1 + rect[0].width;
11992					b[0].y2 = b[0].y1 + rect[0].height;
11993
11994					b[1].x1 = rect[1].x;
11995					b[1].y1 = rect[1].y;
11996					b[1].x2 = b[1].x1 + rect[1].width;
11997					b[1].y2 = b[1].y1 + rect[1].height;
11998
11999					b += 2;
12000					rect += 2;
12001					nbox -= 2;
12002				}
12003				if (nbox) {
12004					b->x1 = rect->x;
12005					b->y1 = rect->y;
12006					b->x2 = b->x1 + rect->width;
12007					b->y2 = b->y1 + rect->height;
12008					b++;
12009					rect++;
12010				}
12011				fill.boxes(sna, &fill, boxes, b-boxes);
12012				b = boxes;
12013			} while (n);
12014		}
12015	} else {
12016		RegionRec clip;
12017
12018		region_set(&clip, extents);
12019		if (!region_maybe_clip(&clip, gc->pCompositeClip))
12020			goto done;
12021
12022		if (clip.data == NULL) {
12023			do {
12024				b->x1 = rect->x + drawable->x;
12025				b->y1 = rect->y + drawable->y;
12026				b->x2 = bound(b->x1, rect->width);
12027				b->y2 = bound(b->y1, rect->height);
12028				rect++;
12029
12030				if (box_intersect(b, &clip.extents)) {
12031					b->x1 += dx;
12032					b->x2 += dx;
12033					b->y1 += dy;
12034					b->y2 += dy;
12035					if (++b == last_box) {
12036						fill.boxes(sna, &fill, boxes, last_box-boxes);
12037						if (damage)
12038							sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
12039						b = boxes;
12040					}
12041				}
12042			} while (--n);
12043		} else {
12044			const BoxRec * const clip_start = RegionBoxptr(&clip);
12045			const BoxRec * const clip_end = clip_start + clip.data->numRects;
12046			const BoxRec *c;
12047
12048			do {
12049				BoxRec box;
12050
12051				box.x1 = rect->x + drawable->x;
12052				box.y1 = rect->y + drawable->y;
12053				box.x2 = bound(box.x1, rect->width);
12054				box.y2 = bound(box.y1, rect->height);
12055				rect++;
12056
12057				c = find_clip_box_for_y(clip_start,
12058							clip_end,
12059							box.y1);
12060				while (c != clip_end) {
12061					if (box.y2 <= c->y1)
12062						break;
12063
12064					*b = box;
12065					if (box_intersect(b, c++)) {
12066						b->x1 += dx;
12067						b->x2 += dx;
12068						b->y1 += dy;
12069						b->y2 += dy;
12070						if (++b == last_box) {
12071							fill.boxes(sna, &fill, boxes, last_box-boxes);
12072							if (damage)
12073								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
12074							b = boxes;
12075						}
12076					}
12077
12078				}
12079			} while (--n);
12080		}
12081
12082		RegionUninit(&clip);
12083		if (b != boxes) {
12084			fill.boxes(sna, &fill, boxes, b-boxes);
12085			if (damage)
12086				sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
12087		}
12088	}
12089done:
12090	fill.done(sna, &fill);
12091	assert_pixmap_damage(pixmap);
12092	return true;
12093}
12094
12095static uint32_t
12096get_pixel(PixmapPtr pixmap)
12097{
12098	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber));
12099	if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
12100		return 0;
12101
12102	switch (pixmap->drawable.bitsPerPixel) {
12103	case 32: return *(uint32_t *)pixmap->devPrivate.ptr;
12104	case 16: return *(uint16_t *)pixmap->devPrivate.ptr;
12105	default: return *(uint8_t *)pixmap->devPrivate.ptr;
12106	}
12107}
12108
12109inline static int
12110_use_fill_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags)
12111{
12112	if (USE_SPANS)
12113		return USE_SPANS > 0;
12114
12115	if (gc->fillStyle == FillTiled && !gc->tileIsPixel &&
12116	    sna_pixmap_is_gpu(gc->tile.pixmap)) {
12117		DBG(("%s: source is already on the gpu\n", __FUNCTION__));
12118		return PREFER_GPU | FORCE_GPU;
12119	}
12120
12121	return PREFER_GPU;
12122}
12123
12124static int
12125use_fill_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags)
12126{
12127	int ret = _use_fill_spans(drawable, gc, extents, flags);
12128	DBG(("%s? %d\n", __FUNCTION__, ret));
12129	return ret;
12130}
12131
12132static void
12133sna_poly_fill_polygon(DrawablePtr draw, GCPtr gc,
12134		      int shape, int mode,
12135		      int n, DDXPointPtr pt)
12136{
12137	struct sna_fill_spans data;
12138	struct sna_pixmap *priv;
12139
12140	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
12141	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
12142	     (gc->fillStyle == FillSolid ||
12143	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
12144	     gc->fillStyle, gc->tileIsPixel,
12145	     gc->alu));
12146	DBG(("%s: draw=%ld, offset=(%d, %d), size=%dx%d\n",
12147	     __FUNCTION__, draw->serialNumber,
12148	     draw->x, draw->y, draw->width, draw->height));
12149
12150	data.flags = sna_poly_point_extents(draw, gc, mode, n, pt,
12151					    &data.region.extents);
12152	if (data.flags == 0) {
12153		DBG(("%s, nothing to do\n", __FUNCTION__));
12154		return;
12155	}
12156
12157	DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
12158	     data.region.extents.x1, data.region.extents.y1,
12159	     data.region.extents.x2, data.region.extents.y2,
12160	     data.flags));
12161
12162	data.region.data = NULL;
12163
12164	if (FORCE_FALLBACK)
12165		goto fallback;
12166
12167	if (!ACCEL_POLY_FILL_POLYGON)
12168		goto fallback;
12169
12170	data.pixmap = get_drawable_pixmap(draw);
12171	data.sna = to_sna_from_pixmap(data.pixmap);
12172	priv = sna_pixmap(data.pixmap);
12173	if (priv == NULL) {
12174		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
12175		goto fallback;
12176	}
12177
12178	if (wedged(data.sna)) {
12179		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
12180		goto fallback;
12181	}
12182
12183	if (!PM_IS_SOLID(draw, gc->planemask))
12184		goto fallback;
12185
12186	if ((data.bo = sna_drawable_use_bo(draw,
12187					   use_fill_spans(draw, gc, &data.region.extents, data.flags),
12188					   &data.region.extents,
12189					   &data.damage))) {
12190		uint32_t color;
12191
12192		sna_gc(gc)->priv = &data;
12193		get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy);
12194
12195		if (gc_is_solid(gc, &color)) {
12196			struct sna_fill_op fill;
12197
12198			if (!sna_fill_init_blt(&fill,
12199					       data.sna, data.pixmap,
12200					       data.bo, gc->alu, color,
12201					       FILL_SPANS))
12202				goto fallback;
12203
12204			data.op = &fill;
12205
12206			if ((data.flags & IS_CLIPPED) == 0) {
12207				if (data.dx | data.dy)
12208					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
12209				else
12210					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
12211			} else {
12212				if (!region_maybe_clip(&data.region,
12213						       gc->pCompositeClip))
12214					return;
12215
12216				if (region_is_singular(&data.region))
12217					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
12218				else
12219					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
12220			}
12221			assert(gc->miTranslate);
12222			gc->ops = &sna_gc_ops__tmp;
12223
12224			miFillPolygon(draw, gc, shape, mode, n, pt);
12225			fill.done(data.sna, &fill);
12226		} else {
12227			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
12228			gc->ops = &sna_gc_ops__tmp;
12229
12230			miFillPolygon(draw, gc, shape, mode, n, pt);
12231		}
12232
12233		gc->ops = (GCOps *)&sna_gc_ops;
12234		if (data.damage) {
12235			if (data.dx | data.dy)
12236				pixman_region_translate(&data.region, data.dx, data.dy);
12237			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
12238			sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap);
12239		}
12240		assert_pixmap_damage(data.pixmap);
12241		RegionUninit(&data.region);
12242		return;
12243	}
12244
12245fallback:
12246	DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__,
12247	     data.region.extents.x1, data.region.extents.y1,
12248	     data.region.extents.x2, data.region.extents.y2));
12249	if (!region_maybe_clip(&data.region, gc->pCompositeClip)) {
12250		DBG(("%s: nothing to do, all clipped\n", __FUNCTION__));
12251		return;
12252	}
12253
12254	if (!sna_gc_move_to_cpu(gc, draw, &data.region))
12255		goto out;
12256	if (!sna_drawable_move_region_to_cpu(draw, &data.region,
12257					     drawable_gc_flags(draw, gc, true)))
12258		goto out;
12259
12260	if (sigtrap_get() == 0) {
12261		DBG(("%s: fallback -- miFillPolygon -> sna_fill_spans__cpu\n",
12262		     __FUNCTION__));
12263		miFillPolygon(draw, gc, shape, mode, n, pt);
12264		sigtrap_put();
12265	}
12266out:
12267	sna_gc_move_to_gpu(gc);
12268	RegionUninit(&data.region);
12269}
12270
12271static struct kgem_bo *
12272sna_pixmap_get_source_bo(PixmapPtr pixmap)
12273{
12274	struct sna_pixmap *priv = sna_pixmap(pixmap);
12275	unsigned flags;
12276	BoxRec box;
12277
12278	box.x1 = box.y1 = 0;
12279	box.x2 = pixmap->drawable.width;
12280	box.y2 = pixmap->drawable.height;
12281
12282	DBG(("%s(pixmap=%ld, size=%dx%d)\n", __FUNCTION__,
12283	     pixmap->drawable.serialNumber, pixmap->drawable.width, pixmap->drawable.height));
12284
12285	if (priv == NULL) {
12286		DBG(("%s: unattached, uploading data into temporary\n", __FUNCTION__));
12287		return kgem_upload_source_image(&to_sna_from_pixmap(pixmap)->kgem,
12288						pixmap->devPrivate.ptr, &box,
12289						pixmap->devKind,
12290						pixmap->drawable.bitsPerPixel);
12291	}
12292
12293	if (priv->gpu_damage) {
12294		if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT))
12295			return kgem_bo_reference(priv->gpu_bo);
12296	} else if (priv->cpu_damage) {
12297		if (priv->cpu_bo)
12298			return kgem_bo_reference(priv->cpu_bo);
12299	} else {
12300		if (priv->gpu_bo)
12301			return kgem_bo_reference(priv->gpu_bo);
12302		if (priv->cpu_bo)
12303			return kgem_bo_reference(priv->cpu_bo);
12304	}
12305
12306	flags = MOVE_READ | MOVE_ASYNC_HINT;
12307	if (priv->gpu_bo && priv->gpu_bo->proxy) {
12308		struct kgem_bo *bo = priv->gpu_bo;
12309		if (bo->rq == NULL && (bo->snoop || bo->pitch >= 4096))
12310			flags |= __MOVE_FORCE;
12311	}
12312	if (priv->gpu_bo == NULL) {
12313		if (++priv->source_count > SOURCE_BIAS)
12314			flags |= __MOVE_FORCE;
12315	}
12316
12317	if (!sna_pixmap_move_to_gpu(pixmap, flags)) {
12318		struct kgem_bo *upload;
12319
12320		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
12321			return NULL;
12322
12323		upload = kgem_upload_source_image(&to_sna_from_pixmap(pixmap)->kgem,
12324						  pixmap->devPrivate.ptr, &box,
12325						  pixmap->devKind,
12326						  pixmap->drawable.bitsPerPixel);
12327		if (upload == NULL)
12328			return NULL;
12329
12330		if (priv->gpu_bo == NULL) {
12331			DBG(("%s: adding upload cache to pixmap=%ld\n",
12332			     __FUNCTION__, pixmap->drawable.serialNumber));
12333			assert(upload->proxy != NULL);
12334			kgem_proxy_bo_attach(upload, &priv->gpu_bo);
12335		}
12336
12337		return upload;
12338	}
12339
12340	return kgem_bo_reference(priv->gpu_bo);
12341}
12342
12343/*
12344static bool
12345tile(DrawablePtr drawable,
12346	struct kgem_bo *bo, struct sna_damage **damage,
12347	PixmapPtr tile, const DDXPointRec * const origin, int alu,
12348	int n, xRectangle *rect,
12349	const BoxRec *extents, unsigned clipped)
12350	*/
12351
12352static bool
12353sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
12354				 struct kgem_bo *bo, struct sna_damage **damage,
12355				 struct kgem_bo *tile_bo, GCPtr gc,
12356				 int n, const xRectangle *r,
12357				 const BoxRec *extents, unsigned clipped)
12358{
12359	PixmapPtr pixmap = get_drawable_pixmap(drawable);
12360	struct sna *sna = to_sna_from_pixmap(pixmap);
12361	const DDXPointRec * const origin = &gc->patOrg;
12362	uint32_t br00, br13;
12363	int tx, ty;
12364	int16_t dx, dy;
12365	uint32_t *b;
12366
12367	if (NO_TILE_8x8)
12368		return false;
12369
12370	DBG(("%s x %d [(%d, %d)x(%d, %d)...], clipped=%x, origin=(%d, %d)\n",
12371	     __FUNCTION__, n, r->x, r->y, r->width, r->height, clipped, origin->x, origin->y));
12372
12373	DBG(("%s: tile_bo tiling=%d, pitch=%d\n", __FUNCTION__, tile_bo->tiling, tile_bo->pitch));
12374	if (tile_bo->tiling)
12375		return false;
12376
12377	if (!kgem_bo_can_blt(&sna->kgem, bo) ||
12378	    !kgem_bo_can_blt(&sna->kgem, tile_bo))
12379		return false;
12380
12381	assert(tile_bo->pitch == 8 * drawable->bitsPerPixel >> 3);
12382
12383	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
12384	assert(kgem_bo_can_blt(&sna->kgem, bo));
12385	if (!kgem_check_batch(&sna->kgem, 10+2*3) ||
12386	    !kgem_check_reloc(&sna->kgem, 2) ||
12387	    !kgem_check_many_bo_fenced(&sna->kgem, bo, tile_bo, NULL)) {
12388		kgem_submit(&sna->kgem);
12389		if (!kgem_check_many_bo_fenced(&sna->kgem, bo, tile_bo, NULL))
12390			return false;
12391		_kgem_set_mode(&sna->kgem, KGEM_BLT);
12392	}
12393	kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
12394
12395	get_drawable_deltas(drawable, pixmap, &dx, &dy);
12396	assert(extents->x1 + dx >= 0);
12397	assert(extents->y1 + dy >= 0);
12398	assert(extents->x2 + dx <= pixmap->drawable.width);
12399	assert(extents->y2 + dy <= pixmap->drawable.height);
12400
12401	br00 = XY_SCANLINE_BLT;
12402	tx = (-drawable->x - dx - origin->x) % 8;
12403	if (tx < 0)
12404		tx += 8;
12405	ty = (-drawable->y - dy - origin->y) % 8;
12406	if (ty < 0)
12407		ty += 8;
12408	br00 |= tx << 12 | ty << 8;
12409
12410	br13 = bo->pitch;
12411	if (sna->kgem.gen >= 040 && bo->tiling) {
12412		br00 |= BLT_DST_TILED;
12413		br13 >>= 2;
12414	}
12415	br13 |= blt_depth(drawable->depth) << 24;
12416	br13 |= fill_ROP[gc->alu] << 16;
12417
12418	if (!clipped) {
12419		dx += drawable->x;
12420		dy += drawable->y;
12421
12422		sna_damage_add_rectangles(damage, r, n, dx, dy);
12423		if (n == 1) {
12424			DBG(("%s: rect=(%d, %d)x(%d, %d) + (%d, %d), tile=(%d, %d)\n",
12425			     __FUNCTION__, r->x, r->y, r->width, r->height, dx, dy, tx, ty));
12426
12427			assert(r->x + dx >= 0);
12428			assert(r->y + dy >= 0);
12429			assert(r->x + dx + r->width  <= pixmap->drawable.width);
12430			assert(r->y + dy + r->height <= pixmap->drawable.height);
12431
12432			assert(sna->kgem.mode == KGEM_BLT);
12433			b = sna->kgem.batch + sna->kgem.nbatch;
12434			if (sna->kgem.gen >= 0100) {
12435				b[0] = XY_PAT_BLT | 3 << 20 | (br00 & 0x7f00) | 6;
12436				b[1] = br13;
12437				b[2] = (r->y + dy) << 16 | (r->x + dx);
12438				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
12439				*(uint64_t *)(b+4) =
12440					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12441							 I915_GEM_DOMAIN_RENDER << 16 |
12442							 I915_GEM_DOMAIN_RENDER |
12443							 KGEM_RELOC_FENCED,
12444							 0);
12445				*(uint64_t *)(b+6) =
12446					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, tile_bo,
12447							 I915_GEM_DOMAIN_RENDER << 16 |
12448							 KGEM_RELOC_FENCED,
12449							 0);
12450				sna->kgem.nbatch += 8;
12451			} else {
12452				b[0] = XY_PAT_BLT | 3 << 20 | (br00 & 0x7f00) | 4;
12453				b[1] = br13;
12454				b[2] = (r->y + dy) << 16 | (r->x + dx);
12455				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
12456				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12457						      I915_GEM_DOMAIN_RENDER << 16 |
12458						      I915_GEM_DOMAIN_RENDER |
12459						      KGEM_RELOC_FENCED,
12460						      0);
12461				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, tile_bo,
12462						      I915_GEM_DOMAIN_RENDER << 16 |
12463						      KGEM_RELOC_FENCED,
12464						      0);
12465				sna->kgem.nbatch += 6;
12466			}
12467		} else do {
12468			int n_this_time, rem;
12469
12470			assert(sna->kgem.mode == KGEM_BLT);
12471			b = sna->kgem.batch + sna->kgem.nbatch;
12472			if (sna->kgem.gen >= 0100) {
12473				b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
12474				b[1] = br13;
12475				b[2] = 0;
12476				b[3] = 0;
12477				*(uint64_t *)(b+4) =
12478					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12479							 I915_GEM_DOMAIN_RENDER << 16 |
12480							 I915_GEM_DOMAIN_RENDER |
12481							 KGEM_RELOC_FENCED,
12482							 0);
12483				b[6] = gc->bgPixel;
12484				b[7] = gc->fgPixel;
12485				*(uint64_t *)(b+8) =
12486					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo,
12487							 I915_GEM_DOMAIN_RENDER << 16 |
12488							 KGEM_RELOC_FENCED,
12489							 0);
12490				sna->kgem.nbatch += 10;
12491			} else {
12492				b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6;
12493				b[1] = br13;
12494				b[2] = 0;
12495				b[3] = 0;
12496				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12497						      I915_GEM_DOMAIN_RENDER << 16 |
12498						      I915_GEM_DOMAIN_RENDER |
12499						      KGEM_RELOC_FENCED,
12500						      0);
12501				b[5] = gc->bgPixel;
12502				b[6] = gc->fgPixel;
12503				b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
12504						      I915_GEM_DOMAIN_RENDER << 16 |
12505						      KGEM_RELOC_FENCED,
12506						      0);
12507				sna->kgem.nbatch += 8;
12508			}
12509
12510			n_this_time = n;
12511			rem = kgem_batch_space(&sna->kgem);
12512			if (3*n_this_time > rem)
12513				n_this_time = rem / 3;
12514			assert(n_this_time);
12515			n -= n_this_time;
12516
12517			assert(sna->kgem.mode == KGEM_BLT);
12518			b = sna->kgem.batch + sna->kgem.nbatch;
12519			sna->kgem.nbatch += 3*n_this_time;
12520			do {
12521				assert(r->x + dx >= 0);
12522				assert(r->y + dy >= 0);
12523				assert(r->x + dx + r->width  <= pixmap->drawable.width);
12524				assert(r->y + dy + r->height <= pixmap->drawable.height);
12525
12526				b[0] = br00;
12527				b[1] = (r->y + dy) << 16 | (r->x + dx);
12528				b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
12529				b += 3; r++;
12530			} while (--n_this_time);
12531
12532			if (!n)
12533				break;
12534
12535			_kgem_submit(&sna->kgem);
12536			_kgem_set_mode(&sna->kgem, KGEM_BLT);
12537			kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
12538		} while (1);
12539	} else {
12540		RegionRec clip;
12541		uint16_t unwind_batch, unwind_reloc;
12542
12543		region_set(&clip, extents);
12544		if (!region_maybe_clip(&clip, gc->pCompositeClip))
12545			goto done;
12546
12547		unwind_batch = sna->kgem.nbatch;
12548		unwind_reloc = sna->kgem.nreloc;
12549
12550		assert(sna->kgem.mode == KGEM_BLT);
12551		b = sna->kgem.batch + sna->kgem.nbatch;
12552		if (sna->kgem.gen >= 0100) {
12553			b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
12554			b[1] = br13;
12555			b[2] = 0;
12556			b[3] = 0;
12557			*(uint64_t *)(b+4) =
12558				kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12559						 I915_GEM_DOMAIN_RENDER << 16 |
12560						 I915_GEM_DOMAIN_RENDER |
12561						 KGEM_RELOC_FENCED,
12562						 0);
12563			b[6] = gc->bgPixel;
12564			b[7] = gc->fgPixel;
12565			*(uint64_t *)(b+8) =
12566				kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo,
12567						 I915_GEM_DOMAIN_RENDER << 16 |
12568						 KGEM_RELOC_FENCED,
12569						 0);
12570			sna->kgem.nbatch += 10;
12571		} else {
12572			b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6;
12573			b[1] = br13;
12574			b[2] = 0;
12575			b[3] = 0;
12576			b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12577					      I915_GEM_DOMAIN_RENDER << 16 |
12578					      I915_GEM_DOMAIN_RENDER |
12579					      KGEM_RELOC_FENCED,
12580					      0);
12581			b[5] = gc->bgPixel;
12582			b[6] = gc->fgPixel;
12583			b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
12584					      I915_GEM_DOMAIN_RENDER << 16 |
12585					      KGEM_RELOC_FENCED,
12586					      0);
12587			sna->kgem.nbatch += 8;
12588		}
12589
12590		if (clip.data == NULL) {
12591			const BoxRec *c = &clip.extents;
12592			DBG(("%s: simple clip, %d boxes\n", __FUNCTION__, n));
12593			while (n--) {
12594				BoxRec box;
12595
12596				box.x1 = r->x + drawable->x;
12597				box.y1 = r->y + drawable->y;
12598				box.x2 = bound(box.x1, r->width);
12599				box.y2 = bound(box.y1, r->height);
12600				r++;
12601
12602				if (box_intersect(&box, c)) {
12603					if (!kgem_check_batch(&sna->kgem, 3)) {
12604						_kgem_submit(&sna->kgem);
12605						_kgem_set_mode(&sna->kgem, KGEM_BLT);
12606						kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
12607
12608						unwind_batch = sna->kgem.nbatch;
12609						unwind_reloc = sna->kgem.nreloc;
12610
12611						assert(sna->kgem.mode == KGEM_BLT);
12612						b = sna->kgem.batch + sna->kgem.nbatch;
12613						if (sna->kgem.gen >= 0100) {
12614							b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
12615							b[1] = br13;
12616							b[2] = 0;
12617							b[3] = 0;
12618							*(uint64_t *)(b+4) =
12619								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12620										 I915_GEM_DOMAIN_RENDER << 16 |
12621										 I915_GEM_DOMAIN_RENDER |
12622										 KGEM_RELOC_FENCED,
12623										 0);
12624							b[6] = gc->bgPixel;
12625							b[7] = gc->fgPixel;
12626							*(uint64_t *)(b+8) =
12627								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo,
12628										 I915_GEM_DOMAIN_RENDER << 16 |
12629										 KGEM_RELOC_FENCED,
12630										 0);
12631							sna->kgem.nbatch += 10;
12632						} else {
12633							b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6;
12634							b[1] = br13;
12635							b[2] = 0;
12636							b[3] = 0;
12637							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12638									      I915_GEM_DOMAIN_RENDER << 16 |
12639									      I915_GEM_DOMAIN_RENDER |
12640									      KGEM_RELOC_FENCED,
12641									      0);
12642							b[5] = gc->bgPixel;
12643							b[6] = gc->fgPixel;
12644							b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
12645									      I915_GEM_DOMAIN_RENDER << 16 |
12646									      KGEM_RELOC_FENCED,
12647									      0);
12648							sna->kgem.nbatch += 8;
12649						}
12650					}
12651
12652					assert(box.x1 + dx >= 0);
12653					assert(box.y1 + dy >= 0);
12654					assert(box.x2 + dx <= pixmap->drawable.width);
12655					assert(box.y2 + dy <= pixmap->drawable.height);
12656
12657					DBG(("%s: box=(%d, %d),(%d, %d) + (%d, %d), tile=(%d, %d)\n",
12658					     __FUNCTION__, box.x1, box.y1, box.x2, box.y2, dx, dy, tx, ty));
12659
12660					assert(sna->kgem.mode == KGEM_BLT);
12661					b = sna->kgem.batch + sna->kgem.nbatch;
12662					b[0] = br00;
12663					b[1] = (box.y1 + dy) << 16 | (box.x1 + dx);
12664					b[2] = (box.y2 + dy) << 16 | (box.x2 + dx);
12665					sna->kgem.nbatch += 3;
12666				}
12667			}
12668		} else {
12669			const BoxRec * const clip_start = RegionBoxptr(&clip);
12670			const BoxRec * const clip_end = clip_start + clip.data->numRects;
12671			const BoxRec *c;
12672
12673			DBG(("%s: complex clip (%ld cliprects), %d boxes\n", __FUNCTION__, (long)clip.data->numRects, n));
12674			do {
12675				BoxRec box;
12676
12677				box.x1 = r->x + drawable->x;
12678				box.y1 = r->y + drawable->y;
12679				box.x2 = bound(box.x1, r->width);
12680				box.y2 = bound(box.y1, r->height);
12681				DBG(("%s: rect=(%d, %d), (%d, %d), box=(%d, %d), (%d, %d)\n", __FUNCTION__,
12682				     r->x, r->y, r->width, r->height,
12683				     box.x1, box.y1, box.x2, box.y2));
12684				r++;
12685
12686				c = find_clip_box_for_y(clip_start,
12687							clip_end,
12688							box.y1);
12689				while (c != clip_end) {
12690					BoxRec bb;
12691
12692					DBG(("%s: clip=(%d, %d), (%d, %d)\n", __FUNCTION__, c->x1, c->y1, c->x2, c->y2));
12693
12694					if (box.y2 <= c->y1)
12695						break;
12696
12697					bb = box;
12698					if (box_intersect(&bb, c++)) {
12699						if (!kgem_check_batch(&sna->kgem, 3)) {
12700							DBG(("%s: emitting split batch\n", __FUNCTION__));
12701							_kgem_submit(&sna->kgem);
12702							_kgem_set_mode(&sna->kgem, KGEM_BLT);
12703							kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
12704
12705							unwind_batch = sna->kgem.nbatch;
12706							unwind_reloc = sna->kgem.nreloc;
12707
12708							assert(sna->kgem.mode == KGEM_BLT);
12709							b = sna->kgem.batch + sna->kgem.nbatch;
12710							if (sna->kgem.gen >= 0100) {
12711								b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
12712								b[1] = br13;
12713								b[2] = 0;
12714								b[3] = 0;
12715								*(uint64_t *)(b+4) =
12716									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12717											 I915_GEM_DOMAIN_RENDER << 16 |
12718											 I915_GEM_DOMAIN_RENDER |
12719											 KGEM_RELOC_FENCED,
12720											 0);
12721								b[6] = gc->bgPixel;
12722								b[7] = gc->fgPixel;
12723								*(uint64_t *)(b+8) =
12724									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo,
12725											 I915_GEM_DOMAIN_RENDER << 16 |
12726											 KGEM_RELOC_FENCED,
12727											 0);
12728								sna->kgem.nbatch += 10;
12729							} else {
12730								b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6;
12731								b[1] = br13;
12732								b[2] = 0;
12733								b[3] = 0;
12734								b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12735										      I915_GEM_DOMAIN_RENDER << 16 |
12736										      I915_GEM_DOMAIN_RENDER |
12737										      KGEM_RELOC_FENCED,
12738										      0);
12739								b[5] = gc->bgPixel;
12740								b[6] = gc->fgPixel;
12741								b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
12742										      I915_GEM_DOMAIN_RENDER << 16 |
12743										      KGEM_RELOC_FENCED,
12744										      0);
12745								sna->kgem.nbatch += 8;
12746							}
12747						}
12748
12749						assert(bb.x1 + dx >= 0);
12750						assert(bb.y1 + dy >= 0);
12751						assert(bb.x2 + dx <= pixmap->drawable.width);
12752						assert(bb.y2 + dy <= pixmap->drawable.height);
12753
12754						DBG(("%s: emit box=(%d, %d),(%d, %d) + (%d, %d), tile=(%d, %d) [relative to drawable: (%d, %d)]\n",
12755						     __FUNCTION__, bb.x1, bb.y1, bb.x2, bb.y2, dx, dy, tx, ty, bb.x1 - drawable->x, bb.y1 - drawable->y));
12756
12757						assert(sna->kgem.mode == KGEM_BLT);
12758						b = sna->kgem.batch + sna->kgem.nbatch;
12759						b[0] = br00;
12760						b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx);
12761						b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx);
12762						sna->kgem.nbatch += 3;
12763					}
12764				}
12765			} while (--n);
12766		}
12767
12768		if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) {
12769			sna->kgem.nbatch = unwind_batch;
12770			sna->kgem.nreloc = unwind_reloc;
12771			if (sna->kgem.nbatch == 0)
12772				kgem_bo_pair_undo(&sna->kgem, bo, tile_bo);
12773		}
12774	}
12775done:
12776	assert_pixmap_damage(pixmap);
12777	blt_done(sna);
12778	return true;
12779}
12780
12781static bool tile8(int x)
12782{
12783	switch(x) {
12784	case 1:
12785	case 2:
12786	case 4:
12787	case 8:
12788		return true;
12789	default:
12790		return false;
12791	}
12792}
12793
12794static int next8(int x, int max)
12795{
12796	if (x > 2 && x <= 4)
12797		x = 4;
12798	else if (x < 8)
12799		x = 8;
12800	return MIN(x, max);
12801}
12802
12803static bool
12804sna_poly_fill_rect_tiled_nxm_blt(DrawablePtr drawable,
12805				 struct kgem_bo *bo,
12806				 struct sna_damage **damage,
12807				 GCPtr gc, int n, const xRectangle *rect,
12808				 const BoxRec *extents, unsigned clipped)
12809{
12810	PixmapPtr pixmap = get_drawable_pixmap(drawable);
12811	struct sna *sna = to_sna_from_pixmap(pixmap);
12812	PixmapPtr tile = gc->tile.pixmap;
12813	int w, h, tx, ty, tw, th, bpp = tile->drawable.bitsPerPixel;
12814	const DDXPointRec origin = gc->patOrg;
12815	struct kgem_bo *upload;
12816	bool ret = false;
12817	uint8_t *src;
12818	void *ptr;
12819
12820	tx = 0, tw = tile->drawable.width;
12821	if (!tile8(tw) && tw > extents->x2 - extents->x1) {
12822		tx = (extents->x1 - gc->patOrg.x - drawable->x) % tw;
12823		if (tx < 0)
12824			tx += tw;
12825		tw = next8(extents->x2 - extents->x1, tw);
12826		gc->patOrg.x = extents->x1 - drawable->x;
12827	}
12828
12829	ty = 0, th = tile->drawable.height;
12830	if (!tile8(th) && th > extents->y2 - extents->y1) {
12831		ty = (extents->y1 - gc->patOrg.y - drawable->y) % th;
12832		if (ty < 0)
12833			ty += th;
12834		th = next8(extents->y2 - extents->y1, th);
12835		gc->patOrg.y = extents->y1 - drawable->y;
12836	}
12837
12838	DBG(("%s: %dx%d+%d+%d (full tile size %dx%d)\n", __FUNCTION__,
12839	     tw, th, tx, ty, tile->drawable.width, tile->drawable.height));
12840	assert(tx < tile->drawable.width && tx >= 0);
12841	assert(ty < tile->drawable.height && ty >= 0);
12842	assert(tw && tw <= 8 && tw <= tile->drawable.width);
12843	assert(is_power_of_two(tw));
12844	assert(th && th <= 8 && th <= tile->drawable.height);
12845	assert(is_power_of_two(th));
12846
12847	if (!sna_pixmap_move_to_cpu(tile, MOVE_READ))
12848		goto out_gc;
12849
12850	assert(tile->devKind);
12851	assert(has_coherent_ptr(sna, sna_pixmap(tile), MOVE_READ));
12852
12853	src = tile->devPrivate.ptr;
12854	src += tile->devKind * ty;
12855	src += tx * bpp/8;
12856
12857	if ((tw | th) == 1) {
12858		uint32_t pixel;
12859		switch (bpp) {
12860			case 32: pixel = *(uint32_t *)src; break;
12861			case 16: pixel = *(uint16_t *)src; break;
12862			default: pixel = *(uint8_t *)src; break;
12863		}
12864		return sna_poly_fill_rect_blt(drawable, bo, damage,
12865					      gc, pixel, n, rect,
12866					      extents, clipped);
12867	}
12868
12869	upload = kgem_create_buffer(&sna->kgem, 8*bpp, KGEM_BUFFER_WRITE, &ptr);
12870	if (upload == NULL)
12871		goto out_gc;
12872
12873	upload->pitch = bpp; /* for sanity checks */
12874
12875	if (sigtrap_get() == 0) {
12876		uint8_t *dst = ptr;
12877		if (tx + tw > tile->drawable.width ||
12878		    ty + th > tile->drawable.height) {
12879			int sy = ty;
12880			src = tile->devPrivate.ptr;
12881			for (h = 0; h < th; h++) {
12882				int sx = tx;
12883				for (w = 0; w < tw; w++) {
12884					memcpy(dst + w*bpp/8, src + sy * tile->devKind + sx*bpp/8, bpp/8);
12885					if (++sx == tile->drawable.width)
12886						sx = 0;
12887				}
12888				w *= bpp/8;
12889				while (w < bpp) {
12890					memcpy(dst+w, dst, w);
12891					w *= 2;
12892				}
12893				if (++sy == tile->drawable.height)
12894					sy = 0;
12895				dst += bpp;
12896			}
12897			while (h < 8) {
12898				memcpy(dst, ptr, bpp*h);
12899				dst += bpp * h;
12900				h *= 2;
12901			}
12902		} else {
12903			for (h = 0; h < th; h++) {
12904				w = tw*bpp/8;
12905				memcpy(dst, src, w);
12906				while (w < bpp) {
12907					memcpy(dst+w, dst, w);
12908					w *= 2;
12909				}
12910				assert(w == bpp);
12911
12912				src += tile->devKind;
12913				dst += bpp;
12914			}
12915			while (h < 8) {
12916				memcpy(dst, ptr, bpp*h);
12917				dst += bpp * h;
12918				h *= 2;
12919			}
12920			assert(h == 8);
12921		}
12922
12923		ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage,
12924						       upload, gc, n, rect,
12925						       extents, clipped);
12926		sigtrap_put();
12927	}
12928
12929	kgem_bo_destroy(&sna->kgem, upload);
12930out_gc:
12931	gc->patOrg = origin;
12932	return ret;
12933}
12934
12935inline static bool tile_is_solid(GCPtr gc, uint32_t *pixel)
12936{
12937	PixmapPtr tile = gc->tile.pixmap;
12938	struct sna_pixmap *priv;
12939
12940	if ((tile->drawable.width | tile->drawable.height) == 1) {
12941		DBG(("%s: single pixel tile pixmap, converting to solid fill\n", __FUNCTION__));
12942		*pixel = get_pixel(tile);
12943		return true;
12944	}
12945
12946	priv = sna_pixmap(tile);
12947	if (priv == NULL || !priv->clear)
12948		return false;
12949
12950	DBG(("%s: tile is clear, converting to solid fill\n", __FUNCTION__));
12951	*pixel = priv->clear_color;
12952	return true;
12953}
12954
12955static bool
12956sna_poly_fill_rect_tiled_blt(DrawablePtr drawable,
12957			     struct kgem_bo *bo,
12958			     struct sna_damage **damage,
12959			     GCPtr gc, int n, xRectangle *rect,
12960			     const BoxRec *extents, unsigned clipped)
12961{
12962	PixmapPtr pixmap = get_drawable_pixmap(drawable);
12963	struct sna *sna = to_sna_from_pixmap(pixmap);
12964	PixmapPtr tile = gc->tile.pixmap;
12965	struct kgem_bo *tile_bo;
12966	const DDXPointRec * const origin = &gc->patOrg;
12967	struct sna_copy_op copy;
12968	CARD32 alu = gc->alu;
12969	int tile_width, tile_height;
12970	int16_t dx, dy;
12971	uint32_t pixel;
12972
12973	DBG(("%s pixmap=%ld, x %d [(%d, %d)x(%d, %d)...], clipped? %d\n",
12974	     __FUNCTION__, pixmap->drawable.serialNumber,
12975	     n, rect->x, rect->y, rect->width, rect->height,
12976	     clipped));
12977
12978	assert(tile->drawable.depth == drawable->depth);
12979	assert(bo);
12980
12981	if (tile_is_solid(gc, &pixel))
12982		return sna_poly_fill_rect_blt(drawable, bo, damage,
12983					      gc, pixel,
12984					      n, rect,
12985					      extents, clipped);
12986
12987	/* XXX [248]x[238] tiling can be reduced to a pattern fill.
12988	 * Also we can do the lg2 reduction for BLT and use repeat modes for
12989	 * RENDER.
12990	 */
12991
12992	tile_width = tile->drawable.width;
12993	tile_height = tile->drawable.height;
12994	if ((tile_width | tile_height) == 8) {
12995		bool ret;
12996
12997		DBG(("%s: have 8x8 tile, using BLT fast path\n", __FUNCTION__));
12998
12999		tile_bo = sna_pixmap_get_source_bo(tile);
13000		if (tile_bo == NULL) {
13001			DBG(("%s: unable to move tile go GPU, fallback\n",
13002			     __FUNCTION__));
13003			return false;
13004		}
13005
13006		ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage,
13007						       tile_bo, gc, n, rect,
13008						       extents, clipped);
13009		if (ret) {
13010			kgem_bo_destroy(&sna->kgem, tile_bo);
13011			return true;
13012		}
13013	} else {
13014		int w = tile_width, h = tile_height;
13015		struct sna_pixmap *priv = sna_pixmap(tile);
13016
13017		if (priv == NULL || priv->gpu_damage == NULL) {
13018			w = next8(extents->x2 - extents->x1, w);
13019			h = next8(extents->y2 - extents->y1, h);
13020		}
13021
13022		DBG(("%s: not 8x8, triming size for tile: %dx%d from %dx%d (area %dx%d)\n",
13023		     __FUNCTION__, w, h, tile_width, tile_height, extents->x2-extents->x1, extents->y2-extents->y1));
13024
13025		if ((w|h) < 0x10 && is_power_of_two(w) && is_power_of_two(h) &&
13026		    sna_poly_fill_rect_tiled_nxm_blt(drawable, bo, damage,
13027						     gc, n, rect,
13028						     extents, clipped))
13029			return true;
13030
13031		tile_bo = sna_pixmap_get_source_bo(tile);
13032		if (tile_bo == NULL) {
13033			DBG(("%s: unable to move tile go GPU, fallback\n",
13034						__FUNCTION__));
13035			return false;
13036		}
13037	}
13038
13039	if (!sna_copy_init_blt(&copy, sna, tile, tile_bo, pixmap, bo, alu)) {
13040		DBG(("%s: unsupported blt\n", __FUNCTION__));
13041		kgem_bo_destroy(&sna->kgem, tile_bo);
13042		return false;
13043	}
13044
13045	get_drawable_deltas(drawable, pixmap, &dx, &dy);
13046	DBG(("%s: drawable offset into pixmap(%ld) = (%d, %d)\n",
13047	     __FUNCTION__, pixmap->drawable.serialNumber, dx, dy));
13048	if (!clipped) {
13049		dx += drawable->x;
13050		dy += drawable->y;
13051
13052		sna_damage_add_rectangles(damage, rect, n, dx, dy);
13053		do {
13054			xRectangle r = *rect++;
13055			int16_t tile_y = (r.y - origin->y) % tile_height;
13056			if (tile_y < 0)
13057				tile_y += tile_height;
13058
13059			assert(r.x + dx >= 0);
13060			assert(r.y + dy >= 0);
13061			assert(r.x + dx + r.width  <= pixmap->drawable.width);
13062			assert(r.y + dy + r.height <= pixmap->drawable.height);
13063
13064			r.y += dy;
13065			do {
13066				int16_t width = r.width;
13067				int16_t x = r.x + dx, tile_x;
13068				int16_t h = tile_height - tile_y;
13069				if (h > r.height)
13070					h = r.height;
13071				r.height -= h;
13072
13073				tile_x = (r.x - origin->x) % tile_width;
13074				if (tile_x < 0)
13075					tile_x += tile_width;
13076
13077				do {
13078					int16_t w = tile_width - tile_x;
13079					if (w > width)
13080						w = width;
13081					width -= w;
13082
13083					copy.blt(sna, &copy,
13084						 tile_x, tile_y,
13085						 w, h,
13086						 x, r.y);
13087
13088					x += w;
13089					tile_x = 0;
13090				} while (width);
13091				r.y += h;
13092				tile_y = 0;
13093			} while (r.height);
13094		} while (--n);
13095	} else {
13096		RegionRec clip;
13097
13098		region_set(&clip, extents);
13099		if (!region_maybe_clip(&clip, gc->pCompositeClip))
13100			goto done;
13101
13102		if (clip.data == NULL) {
13103			const BoxRec *box = &clip.extents;
13104			DBG(("%s: single clip box [(%d, %d), (%d, %d)]\n",
13105			     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
13106			while (n--) {
13107				BoxRec r;
13108
13109				r.x1 = rect->x + drawable->x;
13110				r.y1 = rect->y + drawable->y;
13111				r.x2 = bound(r.x1, rect->width);
13112				r.y2 = bound(r.y1, rect->height);
13113				rect++;
13114
13115				DBG(("%s: rectangle [(%d, %d), (%d, %d)]\n",
13116				     __FUNCTION__, r.x1, r.y1, r.x2, r.y2));
13117
13118				if (box_intersect(&r, box)) {
13119					int height = r.y2 - r.y1;
13120					int dst_y = r.y1;
13121					int tile_y = (r.y1 - drawable->y - origin->y) % tile_height;
13122					if (tile_y < 0)
13123						tile_y += tile_height;
13124
13125					assert(r.x1 + dx >= 0);
13126					assert(r.y1 + dy >= 0);
13127					assert(r.x2 + dx <= pixmap->drawable.width);
13128					assert(r.y2 + dy <= pixmap->drawable.height);
13129
13130					while (height) {
13131						int width = r.x2 - r.x1;
13132						int dst_x = r.x1, tile_x;
13133						int h = tile_height - tile_y;
13134						if (h > height)
13135							h = height;
13136						height -= h;
13137
13138						tile_x = (r.x1 - drawable->x - origin->x) % tile_width;
13139						if (tile_x < 0)
13140							tile_x += tile_width;
13141
13142						while (width > 0) {
13143							int w = tile_width - tile_x;
13144							if (w > width)
13145								w = width;
13146							width -= w;
13147
13148							copy.blt(sna, &copy,
13149								 tile_x, tile_y,
13150								 w, h,
13151								 dst_x + dx, dst_y + dy);
13152							if (damage) {
13153								BoxRec b;
13154
13155								b.x1 = dst_x + dx;
13156								b.y1 = dst_y + dy;
13157								b.x2 = b.x1 + w;
13158								b.y2 = b.y1 + h;
13159
13160								assert_pixmap_contains_box(pixmap, &b);
13161								sna_damage_add_box(damage, &b);
13162							}
13163
13164							dst_x += w;
13165							tile_x = 0;
13166						}
13167						dst_y += h;
13168						tile_y = 0;
13169					}
13170				}
13171			}
13172		} else {
13173			while (n--) {
13174				RegionRec region;
13175				const BoxRec *box;
13176				int nbox;
13177
13178				region.extents.x1 = rect->x + drawable->x;
13179				region.extents.y1 = rect->y + drawable->y;
13180				region.extents.x2 = bound(region.extents.x1, rect->width);
13181				region.extents.y2 = bound(region.extents.y1, rect->height);
13182				rect++;
13183
13184				DBG(("%s: rectangle [(%d, %d), (%d, %d)]\n",
13185				     __FUNCTION__,
13186				     region.extents.x1,
13187				     region.extents.y1,
13188				     region.extents.x2,
13189				     region.extents.y2));
13190
13191				region.data = NULL;
13192				RegionIntersect(&region, &region, &clip);
13193
13194				assert(region.extents.x1 + dx >= 0);
13195				assert(region.extents.y1 + dy >= 0);
13196				assert(region.extents.x2 + dx <= pixmap->drawable.width);
13197				assert(region.extents.y2 + dy <= pixmap->drawable.height);
13198
13199				nbox = region_num_rects(&region);
13200				box = region_rects(&region);
13201				DBG(("%s: split into %d boxes after clipping\n", __FUNCTION__, nbox));
13202				while (nbox--) {
13203					int height = box->y2 - box->y1;
13204					int dst_y = box->y1;
13205					int tile_y = (box->y1 - drawable->y - origin->y) % tile_height;
13206					if (tile_y < 0)
13207						tile_y += tile_height;
13208
13209					while (height) {
13210						int width = box->x2 - box->x1;
13211						int dst_x = box->x1, tile_x;
13212						int h = tile_height - tile_y;
13213						if (h > height)
13214							h = height;
13215						height -= h;
13216
13217						tile_x = (box->x1 - drawable->x - origin->x) % tile_width;
13218						if (tile_x < 0)
13219							tile_x += tile_width;
13220
13221						while (width > 0) {
13222							int w = tile_width - tile_x;
13223							if (w > width)
13224								w = width;
13225							width -= w;
13226
13227							copy.blt(sna, &copy,
13228								 tile_x, tile_y,
13229								 w, h,
13230								 dst_x + dx, dst_y + dy);
13231							if (damage) {
13232								BoxRec b;
13233
13234								b.x1 = dst_x + dx;
13235								b.y1 = dst_y + dy;
13236								b.x2 = b.x1 + w;
13237								b.y2 = b.y1 + h;
13238
13239								assert_pixmap_contains_box(pixmap, &b);
13240								sna_damage_add_box(damage, &b);
13241							}
13242
13243							dst_x += w;
13244							tile_x = 0;
13245						}
13246						dst_y += h;
13247						tile_y = 0;
13248					}
13249					box++;
13250				}
13251
13252				RegionUninit(&region);
13253			}
13254		}
13255
13256		RegionUninit(&clip);
13257	}
13258done:
13259	copy.done(sna, &copy);
13260	assert_pixmap_damage(pixmap);
13261	kgem_bo_destroy(&sna->kgem, tile_bo);
13262	return true;
13263}
13264
13265static bool
13266sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
13267				    struct kgem_bo *bo,
13268				    struct sna_damage **damage,
13269				    GCPtr gc, int n, xRectangle *r,
13270				    const BoxRec *extents, unsigned clipped)
13271{
13272	PixmapPtr pixmap = get_drawable_pixmap(drawable);
13273	struct sna *sna = to_sna_from_pixmap(pixmap);
13274	uint32_t pat[2] = {0, 0}, br00, br13;
13275	int16_t dx, dy;
13276	uint32_t *b;
13277
13278	if (NO_STIPPLE_8x8)
13279		return false;
13280
13281	DBG(("%s: alu=%d, upload (%d, %d), (%d, %d), origin (%d, %d)\n",
13282	     __FUNCTION__, gc->alu,
13283	     extents->x1, extents->y1,
13284	     extents->x2, extents->y2,
13285	     gc->patOrg.x, gc->patOrg.y));
13286
13287	get_drawable_deltas(drawable, pixmap, &dx, &dy);
13288	{
13289		int px, py;
13290
13291		px = (0 - gc->patOrg.x - drawable->x - dx) % 8;
13292		if (px < 0)
13293			px += 8;
13294
13295		py = (0 - gc->patOrg.y - drawable->y - dy) % 8;
13296		if (py < 0)
13297			py += 8;
13298		DBG(("%s: pat offset (%d, %d)\n", __FUNCTION__ ,px, py));
13299
13300		br00 = XY_SCANLINE_BLT | px << 12 | py << 8 | 3 << 20;
13301		br13 = bo->pitch;
13302		if (sna->kgem.gen >= 040 && bo->tiling) {
13303			br00 |= BLT_DST_TILED;
13304			br13 >>= 2;
13305		}
13306		br13 |= (gc->fillStyle == FillStippled) << 28;
13307		br13 |= blt_depth(drawable->depth) << 24;
13308		br13 |= fill_ROP[gc->alu] << 16;
13309	}
13310
13311	assert(gc->stipple->devKind);
13312	{
13313		uint8_t *dst = (uint8_t *)pat;
13314		const uint8_t *src = gc->stipple->devPrivate.ptr;
13315		int stride = gc->stipple->devKind;
13316		int j = gc->stipple->drawable.height;
13317		do {
13318			*dst++ = byte_reverse(*src);
13319			src += stride;
13320		} while (--j);
13321	}
13322
13323	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
13324	assert(kgem_bo_can_blt(&sna->kgem, bo));
13325	if (!kgem_check_batch(&sna->kgem, 10 + 2*3) ||
13326	    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13327	    !kgem_check_reloc(&sna->kgem, 1)) {
13328		kgem_submit(&sna->kgem);
13329		if (!kgem_check_bo_fenced(&sna->kgem, bo))
13330			return false;
13331		_kgem_set_mode(&sna->kgem, KGEM_BLT);
13332	}
13333	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
13334
13335	if (!clipped) {
13336		dx += drawable->x;
13337		dy += drawable->y;
13338
13339		sna_damage_add_rectangles(damage, r, n, dx, dy);
13340		if (n == 1) {
13341			DBG(("%s: single unclipped rect (%d, %d)x(%d, %d)\n",
13342			     __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height));
13343
13344			assert(sna->kgem.mode == KGEM_BLT);
13345			b = sna->kgem.batch + sna->kgem.nbatch;
13346			if (sna->kgem.gen >= 0100) {
13347				b[0] = XY_MONO_PAT | (br00 & 0x7f00) | 3<<20 | 8;
13348				b[1] = br13;
13349				b[2] = (r->y + dy) << 16 | (r->x + dx);
13350				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13351				*(uint64_t *)(b+4) =
13352					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13353							 I915_GEM_DOMAIN_RENDER << 16 |
13354							 I915_GEM_DOMAIN_RENDER |
13355							 KGEM_RELOC_FENCED,
13356							 0);
13357				b[6] = gc->bgPixel;
13358				b[7] = gc->fgPixel;
13359				b[8] = pat[0];
13360				b[9] = pat[1];
13361				sna->kgem.nbatch += 10;
13362			} else {
13363				b[0] = XY_MONO_PAT | (br00 & 0x7f00) | 3<<20 | 7;
13364				b[1] = br13;
13365				b[2] = (r->y + dy) << 16 | (r->x + dx);
13366				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13367				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13368						      I915_GEM_DOMAIN_RENDER << 16 |
13369						      I915_GEM_DOMAIN_RENDER |
13370						      KGEM_RELOC_FENCED,
13371						      0);
13372				b[5] = gc->bgPixel;
13373				b[6] = gc->fgPixel;
13374				b[7] = pat[0];
13375				b[8] = pat[1];
13376				sna->kgem.nbatch += 9;
13377			}
13378		} else do {
13379			int n_this_time, rem;
13380
13381			assert(sna->kgem.mode == KGEM_BLT);
13382			b = sna->kgem.batch + sna->kgem.nbatch;
13383			if (sna->kgem.gen >= 0100) {
13384				b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
13385				b[1] = br13;
13386				b[2] = 0;
13387				b[3] = 0;
13388				*(uint64_t *)(b+4) =
13389					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13390							 I915_GEM_DOMAIN_RENDER << 16 |
13391							 I915_GEM_DOMAIN_RENDER |
13392							 KGEM_RELOC_FENCED,
13393							 0);
13394				b[6] = gc->bgPixel;
13395				b[7] = gc->fgPixel;
13396				b[8] = pat[0];
13397				b[9] = pat[1];
13398				sna->kgem.nbatch += 10;
13399			} else {
13400				b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7;
13401				b[1] = br13;
13402				b[2] = 0;
13403				b[3] = 0;
13404				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13405						      I915_GEM_DOMAIN_RENDER << 16 |
13406						      I915_GEM_DOMAIN_RENDER |
13407						      KGEM_RELOC_FENCED,
13408						      0);
13409				b[5] = gc->bgPixel;
13410				b[6] = gc->fgPixel;
13411				b[7] = pat[0];
13412				b[8] = pat[1];
13413				sna->kgem.nbatch += 9;
13414			}
13415
13416			n_this_time = n;
13417			rem = kgem_batch_space(&sna->kgem);
13418			if (3*n_this_time > rem)
13419				n_this_time = rem / 3;
13420			assert(n_this_time);
13421			n -= n_this_time;
13422
13423			assert(sna->kgem.mode == KGEM_BLT);
13424			b = sna->kgem.batch + sna->kgem.nbatch;
13425			sna->kgem.nbatch += 3 * n_this_time;
13426			do {
13427				DBG(("%s: rect (%d, %d)x(%d, %d)\n",
13428				     __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height));
13429				assert(r->x + dx >= 0);
13430				assert(r->y + dy >= 0);
13431				assert(r->x + dx + r->width  <= pixmap->drawable.width);
13432				assert(r->y + dy + r->height <= pixmap->drawable.height);
13433
13434				b[0] = br00;
13435				b[1] = (r->y + dy) << 16 | (r->x + dx);
13436				b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13437
13438				b += 3; r++;
13439			} while(--n_this_time);
13440
13441			if (!n)
13442				break;
13443
13444			_kgem_submit(&sna->kgem);
13445			_kgem_set_mode(&sna->kgem, KGEM_BLT);
13446			kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
13447		} while (1);
13448	} else {
13449		RegionRec clip;
13450
13451		region_set(&clip, extents);
13452		if (!region_maybe_clip(&clip, gc->pCompositeClip))
13453			return true;
13454
13455		assert(sna->kgem.mode == KGEM_BLT);
13456		b = sna->kgem.batch + sna->kgem.nbatch;
13457		if (sna->kgem.gen >= 0100) {
13458			b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
13459			b[1] = br13;
13460			b[2] = 0;
13461			b[3] = 0;
13462			*(uint64_t *)(b+4) =
13463				kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13464						 I915_GEM_DOMAIN_RENDER << 16 |
13465						 I915_GEM_DOMAIN_RENDER |
13466						 KGEM_RELOC_FENCED,
13467						 0);
13468			b[6] = gc->bgPixel;
13469			b[7] = gc->fgPixel;
13470			b[8] = pat[0];
13471			b[9] = pat[1];
13472			sna->kgem.nbatch += 10;
13473		} else {
13474			b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7;
13475			b[1] = br13;
13476			b[2] = 0;
13477			b[3] = 0;
13478			b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13479					      I915_GEM_DOMAIN_RENDER << 16 |
13480					      I915_GEM_DOMAIN_RENDER |
13481					      KGEM_RELOC_FENCED,
13482					      0);
13483			b[5] = gc->bgPixel;
13484			b[6] = gc->fgPixel;
13485			b[7] = pat[0];
13486			b[8] = pat[1];
13487			sna->kgem.nbatch += 9;
13488		}
13489
13490		if (clip.data == NULL) {
13491			do {
13492				BoxRec box;
13493
13494				box.x1 = r->x + drawable->x;
13495				box.y1 = r->y + drawable->y;
13496				box.x2 = bound(box.x1, r->width);
13497				box.y2 = bound(box.y1, r->height);
13498				r++;
13499
13500				if (box_intersect(&box, &clip.extents)) {
13501					if (!kgem_check_batch(&sna->kgem, 3)) {
13502						_kgem_submit(&sna->kgem);
13503						_kgem_set_mode(&sna->kgem, KGEM_BLT);
13504						kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
13505
13506						assert(sna->kgem.mode == KGEM_BLT);
13507						b = sna->kgem.batch + sna->kgem.nbatch;
13508						if (sna->kgem.gen >= 0100) {
13509							b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
13510							b[1] = br13;
13511							b[2] = 0;
13512							b[3] = 0;
13513							*(uint64_t *)(b+4) =
13514								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13515										 I915_GEM_DOMAIN_RENDER << 16 |
13516										 I915_GEM_DOMAIN_RENDER |
13517										 KGEM_RELOC_FENCED,
13518										 0);
13519							b[6] = gc->bgPixel;
13520							b[7] = gc->fgPixel;
13521							b[8] = pat[0];
13522							b[9] = pat[1];
13523							sna->kgem.nbatch += 10;
13524						} else {
13525							b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7;
13526							b[1] = br13;
13527							b[2] = 0;
13528							b[3] = 0;
13529							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13530									      I915_GEM_DOMAIN_RENDER << 16 |
13531									      I915_GEM_DOMAIN_RENDER |
13532									      KGEM_RELOC_FENCED,
13533									      0);
13534							b[5] = gc->bgPixel;
13535							b[6] = gc->fgPixel;
13536							b[7] = pat[0];
13537							b[8] = pat[1];
13538							sna->kgem.nbatch += 9;
13539						}
13540					}
13541
13542					assert(sna->kgem.mode == KGEM_BLT);
13543					b = sna->kgem.batch + sna->kgem.nbatch;
13544					sna->kgem.nbatch += 3;
13545					b[0] = br00;
13546					b[1] = (box.y1 + dy) << 16 | (box.x1 + dx);
13547					b[2] = (box.y2 + dy) << 16 | (box.x2 + dx);
13548				}
13549			} while (--n);
13550		} else {
13551			const BoxRec * const clip_start = RegionBoxptr(&clip);
13552			const BoxRec * const clip_end = clip_start + clip.data->numRects;
13553			const BoxRec *c;
13554
13555			do {
13556				BoxRec box;
13557
13558				box.x1 = r->x + drawable->x;
13559				box.y1 = r->y + drawable->y;
13560				box.x2 = bound(box.x1, r->width);
13561				box.y2 = bound(box.y1, r->height);
13562				r++;
13563
13564				c = find_clip_box_for_y(clip_start,
13565							clip_end,
13566							box.y1);
13567				while (c != clip_end) {
13568					BoxRec bb;
13569					if (box.y2 <= c->y1)
13570						break;
13571
13572					bb = box;
13573					if (box_intersect(&bb, c++)) {
13574						if (!kgem_check_batch(&sna->kgem, 3)) {
13575							_kgem_submit(&sna->kgem);
13576							_kgem_set_mode(&sna->kgem, KGEM_BLT);
13577							kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
13578
13579							assert(sna->kgem.mode == KGEM_BLT);
13580							b = sna->kgem.batch + sna->kgem.nbatch;
13581							if (sna->kgem.gen >= 0100) {
13582								b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
13583								b[1] = br13;
13584								b[2] = 0;
13585								b[3] = 0;
13586								*(uint64_t *)(b+4) =
13587									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13588											 I915_GEM_DOMAIN_RENDER << 16 |
13589											 I915_GEM_DOMAIN_RENDER |
13590											 KGEM_RELOC_FENCED,
13591											 0);
13592								b[6] = gc->bgPixel;
13593								b[7] = gc->fgPixel;
13594								b[8] = pat[0];
13595								b[9] = pat[1];
13596								sna->kgem.nbatch += 10;
13597							} else {
13598								b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7;
13599								b[1] = br13;
13600								b[2] = 0;
13601								b[3] = 0;
13602								b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13603										      I915_GEM_DOMAIN_RENDER << 16 |
13604										      I915_GEM_DOMAIN_RENDER |
13605										      KGEM_RELOC_FENCED,
13606										      0);
13607								b[5] = gc->bgPixel;
13608								b[6] = gc->fgPixel;
13609								b[7] = pat[0];
13610								b[8] = pat[1];
13611								sna->kgem.nbatch += 9;
13612							}
13613						}
13614
13615						assert(sna->kgem.mode == KGEM_BLT);
13616						b = sna->kgem.batch + sna->kgem.nbatch;
13617						sna->kgem.nbatch += 3;
13618						b[0] = br00;
13619						b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx);
13620						b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx);
13621					}
13622				}
13623			} while (--n);
13624		}
13625	}
13626
13627	assert_pixmap_damage(pixmap);
13628	blt_done(sna);
13629	return true;
13630}
13631
13632static bool
13633sna_poly_fill_rect_stippled_nxm_blt(DrawablePtr drawable,
13634				    struct kgem_bo *bo,
13635				    struct sna_damage **damage,
13636				    GCPtr gc, int n, xRectangle *r,
13637				    const BoxRec *extents, unsigned clipped)
13638{
13639	PixmapPtr scratch, stipple;
13640	uint8_t bytes[8], *dst = bytes;
13641	const uint8_t *src, *end;
13642	int j, stride;
13643	bool ret;
13644
13645	DBG(("%s: expanding %dx%d stipple to 8x8\n",
13646	     __FUNCTION__,
13647	     gc->stipple->drawable.width,
13648	     gc->stipple->drawable.height));
13649
13650	scratch = GetScratchPixmapHeader(drawable->pScreen,
13651					 8, 8, 1, 1, 1, bytes);
13652	if (scratch == NullPixmap)
13653		return false;
13654
13655	stipple = gc->stipple;
13656	gc->stipple = scratch;
13657
13658	assert(stipple->devKind);
13659	stride = stipple->devKind;
13660	src = stipple->devPrivate.ptr;
13661	end = src + stride * stipple->drawable.height;
13662	for(j = 0; j < 8; j++) {
13663		switch (stipple->drawable.width) {
13664		case 1: *dst = (*src & 1) * 0xff; break;
13665		case 2: *dst = (*src & 3) * 0x55; break;
13666		case 4: *dst = (*src & 15) * 0x11; break;
13667		case 8: *dst = *src; break;
13668		default: assert(0); break;
13669		}
13670		dst++;
13671		src += stride;
13672		if (src == end)
13673			src = stipple->devPrivate.ptr;
13674	}
13675
13676	ret = sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage,
13677						  gc, n, r, extents, clipped);
13678
13679	gc->stipple = stipple;
13680	FreeScratchPixmapHeader(scratch);
13681
13682	return ret;
13683}
13684
13685static bool
13686sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
13687				  struct kgem_bo *bo,
13688				  struct sna_damage **damage,
13689				  GCPtr gc, int n, xRectangle *r,
13690				  const BoxRec *extents, unsigned clipped)
13691{
13692	PixmapPtr pixmap = get_drawable_pixmap(drawable);
13693	struct sna *sna = to_sna_from_pixmap(pixmap);
13694	PixmapPtr stipple = gc->stipple;
13695	const DDXPointRec *origin = &gc->patOrg;
13696	int16_t dx, dy;
13697	uint32_t br00, br13;
13698
13699	DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%x\n", __FUNCTION__,
13700	     extents->x1, extents->y1,
13701	     extents->x2, extents->y2,
13702	     origin->x, origin->y,
13703	     clipped));
13704
13705	get_drawable_deltas(drawable, pixmap, &dx, &dy);
13706	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
13707	assert(kgem_bo_can_blt(&sna->kgem, bo));
13708	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
13709
13710	br00 = 3 << 20;
13711	br13 = bo->pitch;
13712	if (sna->kgem.gen >= 040 && bo->tiling) {
13713		br00 |= BLT_DST_TILED;
13714		br13 >>= 2;
13715	}
13716	br13 |= (gc->fillStyle == FillStippled) << 29;
13717	br13 |= blt_depth(drawable->depth) << 24;
13718	br13 |= copy_ROP[gc->alu] << 16;
13719
13720	if (!clipped) {
13721		dx += drawable->x;
13722		dy += drawable->y;
13723
13724		sna_damage_add_rectangles(damage, r, n, dx, dy);
13725		do {
13726			int bx1 = (r->x - origin->x) & ~7;
13727			int bx2 = (r->x + r->width - origin->x + 7) & ~7;
13728			int bw = (bx2 - bx1)/8;
13729			int bh = r->height;
13730			int bstride = ALIGN(bw, 2);
13731			int src_stride;
13732			uint8_t *dst, *src;
13733			uint32_t *b;
13734
13735			DBG(("%s: rect (%d, %d)x(%d, %d) stipple [%d,%d, src_stride=%d]\n",
13736			     __FUNCTION__,
13737			     r->x, r->y, r->width, r->height,
13738			     bx1, bx2, bstride*bh));
13739
13740			src_stride = bstride*bh;
13741			assert(src_stride > 0);
13742			if (src_stride <= 128) {
13743				src_stride = ALIGN(src_stride, 8) / 4;
13744				assert(src_stride <= 32);
13745				if (!kgem_check_batch(&sna->kgem, 8+src_stride) ||
13746				    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13747				    !kgem_check_reloc(&sna->kgem, 1)) {
13748					kgem_submit(&sna->kgem);
13749					if (!kgem_check_bo_fenced(&sna->kgem, bo))
13750						return false;
13751					_kgem_set_mode(&sna->kgem, KGEM_BLT);
13752				}
13753				kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
13754
13755				assert(sna->kgem.mode == KGEM_BLT);
13756				b = sna->kgem.batch + sna->kgem.nbatch;
13757				if (sna->kgem.gen >= 0100) {
13758					b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00;
13759					b[0] |= ((r->x - origin->x) & 7) << 17;
13760					b[1] = br13;
13761					b[2] = (r->y + dy) << 16 | (r->x + dx);
13762					b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13763					*(uint64_t *)(b+4) =
13764						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13765								 I915_GEM_DOMAIN_RENDER << 16 |
13766								 I915_GEM_DOMAIN_RENDER |
13767								 KGEM_RELOC_FENCED,
13768								 0);
13769					b[6] = gc->bgPixel;
13770					b[7] = gc->fgPixel;
13771
13772					dst = (uint8_t *)&b[8];
13773					sna->kgem.nbatch += 8 + src_stride;
13774				} else {
13775					b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
13776					b[0] |= ((r->x - origin->x) & 7) << 17;
13777					b[1] = br13;
13778					b[2] = (r->y + dy) << 16 | (r->x + dx);
13779					b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13780					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13781							      I915_GEM_DOMAIN_RENDER << 16 |
13782							      I915_GEM_DOMAIN_RENDER |
13783							      KGEM_RELOC_FENCED,
13784							      0);
13785					b[5] = gc->bgPixel;
13786					b[6] = gc->fgPixel;
13787
13788					dst = (uint8_t *)&b[7];
13789					sna->kgem.nbatch += 7 + src_stride;
13790				}
13791				assert(stipple->devKind);
13792				src_stride = stipple->devKind;
13793				src = stipple->devPrivate.ptr;
13794				src += (r->y - origin->y) * src_stride + bx1/8;
13795				src_stride -= bstride;
13796				do {
13797					int i = bstride;
13798					do {
13799						*dst++ = byte_reverse(*src++);
13800						*dst++ = byte_reverse(*src++);
13801						i -= 2;
13802					} while (i);
13803					src += src_stride;
13804				} while (--bh);
13805			} else {
13806				struct kgem_bo *upload;
13807				void *ptr;
13808
13809				if (!kgem_check_batch(&sna->kgem, 10) ||
13810				    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13811				    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
13812					kgem_submit(&sna->kgem);
13813					if (!kgem_check_bo_fenced(&sna->kgem, bo))
13814						return false;
13815					_kgem_set_mode(&sna->kgem, KGEM_BLT);
13816				}
13817				kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
13818
13819				upload = kgem_create_buffer(&sna->kgem,
13820							    bstride*bh,
13821							    KGEM_BUFFER_WRITE_INPLACE,
13822							    &ptr);
13823				if (!upload)
13824					break;
13825
13826				if (sigtrap_get() == 0) {
13827					dst = ptr;
13828					assert(stipple->devKind);
13829					src_stride = stipple->devKind;
13830					src = stipple->devPrivate.ptr;
13831					src += (r->y - origin->y) * src_stride + bx1/8;
13832					src_stride -= bstride;
13833					do {
13834						int i = bstride;
13835						do {
13836							*dst++ = byte_reverse(*src++);
13837							*dst++ = byte_reverse(*src++);
13838							i -= 2;
13839						} while (i);
13840						src += src_stride;
13841					} while (--bh);
13842
13843					assert(sna->kgem.mode == KGEM_BLT);
13844					b = sna->kgem.batch + sna->kgem.nbatch;
13845					if (sna->kgem.gen >= 0100) {
13846						b[0] = XY_MONO_SRC_COPY | br00 | 8;
13847						b[0] |= ((r->x - origin->x) & 7) << 17;
13848						b[1] = br13;
13849						b[2] = (r->y + dy) << 16 | (r->x + dx);
13850						b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13851						*(uint64_t *)(b+4) =
13852							kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13853									I915_GEM_DOMAIN_RENDER << 16 |
13854									I915_GEM_DOMAIN_RENDER |
13855									KGEM_RELOC_FENCED,
13856									0);
13857						*(uint64_t *)(b+6) =
13858							kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
13859									I915_GEM_DOMAIN_RENDER << 16 |
13860									KGEM_RELOC_FENCED,
13861									0);
13862						b[8] = gc->bgPixel;
13863						b[9] = gc->fgPixel;
13864						sna->kgem.nbatch += 10;
13865					} else {
13866						b[0] = XY_MONO_SRC_COPY | br00 | 6;
13867						b[0] |= ((r->x - origin->x) & 7) << 17;
13868						b[1] = br13;
13869						b[2] = (r->y + dy) << 16 | (r->x + dx);
13870						b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13871						b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13872								I915_GEM_DOMAIN_RENDER << 16 |
13873								I915_GEM_DOMAIN_RENDER |
13874								KGEM_RELOC_FENCED,
13875								0);
13876						b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
13877								I915_GEM_DOMAIN_RENDER << 16 |
13878								KGEM_RELOC_FENCED,
13879								0);
13880						b[6] = gc->bgPixel;
13881						b[7] = gc->fgPixel;
13882
13883						sna->kgem.nbatch += 8;
13884					}
13885					sigtrap_put();
13886				}
13887
13888				kgem_bo_destroy(&sna->kgem, upload);
13889			}
13890
13891			r++;
13892		} while (--n);
13893	} else {
13894		RegionRec clip;
13895		DDXPointRec pat;
13896
13897		region_set(&clip, extents);
13898		if (!region_maybe_clip(&clip, gc->pCompositeClip))
13899			return true;
13900
13901		DBG(("%s: clip.extents=[(%d, %d), (%d, %d)] region?=%d\n",
13902		     __FUNCTION__,
13903		     clip.extents.x1, clip.extents.y1,
13904		     clip.extents.x2, clip.extents.y2,
13905		     clip.data ? clip.data->numRects : 0));
13906
13907		pat.x = origin->x + drawable->x;
13908		pat.y = origin->y + drawable->y;
13909
13910		if (clip.data == NULL) {
13911			do {
13912				BoxRec box;
13913				int bx1, bx2, bw, bh, bstride;
13914				int src_stride;
13915				uint8_t *dst, *src;
13916				uint32_t *b;
13917				struct kgem_bo *upload;
13918				void *ptr;
13919
13920				box.x1 = r->x + drawable->x;
13921				box.x2 = bound(box.x1, r->width);
13922				box.y1 = r->y + drawable->y;
13923				box.y2 = bound(box.y1, r->height);
13924				r++;
13925
13926				if (!box_intersect(&box, &clip.extents))
13927					continue;
13928
13929				bx1 = (box.x1 - pat.x) & ~7;
13930				bx2 = (box.x2 - pat.x + 7) & ~7;
13931				bw = (bx2 - bx1)/8;
13932				bh = box.y2 - box.y1;
13933				bstride = ALIGN(bw, 2);
13934
13935				DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d], pitch=%d, stride=%d, len=%d\n",
13936				     __FUNCTION__,
13937				     r->x, r->y, r->width, r->height,
13938				     box.x1, box.y1, box.x2, box.y2,
13939				     bx1, bx2, bw, bstride, bstride*bh));
13940
13941				src_stride = bstride*bh;
13942				assert(src_stride > 0);
13943				if (src_stride <= 128) {
13944					src_stride = ALIGN(src_stride, 8) / 4;
13945					assert(src_stride <= 32);
13946					if (!kgem_check_batch(&sna->kgem, 8+src_stride) ||
13947					    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13948					    !kgem_check_reloc(&sna->kgem, 1)) {
13949						kgem_submit(&sna->kgem);
13950						if (!kgem_check_bo_fenced(&sna->kgem, bo))
13951							return false;
13952						_kgem_set_mode(&sna->kgem, KGEM_BLT);
13953					}
13954					kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
13955
13956					assert(sna->kgem.mode == KGEM_BLT);
13957					b = sna->kgem.batch + sna->kgem.nbatch;
13958					if (sna->kgem.gen >= 0100) {
13959						b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00;
13960						b[0] |= ((box.x1 - pat.x) & 7) << 17;
13961						b[1] = br13;
13962						b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13963						b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13964						*(uint64_t *)(b+4) =
13965							kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13966									 I915_GEM_DOMAIN_RENDER << 16 |
13967									 I915_GEM_DOMAIN_RENDER |
13968									 KGEM_RELOC_FENCED,
13969									 0);
13970						b[6] = gc->bgPixel;
13971						b[7] = gc->fgPixel;
13972
13973						dst = (uint8_t *)&b[8];
13974						sna->kgem.nbatch += 8 + src_stride;
13975					} else {
13976						b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
13977						b[0] |= ((box.x1 - pat.x) & 7) << 17;
13978						b[1] = br13;
13979						b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13980						b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13981						b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13982								      I915_GEM_DOMAIN_RENDER << 16 |
13983								      I915_GEM_DOMAIN_RENDER |
13984								      KGEM_RELOC_FENCED,
13985								      0);
13986						b[5] = gc->bgPixel;
13987						b[6] = gc->fgPixel;
13988
13989						dst = (uint8_t *)&b[7];
13990						sna->kgem.nbatch += 7 + src_stride;
13991					}
13992
13993					assert(stipple->devKind);
13994					src_stride = stipple->devKind;
13995					src = stipple->devPrivate.ptr;
13996					src += (box.y1 - pat.y) * src_stride + bx1/8;
13997					src_stride -= bstride;
13998					do {
13999						int i = bstride;
14000						do {
14001							*dst++ = byte_reverse(*src++);
14002							*dst++ = byte_reverse(*src++);
14003							i -= 2;
14004						} while (i);
14005						src += src_stride;
14006					} while (--bh);
14007				} else {
14008					if (!kgem_check_batch(&sna->kgem, 10) ||
14009					    !kgem_check_bo_fenced(&sna->kgem, bo) ||
14010					    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
14011						kgem_submit(&sna->kgem);
14012						if (!kgem_check_bo_fenced(&sna->kgem, bo))
14013							return false;
14014						_kgem_set_mode(&sna->kgem, KGEM_BLT);
14015					}
14016					kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
14017
14018					upload = kgem_create_buffer(&sna->kgem,
14019								    bstride*bh,
14020								    KGEM_BUFFER_WRITE_INPLACE,
14021								    &ptr);
14022					if (!upload)
14023						break;
14024
14025					if (sigtrap_get() == 0) {
14026						dst = ptr;
14027						assert(stipple->devKind);
14028						src_stride = stipple->devKind;
14029						src = stipple->devPrivate.ptr;
14030						src += (box.y1 - pat.y) * src_stride + bx1/8;
14031						src_stride -= bstride;
14032						do {
14033							int i = bstride;
14034							do {
14035								*dst++ = byte_reverse(*src++);
14036								*dst++ = byte_reverse(*src++);
14037								i -= 2;
14038							} while (i);
14039							src += src_stride;
14040						} while (--bh);
14041
14042						assert(sna->kgem.mode == KGEM_BLT);
14043						b = sna->kgem.batch + sna->kgem.nbatch;
14044						if (sna->kgem.gen >= 0100) {
14045							b[0] = XY_MONO_SRC_COPY | br00 | 8;
14046							b[0] |= ((box.x1 - pat.x) & 7) << 17;
14047							b[1] = br13;
14048							b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
14049							b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
14050							*(uint64_t *)(b+4) =
14051								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14052										I915_GEM_DOMAIN_RENDER << 16 |
14053										I915_GEM_DOMAIN_RENDER |
14054										KGEM_RELOC_FENCED,
14055										0);
14056							*(uint64_t *)(b+6) =
14057								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
14058										I915_GEM_DOMAIN_RENDER << 16 |
14059										KGEM_RELOC_FENCED,
14060										0);
14061							b[8] = gc->bgPixel;
14062							b[9] = gc->fgPixel;
14063							sna->kgem.nbatch += 10;
14064						} else {
14065							b[0] = XY_MONO_SRC_COPY | br00 | 6;
14066							b[0] |= ((box.x1 - pat.x) & 7) << 17;
14067							b[1] = br13;
14068							b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
14069							b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
14070							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14071									I915_GEM_DOMAIN_RENDER << 16 |
14072									I915_GEM_DOMAIN_RENDER |
14073									KGEM_RELOC_FENCED,
14074									0);
14075							b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
14076									I915_GEM_DOMAIN_RENDER << 16 |
14077									KGEM_RELOC_FENCED,
14078									0);
14079							b[6] = gc->bgPixel;
14080							b[7] = gc->fgPixel;
14081
14082							sna->kgem.nbatch += 8;
14083						}
14084						sigtrap_put();
14085					}
14086					kgem_bo_destroy(&sna->kgem, upload);
14087				}
14088			} while (--n);
14089		} else {
14090			const BoxRec * const clip_start = RegionBoxptr(&clip);
14091			const BoxRec * const clip_end = clip_start + clip.data->numRects;
14092			const BoxRec *c;
14093
14094			do {
14095				BoxRec unclipped;
14096				int bx1, bx2, bw, bh, bstride;
14097				int src_stride;
14098				uint8_t *dst, *src;
14099				uint32_t *b;
14100				struct kgem_bo *upload;
14101				void *ptr;
14102
14103				unclipped.x1 = r->x + drawable->x;
14104				unclipped.x2 = bound(unclipped.x1, r->width);
14105				unclipped.y1 = r->y + drawable->y;
14106				unclipped.y2 = bound(unclipped.y1, r->height);
14107				r++;
14108
14109				c = find_clip_box_for_y(clip_start,
14110							clip_end,
14111							unclipped.y1);
14112				while (c != clip_end) {
14113					BoxRec box;
14114
14115					if (unclipped.y2 <= c->y1)
14116						break;
14117
14118					box = unclipped;
14119					if (!box_intersect(&box, c++))
14120						continue;
14121
14122					bx1 = (box.x1 - pat.x) & ~7;
14123					bx2 = (box.x2 - pat.x + 7) & ~7;
14124					bw = (bx2 - bx1)/8;
14125					bh = box.y2 - box.y1;
14126					bstride = ALIGN(bw, 2);
14127
14128					DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d]\n",
14129					     __FUNCTION__,
14130					     r->x, r->y, r->width, r->height,
14131					     box.x1, box.y1, box.x2, box.y2,
14132					     bx1, bx2));
14133
14134					src_stride = bstride*bh;
14135					assert(src_stride > 0);
14136					if (src_stride <= 128) {
14137						src_stride = ALIGN(src_stride, 8) / 4;
14138						assert(src_stride <= 32);
14139						if (!kgem_check_batch(&sna->kgem, 8+src_stride) ||
14140						    !kgem_check_bo_fenced(&sna->kgem, bo) ||
14141						    !kgem_check_reloc(&sna->kgem, 1)) {
14142							kgem_submit(&sna->kgem);
14143							if (!kgem_check_bo_fenced(&sna->kgem, bo))
14144								return false;
14145							_kgem_set_mode(&sna->kgem, KGEM_BLT);
14146						}
14147						kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
14148
14149						assert(sna->kgem.mode == KGEM_BLT);
14150						b = sna->kgem.batch + sna->kgem.nbatch;
14151						if (sna->kgem.gen >= 0100) {
14152							b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00;
14153							b[0] |= ((box.x1 - pat.x) & 7) << 17;
14154							b[1] = br13;
14155							b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
14156							b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
14157							*(uint64_t *)(b+4) =
14158								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14159										 I915_GEM_DOMAIN_RENDER << 16 |
14160										 I915_GEM_DOMAIN_RENDER |
14161										 KGEM_RELOC_FENCED,
14162										 0);
14163							b[6] = gc->bgPixel;
14164							b[7] = gc->fgPixel;
14165
14166							dst = (uint8_t *)&b[8];
14167							sna->kgem.nbatch += 8 + src_stride;
14168						} else {
14169							b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
14170							b[0] |= ((box.x1 - pat.x) & 7) << 17;
14171							b[1] = br13;
14172							b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
14173							b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
14174							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14175									      I915_GEM_DOMAIN_RENDER << 16 |
14176									      I915_GEM_DOMAIN_RENDER |
14177									      KGEM_RELOC_FENCED,
14178									      0);
14179							b[5] = gc->bgPixel;
14180							b[6] = gc->fgPixel;
14181
14182							dst = (uint8_t *)&b[7];
14183							sna->kgem.nbatch += 7 + src_stride;
14184						}
14185						assert(stipple->devKind);
14186						src_stride = stipple->devKind;
14187						src = stipple->devPrivate.ptr;
14188						src += (box.y1 - pat.y) * src_stride + bx1/8;
14189						src_stride -= bstride;
14190						do {
14191							int i = bstride;
14192							do {
14193								*dst++ = byte_reverse(*src++);
14194								*dst++ = byte_reverse(*src++);
14195								i -= 2;
14196							} while (i);
14197							src += src_stride;
14198						} while (--bh);
14199					} else {
14200						if (!kgem_check_batch(&sna->kgem, 10) ||
14201						    !kgem_check_bo_fenced(&sna->kgem, bo) ||
14202						    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
14203							kgem_submit(&sna->kgem);
14204							if (!kgem_check_bo_fenced(&sna->kgem, bo))
14205								return false;
14206							_kgem_set_mode(&sna->kgem, KGEM_BLT);
14207						}
14208						kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
14209
14210						upload = kgem_create_buffer(&sna->kgem,
14211									    bstride*bh,
14212									    KGEM_BUFFER_WRITE_INPLACE,
14213									    &ptr);
14214						if (!upload)
14215							break;
14216
14217						if (sigtrap_get() == 0) {
14218							dst = ptr;
14219							assert(stipple->devKind);
14220							src_stride = stipple->devKind;
14221							src = stipple->devPrivate.ptr;
14222							src += (box.y1 - pat.y) * src_stride + bx1/8;
14223							src_stride -= bstride;
14224							do {
14225								int i = bstride;
14226								do {
14227									*dst++ = byte_reverse(*src++);
14228									*dst++ = byte_reverse(*src++);
14229									i -= 2;
14230								} while (i);
14231								src += src_stride;
14232							} while (--bh);
14233
14234							assert(sna->kgem.mode == KGEM_BLT);
14235							b = sna->kgem.batch + sna->kgem.nbatch;
14236							if (sna->kgem.gen >= 0100) {
14237								b[0] = XY_MONO_SRC_COPY | br00 | 8;
14238								b[0] |= ((box.x1 - pat.x) & 7) << 17;
14239								b[1] = br13;
14240								b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
14241								b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
14242								*(uint64_t *)(b+4) =
14243									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14244											I915_GEM_DOMAIN_RENDER << 16 |
14245											I915_GEM_DOMAIN_RENDER |
14246											KGEM_RELOC_FENCED,
14247											0);
14248								*(uint64_t *)(b+6) =
14249									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
14250											I915_GEM_DOMAIN_RENDER << 16 |
14251											KGEM_RELOC_FENCED,
14252											0);
14253								b[8] = gc->bgPixel;
14254								b[9] = gc->fgPixel;
14255								sna->kgem.nbatch += 10;
14256							} else {
14257								b[0] = XY_MONO_SRC_COPY | br00 | 6;
14258								b[0] |= ((box.x1 - pat.x) & 7) << 17;
14259								b[1] = br13;
14260								b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
14261								b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
14262								b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14263										I915_GEM_DOMAIN_RENDER << 16 |
14264										I915_GEM_DOMAIN_RENDER |
14265										KGEM_RELOC_FENCED,
14266										0);
14267								b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
14268										I915_GEM_DOMAIN_RENDER << 16 |
14269										KGEM_RELOC_FENCED,
14270										0);
14271								b[6] = gc->bgPixel;
14272								b[7] = gc->fgPixel;
14273
14274								sna->kgem.nbatch += 8;
14275							}
14276							sigtrap_put();
14277						}
14278						kgem_bo_destroy(&sna->kgem, upload);
14279					}
14280				}
14281			} while (--n);
14282
14283		}
14284	}
14285
14286	blt_done(sna);
14287	return true;
14288}
14289
14290static void
14291sna_poly_fill_rect_stippled_n_box__imm(struct sna *sna,
14292				       struct kgem_bo *bo,
14293				       uint32_t br00, uint32_t br13,
14294				       const GC *gc,
14295				       const BoxRec *box,
14296				       const DDXPointRec *origin)
14297{
14298	int x1, x2, y1, y2;
14299	uint32_t *b;
14300
14301	for (y1 = box->y1; y1 < box->y2; y1 = y2) {
14302		int oy = (y1 - origin->y) % gc->stipple->drawable.height;
14303		if (oy < 0)
14304			oy += gc->stipple->drawable.height;
14305
14306		y2 = box->y2;
14307		if (y2 - y1 > gc->stipple->drawable.height - oy)
14308			y2 = y1 + gc->stipple->drawable.height - oy;
14309
14310		for (x1 = box->x1; x1 < box->x2; x1 = x2) {
14311			int bx1, bx2, bw, bh, len, ox;
14312			uint8_t *dst, *src;
14313
14314			x2 = box->x2;
14315			ox = (x1 - origin->x) % gc->stipple->drawable.width;
14316			if (ox < 0)
14317				ox += gc->stipple->drawable.width;
14318			bx1 = ox & ~7;
14319			bx2 = ox + (x2 - x1);
14320			if (bx2 > gc->stipple->drawable.width) {
14321				bx2 = gc->stipple->drawable.width;
14322				x2 = x1 + bx2-ox;
14323			}
14324			bw = (bx2 - bx1 + 7)/8;
14325			bw = ALIGN(bw, 2);
14326			bh = y2 - y1;
14327
14328			DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d\n",
14329			     __FUNCTION__,
14330			     x1, y1, x2-x1, y2-y1,
14331			     origin->x, origin->y,
14332			     ox, oy, bx1, bx2,
14333			     gc->stipple->drawable.width,
14334			     gc->stipple->drawable.height));
14335
14336			len = bw*bh;
14337			len = ALIGN(len, 8) / 4;
14338			assert(len > 0);
14339			assert(len <= 32);
14340			if (!kgem_check_batch(&sna->kgem, 8+len) ||
14341			    !kgem_check_bo_fenced(&sna->kgem, bo) ||
14342			    !kgem_check_reloc(&sna->kgem, 1)) {
14343				kgem_submit(&sna->kgem);
14344				if (!kgem_check_bo_fenced(&sna->kgem, bo))
14345					return; /* XXX fallback? */
14346				_kgem_set_mode(&sna->kgem, KGEM_BLT);
14347			}
14348			kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
14349
14350			assert(sna->kgem.mode == KGEM_BLT);
14351			b = sna->kgem.batch + sna->kgem.nbatch;
14352			if (sna->kgem.gen >= 0100) {
14353				b[0] = br00 | (6 + len) | (ox & 7) << 17;
14354				b[1] = br13;
14355				b[2] = y1 << 16 | x1;
14356				b[3] = y2 << 16 | x2;
14357				*(uint64_t *)(b+4) =
14358					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14359							 I915_GEM_DOMAIN_RENDER << 16 |
14360							 I915_GEM_DOMAIN_RENDER |
14361							 KGEM_RELOC_FENCED,
14362							 0);
14363				b[6] = gc->bgPixel;
14364				b[7] = gc->fgPixel;
14365				dst = (uint8_t *)&b[8];
14366				sna->kgem.nbatch += 8 + len;
14367			} else {
14368				b[0] = br00 | (5 + len) | (ox & 7) << 17;
14369				b[1] = br13;
14370				b[2] = y1 << 16 | x1;
14371				b[3] = y2 << 16 | x2;
14372				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14373						      I915_GEM_DOMAIN_RENDER << 16 |
14374						      I915_GEM_DOMAIN_RENDER |
14375						      KGEM_RELOC_FENCED,
14376						      0);
14377				b[5] = gc->bgPixel;
14378				b[6] = gc->fgPixel;
14379				dst = (uint8_t *)&b[7];
14380				sna->kgem.nbatch += 7 + len;
14381			}
14382
14383			assert(gc->stipple->devKind);
14384			len = gc->stipple->devKind;
14385			src = gc->stipple->devPrivate.ptr;
14386			src += oy*len + ox/8;
14387			len -= bw;
14388			do {
14389				int i = bw;
14390				do {
14391					*dst++ = byte_reverse(*src++);
14392					*dst++ = byte_reverse(*src++);
14393					i -= 2;
14394				} while (i);
14395				src += len;
14396			} while (--bh);
14397		}
14398	}
14399}
14400
14401static void
14402sna_poly_fill_rect_stippled_n_box(struct sna *sna,
14403				  struct kgem_bo *bo,
14404				  struct kgem_bo **tile,
14405				  uint32_t br00, uint32_t br13,
14406				  const GC *gc,
14407				  const BoxRec *box,
14408				  const DDXPointRec *origin)
14409{
14410	int x1, x2, y1, y2;
14411	int w = gc->stipple->drawable.width;
14412	int h = gc->stipple->drawable.height;
14413	int stride = gc->stipple->devKind;
14414	uint32_t *b;
14415
14416	assert(stride);
14417	if ((((box->y2-box->y1) | (box->x2-box->x1)) & ~31) == 0) {
14418		br00 = XY_MONO_SRC_COPY_IMM |(br00 & (BLT_DST_TILED | 3 << 20));
14419		sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
14420						       br00, br13, gc,
14421						       box, origin);
14422		return;
14423	}
14424
14425	for (y1 = box->y1; y1 < box->y2; y1 = y2) {
14426		int row, oy = (y1 - origin->y) % gc->stipple->drawable.height;
14427		if (oy < 0)
14428			oy += h;
14429
14430		y2 = box->y2;
14431		if (y2 - y1 > h - oy)
14432			y2 = y1 + h - oy;
14433
14434		row = oy * stride;
14435		for (x1 = box->x1; x1 < box->x2; x1 = x2) {
14436			int bx1, bx2, bw, bh, len, ox;
14437			bool use_tile;
14438
14439			x2 = box->x2;
14440			ox = (x1 - origin->x) % w;
14441			if (ox < 0)
14442				ox += w;
14443			bx1 = ox & ~7;
14444			bx2 = ox + (x2 - x1);
14445			if (bx2 > w) {
14446				bx2 = w;
14447				x2 = x1 + bx2-ox;
14448			}
14449
14450			use_tile = y2-y1 == h && x2-x1 == w;
14451
14452			DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d, full tile?=%d\n",
14453			     __FUNCTION__,
14454			     x1, y1, x2-x1, y2-y1,
14455			     origin->x, origin->y,
14456			     ox, oy, bx1, bx2, w, h,
14457			     use_tile));
14458
14459			bw = (bx2 - bx1 + 7)/8;
14460			bw = ALIGN(bw, 2);
14461			bh = y2 - y1;
14462
14463			len = bw*bh;
14464			len = ALIGN(len, 8) / 4;
14465			assert(len > 0);
14466			if (!kgem_check_batch(&sna->kgem, 8+len) ||
14467			    !kgem_check_bo_fenced(&sna->kgem, bo) ||
14468			    !kgem_check_reloc(&sna->kgem, 2)) {
14469				kgem_submit(&sna->kgem);
14470				if (!kgem_check_bo_fenced(&sna->kgem, bo))
14471					return; /* XXX fallback? */
14472				_kgem_set_mode(&sna->kgem, KGEM_BLT);
14473			}
14474			kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
14475
14476			assert(sna->kgem.mode == KGEM_BLT);
14477			b = sna->kgem.batch + sna->kgem.nbatch;
14478
14479			if (!use_tile && len <= 32) {
14480				uint8_t *dst, *src;
14481
14482				if (sna->kgem.gen >= 0100) {
14483					b[0] = XY_MONO_SRC_COPY_IMM;
14484					b[0] |= (br00 & (BLT_DST_TILED | 3 << 20));
14485					b[0] |= (ox & 7) << 17;
14486					b[0] |= (6 + len);
14487					b[1] = br13;
14488					b[2] = y1 << 16 | x1;
14489					b[3] = y2 << 16 | x2;
14490					*(uint64_t *)(b+4) =
14491						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14492								 I915_GEM_DOMAIN_RENDER << 16 |
14493								 I915_GEM_DOMAIN_RENDER |
14494								 KGEM_RELOC_FENCED,
14495								 0);
14496					b[6] = gc->bgPixel;
14497					b[7] = gc->fgPixel;
14498
14499					dst = (uint8_t *)&b[8];
14500					sna->kgem.nbatch += 8 + len;
14501				} else {
14502					b[0] = XY_MONO_SRC_COPY_IMM;
14503					b[0] |= (br00 & (BLT_DST_TILED | 3 << 20));
14504					b[0] |= (ox & 7) << 17;
14505					b[0] |= (5 + len);
14506					b[1] = br13;
14507					b[2] = y1 << 16 | x1;
14508					b[3] = y2 << 16 | x2;
14509					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14510							      I915_GEM_DOMAIN_RENDER << 16 |
14511							      I915_GEM_DOMAIN_RENDER |
14512							      KGEM_RELOC_FENCED,
14513							      0);
14514					b[5] = gc->bgPixel;
14515					b[6] = gc->fgPixel;
14516
14517					dst = (uint8_t *)&b[7];
14518					sna->kgem.nbatch += 7 + len;
14519				}
14520
14521				assert(gc->stipple->devKind);
14522				len = gc->stipple->devKind;
14523				src = gc->stipple->devPrivate.ptr;
14524				src += oy*len + ox/8;
14525				len -= bw;
14526				do {
14527					int i = bw;
14528					do {
14529						*dst++ = byte_reverse(*src++);
14530						*dst++ = byte_reverse(*src++);
14531						i -= 2;
14532					} while (i);
14533					src += len;
14534				} while (--bh);
14535			} else {
14536				bool has_tile = use_tile && *tile;
14537				struct kgem_bo *upload;
14538				uint8_t *dst, *src;
14539				void *ptr;
14540
14541				if (has_tile) {
14542					upload = kgem_bo_reference(*tile);
14543				} else {
14544					upload = kgem_create_buffer(&sna->kgem, bw*bh,
14545								    KGEM_BUFFER_WRITE_INPLACE,
14546								    &ptr);
14547					if (!upload)
14548						return;
14549				}
14550
14551				assert(sna->kgem.mode == KGEM_BLT);
14552				b = sna->kgem.batch + sna->kgem.nbatch;
14553				if (sna->kgem.gen >= 0100) {
14554					b[0] = br00 | (ox & 7) << 17 | 8;
14555					b[1] = br13;
14556					b[2] = y1 << 16 | x1;
14557					b[3] = y2 << 16 | x2;
14558					*(uint64_t *)(b+4) =
14559						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14560								 I915_GEM_DOMAIN_RENDER << 16 |
14561								 I915_GEM_DOMAIN_RENDER |
14562								 KGEM_RELOC_FENCED,
14563								 0);
14564					*(uint64_t *)(b+6) =
14565						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
14566							       I915_GEM_DOMAIN_RENDER << 16 |
14567							       KGEM_RELOC_FENCED,
14568							       0);
14569					b[8] = gc->bgPixel;
14570					b[9] = gc->fgPixel;
14571					sna->kgem.nbatch += 10;
14572				} else {
14573					b[0] = br00 | (ox & 7) << 17 | 6;
14574					b[1] = br13;
14575					b[2] = y1 << 16 | x1;
14576					b[3] = y2 << 16 | x2;
14577					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14578							      I915_GEM_DOMAIN_RENDER << 16 |
14579							      I915_GEM_DOMAIN_RENDER |
14580							      KGEM_RELOC_FENCED,
14581							      0);
14582					b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
14583							      I915_GEM_DOMAIN_RENDER << 16 |
14584							      KGEM_RELOC_FENCED,
14585							      0);
14586					b[6] = gc->bgPixel;
14587					b[7] = gc->fgPixel;
14588					sna->kgem.nbatch += 8;
14589				}
14590
14591				if (!has_tile) {
14592					dst = ptr;
14593					len = stride;
14594					src = gc->stipple->devPrivate.ptr;
14595					src += row + (ox >> 3);
14596					len -= bw;
14597					do {
14598						int i = bw;
14599						do {
14600							*dst++ = byte_reverse(*src++);
14601							*dst++ = byte_reverse(*src++);
14602							i -= 2;
14603						} while (i);
14604						src += len;
14605					} while (--bh);
14606					if (use_tile)
14607						*tile = kgem_bo_reference(upload);
14608				}
14609
14610				kgem_bo_destroy(&sna->kgem, upload);
14611			}
14612		}
14613	}
14614}
14615
14616static bool
14617sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable,
14618				       struct kgem_bo *bo,
14619				       struct sna_damage **damage,
14620				       GCPtr gc, int n, xRectangle *r,
14621				       const BoxRec *extents, unsigned clipped)
14622{
14623	PixmapPtr pixmap = get_drawable_pixmap(drawable);
14624	struct sna *sna = to_sna_from_pixmap(pixmap);
14625	DDXPointRec origin = gc->patOrg;
14626	int16_t dx, dy;
14627	uint32_t br00, br13;
14628
14629	DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__,
14630	     extents->x1, extents->y1,
14631	     extents->x2, extents->y2,
14632	     origin.x, origin.y,
14633	     clipped, gc->alu, gc->fillStyle == FillOpaqueStippled));
14634
14635	get_drawable_deltas(drawable, pixmap, &dx, &dy);
14636	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
14637	assert(kgem_bo_can_blt(&sna->kgem, bo));
14638	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
14639
14640	br00 = XY_MONO_SRC_COPY_IMM | 3 << 20;
14641	br13 = bo->pitch;
14642	if (sna->kgem.gen >= 040 && bo->tiling) {
14643		br00 |= BLT_DST_TILED;
14644		br13 >>= 2;
14645	}
14646	br13 |= (gc->fillStyle == FillStippled) << 29;
14647	br13 |= blt_depth(drawable->depth) << 24;
14648	br13 |= copy_ROP[gc->alu] << 16;
14649
14650	origin.x += dx + drawable->x;
14651	origin.y += dy + drawable->y;
14652
14653	if (!clipped) {
14654		dx += drawable->x;
14655		dy += drawable->y;
14656
14657		sna_damage_add_rectangles(damage, r, n, dx, dy);
14658		do {
14659			BoxRec box;
14660
14661			box.x1 = r->x + dx;
14662			box.y1 = r->y + dy;
14663			box.x2 = box.x1 + r->width;
14664			box.y2 = box.y1 + r->height;
14665
14666			sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
14667							       br00, br13, gc,
14668							       &box, &origin);
14669			r++;
14670		} while (--n);
14671	} else {
14672		RegionRec clip;
14673
14674		region_set(&clip, extents);
14675		if (!region_maybe_clip(&clip, gc->pCompositeClip)) {
14676			DBG(("%s: all clipped\n", __FUNCTION__));
14677			return true;
14678		}
14679
14680		if (clip.data == NULL) {
14681			DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n",
14682			     __FUNCTION__,
14683			     clip.extents.x1, clip.extents.y1,
14684			     clip.extents.x2, clip.extents.y2));
14685			do {
14686				BoxRec box;
14687
14688				box.x1 = r->x + drawable->x;
14689				box.x2 = bound(box.x1, r->width);
14690				box.y1 = r->y + drawable->y;
14691				box.y2 = bound(box.y1, r->height);
14692				r++;
14693
14694				DBG(("%s: box (%d, %d), (%d, %d)\n",
14695				     __FUNCTION__,
14696				     box.x1, box.y1, box.x2, box.y2));
14697				if (!box_intersect(&box, &clip.extents))
14698					continue;
14699
14700				box.x1 += dx; box.x2 += dx;
14701				box.y1 += dy; box.y2 += dy;
14702
14703				sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
14704								       br00, br13, gc,
14705								       &box, &origin);
14706			} while (--n);
14707		} else {
14708			const BoxRec * const clip_start = RegionBoxptr(&clip);
14709			const BoxRec * const clip_end = clip_start + clip.data->numRects;
14710			const BoxRec *c;
14711
14712			DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__,
14713			     clip_start->x1, clip_start->y1,
14714			     clip_start->x2, clip_start->y2,
14715			     clip_end->x1, clip_end->y1,
14716			     clip_end->x2, clip_end->y2));
14717			do {
14718				BoxRec unclipped;
14719
14720				unclipped.x1 = r->x + drawable->x;
14721				unclipped.x2 = bound(unclipped.x1, r->width);
14722				unclipped.y1 = r->y + drawable->y;
14723				unclipped.y2 = bound(unclipped.y1, r->height);
14724				r++;
14725
14726				c = find_clip_box_for_y(clip_start,
14727							clip_end,
14728							unclipped.y1);
14729				while (c != clip_end) {
14730					BoxRec box;
14731
14732					if (unclipped.y2 <= c->y1)
14733						break;
14734
14735					box = unclipped;
14736					if (!box_intersect(&box, c++))
14737						continue;
14738
14739					box.x1 += dx; box.x2 += dx;
14740					box.y1 += dy; box.y2 += dy;
14741
14742					sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
14743									       br00, br13, gc,
14744									       &box, &origin);
14745				}
14746			} while (--n);
14747		}
14748	}
14749
14750	assert_pixmap_damage(pixmap);
14751	blt_done(sna);
14752	return true;
14753}
14754
14755static bool
14756sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable,
14757				  struct kgem_bo *bo,
14758				  struct sna_damage **damage,
14759				  GCPtr gc, int n, xRectangle *r,
14760				  const BoxRec *extents, unsigned clipped)
14761{
14762	PixmapPtr pixmap = get_drawable_pixmap(drawable);
14763	struct sna *sna = to_sna_from_pixmap(pixmap);
14764	DDXPointRec origin = gc->patOrg;
14765	struct kgem_bo *tile = NULL;
14766	int16_t dx, dy;
14767	uint32_t br00, br13;
14768
14769	DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__,
14770	     extents->x1, extents->y1,
14771	     extents->x2, extents->y2,
14772	     origin.x, origin.y,
14773	     clipped, gc->alu, gc->fillStyle == FillOpaqueStippled));
14774
14775	if (((gc->stipple->drawable.width | gc->stipple->drawable.height) & ~31) == 0)
14776		return sna_poly_fill_rect_stippled_n_blt__imm(drawable,
14777							      bo, damage,
14778							      gc, n, r,
14779							      extents, clipped);
14780
14781	get_drawable_deltas(drawable, pixmap, &dx, &dy);
14782	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
14783	assert(kgem_bo_can_blt(&sna->kgem, bo));
14784	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
14785
14786	br00 = XY_MONO_SRC_COPY | 3 << 20;
14787	br13 = bo->pitch;
14788	if (sna->kgem.gen >= 040 && bo->tiling) {
14789		br00 |= BLT_DST_TILED;
14790		br13 >>= 2;
14791	}
14792	br13 |= (gc->fillStyle == FillStippled) << 29;
14793	br13 |= blt_depth(drawable->depth) << 24;
14794	br13 |= copy_ROP[gc->alu] << 16;
14795
14796	origin.x += dx + drawable->x;
14797	origin.y += dy + drawable->y;
14798
14799	if (!clipped) {
14800		dx += drawable->x;
14801		dy += drawable->y;
14802
14803		sna_damage_add_rectangles(damage, r, n, dx, dy);
14804		do {
14805			BoxRec box;
14806
14807			box.x1 = r->x + dx;
14808			box.y1 = r->y + dy;
14809			box.x2 = box.x1 + r->width;
14810			box.y2 = box.y1 + r->height;
14811
14812			sna_poly_fill_rect_stippled_n_box(sna, bo, &tile,
14813							  br00, br13, gc,
14814							  &box, &origin);
14815			r++;
14816		} while (--n);
14817	} else {
14818		RegionRec clip;
14819
14820		region_set(&clip, extents);
14821		if (!region_maybe_clip(&clip, gc->pCompositeClip)) {
14822			DBG(("%s: all clipped\n", __FUNCTION__));
14823			return true;
14824		}
14825
14826		if (clip.data == NULL) {
14827			DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n",
14828			     __FUNCTION__,
14829			     clip.extents.x1, clip.extents.y1,
14830			     clip.extents.x2, clip.extents.y2));
14831			do {
14832				BoxRec box;
14833
14834				box.x1 = r->x + drawable->x;
14835				box.x2 = bound(box.x1, r->width);
14836				box.y1 = r->y + drawable->y;
14837				box.y2 = bound(box.y1, r->height);
14838				r++;
14839
14840				DBG(("%s: box (%d, %d), (%d, %d)\n",
14841				     __FUNCTION__,
14842				     box.x1, box.y1, box.x2, box.y2));
14843				if (!box_intersect(&box, &clip.extents))
14844					continue;
14845
14846				box.x1 += dx; box.x2 += dx;
14847				box.y1 += dy; box.y2 += dy;
14848
14849				sna_poly_fill_rect_stippled_n_box(sna, bo, &tile,
14850								  br00, br13, gc,
14851								  &box, &origin);
14852			} while (--n);
14853		} else {
14854			const BoxRec * const clip_start = RegionBoxptr(&clip);
14855			const BoxRec * const clip_end = clip_start + clip.data->numRects;
14856			const BoxRec *c;
14857
14858			DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__,
14859			     clip_start->x1, clip_start->y1,
14860			     clip_start->x2, clip_start->y2,
14861			     clip_end->x1, clip_end->y1,
14862			     clip_end->x2, clip_end->y2));
14863			do {
14864				BoxRec unclipped;
14865
14866				unclipped.x1 = r->x + drawable->x;
14867				unclipped.x2 = bound(unclipped.x1, r->width);
14868				unclipped.y1 = r->y + drawable->y;
14869				unclipped.y2 = bound(unclipped.y1, r->height);
14870				r++;
14871
14872				c = find_clip_box_for_y(clip_start,
14873							clip_end,
14874							unclipped.y1);
14875				while (c != clip_end) {
14876					BoxRec box;
14877
14878					if (unclipped.y2 <= c->y1)
14879						break;
14880
14881					box = unclipped;
14882					if (!box_intersect(&box, c++))
14883						continue;
14884
14885					box.x1 += dx; box.x2 += dx;
14886					box.y1 += dy; box.y2 += dy;
14887
14888					sna_poly_fill_rect_stippled_n_box(sna, bo, &tile,
14889									  br00, br13, gc,
14890									  &box, &origin);
14891				}
14892			} while (--n);
14893		}
14894	}
14895
14896	assert_pixmap_damage(pixmap);
14897	if (tile)
14898		kgem_bo_destroy(&sna->kgem, tile);
14899	blt_done(sna);
14900	return true;
14901}
14902
14903static bool
14904sna_poly_fill_rect_stippled_blt(DrawablePtr drawable,
14905				struct kgem_bo *bo,
14906				struct sna_damage **damage,
14907				GCPtr gc, int n, xRectangle *rect,
14908				const BoxRec *extents, unsigned clipped)
14909{
14910
14911	PixmapPtr stipple = gc->stipple;
14912	PixmapPtr pixmap = get_drawable_pixmap(drawable);
14913
14914	if (bo->tiling == I915_TILING_Y) {
14915		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
14916		/* This is cheating, but only the gpu_bo can be tiled */
14917		assert(bo == __sna_pixmap_get_bo(pixmap));
14918		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
14919		if (bo == NULL) {
14920			DBG(("%s: fallback -- unable to change tiling\n",
14921			     __FUNCTION__));
14922			return false;
14923		}
14924	}
14925
14926	if (!kgem_bo_can_blt(&to_sna_from_pixmap(pixmap)->kgem, bo))
14927		return false;
14928
14929	if (!sna_drawable_move_to_cpu(&stipple->drawable, MOVE_READ))
14930		return false;
14931
14932	DBG(("%s: origin (%d, %d), extents (stipple): (%d, %d), stipple size %dx%d\n",
14933	     __FUNCTION__, gc->patOrg.x, gc->patOrg.y,
14934	     extents->x2 - gc->patOrg.x - drawable->x,
14935	     extents->y2 - gc->patOrg.y - drawable->y,
14936	     stipple->drawable.width, stipple->drawable.height));
14937
14938	if ((stipple->drawable.width | stipple->drawable.height) == 8)
14939		return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage,
14940							   gc, n, rect,
14941							   extents, clipped);
14942
14943	if ((stipple->drawable.width | stipple->drawable.height) <= 0xc &&
14944	    is_power_of_two(stipple->drawable.width) &&
14945	    is_power_of_two(stipple->drawable.height))
14946		return sna_poly_fill_rect_stippled_nxm_blt(drawable, bo, damage,
14947							   gc, n, rect,
14948							   extents, clipped);
14949
14950	if (extents->x1 - gc->patOrg.x - drawable->x >= 0 &&
14951	    extents->x2 - gc->patOrg.x - drawable->x <= stipple->drawable.width &&
14952	    extents->y1 - gc->patOrg.y - drawable->y >= 0 &&
14953	    extents->y2 - gc->patOrg.y - drawable->y <= stipple->drawable.height) {
14954		if (stipple->drawable.width <= 8 && stipple->drawable.height <= 8)
14955			return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage,
14956								   gc, n, rect,
14957								   extents, clipped);
14958		else
14959			return sna_poly_fill_rect_stippled_1_blt(drawable, bo, damage,
14960								 gc, n, rect,
14961								 extents, clipped);
14962	} else {
14963		return sna_poly_fill_rect_stippled_n_blt(drawable, bo, damage,
14964							 gc, n, rect,
14965							 extents, clipped);
14966	}
14967}
14968
14969static unsigned
14970sna_poly_fill_rect_extents(DrawablePtr drawable, GCPtr gc,
14971			   int *_n, xRectangle **_r,
14972			   BoxPtr out)
14973{
14974	int n;
14975	xRectangle *r;
14976	Box32Rec box;
14977	bool clipped;
14978
14979	if (*_n == 0)
14980		return 0;
14981
14982	DBG(("%s: [0] = (%d, %d)x(%d, %d)\n",
14983	     __FUNCTION__, (*_r)->x, (*_r)->y, (*_r)->width, (*_r)->height));
14984
14985	/* Remove any zero-size rectangles from the array */
14986	while (*_n && ((*_r)->width == 0 || (*_r)->height == 0))
14987		--*_n, ++*_r;
14988
14989	if (*_n == 0)
14990		return 0;
14991
14992	n = *_n;
14993	r = *_r;
14994
14995	box.x1 = r->x;
14996	box.x2 = box.x1 + r->width;
14997	box.y1 = r->y;
14998	box.y2 = box.y1 + r->height;
14999	r++;
15000
15001	while (--n) {
15002		if (r->width == 0 || r->height == 0)
15003			goto slow;
15004
15005		box32_add_rect(&box, r++);
15006	}
15007	goto done;
15008slow:
15009	{
15010		xRectangle *rr = r;
15011		do {
15012			do {
15013				--*_n, r++;
15014			} while (--n && (r->width == 0 || r->height == 0));
15015			while (n && r->width && r->height) {
15016				box32_add_rect(&box, r);
15017				*rr++ = *r++;
15018				n--;
15019			}
15020		} while (n);
15021	}
15022done:
15023
15024	clipped = box32_trim_and_translate(&box, drawable, gc);
15025	if (!box32_to_box16(&box, out))
15026		return 0;
15027
15028	return 1 | clipped << 1;
15029}
15030
15031static void
15032sna_poly_fill_rect(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect)
15033{
15034	PixmapPtr pixmap = get_drawable_pixmap(draw);
15035	struct sna *sna = to_sna_from_pixmap(pixmap);
15036	struct sna_pixmap *priv = sna_pixmap(pixmap);
15037	struct sna_damage **damage;
15038	struct kgem_bo *bo;
15039	RegionRec region;
15040	unsigned flags, hint;
15041	uint32_t color;
15042
15043	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
15044	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
15045	     (gc->fillStyle == FillSolid ||
15046	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
15047	     gc->fillStyle, gc->tileIsPixel,
15048	     gc->alu));
15049
15050	flags = sna_poly_fill_rect_extents(draw, gc, &n, &rect, &region.extents);
15051	if (flags == 0) {
15052		DBG(("%s, nothing to do\n", __FUNCTION__));
15053		return;
15054	}
15055
15056	DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
15057	     region.extents.x1, region.extents.y1,
15058	     region.extents.x2, region.extents.y2,
15059	     flags));
15060
15061	if (FORCE_FALLBACK || !ACCEL_POLY_FILL_RECT) {
15062		DBG(("%s: fallback forced\n", __FUNCTION__));
15063		goto fallback;
15064	}
15065
15066	if (priv == NULL) {
15067		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
15068		goto fallback;
15069	}
15070
15071	if (wedged(sna)) {
15072		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
15073		goto fallback;
15074	}
15075
15076	if (!PM_IS_SOLID(draw, gc->planemask)) {
15077		DBG(("%s: fallback -- planemask=0x%lx (not-solid)\n",
15078		     __FUNCTION__, gc->planemask));
15079		goto fallback;
15080	}
15081
15082	if (alu_overwrites(gc->alu))
15083		flags |= OVERWRITES;
15084
15085	/* Clear the cpu damage so that we refresh the GPU status of the
15086	 * pixmap upon a redraw after a period of inactivity.
15087	 */
15088	hint = PREFER_GPU;
15089	if (n == 1 && gc->fillStyle != FillStippled && flags & OVERWRITES) {
15090		int16_t dx, dy;
15091
15092		region.data = NULL;
15093
15094		if (get_drawable_deltas(draw, pixmap, &dx, &dy)) {
15095			DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy));
15096			RegionTranslate(&region, dx, dy);
15097		}
15098
15099		if ((flags & IS_CLIPPED) == 0) {
15100			hint |= IGNORE_DAMAGE;
15101			if (region_subsumes_drawable(&region, &pixmap->drawable)) {
15102				discard_cpu_damage(sna, priv);
15103				hint |= REPLACES;
15104			} else {
15105				if (priv->cpu_damage &&
15106				    region_subsumes_damage(&region, priv->cpu_damage))
15107					discard_cpu_damage(sna, priv);
15108			}
15109		}
15110		if (priv->cpu_damage == NULL) {
15111			if (priv->gpu_bo &&
15112			    (hint & REPLACES ||
15113			     box_covers_pixmap(pixmap, &region.extents) ||
15114			     box_inplace(pixmap, &region.extents))) {
15115				DBG(("%s: promoting to full GPU\n",
15116				     __FUNCTION__));
15117				assert(priv->gpu_bo->proxy == NULL);
15118				sna_damage_all(&priv->gpu_damage, pixmap);
15119			}
15120			DBG(("%s: dropping last-cpu hint\n", __FUNCTION__));
15121			priv->cpu = false;
15122		}
15123
15124		if (dx | dy)
15125			RegionTranslate(&region, -dx, -dy);
15126	}
15127
15128	/* If the source is already on the GPU, keep the operation on the GPU */
15129	if (gc->fillStyle == FillTiled && !gc->tileIsPixel &&
15130	    sna_pixmap_is_gpu(gc->tile.pixmap)) {
15131		DBG(("%s: source is already on the gpu\n", __FUNCTION__));
15132		hint |= FORCE_GPU;
15133	}
15134
15135	bo = sna_drawable_use_bo(draw, hint, &region.extents, &damage);
15136	if (bo == NULL) {
15137		DBG(("%s: not using GPU, hint=%x\n", __FUNCTION__, hint));
15138		goto fallback;
15139	}
15140	if (hint & REPLACES && UNDO)
15141		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
15142
15143	if (gc_is_solid(gc, &color)) {
15144		DBG(("%s: solid fill [%08x], testing for blt\n",
15145		     __FUNCTION__, color));
15146
15147		if (sna_poly_fill_rect_blt(draw,
15148					   bo, damage,
15149					   gc, color, n, rect,
15150					   &region.extents, flags))
15151			return;
15152	} else if (gc->fillStyle == FillTiled) {
15153		DBG(("%s: tiled fill, testing for blt\n", __FUNCTION__));
15154
15155		if (sna_poly_fill_rect_tiled_blt(draw, bo, damage,
15156						 gc, n, rect,
15157						 &region.extents, flags))
15158			return;
15159	} else {
15160		DBG(("%s: stippled fill, testing for blt\n", __FUNCTION__));
15161
15162		if (sna_poly_fill_rect_stippled_blt(draw, bo, damage,
15163						    gc, n, rect,
15164						    &region.extents, flags))
15165			return;
15166	}
15167
15168fallback:
15169	DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__,
15170	     region.extents.x1, region.extents.y1,
15171	     region.extents.x2, region.extents.y2));
15172	region.data = NULL;
15173	if (!region_maybe_clip(&region, gc->pCompositeClip)) {
15174		DBG(("%s: nothing to do, all clipped\n", __FUNCTION__));
15175		return;
15176	}
15177
15178	if (!sna_gc_move_to_cpu(gc, draw, &region))
15179		goto out;
15180	if (!sna_drawable_move_region_to_cpu(draw, &region,
15181					     drawable_gc_flags(draw, gc, n > 1)))
15182		goto out;
15183
15184	if (sigtrap_get() == 0) {
15185		DBG(("%s: fallback - fbPolyFillRect\n", __FUNCTION__));
15186		fbPolyFillRect(draw, gc, n, rect);
15187		FALLBACK_FLUSH(draw);
15188		sigtrap_put();
15189	}
15190out:
15191	sna_gc_move_to_gpu(gc);
15192	RegionUninit(&region);
15193}
15194
15195static void
15196sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *r)
15197{
15198	struct sna_fill_spans *data = sna_gc(gc)->priv;
15199	uint32_t color;
15200
15201	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
15202	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
15203	     (gc->fillStyle == FillSolid ||
15204	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
15205	     gc->fillStyle, gc->tileIsPixel,
15206	     gc->alu));
15207
15208	assert(PM_IS_SOLID(draw, gc->planemask));
15209	if (n == 0)
15210		return;
15211
15212	/* The mi routines do not attempt to keep the spans it generates
15213	 * within the clip, so we must run them through the clipper.
15214	 */
15215
15216	if (gc_is_solid(gc, &color)) {
15217		(void)sna_poly_fill_rect_blt(draw,
15218					     data->bo, NULL,
15219					     gc, color, n, r,
15220					     &data->region.extents,
15221					     IS_CLIPPED);
15222	} else if (gc->fillStyle == FillTiled) {
15223		(void)sna_poly_fill_rect_tiled_blt(draw,
15224						   data->bo, NULL,
15225						   gc, n, r,
15226						   &data->region.extents,
15227						   IS_CLIPPED);
15228	} else {
15229		(void)sna_poly_fill_rect_stippled_blt(draw,
15230						    data->bo, NULL,
15231						    gc, n, r,
15232						    &data->region.extents,
15233						    IS_CLIPPED);
15234	}
15235}
15236
15237static void
15238sna_poly_fill_arc(DrawablePtr draw, GCPtr gc, int n, xArc *arc)
15239{
15240	struct sna_fill_spans data;
15241	struct sna_pixmap *priv;
15242
15243	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
15244	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
15245	     (gc->fillStyle == FillSolid ||
15246	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
15247	     gc->fillStyle, gc->tileIsPixel,
15248	     gc->alu));
15249
15250	data.flags = sna_poly_arc_extents(draw, gc, n, arc,
15251					  &data.region.extents);
15252	if (data.flags == 0)
15253		return;
15254
15255	DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
15256	     data.region.extents.x1, data.region.extents.y1,
15257	     data.region.extents.x2, data.region.extents.y2,
15258	     data.flags));
15259
15260	data.region.data = NULL;
15261
15262	if (FORCE_FALLBACK)
15263		goto fallback;
15264
15265	if (!ACCEL_POLY_FILL_ARC)
15266		goto fallback;
15267
15268	data.pixmap = get_drawable_pixmap(draw);
15269	data.sna = to_sna_from_pixmap(data.pixmap);
15270	priv = sna_pixmap(data.pixmap);
15271	if (priv == NULL) {
15272		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
15273		goto fallback;
15274	}
15275
15276	if (wedged(data.sna)) {
15277		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
15278		goto fallback;
15279	}
15280
15281	if (!PM_IS_SOLID(draw, gc->planemask))
15282		goto fallback;
15283
15284	if ((data.bo = sna_drawable_use_bo(draw,
15285					   use_fill_spans(draw, gc, &data.region.extents, data.flags),
15286					   &data.region.extents,
15287					   &data.damage))) {
15288		uint32_t color;
15289
15290		get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy);
15291		sna_gc(gc)->priv = &data;
15292
15293		if (gc_is_solid(gc, &color)) {
15294			struct sna_fill_op fill;
15295
15296			if (!sna_fill_init_blt(&fill,
15297					       data.sna, data.pixmap,
15298					       data.bo, gc->alu, color,
15299					       FILL_SPANS))
15300				goto fallback;
15301
15302			data.op = &fill;
15303
15304			if ((data.flags & IS_CLIPPED) == 0) {
15305				if (data.dx | data.dy)
15306					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
15307				else
15308					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
15309			} else {
15310				if (!region_maybe_clip(&data.region,
15311						       gc->pCompositeClip))
15312					return;
15313
15314				if (region_is_singular(&data.region))
15315					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
15316				else
15317					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
15318			}
15319			assert(gc->miTranslate);
15320			gc->ops = &sna_gc_ops__tmp;
15321
15322			miPolyFillArc(draw, gc, n, arc);
15323			fill.done(data.sna, &fill);
15324		} else {
15325			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
15326			gc->ops = &sna_gc_ops__tmp;
15327
15328			miPolyFillArc(draw, gc, n, arc);
15329		}
15330
15331		gc->ops = (GCOps *)&sna_gc_ops;
15332		if (data.damage) {
15333			if (data.dx | data.dy)
15334				pixman_region_translate(&data.region, data.dx, data.dy);
15335			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
15336			sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap);
15337		}
15338		assert_pixmap_damage(data.pixmap);
15339		RegionUninit(&data.region);
15340		return;
15341	}
15342
15343fallback:
15344	DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__,
15345	     data.region.extents.x1, data.region.extents.y1,
15346	     data.region.extents.x2, data.region.extents.y2));
15347	if (!region_maybe_clip(&data.region, gc->pCompositeClip)) {
15348		DBG(("%s: nothing to do, all clipped\n", __FUNCTION__));
15349		return;
15350	}
15351
15352	if (!sna_gc_move_to_cpu(gc, draw, &data.region))
15353		goto out;
15354	if (!sna_drawable_move_region_to_cpu(draw, &data.region,
15355					     drawable_gc_flags(draw, gc, true)))
15356		goto out;
15357
15358	if (sigtrap_get() == 0) {
15359		DBG(("%s: fallback -- miPolyFillArc -> sna_fill_spans__cpu\n",
15360		     __FUNCTION__));
15361		miPolyFillArc(draw, gc, n, arc);
15362		sigtrap_put();
15363	}
15364out:
15365	sna_gc_move_to_gpu(gc);
15366	RegionUninit(&data.region);
15367}
15368
15369struct sna_font {
15370	CharInfoRec glyphs8[256];
15371	CharInfoRec *glyphs16[256];
15372};
15373#define GLYPH_INVALID (void *)1
15374#define GLYPH_EMPTY (void *)2
15375
15376static Bool
15377sna_realize_font(ScreenPtr screen, FontPtr font)
15378{
15379	struct sna_font *priv;
15380
15381	DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key));
15382
15383	priv = calloc(1, sizeof(struct sna_font));
15384	if (priv == NULL)
15385		return FALSE;
15386
15387	if (!FontSetPrivate(font, sna_font_key, priv)) {
15388		free(priv);
15389		return FALSE;
15390	}
15391
15392	return TRUE;
15393}
15394
15395static Bool
15396sna_unrealize_font(ScreenPtr screen, FontPtr font)
15397{
15398	struct sna_font *priv = FontGetPrivate(font, sna_font_key);
15399	int i, j;
15400
15401	DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key));
15402
15403	if (priv == NULL)
15404		return TRUE;
15405
15406	for (i = 0; i < 256; i++) {
15407		if ((uintptr_t)priv->glyphs8[i].bits & ~3)
15408			free(priv->glyphs8[i].bits);
15409	}
15410	for (j = 0; j < 256; j++) {
15411		if (priv->glyphs16[j] == NULL)
15412			continue;
15413
15414		for (i = 0; i < 256; i++) {
15415			if ((uintptr_t)priv->glyphs16[j][i].bits & ~3)
15416				free(priv->glyphs16[j][i].bits);
15417		}
15418		free(priv->glyphs16[j]);
15419	}
15420	free(priv);
15421
15422	FontSetPrivate(font, sna_font_key, NULL);
15423	return TRUE;
15424}
15425
15426static bool
15427sna_glyph_blt(DrawablePtr drawable, GCPtr gc,
15428	      int _x, int _y, unsigned int _n,
15429	      CharInfoPtr *_info,
15430	      RegionRec *clip,
15431	      uint32_t fg, uint32_t bg,
15432	      bool transparent)
15433{
15434	PixmapPtr pixmap = get_drawable_pixmap(drawable);
15435	struct sna *sna = to_sna_from_pixmap(pixmap);
15436	struct kgem_bo *bo;
15437	struct sna_damage **damage;
15438	const BoxRec *extents, *last_extents;
15439	uint32_t *b;
15440	int16_t dx, dy;
15441	uint32_t br00;
15442	uint16_t unwind_batch, unwind_reloc;
15443	unsigned hint;
15444
15445	uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S;
15446
15447	DBG(("%s (%d, %d) x %d, fg=%08x, bg=%08x alu=%02x\n",
15448	     __FUNCTION__, _x, _y, _n, fg, bg, rop));
15449
15450	if (wedged(sna)) {
15451		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
15452		return false;
15453	}
15454
15455	if (!transparent && clip->data == NULL)
15456		hint = PREFER_GPU | IGNORE_DAMAGE;
15457	else
15458		hint = PREFER_GPU;
15459
15460	bo = sna_drawable_use_bo(drawable, hint, &clip->extents, &damage);
15461	if (bo == NULL)
15462		return false;
15463
15464	if (bo->tiling == I915_TILING_Y) {
15465		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
15466		assert(bo == __sna_pixmap_get_bo(pixmap));
15467		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
15468		if (bo == NULL) {
15469			DBG(("%s: fallback -- unable to change tiling\n",
15470			     __FUNCTION__));
15471			return false;
15472		}
15473	}
15474
15475	if (!kgem_bo_can_blt(&sna->kgem, bo))
15476		return false;
15477
15478	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
15479		RegionTranslate(clip, dx, dy);
15480	_x += drawable->x + dx;
15481	_y += drawable->y + dy;
15482
15483	extents = region_rects(clip);
15484	last_extents = extents + region_num_rects(clip);
15485
15486	if (!transparent) { /* emulate miImageGlyphBlt */
15487		if (!sna_blt_fill_boxes(sna, GXcopy,
15488					bo, drawable->bitsPerPixel,
15489					bg, extents, last_extents - extents)) {
15490			RegionTranslate(clip, -dx, -dy);
15491			return false;
15492		}
15493	}
15494
15495	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
15496	assert(kgem_bo_can_blt(&sna->kgem, bo));
15497	if (!kgem_check_batch(&sna->kgem, 20) ||
15498	    !kgem_check_bo_fenced(&sna->kgem, bo) ||
15499	    !kgem_check_reloc(&sna->kgem, 1)) {
15500		kgem_submit(&sna->kgem);
15501		if (!kgem_check_bo_fenced(&sna->kgem, bo)) {
15502			RegionTranslate(clip, -dx, -dy);
15503			return false;
15504		}
15505		_kgem_set_mode(&sna->kgem, KGEM_BLT);
15506	}
15507	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
15508
15509	DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
15510	     __FUNCTION__,
15511	     extents->x1, extents->y1,
15512	     extents->x2, extents->y2));
15513
15514	unwind_batch = sna->kgem.nbatch;
15515	unwind_reloc = sna->kgem.nreloc;
15516
15517	assert(sna->kgem.mode == KGEM_BLT);
15518	b = sna->kgem.batch + sna->kgem.nbatch;
15519	if (sna->kgem.gen >= 0100) {
15520		b[0] = XY_SETUP_BLT | 3 << 20 | 8;
15521		b[1] = bo->pitch;
15522		if (sna->kgem.gen >= 040 && bo->tiling) {
15523			b[0] |= BLT_DST_TILED;
15524			b[1] >>= 2;
15525		}
15526		b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15527		b[2] = extents->y1 << 16 | extents->x1;
15528		b[3] = extents->y2 << 16 | extents->x2;
15529		*(uint64_t *)(b+4) =
15530			kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
15531					 I915_GEM_DOMAIN_RENDER << 16 |
15532					 I915_GEM_DOMAIN_RENDER |
15533					 KGEM_RELOC_FENCED,
15534					 0);
15535		b[6] = bg;
15536		b[7] = fg;
15537		b[8] = 0;
15538		b[9] = 0;
15539		sna->kgem.nbatch += 10;
15540	} else {
15541		b[0] = XY_SETUP_BLT | 3 << 20 | 6;
15542		b[1] = bo->pitch;
15543		if (sna->kgem.gen >= 040 && bo->tiling) {
15544			b[0] |= BLT_DST_TILED;
15545			b[1] >>= 2;
15546		}
15547		b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15548		b[2] = extents->y1 << 16 | extents->x1;
15549		b[3] = extents->y2 << 16 | extents->x2;
15550		b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
15551				      I915_GEM_DOMAIN_RENDER << 16 |
15552				      I915_GEM_DOMAIN_RENDER |
15553				      KGEM_RELOC_FENCED,
15554				      0);
15555		b[5] = bg;
15556		b[6] = fg;
15557		b[7] = 0;
15558		sna->kgem.nbatch += 8;
15559	}
15560
15561	br00 = XY_TEXT_IMMEDIATE_BLT;
15562	if (bo->tiling && sna->kgem.gen >= 040)
15563		br00 |= BLT_DST_TILED;
15564
15565	do {
15566		CharInfoPtr *info = _info;
15567		int x = _x, y = _y, n = _n;
15568
15569		do {
15570			CharInfoPtr c = *info++;
15571			int w = GLYPHWIDTHPIXELS(c);
15572			int h = GLYPHHEIGHTPIXELS(c);
15573			int w8 = (w + 7) >> 3;
15574			int x1, y1, len;
15575
15576			if (c->bits == GLYPH_EMPTY)
15577				goto skip;
15578
15579			len = (w8 * h + 7) >> 3 << 1;
15580			x1 = x + c->metrics.leftSideBearing;
15581			y1 = y - c->metrics.ascent;
15582
15583			DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__,
15584			     x,y, x1, y1, w, w8, h, len));
15585
15586			if (x1 >= extents->x2 || y1 >= extents->y2)
15587				goto skip;
15588			if (x1 + w <= extents->x1 || y1 + h <= extents->y1)
15589				goto skip;
15590
15591			assert(len > 0);
15592			if (!kgem_check_batch(&sna->kgem, 3+len)) {
15593				_kgem_submit(&sna->kgem);
15594				_kgem_set_mode(&sna->kgem, KGEM_BLT);
15595				kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
15596
15597				DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n",
15598				     __FUNCTION__,
15599				     extents->x1, extents->y1,
15600				     extents->x2, extents->y2));
15601
15602				unwind_batch = sna->kgem.nbatch;
15603				unwind_reloc = sna->kgem.nreloc;
15604
15605				assert(sna->kgem.mode == KGEM_BLT);
15606				b = sna->kgem.batch + sna->kgem.nbatch;
15607				if (sna->kgem.gen >= 0100) {
15608					b[0] = XY_SETUP_BLT | 3 << 20 | 8;
15609					b[1] = bo->pitch;
15610					if (bo->tiling) {
15611						b[0] |= BLT_DST_TILED;
15612						b[1] >>= 2;
15613					}
15614					b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15615					b[2] = extents->y1 << 16 | extents->x1;
15616					b[3] = extents->y2 << 16 | extents->x2;
15617					*(uint64_t *)(b+4) =
15618						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
15619								 I915_GEM_DOMAIN_RENDER << 16 |
15620								 I915_GEM_DOMAIN_RENDER |
15621								 KGEM_RELOC_FENCED,
15622								 0);
15623					b[6] = bg;
15624					b[7] = fg;
15625					b[8] = 0;
15626					b[9] = 0;
15627					sna->kgem.nbatch += 10;
15628				} else {
15629					b[0] = XY_SETUP_BLT | 3 << 20 | 6;
15630					b[1] = bo->pitch;
15631					if (sna->kgem.gen >= 040 && bo->tiling) {
15632						b[0] |= BLT_DST_TILED;
15633						b[1] >>= 2;
15634					}
15635					b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15636					b[2] = extents->y1 << 16 | extents->x1;
15637					b[3] = extents->y2 << 16 | extents->x2;
15638					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
15639							      I915_GEM_DOMAIN_RENDER << 16 |
15640							      I915_GEM_DOMAIN_RENDER |
15641							      KGEM_RELOC_FENCED,
15642							      0);
15643					b[5] = bg;
15644					b[6] = fg;
15645					b[7] = 0;
15646					sna->kgem.nbatch += 8;
15647				}
15648			}
15649
15650			assert(sna->kgem.mode == KGEM_BLT);
15651			b = sna->kgem.batch + sna->kgem.nbatch;
15652			sna->kgem.nbatch += 3 + len;
15653
15654			b[0] = br00 | (1 + len);
15655			b[1] = (uint16_t)y1 << 16 | (uint16_t)x1;
15656			b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w);
15657			{
15658				uint64_t *src = (uint64_t *)c->bits;
15659				uint64_t *dst = (uint64_t *)(b + 3);
15660				do  {
15661					*dst++ = *src++;
15662					len -= 2;
15663				} while (len);
15664			}
15665
15666			if (damage) {
15667				BoxRec r;
15668
15669				r.x1 = x1;
15670				r.y1 = y1;
15671				r.x2 = x1 + w;
15672				r.y2 = y1 + h;
15673				if (box_intersect(&r, extents))
15674					sna_damage_add_box(damage, &r);
15675			}
15676skip:
15677			x += c->metrics.characterWidth;
15678		} while (--n);
15679
15680		if (++extents == last_extents)
15681			break;
15682
15683		if (kgem_check_batch(&sna->kgem, 3)) {
15684			assert(sna->kgem.mode == KGEM_BLT);
15685			b = sna->kgem.batch + sna->kgem.nbatch;
15686			sna->kgem.nbatch += 3;
15687
15688			DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
15689			     __FUNCTION__,
15690			     extents->x1, extents->y1,
15691			     extents->x2, extents->y2));
15692
15693			b[0] = XY_SETUP_CLIP;
15694			b[1] = extents->y1 << 16 | extents->x1;
15695			b[2] = extents->y2 << 16 | extents->x2;
15696		}
15697	} while (1);
15698
15699	if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) {
15700		sna->kgem.nbatch = unwind_batch;
15701		sna->kgem.nreloc = unwind_reloc;
15702		if (sna->kgem.nbatch == 0)
15703			kgem_bo_undo(&sna->kgem, bo);
15704	}
15705
15706	assert_pixmap_damage(pixmap);
15707	blt_done(sna);
15708	return true;
15709}
15710
15711static void
15712sna_glyph_extents(FontPtr font,
15713		  CharInfoPtr *info,
15714		  unsigned long count,
15715		  ExtentInfoRec *extents)
15716{
15717	extents->drawDirection = font->info.drawDirection;
15718	extents->fontAscent = font->info.fontAscent;
15719	extents->fontDescent = font->info.fontDescent;
15720
15721	extents->overallAscent = info[0]->metrics.ascent;
15722	extents->overallDescent = info[0]->metrics.descent;
15723	extents->overallLeft = info[0]->metrics.leftSideBearing;
15724	extents->overallRight = info[0]->metrics.rightSideBearing;
15725	extents->overallWidth = info[0]->metrics.characterWidth;
15726
15727	while (--count) {
15728		CharInfoPtr p =*++info;
15729		int v;
15730
15731		if (p->metrics.ascent > extents->overallAscent)
15732			extents->overallAscent = p->metrics.ascent;
15733		if (p->metrics.descent > extents->overallDescent)
15734			extents->overallDescent = p->metrics.descent;
15735
15736		v = extents->overallWidth + p->metrics.leftSideBearing;
15737		if (v < extents->overallLeft)
15738			extents->overallLeft = v;
15739
15740		v = extents->overallWidth + p->metrics.rightSideBearing;
15741		if (v > extents->overallRight)
15742			extents->overallRight = v;
15743
15744		extents->overallWidth += p->metrics.characterWidth;
15745	}
15746}
15747
15748static bool sna_set_glyph(CharInfoPtr in, CharInfoPtr out)
15749{
15750	int w = GLYPHWIDTHPIXELS(in);
15751	int h = GLYPHHEIGHTPIXELS(in);
15752	int stride = GLYPHWIDTHBYTESPADDED(in);
15753	uint8_t *dst, *src;
15754	int clear = 1;
15755
15756	out->metrics = in->metrics;
15757
15758	/* Skip empty glyphs */
15759	if (w == 0 || h == 0 || ((w|h) == 1 && (in->bits[0] & 1) == 0)) {
15760		out->bits = GLYPH_EMPTY;
15761		return true;
15762	}
15763
15764	w = (w + 7) >> 3;
15765
15766	out->bits = malloc((w*h + 7) & ~7);
15767	if (out->bits == NULL)
15768		return false;
15769
15770	VG(memset(out->bits, 0, (w*h + 7) & ~7));
15771	src = (uint8_t *)in->bits;
15772	dst = (uint8_t *)out->bits;
15773	stride -= w;
15774	do {
15775		int i = w;
15776		do {
15777			clear &= *src == 0;
15778			*dst++ = byte_reverse(*src++);
15779		} while (--i);
15780		src += stride;
15781	} while (--h);
15782
15783	if (clear) {
15784		free(out->bits);
15785		out->bits = GLYPH_EMPTY;
15786	}
15787
15788	return true;
15789}
15790
15791inline static bool sna_get_glyph8(FontPtr font, struct sna_font *priv,
15792				  uint8_t g, CharInfoPtr *out)
15793{
15794	unsigned long n;
15795	CharInfoPtr p, ret;
15796
15797	p = &priv->glyphs8[g];
15798	if (p->bits) {
15799		*out = p;
15800		return p->bits != GLYPH_INVALID;
15801	}
15802
15803	font->get_glyphs(font, 1, &g, Linear8Bit, &n, &ret);
15804	if (n == 0) {
15805		p->bits = GLYPH_INVALID;
15806		return false;
15807	}
15808
15809	return sna_set_glyph(ret, *out = p);
15810}
15811
15812inline static bool sna_get_glyph16(FontPtr font, struct sna_font *priv,
15813				   uint16_t g, CharInfoPtr *out)
15814{
15815	unsigned long n;
15816	CharInfoPtr page, p, ret;
15817
15818	page = priv->glyphs16[g>>8];
15819	if (page == NULL)
15820		page = priv->glyphs16[g>>8] = calloc(256, sizeof(CharInfoRec));
15821
15822	p = &page[g&0xff];
15823	if (p->bits) {
15824		*out = p;
15825		return p->bits != GLYPH_INVALID;
15826	}
15827
15828	font->get_glyphs(font, 1, (unsigned char *)&g,
15829			 FONTLASTROW(font) ? TwoD16Bit : Linear16Bit,
15830			 &n, &ret);
15831	if (n == 0) {
15832		p->bits = GLYPH_INVALID;
15833		return false;
15834	}
15835
15836	return sna_set_glyph(ret, *out = p);
15837}
15838
15839static inline bool sna_font_too_large(FontPtr font)
15840{
15841	int top = max(FONTMAXBOUNDS(font, ascent), FONTASCENT(font));
15842	int bot = max(FONTMAXBOUNDS(font, descent), FONTDESCENT(font));
15843	int width = max(FONTMAXBOUNDS(font, characterWidth), -FONTMINBOUNDS(font, characterWidth));
15844	DBG(("%s? (%d + %d) x %d: %d > 124\n", __FUNCTION__,
15845	     top, bot, width, (top + bot) * (width + 7)/8));
15846	return (top + bot) * (width + 7)/8 > 124;
15847}
15848
15849static int
15850sna_poly_text8(DrawablePtr drawable, GCPtr gc,
15851	       int x, int y,
15852	       int count, char *chars)
15853{
15854	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
15855	CharInfoPtr info[255];
15856	ExtentInfoRec extents;
15857	RegionRec region;
15858	long unsigned i, n;
15859	uint32_t fg;
15860
15861	for (i = n = 0; i < count; i++) {
15862		if (sna_get_glyph8(gc->font, priv, chars[i], &info[n]))
15863			n++;
15864	}
15865	if (n == 0)
15866		return x;
15867
15868	sna_glyph_extents(gc->font, info, n, &extents);
15869	region.extents.x1 = x + extents.overallLeft;
15870	region.extents.y1 = y - extents.overallAscent;
15871	region.extents.x2 = x + extents.overallRight;
15872	region.extents.y2 = y + extents.overallDescent;
15873
15874	translate_box(&region.extents, drawable);
15875	clip_box(&region.extents, gc);
15876	if (box_empty(&region.extents))
15877		return x + extents.overallRight;
15878
15879	region.data = NULL;
15880	if (!region_maybe_clip(&region, gc->pCompositeClip))
15881		return x + extents.overallRight;
15882
15883	if (FORCE_FALLBACK)
15884		goto fallback;
15885
15886	if (!ACCEL_POLY_TEXT8)
15887		goto fallback;
15888
15889	if (sna_font_too_large(gc->font))
15890		goto fallback;
15891
15892	if (!PM_IS_SOLID(drawable, gc->planemask))
15893		goto fallback;
15894
15895	if (!gc_is_solid(gc, &fg))
15896		goto fallback;
15897
15898	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region, fg, -1, true)) {
15899fallback:
15900		DBG(("%s: fallback\n", __FUNCTION__));
15901		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
15902				     Linear8Bit, &n, info);
15903
15904		if (!sna_gc_move_to_cpu(gc, drawable, &region))
15905			goto out;
15906		if (!sna_drawable_move_region_to_cpu(drawable, &region,
15907						     MOVE_READ | MOVE_WRITE))
15908			goto out;
15909
15910		if (sigtrap_get() == 0) {
15911			DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
15912			fbPolyGlyphBlt(drawable, gc, x, y, n,
15913				       info, FONTGLYPHS(gc->font));
15914			FALLBACK_FLUSH(drawable);
15915			sigtrap_put();
15916		}
15917out:
15918		sna_gc_move_to_gpu(gc);
15919	}
15920	RegionUninit(&region);
15921	return x + extents.overallRight;
15922}
15923
15924static int
15925sna_poly_text16(DrawablePtr drawable, GCPtr gc,
15926		int x, int y,
15927		int count, unsigned short *chars)
15928{
15929	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
15930	CharInfoPtr info[255];
15931	ExtentInfoRec extents;
15932	RegionRec region;
15933	long unsigned i, n;
15934	uint32_t fg;
15935
15936	for (i = n = 0; i < count; i++) {
15937		if (sna_get_glyph16(gc->font, priv, chars[i], &info[n]))
15938			n++;
15939	}
15940	if (n == 0)
15941		return x;
15942
15943	sna_glyph_extents(gc->font, info, n, &extents);
15944	region.extents.x1 = x + extents.overallLeft;
15945	region.extents.y1 = y - extents.overallAscent;
15946	region.extents.x2 = x + extents.overallRight;
15947	region.extents.y2 = y + extents.overallDescent;
15948
15949	translate_box(&region.extents, drawable);
15950	clip_box(&region.extents, gc);
15951	if (box_empty(&region.extents))
15952		return x + extents.overallRight;
15953
15954	region.data = NULL;
15955	if (!region_maybe_clip(&region, gc->pCompositeClip))
15956		return x + extents.overallRight;
15957
15958	if (FORCE_FALLBACK)
15959		goto fallback;
15960
15961	if (!ACCEL_POLY_TEXT16)
15962		goto fallback;
15963
15964	if (sna_font_too_large(gc->font))
15965		goto fallback;
15966
15967	if (!PM_IS_SOLID(drawable, gc->planemask))
15968		goto fallback;
15969
15970	if (!gc_is_solid(gc, &fg))
15971		goto fallback;
15972
15973	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region, fg, -1, true)) {
15974fallback:
15975		DBG(("%s: fallback\n", __FUNCTION__));
15976		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
15977				     FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit,
15978				     &n, info);
15979
15980		if (!sna_gc_move_to_cpu(gc, drawable, &region))
15981			goto out;
15982		if (!sna_drawable_move_region_to_cpu(drawable, &region,
15983						     MOVE_READ | MOVE_WRITE))
15984			goto out;
15985
15986		if (sigtrap_get() == 0) {
15987			DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
15988			fbPolyGlyphBlt(drawable, gc, x, y, n,
15989				       info, FONTGLYPHS(gc->font));
15990			FALLBACK_FLUSH(drawable);
15991			sigtrap_put();
15992		}
15993out:
15994		sna_gc_move_to_gpu(gc);
15995	}
15996	RegionUninit(&region);
15997	return x + extents.overallRight;
15998}
15999
16000static void
16001sna_image_text8(DrawablePtr drawable, GCPtr gc,
16002		int x, int y,
16003		int count, char *chars)
16004{
16005	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
16006	CharInfoPtr info[255];
16007	ExtentInfoRec extents;
16008	RegionRec region;
16009	long unsigned i, n;
16010
16011	for (i = n = 0; i < count; i++) {
16012		if (sna_get_glyph8(gc->font, priv, chars[i], &info[n]))
16013			n++;
16014	}
16015	if (n == 0)
16016		return;
16017
16018	sna_glyph_extents(gc->font, info, n, &extents);
16019	region.extents.x1 = x + MIN(0, extents.overallLeft);
16020	region.extents.y1 = y - extents.fontAscent;
16021	region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight);
16022	region.extents.y2 = y + extents.fontDescent;
16023
16024	DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n",
16025	     __FUNCTION__, n, count,
16026	     extents.overallLeft, extents.overallRight, extents.overallWidth,
16027	     extents.fontAscent, extents.fontDescent,
16028	     region.extents.x1, region.extents.y1,
16029	     region.extents.x2, region.extents.y2));
16030
16031	translate_box(&region.extents, drawable);
16032	clip_box(&region.extents, gc);
16033	if (box_empty(&region.extents))
16034		return;
16035
16036	region.data = NULL;
16037	if (!region_maybe_clip(&region, gc->pCompositeClip))
16038		return;
16039
16040	DBG(("%s: clipped extents (%d, %d), (%d, %d)\n",
16041	     __FUNCTION__,
16042	     region.extents.x1, region.extents.y1,
16043	     region.extents.x2, region.extents.y2));
16044
16045	if (FORCE_FALLBACK)
16046		goto fallback;
16047
16048	if (!ACCEL_IMAGE_TEXT8)
16049		goto fallback;
16050
16051	if (sna_font_too_large(gc->font))
16052		goto fallback;
16053
16054	if (!PM_IS_SOLID(drawable, gc->planemask))
16055		goto fallback;
16056
16057	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region,
16058			   gc->fgPixel, gc->bgPixel, false)) {
16059fallback:
16060		DBG(("%s: fallback\n", __FUNCTION__));
16061		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
16062				     Linear8Bit, &n, info);
16063
16064		if (!sna_gc_move_to_cpu(gc, drawable, &region))
16065			goto out;
16066		if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_WRITE))
16067			goto out;
16068
16069		if (sigtrap_get() == 0) {
16070			DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
16071			fbImageGlyphBlt(drawable, gc, x, y, n,
16072					info, FONTGLYPHS(gc->font));
16073			FALLBACK_FLUSH(drawable);
16074			sigtrap_put();
16075		}
16076out:
16077		sna_gc_move_to_gpu(gc);
16078	}
16079	RegionUninit(&region);
16080}
16081
16082static void
16083sna_image_text16(DrawablePtr drawable, GCPtr gc,
16084		int x, int y,
16085		int count, unsigned short *chars)
16086{
16087	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
16088	CharInfoPtr info[255];
16089	ExtentInfoRec extents;
16090	RegionRec region;
16091	long unsigned i, n;
16092
16093	for (i = n = 0; i < count; i++) {
16094		if (sna_get_glyph16(gc->font, priv, chars[i], &info[n]))
16095			n++;
16096	}
16097	if (n == 0)
16098		return;
16099
16100	sna_glyph_extents(gc->font, info, n, &extents);
16101	region.extents.x1 = x + MIN(0, extents.overallLeft);
16102	region.extents.y1 = y - extents.fontAscent;
16103	region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight);
16104	region.extents.y2 = y + extents.fontDescent;
16105
16106	DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n",
16107	     __FUNCTION__, n, count,
16108	     extents.overallLeft, extents.overallRight, extents.overallWidth,
16109	     extents.fontAscent, extents.fontDescent,
16110	     region.extents.x1, region.extents.y1,
16111	     region.extents.x2, region.extents.y2));
16112
16113	translate_box(&region.extents, drawable);
16114	clip_box(&region.extents, gc);
16115	if (box_empty(&region.extents))
16116		return;
16117
16118	region.data = NULL;
16119	if (!region_maybe_clip(&region, gc->pCompositeClip))
16120		return;
16121
16122	DBG(("%s: clipped extents (%d, %d), (%d, %d)\n",
16123	     __FUNCTION__,
16124	     region.extents.x1, region.extents.y1,
16125	     region.extents.x2, region.extents.y2));
16126
16127	if (FORCE_FALLBACK)
16128		goto fallback;
16129
16130	if (!ACCEL_IMAGE_TEXT16)
16131		goto fallback;
16132
16133	if (sna_font_too_large(gc->font))
16134		goto fallback;
16135
16136	if (!PM_IS_SOLID(drawable, gc->planemask))
16137		goto fallback;
16138
16139	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region,
16140			   gc->fgPixel, gc->bgPixel, false)) {
16141fallback:
16142		DBG(("%s: fallback\n", __FUNCTION__));
16143		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
16144				     FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit,
16145				     &n, info);
16146
16147		if (!sna_gc_move_to_cpu(gc, drawable, &region))
16148			goto out;
16149		if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_WRITE))
16150			goto out;
16151
16152		if (sigtrap_get() == 0) {
16153			DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
16154			fbImageGlyphBlt(drawable, gc, x, y, n,
16155					info, FONTGLYPHS(gc->font));
16156			FALLBACK_FLUSH(drawable);
16157			sigtrap_put();
16158		}
16159out:
16160		sna_gc_move_to_gpu(gc);
16161	}
16162	RegionUninit(&region);
16163}
16164
16165/* XXX Damage bypasses the Text interface and so we lose our custom gluphs */
16166static bool
16167sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc,
16168		       int _x, int _y, unsigned int _n,
16169		       CharInfoPtr *_info, pointer _base,
16170		       struct kgem_bo *bo,
16171		       struct sna_damage **damage,
16172		       RegionPtr clip,
16173		       uint32_t fg, uint32_t bg,
16174		       bool transparent)
16175{
16176	PixmapPtr pixmap = get_drawable_pixmap(drawable);
16177	struct sna *sna = to_sna_from_pixmap(pixmap);
16178	const BoxRec *extents, *last_extents;
16179	uint32_t *b;
16180	int16_t dx, dy;
16181	uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S;
16182	uint16_t unwind_batch, unwind_reloc;
16183
16184	DBG(("%s: pixmap=%ld, bo=%d, damage=%p, fg=%08x, bg=%08x\n",
16185	     __FUNCTION__, pixmap->drawable.serialNumber, bo->handle, damage, fg, bg));
16186
16187	if (bo->tiling == I915_TILING_Y) {
16188		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
16189		assert(bo == __sna_pixmap_get_bo(pixmap));
16190		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
16191		if (bo == NULL) {
16192			DBG(("%s: fallback -- unable to change tiling\n",
16193			     __FUNCTION__));
16194			return false;
16195		}
16196	}
16197
16198	if (!kgem_bo_can_blt(&sna->kgem, bo))
16199		return false;
16200
16201	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
16202		RegionTranslate(clip, dx, dy);
16203	_x += drawable->x + dx;
16204	_y += drawable->y + dy;
16205
16206	extents = region_rects(clip);
16207	last_extents = extents + region_num_rects(clip);
16208
16209	if (!transparent) { /* emulate miImageGlyphBlt */
16210		if (!sna_blt_fill_boxes(sna, GXcopy,
16211					bo, drawable->bitsPerPixel,
16212					bg, extents, last_extents - extents)) {
16213			RegionTranslate(clip, -dx, -dy);
16214			return false;
16215		}
16216	}
16217
16218	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
16219	assert(kgem_bo_can_blt(&sna->kgem, bo));
16220	if (!kgem_check_batch(&sna->kgem, 20) ||
16221	    !kgem_check_bo_fenced(&sna->kgem, bo) ||
16222	    !kgem_check_reloc(&sna->kgem, 1)) {
16223		kgem_submit(&sna->kgem);
16224		if (!kgem_check_bo_fenced(&sna->kgem, bo)) {
16225			RegionTranslate(clip, -dx, -dy);
16226			return false;
16227		}
16228		_kgem_set_mode(&sna->kgem, KGEM_BLT);
16229	}
16230	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
16231
16232	unwind_batch = sna->kgem.nbatch;
16233	unwind_reloc = sna->kgem.nreloc;
16234
16235	DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
16236	     __FUNCTION__,
16237	     extents->x1, extents->y1,
16238	     extents->x2, extents->y2));
16239
16240	assert(sna->kgem.mode == KGEM_BLT);
16241	b = sna->kgem.batch + sna->kgem.nbatch;
16242	if (sna->kgem.gen >= 0100) {
16243		b[0] = XY_SETUP_BLT | 1 << 20 | 8;
16244		b[1] = bo->pitch;
16245		if (sna->kgem.gen >= 040 && bo->tiling) {
16246			b[0] |= BLT_DST_TILED;
16247			b[1] >>= 2;
16248		}
16249		b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
16250		b[2] = extents->y1 << 16 | extents->x1;
16251		b[3] = extents->y2 << 16 | extents->x2;
16252		*(uint64_t *)(b+4) =
16253			kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
16254					 I915_GEM_DOMAIN_RENDER << 16 |
16255					 I915_GEM_DOMAIN_RENDER |
16256					 KGEM_RELOC_FENCED,
16257					 0);
16258		b[6] = bg;
16259		b[7] = fg;
16260		b[8] = 0;
16261		b[9] = 0;
16262		sna->kgem.nbatch += 10;
16263	} else {
16264		b[0] = XY_SETUP_BLT | 1 << 20 | 6;
16265		b[1] = bo->pitch;
16266		if (sna->kgem.gen >= 040 && bo->tiling) {
16267			b[0] |= BLT_DST_TILED;
16268			b[1] >>= 2;
16269		}
16270		b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
16271		b[2] = extents->y1 << 16 | extents->x1;
16272		b[3] = extents->y2 << 16 | extents->x2;
16273		b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
16274				      I915_GEM_DOMAIN_RENDER << 16 |
16275				      I915_GEM_DOMAIN_RENDER |
16276				      KGEM_RELOC_FENCED,
16277				      0);
16278		b[5] = bg;
16279		b[6] = fg;
16280		b[7] = 0;
16281		sna->kgem.nbatch += 8;
16282	}
16283
16284	do {
16285		CharInfoPtr *info = _info;
16286		int x = _x, y = _y, n = _n;
16287
16288		do {
16289			CharInfoPtr c = *info++;
16290			uint8_t *glyph = FONTGLYPHBITS(base, c);
16291			int w = GLYPHWIDTHPIXELS(c);
16292			int h = GLYPHHEIGHTPIXELS(c);
16293			int stride = GLYPHWIDTHBYTESPADDED(c);
16294			int w8 = (w + 7) >> 3;
16295			int x1, y1, len, i;
16296			uint8_t *byte;
16297
16298			if (w == 0 || h == 0)
16299				goto skip;
16300
16301			len = (w8 * h + 7) >> 3 << 1;
16302			x1 = x + c->metrics.leftSideBearing;
16303			y1 = y - c->metrics.ascent;
16304
16305			DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__,
16306			     x,y, x1, y1, w, w8, h, len));
16307
16308			if (x1 >= extents->x2 || y1 >= extents->y2 ||
16309			    x1 + w <= extents->x1 || y1 + h <= extents->y1) {
16310				DBG(("%s: glyph is clipped (%d, %d)x(%d,%d) against extents (%d, %d), (%d, %d)\n",
16311				     __FUNCTION__,
16312				     x1, y1, w, h,
16313				     extents->x1, extents->y1,
16314				     extents->x2, extents->y2));
16315				goto skip;
16316			}
16317
16318			{
16319				int clear = 1, j = h;
16320				uint8_t *g = glyph;
16321
16322				do {
16323					i = w8;
16324					do {
16325						clear = *g++ == 0;
16326					} while (clear && --i);
16327					g += stride - w8;
16328				} while (clear && --j);
16329				if (clear) {
16330					DBG(("%s: skipping clear glyph for ImageGlyph\n",
16331					     __FUNCTION__));
16332					goto skip;
16333				}
16334			}
16335
16336			assert(len > 0);
16337			if (!kgem_check_batch(&sna->kgem, 3+len)) {
16338				_kgem_submit(&sna->kgem);
16339				_kgem_set_mode(&sna->kgem, KGEM_BLT);
16340				kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
16341
16342				unwind_batch = sna->kgem.nbatch;
16343				unwind_reloc = sna->kgem.nreloc;
16344
16345				DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n",
16346				     __FUNCTION__,
16347				     extents->x1, extents->y1,
16348				     extents->x2, extents->y2));
16349
16350				assert(sna->kgem.mode == KGEM_BLT);
16351				b = sna->kgem.batch + sna->kgem.nbatch;
16352				if (sna->kgem.gen >= 0100) {
16353					b[0] = XY_SETUP_BLT | 1 << 20 | 8;
16354					b[1] = bo->pitch;
16355					if (bo->tiling) {
16356						b[0] |= BLT_DST_TILED;
16357						b[1] >>= 2;
16358					}
16359					b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
16360					b[2] = extents->y1 << 16 | extents->x1;
16361					b[3] = extents->y2 << 16 | extents->x2;
16362					*(uint64_t *)(b+4) =
16363						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
16364								 I915_GEM_DOMAIN_RENDER << 16 |
16365								 I915_GEM_DOMAIN_RENDER |
16366								 KGEM_RELOC_FENCED,
16367								 0);
16368					b[6] = bg;
16369					b[7] = fg;
16370					b[8] = 0;
16371					b[9] = 0;
16372					sna->kgem.nbatch += 10;
16373				} else {
16374					b[0] = XY_SETUP_BLT | 1 << 20 | 6;
16375					b[1] = bo->pitch;
16376					if (sna->kgem.gen >= 040 && bo->tiling) {
16377						b[0] |= BLT_DST_TILED;
16378						b[1] >>= 2;
16379					}
16380					b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
16381					b[2] = extents->y1 << 16 | extents->x1;
16382					b[3] = extents->y2 << 16 | extents->x2;
16383					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
16384							      I915_GEM_DOMAIN_RENDER << 16 |
16385							      I915_GEM_DOMAIN_RENDER |
16386							      KGEM_RELOC_FENCED,
16387							      0);
16388					b[5] = bg;
16389					b[6] = fg;
16390					b[7] = 0;
16391					sna->kgem.nbatch += 8;
16392				}
16393			}
16394
16395			assert(sna->kgem.mode == KGEM_BLT);
16396			b = sna->kgem.batch + sna->kgem.nbatch;
16397			sna->kgem.nbatch += 3 + len;
16398
16399			b[0] = XY_TEXT_IMMEDIATE_BLT | (1 + len);
16400			if (bo->tiling && sna->kgem.gen >= 040)
16401				b[0] |= BLT_DST_TILED;
16402			b[1] = (uint16_t)y1 << 16 | (uint16_t)x1;
16403			b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w);
16404
16405			byte = (uint8_t *)&b[3];
16406			stride -= w8;
16407			do {
16408				i = w8;
16409				do {
16410					*byte++ = byte_reverse(*glyph++);
16411				} while (--i);
16412				glyph += stride;
16413			} while (--h);
16414			while ((byte - (uint8_t *)&b[3]) & 7)
16415				*byte++ = 0;
16416			assert((uint32_t *)byte == sna->kgem.batch + sna->kgem.nbatch);
16417
16418			if (damage) {
16419				BoxRec r;
16420
16421				r.x1 = x1;
16422				r.y1 = y1;
16423				r.x2 = x1 + w;
16424				r.y2 = y1 + h;
16425				if (box_intersect(&r, extents))
16426					sna_damage_add_box(damage, &r);
16427			}
16428skip:
16429			x += c->metrics.characterWidth;
16430		} while (--n);
16431
16432		if (++extents == last_extents)
16433			break;
16434
16435		if (kgem_check_batch(&sna->kgem, 3 + 5)) {
16436			assert(sna->kgem.mode == KGEM_BLT);
16437			b = sna->kgem.batch + sna->kgem.nbatch;
16438			sna->kgem.nbatch += 3;
16439
16440			DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
16441			     __FUNCTION__,
16442			     extents->x1, extents->y1,
16443			     extents->x2, extents->y2));
16444
16445			b[0] = XY_SETUP_CLIP;
16446			b[1] = extents->y1 << 16 | extents->x1;
16447			b[2] = extents->y2 << 16 | extents->x2;
16448		}
16449	} while (1);
16450
16451	if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) {
16452		sna->kgem.nbatch = unwind_batch;
16453		sna->kgem.nreloc = unwind_reloc;
16454		if (sna->kgem.nbatch == 0)
16455			kgem_bo_undo(&sna->kgem, bo);
16456	}
16457
16458	assert_pixmap_damage(pixmap);
16459	blt_done(sna);
16460	return true;
16461}
16462
16463static void
16464sna_image_glyph(DrawablePtr drawable, GCPtr gc,
16465		int x, int y, unsigned int n,
16466		CharInfoPtr *info, pointer base)
16467{
16468	PixmapPtr pixmap = get_drawable_pixmap(drawable);
16469	struct sna *sna = to_sna_from_pixmap(pixmap);
16470	ExtentInfoRec extents;
16471	RegionRec region;
16472	struct sna_damage **damage;
16473	struct kgem_bo *bo;
16474	unsigned hint;
16475
16476	if (n == 0)
16477		return;
16478
16479	sna_glyph_extents(gc->font, info, n, &extents);
16480	region.extents.x1 = x + MIN(0, extents.overallLeft);
16481	region.extents.y1 = y - extents.fontAscent;
16482	region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight);
16483	region.extents.y2 = y + extents.fontDescent;
16484
16485	DBG(("%s: count=%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n",
16486	     __FUNCTION__, n,
16487	     extents.overallLeft, extents.overallRight, extents.overallWidth,
16488	     extents.fontAscent, extents.fontDescent,
16489	     region.extents.x1, region.extents.y1,
16490	     region.extents.x2, region.extents.y2));
16491
16492	translate_box(&region.extents, drawable);
16493	clip_box(&region.extents, gc);
16494	if (box_empty(&region.extents))
16495		return;
16496
16497	DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__,
16498	     region.extents.x1, region.extents.y1,
16499	     region.extents.x2, region.extents.y2));
16500
16501	region.data = NULL;
16502	if (!region_maybe_clip(&region, gc->pCompositeClip))
16503		return;
16504
16505	if (FORCE_FALLBACK)
16506		goto fallback;
16507
16508	if (!ACCEL_IMAGE_GLYPH)
16509		goto fallback;
16510
16511	if (wedged(sna)) {
16512		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
16513		goto fallback;
16514	}
16515
16516	if (!PM_IS_SOLID(drawable, gc->planemask))
16517		goto fallback;
16518
16519	if (sna_font_too_large(gc->font))
16520		goto fallback;
16521
16522	if (region.data == NULL)
16523		hint = IGNORE_DAMAGE | PREFER_GPU;
16524	else
16525		hint = PREFER_GPU;
16526	if ((bo = sna_drawable_use_bo(drawable, hint,
16527				      &region.extents, &damage)) &&
16528	    sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base,
16529				   bo, damage, &region,
16530				   gc->fgPixel, gc->bgPixel, false))
16531		goto out;
16532
16533fallback:
16534	DBG(("%s: fallback\n", __FUNCTION__));
16535	if (!sna_gc_move_to_cpu(gc, drawable, &region))
16536		goto out_gc;
16537	if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_WRITE))
16538		goto out_gc;
16539
16540	if (sigtrap_get() == 0) {
16541		DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
16542		fbImageGlyphBlt(drawable, gc, x, y, n, info, base);
16543		FALLBACK_FLUSH(drawable);
16544		sigtrap_put();
16545	}
16546out_gc:
16547	sna_gc_move_to_gpu(gc);
16548out:
16549	RegionUninit(&region);
16550}
16551
16552static void
16553sna_poly_glyph(DrawablePtr drawable, GCPtr gc,
16554	       int x, int y, unsigned int n,
16555	       CharInfoPtr *info, pointer base)
16556{
16557	PixmapPtr pixmap = get_drawable_pixmap(drawable);
16558	struct sna *sna = to_sna_from_pixmap(pixmap);
16559	ExtentInfoRec extents;
16560	RegionRec region;
16561	struct sna_damage **damage;
16562	struct kgem_bo *bo;
16563	uint32_t fg;
16564
16565	if (n == 0)
16566		return;
16567
16568	sna_glyph_extents(gc->font, info, n, &extents);
16569	region.extents.x1 = x + extents.overallLeft;
16570	region.extents.y1 = y - extents.overallAscent;
16571	region.extents.x2 = x + extents.overallRight;
16572	region.extents.y2 = y + extents.overallDescent;
16573
16574	translate_box(&region.extents, drawable);
16575	clip_box(&region.extents, gc);
16576	if (box_empty(&region.extents))
16577		return;
16578
16579	DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__,
16580	     region.extents.x1, region.extents.y1,
16581	     region.extents.x2, region.extents.y2));
16582
16583	region.data = NULL;
16584	if (!region_maybe_clip(&region, gc->pCompositeClip))
16585		return;
16586
16587	if (FORCE_FALLBACK)
16588		goto fallback;
16589
16590	if (!ACCEL_POLY_GLYPH)
16591		goto fallback;
16592
16593	if (wedged(sna)) {
16594		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
16595		goto fallback;
16596	}
16597
16598	if (!PM_IS_SOLID(drawable, gc->planemask))
16599		goto fallback;
16600
16601	if (!gc_is_solid(gc, &fg))
16602		goto fallback;
16603
16604	if (sna_font_too_large(gc->font))
16605		goto fallback;
16606
16607	if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU,
16608				      &region.extents, &damage)) &&
16609	    sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base,
16610				   bo, damage, &region, fg, -1, true))
16611		goto out;
16612
16613fallback:
16614	DBG(("%s: fallback\n", __FUNCTION__));
16615	if (!sna_gc_move_to_cpu(gc, drawable, &region))
16616		goto out_gc;
16617	if (!sna_drawable_move_region_to_cpu(drawable, &region,
16618					     MOVE_READ | MOVE_WRITE))
16619		goto out_gc;
16620
16621	if (sigtrap_get() == 0) {
16622		DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
16623		fbPolyGlyphBlt(drawable, gc, x, y, n, info, base);
16624		FALLBACK_FLUSH(drawable);
16625		sigtrap_put();
16626	}
16627out_gc:
16628	sna_gc_move_to_gpu(gc);
16629out:
16630	RegionUninit(&region);
16631}
16632
16633static bool
16634sna_push_pixels_solid_blt(GCPtr gc,
16635			  PixmapPtr bitmap,
16636			  DrawablePtr drawable,
16637			  RegionPtr region)
16638{
16639	PixmapPtr pixmap = get_drawable_pixmap(drawable);
16640	struct sna *sna = to_sna_from_pixmap(pixmap);
16641	struct sna_damage **damage;
16642	struct kgem_bo *bo;
16643	const BoxRec *box;
16644	int16_t dx, dy;
16645	int n;
16646	uint8_t rop = copy_ROP[gc->alu];
16647
16648	bo = sna_drawable_use_bo(drawable, PREFER_GPU, &region->extents, &damage);
16649	if (bo == NULL)
16650		return false;
16651
16652	if (bo->tiling == I915_TILING_Y) {
16653		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
16654		assert(bo == __sna_pixmap_get_bo(pixmap));
16655		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
16656		if (bo == NULL) {
16657			DBG(("%s: fallback -- unable to change tiling\n",
16658			     __FUNCTION__));
16659			return false;
16660		}
16661	}
16662
16663	if (!kgem_bo_can_blt(&sna->kgem, bo))
16664		return false;
16665
16666	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
16667		RegionTranslate(region, dx, dy);
16668
16669	assert_pixmap_contains_box(pixmap, RegionExtents(region));
16670	if (damage)
16671		sna_damage_add_to_pixmap(damage, region, pixmap);
16672	assert_pixmap_damage(pixmap);
16673
16674	DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__,
16675	     region->extents.x1, region->extents.y1,
16676	     region->extents.x2, region->extents.y2));
16677
16678	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
16679	assert(kgem_bo_can_blt(&sna->kgem, bo));
16680	kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
16681
16682	/* Region is pre-clipped and translated into pixmap space */
16683	box = region_rects(region);
16684	n = region_num_rects(region);
16685	do {
16686		int bx1 = (box->x1 - region->extents.x1) & ~7;
16687		int bx2 = (box->x2 - region->extents.x1 + 7) & ~7;
16688		int bw = (bx2 - bx1)/8;
16689		int bh = box->y2 - box->y1;
16690		int bstride = ALIGN(bw, 2);
16691		struct kgem_bo *upload;
16692		void *ptr;
16693
16694		if (!kgem_check_batch(&sna->kgem, 10) ||
16695		    !kgem_check_bo_fenced(&sna->kgem, bo) ||
16696		    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
16697			kgem_submit(&sna->kgem);
16698			if (!kgem_check_bo_fenced(&sna->kgem, bo))
16699				return false;
16700			_kgem_set_mode(&sna->kgem, KGEM_BLT);
16701		}
16702		kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
16703
16704		upload = kgem_create_buffer(&sna->kgem,
16705					    bstride*bh,
16706					    KGEM_BUFFER_WRITE_INPLACE,
16707					    &ptr);
16708		if (!upload)
16709			break;
16710
16711		if (sigtrap_get() == 0) {
16712			uint8_t *dst = ptr;
16713
16714			int src_stride = bitmap->devKind;
16715			uint8_t *src;
16716			uint32_t *b;
16717
16718			assert(src_stride);
16719			src = (uint8_t*)bitmap->devPrivate.ptr;
16720			src += (box->y1 - region->extents.y1) * src_stride + bx1/8;
16721			src_stride -= bstride;
16722			do {
16723				int i = bstride;
16724				do {
16725					*dst++ = byte_reverse(*src++);
16726					*dst++ = byte_reverse(*src++);
16727					i -= 2;
16728				} while (i);
16729				src += src_stride;
16730			} while (--bh);
16731
16732			assert(sna->kgem.mode == KGEM_BLT);
16733			b = sna->kgem.batch + sna->kgem.nbatch;
16734			if (sna->kgem.gen >= 0100) {
16735				b[0] = XY_MONO_SRC_COPY | 3 << 20 | 8;
16736				b[0] |= ((box->x1 - region->extents.x1) & 7) << 17;
16737				b[1] = bo->pitch;
16738				if (sna->kgem.gen >= 040 && bo->tiling) {
16739					b[0] |= BLT_DST_TILED;
16740					b[1] >>= 2;
16741				}
16742				b[1] |= 1 << 29;
16743				b[1] |= blt_depth(drawable->depth) << 24;
16744				b[1] |= rop << 16;
16745				b[2] = box->y1 << 16 | box->x1;
16746				b[3] = box->y2 << 16 | box->x2;
16747				*(uint64_t *)(b+4) =
16748					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
16749							I915_GEM_DOMAIN_RENDER << 16 |
16750							I915_GEM_DOMAIN_RENDER |
16751							KGEM_RELOC_FENCED,
16752							0);
16753				*(uint64_t *)(b+6) =
16754					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
16755							I915_GEM_DOMAIN_RENDER << 16 |
16756							KGEM_RELOC_FENCED,
16757							0);
16758				b[8] = gc->bgPixel;
16759				b[9] = gc->fgPixel;
16760				sna->kgem.nbatch += 10;
16761			} else {
16762				b[0] = XY_MONO_SRC_COPY | 3 << 20 | 6;
16763				b[0] |= ((box->x1 - region->extents.x1) & 7) << 17;
16764				b[1] = bo->pitch;
16765				if (sna->kgem.gen >= 040 && bo->tiling) {
16766					b[0] |= BLT_DST_TILED;
16767					b[1] >>= 2;
16768				}
16769				b[1] |= 1 << 29;
16770				b[1] |= blt_depth(drawable->depth) << 24;
16771				b[1] |= rop << 16;
16772				b[2] = box->y1 << 16 | box->x1;
16773				b[3] = box->y2 << 16 | box->x2;
16774				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
16775						I915_GEM_DOMAIN_RENDER << 16 |
16776						I915_GEM_DOMAIN_RENDER |
16777						KGEM_RELOC_FENCED,
16778						0);
16779				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
16780						I915_GEM_DOMAIN_RENDER << 16 |
16781						KGEM_RELOC_FENCED,
16782						0);
16783				b[6] = gc->bgPixel;
16784				b[7] = gc->fgPixel;
16785
16786				sna->kgem.nbatch += 8;
16787			}
16788			sigtrap_put();
16789		}
16790
16791		kgem_bo_destroy(&sna->kgem, upload);
16792
16793		box++;
16794	} while (--n);
16795
16796	blt_done(sna);
16797	return true;
16798}
16799
16800static void
16801sna_push_pixels(GCPtr gc, PixmapPtr bitmap, DrawablePtr drawable,
16802		int w, int h,
16803		int x, int y)
16804{
16805	RegionRec region;
16806
16807	if (w == 0 || h == 0)
16808		return;
16809
16810	DBG(("%s (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
16811
16812	region.extents.x1 = x;
16813	region.extents.y1 = y;
16814	region.extents.x2 = region.extents.x1 + w;
16815	region.extents.y2 = region.extents.y1 + h;
16816
16817	clip_box(&region.extents, gc);
16818	if (box_empty(&region.extents))
16819		return;
16820
16821	DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__,
16822	     region.extents.x1, region.extents.y1,
16823	     region.extents.x2, region.extents.y2));
16824
16825	region.data = NULL;
16826	if (!region_maybe_clip(&region, gc->pCompositeClip))
16827		return;
16828
16829	switch (gc->fillStyle) {
16830	case FillSolid:
16831		if (sna_push_pixels_solid_blt(gc, bitmap, drawable, &region))
16832			return;
16833		break;
16834	default:
16835		break;
16836	}
16837
16838	DBG(("%s: fallback\n", __FUNCTION__));
16839	if (!sna_gc_move_to_cpu(gc, drawable, &region))
16840		goto out;
16841	if (!sna_pixmap_move_to_cpu(bitmap, MOVE_READ))
16842		goto out;
16843	if (!sna_drawable_move_region_to_cpu(drawable, &region,
16844					     drawable_gc_flags(drawable, gc, false)))
16845		goto out;
16846
16847	if (sigtrap_get() == 0) {
16848		DBG(("%s: fallback, fbPushPixels(%d, %d, %d %d)\n",
16849		     __FUNCTION__, w, h, x, y));
16850		fbPushPixels(gc, bitmap, drawable, w, h, x, y);
16851		FALLBACK_FLUSH(drawable);
16852		sigtrap_put();
16853	}
16854out:
16855	sna_gc_move_to_gpu(gc);
16856	RegionUninit(&region);
16857}
16858
16859static const GCOps sna_gc_ops = {
16860	sna_fill_spans,
16861	sna_set_spans,
16862	sna_put_image,
16863	sna_copy_area,
16864	sna_copy_plane,
16865	sna_poly_point,
16866	sna_poly_line,
16867	sna_poly_segment,
16868	sna_poly_rectangle,
16869	sna_poly_arc,
16870	sna_poly_fill_polygon,
16871	sna_poly_fill_rect,
16872	sna_poly_fill_arc,
16873	sna_poly_text8,
16874	sna_poly_text16,
16875	sna_image_text8,
16876	sna_image_text16,
16877	sna_image_glyph,
16878	sna_poly_glyph,
16879	sna_push_pixels,
16880};
16881
16882static const GCOps sna_gc_ops__cpu = {
16883	fbFillSpans,
16884	fbSetSpans,
16885	fbPutImage,
16886	fbCopyArea,
16887	fbCopyPlane,
16888	sna_poly_point__cpu,
16889	fbPolyLine,
16890	fbPolySegment,
16891	miPolyRectangle,
16892	fbPolyArc,
16893	miFillPolygon,
16894	fbPolyFillRect,
16895	miPolyFillArc,
16896	miPolyText8,
16897	miPolyText16,
16898	miImageText8,
16899	miImageText16,
16900	fbImageGlyphBlt,
16901	fbPolyGlyphBlt,
16902	fbPushPixels
16903};
16904
16905static GCOps sna_gc_ops__tmp = {
16906	sna_fill_spans,
16907	sna_set_spans,
16908	sna_put_image,
16909	sna_copy_area,
16910	sna_copy_plane,
16911	sna_poly_point,
16912	sna_poly_line,
16913	sna_poly_segment,
16914	sna_poly_rectangle,
16915	sna_poly_arc,
16916	sna_poly_fill_polygon,
16917	sna_poly_fill_rect,
16918	sna_poly_fill_arc,
16919	sna_poly_text8,
16920	sna_poly_text16,
16921	sna_image_text8,
16922	sna_image_text16,
16923	sna_image_glyph,
16924	sna_poly_glyph,
16925	sna_push_pixels,
16926};
16927
16928static void
16929sna_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable)
16930{
16931	DBG(("%s(%p) changes=%lx, previous serial=%lx, drawable=%lx\n", __FUNCTION__, gc,
16932	     changes, gc->serialNumber, drawable->serialNumber));
16933
16934	if (changes & (GCClipMask|GCSubwindowMode) ||
16935	    drawable->serialNumber != (gc->serialNumber & DRAWABLE_SERIAL_BITS) ||
16936	    (has_clip(gc) && (changes & (GCClipXOrigin | GCClipYOrigin)))) {
16937		DBG(("%s: recomputing clip\n", __FUNCTION__));
16938		miComputeCompositeClip(gc, drawable);
16939		DBG(("%s: composite clip=%dx[(%d, %d), (%d, %d)] [%p]\n",
16940		     __FUNCTION__,
16941		     region_num_rects(gc->pCompositeClip),
16942		     gc->pCompositeClip->extents.x1,
16943		     gc->pCompositeClip->extents.y1,
16944		     gc->pCompositeClip->extents.x2,
16945		     gc->pCompositeClip->extents.y2,
16946		     gc->pCompositeClip));
16947	}
16948
16949	assert(gc->pCompositeClip);
16950	assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.x1 >= drawable->x);
16951	assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.y1 >= drawable->y);
16952	assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.x2 - drawable->x <= drawable->width);
16953	assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.y2 - drawable->y <= drawable->height);
16954
16955	sna_gc(gc)->changes |= changes;
16956	sna_gc(gc)->serial = gc->serialNumber;
16957}
16958
16959static const GCFuncs sna_gc_funcs = {
16960	sna_validate_gc,
16961	miChangeGC,
16962	miCopyGC,
16963	miDestroyGC,
16964	miChangeClip,
16965	miDestroyClip,
16966	miCopyClip
16967};
16968
16969static const GCFuncs sna_gc_funcs__cpu = {
16970	fbValidateGC,
16971	miChangeGC,
16972	miCopyGC,
16973	miDestroyGC,
16974	miChangeClip,
16975	miDestroyClip,
16976	miCopyClip
16977};
16978
16979static int sna_create_gc(GCPtr gc)
16980{
16981	gc->miTranslate = 1;
16982	gc->fExpose = 1;
16983
16984	gc->freeCompClip = 0;
16985	gc->pCompositeClip = 0;
16986#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,19,99,1,0)
16987	gc->pRotatedPixmap = 0;
16988#endif
16989
16990	fb_gc(gc)->bpp = bits_per_pixel(gc->depth);
16991
16992	gc->funcs = (GCFuncs *)&sna_gc_funcs;
16993	gc->ops = (GCOps *)&sna_gc_ops;
16994	return true;
16995}
16996
16997static bool
16998sna_get_image__inplace(PixmapPtr pixmap,
16999		       RegionPtr region,
17000		       char *dst,
17001		       unsigned flags,
17002		       bool idle)
17003{
17004	struct sna_pixmap *priv = sna_pixmap(pixmap);
17005	struct sna *sna = to_sna_from_pixmap(pixmap);
17006	char *src;
17007
17008	if (!USE_INPLACE)
17009		return false;
17010
17011	assert(priv && priv->gpu_bo);
17012
17013	switch (priv->gpu_bo->tiling) {
17014	case I915_TILING_Y:
17015		return false;
17016	case I915_TILING_X:
17017		if (!sna->kgem.memcpy_from_tiled_x)
17018			return false;
17019	default:
17020		break;
17021	}
17022
17023	if ((flags & MOVE_INPLACE_HINT) == 0 &&
17024	    !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC))
17025		return false;
17026
17027	if (idle && __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
17028		return false;
17029
17030	if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ))
17031		return false;
17032
17033	assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
17034	assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
17035
17036	if (kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC)) {
17037		src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
17038		if (src == NULL)
17039			return false;
17040
17041		kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC);
17042	} else {
17043		src = kgem_bo_map__wc(&sna->kgem, priv->gpu_bo);
17044		if (src == NULL)
17045			return false;
17046
17047		kgem_bo_sync__gtt(&sna->kgem, priv->gpu_bo);
17048	}
17049
17050	if (sigtrap_get())
17051		return false;
17052
17053	if (priv->gpu_bo->tiling) {
17054		DBG(("%s: download through a tiled CPU map\n", __FUNCTION__));
17055		memcpy_from_tiled_x(&sna->kgem, src, dst,
17056				    pixmap->drawable.bitsPerPixel,
17057				    priv->gpu_bo->pitch,
17058				    PixmapBytePad(region->extents.x2 - region->extents.x1,
17059						  pixmap->drawable.depth),
17060				    region->extents.x1, region->extents.y1,
17061				    0, 0,
17062				    region->extents.x2 - region->extents.x1,
17063				    region->extents.y2 - region->extents.y1);
17064	} else {
17065		DBG(("%s: download through a linear CPU map\n", __FUNCTION__));
17066		memcpy_blt(src, dst,
17067			   pixmap->drawable.bitsPerPixel,
17068			   priv->gpu_bo->pitch,
17069			   PixmapBytePad(region->extents.x2 - region->extents.x1,
17070					 pixmap->drawable.depth),
17071			   region->extents.x1, region->extents.y1,
17072			   0, 0,
17073			   region->extents.x2 - region->extents.x1,
17074			   region->extents.y2 - region->extents.y1);
17075		if (!priv->shm) {
17076			pixmap->devPrivate.ptr = src;
17077			pixmap->devKind = priv->gpu_bo->pitch;
17078			priv->mapped = src == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
17079			assert_pixmap_map(pixmap, priv);
17080			priv->cpu &= priv->mapped == MAPPED_CPU;
17081		}
17082	}
17083
17084	sigtrap_put();
17085	return true;
17086}
17087
17088static bool
17089sna_get_image__blt(PixmapPtr pixmap,
17090		   RegionPtr region,
17091		   char *dst,
17092		   unsigned flags)
17093{
17094	struct sna_pixmap *priv = sna_pixmap(pixmap);
17095	struct sna *sna = to_sna_from_pixmap(pixmap);
17096	struct kgem_bo *dst_bo;
17097	bool ok = false;
17098	int pitch;
17099
17100	assert(priv && priv->gpu_bo);
17101
17102	if (!sna->kgem.has_userptr || !USE_USERPTR_DOWNLOADS)
17103		return false;
17104
17105	if (!sna->kgem.can_blt_cpu)
17106		return false;
17107
17108	if ((priv->create & (KGEM_CAN_CREATE_GTT | KGEM_CAN_CREATE_LARGE)) == KGEM_CAN_CREATE_GTT &&
17109	    kgem_bo_can_map(&sna->kgem, priv->gpu_bo)) {
17110		if (flags & (MOVE_WHOLE_HINT | MOVE_INPLACE_HINT))
17111			return false;
17112
17113		if (priv->gpu_damage == NULL)
17114			return false;
17115
17116		assert(priv->gpu_bo);
17117		if (!__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
17118			return false;
17119	} else {
17120		if (priv->gpu_damage == NULL)
17121			return false;
17122
17123		assert(priv->gpu_bo);
17124	}
17125
17126	if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ))
17127		return false;
17128
17129	DBG(("%s: download through a temporary map\n", __FUNCTION__));
17130
17131	assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
17132	assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
17133
17134	pitch = PixmapBytePad(region->extents.x2 - region->extents.x1,
17135			      pixmap->drawable.depth);
17136	dst_bo = kgem_create_map(&sna->kgem, dst,
17137				 pitch * (region->extents.y2 - region->extents.y1),
17138				 false);
17139	if (dst_bo) {
17140		dst_bo->pitch = pitch;
17141		kgem_bo_mark_unreusable(dst_bo);
17142
17143		ok = sna->render.copy_boxes(sna, GXcopy,
17144					    &pixmap->drawable, priv->gpu_bo, 0, 0,
17145					    &pixmap->drawable, dst_bo,
17146					    -region->extents.x1,
17147					    -region->extents.y1,
17148					    &region->extents, 1,
17149					    COPY_LAST);
17150
17151		kgem_bo_sync__cpu(&sna->kgem, dst_bo);
17152		assert(dst_bo->rq == NULL);
17153		kgem_bo_destroy(&sna->kgem, dst_bo);
17154	}
17155
17156	return ok;
17157}
17158
17159static bool
17160sna_get_image__fast(PixmapPtr pixmap,
17161		   RegionPtr region,
17162		   char *dst,
17163		   unsigned flags)
17164{
17165	struct sna_pixmap *priv = sna_pixmap(pixmap);
17166
17167	DBG(("%s: attached?=%d, has gpu damage?=%d\n",
17168	     __FUNCTION__, priv != NULL,  priv && priv->gpu_damage));
17169	if (priv == NULL || priv->gpu_damage == NULL)
17170		return false;
17171
17172	if (priv->clear && sigtrap_get() == 0) {
17173		int w = region->extents.x2 - region->extents.x1;
17174		int h = region->extents.y2 - region->extents.y1;
17175		int pitch = PixmapBytePad(w, pixmap->drawable.depth);
17176
17177		DBG(("%s: applying clear [%08x]\n",
17178		     __FUNCTION__, priv->clear_color));
17179		assert(DAMAGE_IS_ALL(priv->gpu_damage));
17180		assert(priv->cpu_damage == NULL);
17181		sigtrap_assert_active();
17182
17183		if (priv->clear_color == 0 ||
17184		    pixmap->drawable.bitsPerPixel == 8 ||
17185		    priv->clear_color == (1U << pixmap->drawable.depth) - 1) {
17186			DBG(("%s: memset clear [%02x]\n",
17187			     __FUNCTION__, priv->clear_color & 0xff));
17188			memset(dst, priv->clear_color, pitch * h);
17189		} else {
17190			pixman_fill((uint32_t *)dst,
17191				    pitch/sizeof(uint32_t),
17192				    pixmap->drawable.bitsPerPixel,
17193				    0, 0,
17194				    w, h,
17195				    priv->clear_color);
17196		}
17197
17198		sigtrap_put();
17199		return true;
17200	}
17201
17202	if (!DAMAGE_IS_ALL(priv->gpu_damage) &&
17203	    !sna_damage_contains_box__no_reduce(priv->gpu_damage,
17204						&region->extents))
17205		return false;
17206
17207	if (sna_get_image__inplace(pixmap, region, dst, flags, true))
17208		return true;
17209
17210	if (sna_get_image__blt(pixmap, region, dst, flags))
17211		return true;
17212
17213	if (sna_get_image__inplace(pixmap, region, dst, flags, false))
17214		return true;
17215
17216	return false;
17217}
17218
17219static void
17220sna_get_image(DrawablePtr drawable,
17221	      int x, int y, int w, int h,
17222	      unsigned int format, unsigned long mask,
17223	      char *dst)
17224{
17225	RegionRec region;
17226	unsigned int flags;
17227
17228	if (!fbDrawableEnabled(drawable))
17229		return;
17230
17231	DBG(("%s: pixmap=%ld (%d, %d)x(%d, %d), format=%d, mask=%lx, depth=%d\n",
17232	     __FUNCTION__,
17233	     (long)get_drawable_pixmap(drawable)->drawable.serialNumber,
17234	     x, y, w, h, format, mask, drawable->depth));
17235
17236	flags = MOVE_READ;
17237	if ((w | h) == 1)
17238		flags |= MOVE_INPLACE_HINT;
17239	if (w == drawable->width)
17240		flags |= MOVE_WHOLE_HINT;
17241
17242	if (ACCEL_GET_IMAGE &&
17243	    !FORCE_FALLBACK &&
17244	    format == ZPixmap &&
17245	    drawable->bitsPerPixel >= 8) {
17246		PixmapPtr pixmap = get_drawable_pixmap(drawable);
17247		int16_t dx, dy;
17248
17249		get_drawable_deltas(drawable, pixmap, &dx, &dy);
17250		region.extents.x1 = x + drawable->x + dx;
17251		region.extents.y1 = y + drawable->y + dy;
17252		region.extents.x2 = region.extents.x1 + w;
17253		region.extents.y2 = region.extents.y1 + h;
17254		region.data = NULL;
17255
17256		if (sna_get_image__fast(pixmap, &region, dst, flags))
17257			goto apply_planemask;
17258
17259		if (!sna_drawable_move_region_to_cpu(&pixmap->drawable,
17260						     &region, flags))
17261			return;
17262
17263		DBG(("%s: copy box (%d, %d), (%d, %d)\n",
17264		     __FUNCTION__,
17265		     region.extents.x1, region.extents.y1,
17266		     region.extents.x2, region.extents.y2));
17267		assert(has_coherent_ptr(to_sna_from_pixmap(pixmap), sna_pixmap(pixmap), MOVE_READ));
17268		if (sigtrap_get() == 0) {
17269			assert(pixmap->devKind);
17270			memcpy_blt(pixmap->devPrivate.ptr, dst, drawable->bitsPerPixel,
17271				   pixmap->devKind, PixmapBytePad(w, drawable->depth),
17272				   region.extents.x1, region.extents.y1, 0, 0, w, h);
17273			sigtrap_put();
17274		}
17275
17276apply_planemask:
17277		if (!PM_IS_SOLID(drawable, mask)) {
17278			FbStip pm = fbReplicatePixel(mask, drawable->bitsPerPixel);
17279			FbStip *d = (FbStip *)dst;
17280			int i, n = PixmapBytePad(w, drawable->depth) / sizeof(FbStip) * h;
17281
17282			for (i = 0; i < n; i++)
17283				d[i] &= pm;
17284		}
17285	} else {
17286		region.extents.x1 = x + drawable->x;
17287		region.extents.y1 = y + drawable->y;
17288		region.extents.x2 = region.extents.x1 + w;
17289		region.extents.y2 = region.extents.y1 + h;
17290		region.data = NULL;
17291
17292		if (sna_drawable_move_region_to_cpu(drawable, &region, flags))
17293			fbGetImage(drawable, x, y, w, h, format, mask, dst);
17294	}
17295}
17296
17297static void
17298sna_get_spans(DrawablePtr drawable, int wMax,
17299	      DDXPointPtr pt, int *width, int n, char *start)
17300{
17301	RegionRec region;
17302
17303	if (!fbDrawableEnabled(drawable))
17304		return;
17305
17306	if (sna_spans_extents(drawable, NULL, n, pt, width, &region.extents) == 0)
17307		return;
17308
17309	region.data = NULL;
17310	if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_READ))
17311		return;
17312
17313	fbGetSpans(drawable, wMax, pt, width, n, start);
17314}
17315
17316static void
17317sna_copy_window(WindowPtr win, DDXPointRec origin, RegionPtr src)
17318{
17319	PixmapPtr pixmap = get_window_pixmap(win);
17320	struct sna *sna = to_sna_from_pixmap(pixmap);
17321	RegionRec dst;
17322	int dx, dy;
17323
17324	DBG(("%s origin=(%d, %d)\n", __FUNCTION__, origin.x, origin.y));
17325	if (!fbWindowEnabled(win))
17326		return;
17327
17328	dx = origin.x - win->drawable.x;
17329	dy = origin.y - win->drawable.y;
17330	RegionTranslate(src, -dx, -dy);
17331
17332	RegionNull(&dst);
17333	RegionIntersect(&dst, &win->borderClip, src);
17334	if (box_empty(&dst.extents))
17335		return;
17336
17337#ifdef COMPOSITE
17338	if (pixmap->screen_x | pixmap->screen_y)
17339		RegionTranslate(&dst, -pixmap->screen_x, -pixmap->screen_y);
17340#endif
17341
17342	if (wedged(sna) || FORCE_FALLBACK || !ACCEL_COPY_WINDOW) {
17343		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
17344		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE))
17345			return;
17346
17347		if (sigtrap_get() == 0) {
17348			miCopyRegion(&pixmap->drawable, &pixmap->drawable,
17349				     0, &dst, dx, dy, fbCopyNtoN, 0, NULL);
17350			sigtrap_put();
17351		}
17352	} else {
17353		sna_self_copy_boxes(&pixmap->drawable, &pixmap->drawable, NULL,
17354				    &dst, dx, dy, 0, NULL);
17355	}
17356
17357	RegionUninit(&dst);
17358}
17359
17360static Bool sna_change_window_attributes(WindowPtr win, unsigned long mask)
17361{
17362	bool ret = true;
17363
17364	DBG(("%s\n", __FUNCTION__));
17365
17366	/* Check if the fb layer wishes to modify the attached pixmaps,
17367	 * to fix up mismatches between the window and pixmap depths.
17368	 */
17369	if (mask & CWBackPixmap && win->backgroundState == BackgroundPixmap) {
17370		DBG(("%s: flushing background pixmap\n", __FUNCTION__));
17371		ret &= sna_validate_pixmap(&win->drawable, win->background.pixmap);
17372	}
17373
17374	if (mask & CWBorderPixmap && win->borderIsPixel == false) {
17375		DBG(("%s: flushing border pixmap\n", __FUNCTION__));
17376		ret &= sna_validate_pixmap(&win->drawable, win->border.pixmap);
17377	}
17378
17379	return ret;
17380}
17381
17382void sna_accel_flush(struct sna *sna)
17383{
17384	struct sna_pixmap *priv;
17385
17386	/* XXX we should be able to reduce the frequency of flushes further
17387	 * by checking for outgoing damage events or sync replies. Tricky,
17388	 * and doesn't appear to mitigate the performance loss.
17389	 */
17390	DBG(("%s: flush?=%d, dirty?=%d\n", __FUNCTION__,
17391	     sna->kgem.flush, !list_is_empty(&sna->flush_pixmaps)));
17392
17393	/* flush any pending damage from shadow copies to tfp clients */
17394	while (!list_is_empty(&sna->flush_pixmaps)) {
17395		bool ret;
17396
17397		priv = list_first_entry(&sna->flush_pixmaps,
17398					struct sna_pixmap, flush_list);
17399
17400		list_del(&priv->flush_list);
17401		if (priv->shm) {
17402			DBG(("%s: syncing SHM pixmap=%ld (refcnt=%d)\n",
17403			     __FUNCTION__,
17404			     priv->pixmap->drawable.serialNumber,
17405			     priv->pixmap->refcnt));
17406			assert(!priv->flush);
17407			ret = sna_pixmap_move_to_cpu(priv->pixmap,
17408						     MOVE_READ | MOVE_WRITE);
17409			assert(!ret || priv->gpu_bo == NULL);
17410			if (priv->pixmap->refcnt == 0) {
17411				sna_damage_destroy(&priv->cpu_damage);
17412				__sna_free_pixmap(sna, priv->pixmap, priv);
17413			}
17414		} else {
17415			unsigned hints;
17416			DBG(("%s: flushing DRI pixmap=%ld\n", __FUNCTION__,
17417			     priv->pixmap->drawable.serialNumber));
17418			assert(priv->flush);
17419			hints = MOVE_READ | __MOVE_FORCE;
17420			if (priv->flush & FLUSH_WRITE)
17421				hints |= MOVE_WRITE;
17422			if (sna_pixmap_move_to_gpu(priv->pixmap, hints)) {
17423				if (priv->flush & FLUSH_WRITE) {
17424					kgem_bo_unclean(&sna->kgem, priv->gpu_bo);
17425					sna_damage_all(&priv->gpu_damage, priv->pixmap);
17426					assert(priv->cpu_damage == NULL);
17427					assert(priv->clear == false);
17428				}
17429			}
17430		}
17431		(void)ret;
17432	}
17433
17434	if (sna->kgem.flush)
17435		kgem_submit(&sna->kgem);
17436}
17437
17438static void
17439sna_shm_flush_callback(CallbackListPtr *list,
17440		       pointer user_data, pointer call_data)
17441{
17442	struct sna *sna = user_data;
17443
17444	if (!sna->needs_shm_flush)
17445		return;
17446
17447	sna_accel_flush(sna);
17448	sna->needs_shm_flush = false;
17449}
17450
17451static void
17452sna_flush_callback(CallbackListPtr *list, pointer user_data, pointer call_data)
17453{
17454	struct sna *sna = user_data;
17455
17456#if 0 /* XXX requires mesa to implement glXWaitX()! */
17457	if (!sna->needs_dri_flush)
17458		return;
17459
17460	sna_accel_flush(sna);
17461	sna->needs_dri_flush = false;
17462#else
17463	sna_accel_flush(sna);
17464#endif
17465}
17466
17467static void
17468sna_event_callback(CallbackListPtr *list, pointer user_data, pointer call_data)
17469{
17470	EventInfoRec *eventinfo = call_data;
17471	struct sna *sna = user_data;
17472	int i;
17473
17474	if (sna->needs_dri_flush)
17475		return;
17476
17477	for (i = 0; i < eventinfo->count; i++) {
17478		if (eventinfo->events[i].u.u.type == sna->damage_event) {
17479			sna->needs_dri_flush = true;
17480			return;
17481		}
17482	}
17483}
17484
17485static struct sna_pixmap *sna_accel_scanout(struct sna *sna)
17486{
17487	struct sna_pixmap *priv;
17488
17489	if (sna->mode.front_active == 0)
17490		return NULL;
17491
17492	assert(sna->vblank_interval);
17493	assert(sna->front);
17494	assert(!sna->mode.hidden);
17495
17496	priv = sna_pixmap(sna->front);
17497	if (priv->gpu_bo == NULL)
17498		return NULL;
17499
17500	return priv;
17501}
17502
17503#define TIME currentTime.milliseconds
17504static void sna_accel_disarm_timer(struct sna *sna, int id)
17505{
17506	DBG(("%s[%d] (time=%ld)\n", __FUNCTION__, id, (long)TIME));
17507	sna->timer_active &= ~(1<<id);
17508}
17509
17510static bool has_offload_slaves(struct sna *sna)
17511{
17512#if HAS_PIXMAP_SHARING
17513	ScreenPtr screen = to_screen_from_sna(sna);
17514	PixmapDirtyUpdatePtr dirty;
17515
17516	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
17517		assert(dirty->src == sna->front);
17518		if (RegionNotEmpty(DamageRegion(dirty->damage)))
17519			return true;
17520	}
17521#endif
17522	return false;
17523}
17524
17525static bool has_shadow(struct sna *sna)
17526{
17527	DamagePtr damage;
17528
17529	if (!sna->mode.shadow_enabled)
17530		return false;
17531
17532	damage = sna->mode.shadow_damage;
17533	assert(damage);
17534
17535	DBG(("%s: has pending damage? %d, outstanding flips: %d\n",
17536	     __FUNCTION__,
17537	     RegionNotEmpty(DamageRegion(damage)),
17538	     sna->mode.flip_active));
17539
17540	return RegionNotEmpty(DamageRegion(damage));
17541}
17542
17543static bool start_flush(struct sna *sna)
17544{
17545	struct sna_pixmap *scanout;
17546
17547	if (has_offload_slaves(sna)) {
17548		DBG(("%s: has offload slaves\n", __FUNCTION__));
17549		return true;
17550	}
17551
17552	if (has_shadow(sna)) {
17553		DBG(("%s: has dirty shadow\n", __FUNCTION__));
17554		return true;
17555	}
17556
17557	scanout = sna_accel_scanout(sna);
17558	if (!scanout)
17559		return false;
17560
17561	if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) {
17562		scanout->gpu_bo->needs_flush = true;
17563		return true;
17564	}
17565
17566	if (scanout->cpu_damage || scanout->gpu_bo->needs_flush)
17567		return true;
17568
17569	kgem_scanout_flush(&sna->kgem, scanout->gpu_bo);
17570	return false;
17571}
17572
17573static bool stop_flush(struct sna *sna, struct sna_pixmap *scanout)
17574{
17575	DBG(("%s: scanout=%d shadow?=%d, slaves?=%d, (cpu?=%d || gpu?=%d))\n",
17576	     __FUNCTION__,
17577	     scanout && scanout->gpu_bo ? scanout->gpu_bo->handle : 0,
17578	     has_shadow(sna), has_offload_slaves(sna),
17579	     scanout && scanout->cpu_damage != NULL,
17580	     scanout && scanout->gpu_bo && scanout->gpu_bo->rq != NULL));
17581
17582	if (has_offload_slaves(sna))
17583		return true;
17584
17585	if (has_shadow(sna))
17586		return true;
17587
17588	if (!scanout)
17589		return false;
17590
17591	if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) {
17592		scanout->gpu_bo->needs_flush = true;
17593		return true;
17594	}
17595
17596	return scanout->cpu_damage || scanout->gpu_bo->needs_flush;
17597}
17598
17599static void timer_enable(struct sna *sna, int whom, int interval)
17600{
17601	if (!sna->timer_active)
17602		UpdateCurrentTimeIf();
17603	sna->timer_active |= 1 << whom;
17604	sna->timer_expire[whom] = TIME + interval;
17605	DBG(("%s (time=%ld), starting timer %d\n", __FUNCTION__, (long)TIME, whom));
17606}
17607
17608static bool sna_scanout_do_flush(struct sna *sna)
17609{
17610	int interval = sna->vblank_interval ?: 50;
17611	if (sna->timer_active & (1<<(FLUSH_TIMER))) {
17612		int32_t delta = sna->timer_expire[FLUSH_TIMER] - TIME;
17613		DBG(("%s: flush timer active: delta=%d\n",
17614		     __FUNCTION__, delta));
17615		if (delta <= 3) {
17616			DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME));
17617			sna->timer_expire[FLUSH_TIMER] = TIME + interval;
17618			return true;
17619		}
17620	} else {
17621		if (start_flush(sna))
17622			timer_enable(sna, FLUSH_TIMER, interval/2);
17623	}
17624
17625	return false;
17626}
17627
17628static bool sna_accel_do_throttle(struct sna *sna)
17629{
17630	if (sna->timer_active & (1<<(THROTTLE_TIMER))) {
17631		int32_t delta = sna->timer_expire[THROTTLE_TIMER] - TIME;
17632		if (delta <= 3) {
17633			DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME));
17634			sna->timer_expire[THROTTLE_TIMER] = TIME + 20;
17635			return true;
17636		}
17637	} else if (!sna->kgem.need_retire) {
17638		DBG(("%s -- no pending activity\n", __FUNCTION__));
17639	} else
17640		timer_enable(sna, THROTTLE_TIMER, 20);
17641
17642	return false;
17643}
17644
17645static bool sna_accel_do_expire(struct sna *sna)
17646{
17647	if (sna->timer_active & (1<<(EXPIRE_TIMER))) {
17648		int32_t delta = sna->timer_expire[EXPIRE_TIMER] - TIME;
17649		if (delta <= 3) {
17650			DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME));
17651			sna->timer_expire[EXPIRE_TIMER] =
17652				TIME + MAX_INACTIVE_TIME * 1000;
17653			return true;
17654		}
17655	} else if (sna->kgem.need_expire)
17656		timer_enable(sna, EXPIRE_TIMER, MAX_INACTIVE_TIME * 1000);
17657
17658	return false;
17659}
17660
17661static void sna_accel_post_damage(struct sna *sna)
17662{
17663#if HAS_PIXMAP_SHARING
17664	ScreenPtr screen = to_screen_from_sna(sna);
17665	PixmapDirtyUpdatePtr dirty;
17666
17667	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
17668		RegionRec region, *damage;
17669		PixmapPtr src, dst;
17670		const BoxRec *box;
17671		int16_t dx, dy;
17672		int n;
17673
17674		damage = DamageRegion(dirty->damage);
17675		if (RegionNil(damage))
17676			continue;
17677
17678		src = (PixmapPtr)dirty->src;
17679		dst = dirty->slave_dst->master_pixmap;
17680
17681		region.extents.x1 = dirty->x;
17682		region.extents.x2 = dirty->x + dst->drawable.width;
17683		region.extents.y1 = dirty->y;
17684		region.extents.y2 = dirty->y + dst->drawable.height;
17685		region.data = NULL;
17686
17687		DBG(("%s: pushing damage ((%d, %d), (%d, %d))x%d to slave pixmap=%d, ((%d, %d), (%d, %d))\n", __FUNCTION__,
17688		     damage->extents.x1, damage->extents.y1,
17689		     damage->extents.x2, damage->extents.y2,
17690		     region_num_rects(damage),
17691		     dst->drawable.serialNumber,
17692		     region.extents.x1, region.extents.y1,
17693		     region.extents.x2, region.extents.y2));
17694
17695		RegionIntersect(&region, &region, damage);
17696		if (RegionNil(&region))
17697			goto skip;
17698
17699		dx = -dirty->x;
17700		dy = -dirty->y;
17701#if HAS_DIRTYTRACKING2
17702		dx += dirty->dst_x;
17703		dy += dirty->dst_y;
17704#endif
17705		RegionTranslate(&region, dx, dy);
17706		DamageRegionAppend(&dirty->slave_dst->drawable, &region);
17707
17708		DBG(("%s: slave:  ((%d, %d), (%d, %d))x%d\n", __FUNCTION__,
17709		     region.extents.x1, region.extents.y1,
17710		     region.extents.x2, region.extents.y2,
17711		     region_num_rects(&region)));
17712
17713		box = region_rects(&region);
17714		n = region_num_rects(&region);
17715		if (wedged(sna)) {
17716fallback:
17717			if (!sna_pixmap_move_to_cpu(src, MOVE_READ))
17718				goto skip;
17719
17720			if (!sna_pixmap_move_to_cpu(dst, MOVE_READ | MOVE_WRITE | MOVE_INPLACE_HINT))
17721				goto skip;
17722
17723			if (sigtrap_get() == 0) {
17724				assert(src->drawable.bitsPerPixel == dst->drawable.bitsPerPixel);
17725				do {
17726					DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n",
17727					     __FUNCTION__,
17728					     box->x1 - dx, box->y1 - dy,
17729					     box->x1, box->y1,
17730					     box->x2 - box->x1, box->y2 - box->y1));
17731
17732					assert(box->x2 > box->x1);
17733					assert(box->y2 > box->y1);
17734
17735					assert(box->x1 - dx >= 0);
17736					assert(box->y1 - dy >= 0);
17737					assert(box->x2 - dx <= src->drawable.width);
17738					assert(box->y2 - dy <= src->drawable.height);
17739
17740					assert(box->x1 >= 0);
17741					assert(box->y1 >= 0);
17742					assert(box->x2 <= src->drawable.width);
17743					assert(box->y2 <= src->drawable.height);
17744
17745					assert(has_coherent_ptr(sna, sna_pixmap(src), MOVE_READ));
17746					assert(has_coherent_ptr(sna, sna_pixmap(dst), MOVE_WRITE));
17747					assert(src->devKind);
17748					assert(dst->devKind);
17749					memcpy_blt(src->devPrivate.ptr,
17750						   dst->devPrivate.ptr,
17751						   src->drawable.bitsPerPixel,
17752						   src->devKind, dst->devKind,
17753						   box->x1 - dx,      box->y1 - dy,
17754						   box->x1,           box->y1,
17755						   box->x2 - box->x1, box->y2 - box->y1);
17756					box++;
17757				} while (--n);
17758				sigtrap_put();
17759			}
17760		} else {
17761			if (!sna_pixmap_move_to_gpu(src, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE))
17762				goto fallback;
17763
17764			if (!sna_pixmap_move_to_gpu(dst, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE))
17765				goto fallback;
17766
17767			if (!sna->render.copy_boxes(sna, GXcopy,
17768						    &src->drawable, __sna_pixmap_get_bo(src), -dx, -dy,
17769						    &dst->drawable, __sna_pixmap_get_bo(dst),   0,   0,
17770						    box, n, COPY_LAST))
17771				goto fallback;
17772
17773			/* Before signalling the slave via ProcessPending,
17774			 * ensure not only the batch is submitted as the
17775			 * slave may be using the Damage callback to perform
17776			 * its copy, but also that the memory must be coherent
17777			 * - we need to treat it as uncached for the PCI slave
17778			 * will bypass LLC.
17779			 */
17780			kgem_bo_sync__gtt(&sna->kgem, __sna_pixmap_get_bo(dst));
17781		}
17782
17783		DamageRegionProcessPending(&dirty->slave_dst->drawable);
17784skip:
17785		RegionUninit(&region);
17786		DamageEmpty(dirty->damage);
17787	}
17788#endif
17789}
17790
17791static void sna_scanout_flush(struct sna *sna)
17792{
17793	struct sna_pixmap *priv = sna_accel_scanout(sna);
17794	bool busy;
17795
17796	DBG(("%s (time=%ld), cpu damage? %d, exec? %d nbatch=%d, busy? %d\n",
17797	     __FUNCTION__, (long)TIME,
17798	     priv && priv->cpu_damage,
17799	     priv && priv->gpu_bo->exec != NULL,
17800	     sna->kgem.nbatch,
17801	     sna->kgem.busy));
17802
17803	busy = stop_flush(sna, priv);
17804	if (!sna->kgem.busy && !busy)
17805		sna_accel_disarm_timer(sna, FLUSH_TIMER);
17806	sna->kgem.busy = busy;
17807
17808	if (priv &&
17809	    sna->mode.shadow_damage == NULL &&
17810	    sna_pixmap_force_to_gpu(priv->pixmap,
17811				    MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT))
17812		kgem_scanout_flush(&sna->kgem, priv->gpu_bo);
17813
17814	sna_mode_redisplay(sna);
17815	sna_accel_post_damage(sna);
17816}
17817
17818static void sna_accel_throttle(struct sna *sna)
17819{
17820	DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME));
17821
17822	if (sna->kgem.need_throttle) {
17823		kgem_submit(&sna->kgem);
17824		kgem_throttle(&sna->kgem);
17825	}
17826
17827	if (!sna->kgem.need_retire)
17828		sna_accel_disarm_timer(sna, THROTTLE_TIMER);
17829}
17830
17831static void sna_pixmap_expire(struct sna *sna)
17832{
17833	while (sna->freed_pixmap) {
17834		PixmapPtr pixmap = __pop_freed_pixmap(sna);
17835		free(sna_pixmap(pixmap));
17836		FreePixmap(pixmap);
17837	}
17838}
17839
17840static void sna_accel_expire(struct sna *sna)
17841{
17842	DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME));
17843
17844	kgem_expire_cache(&sna->kgem);
17845	sna_pixmap_expire(sna);
17846
17847	if (!sna->kgem.need_expire)
17848		sna_accel_disarm_timer(sna, EXPIRE_TIMER);
17849}
17850
17851#ifdef DEBUG_MEMORY
17852static bool sna_accel_do_debug_memory(struct sna *sna)
17853{
17854	int32_t delta = sna->timer_expire[DEBUG_MEMORY_TIMER] - TIME;
17855
17856	if (delta <= 3) {
17857		sna->timer_expire[DEBUG_MEMORY_TIMER] = TIME + 10 * 1000;
17858		return true;
17859	} else
17860		return false;
17861}
17862
17863static void sna_accel_debug_memory(struct sna *sna)
17864{
17865	ErrorF("Allocated pixmaps: %d (cached: %d), bo: %d, %lu bytes (CPU bo: %d, %lu bytes)\n",
17866	       sna->debug_memory.pixmap_allocs,
17867	       sna->debug_memory.pixmap_cached,
17868	       sna->kgem.debug_memory.bo_allocs,
17869	       (unsigned long)sna->kgem.debug_memory.bo_bytes,
17870	       sna->debug_memory.cpu_bo_allocs,
17871	       (unsigned long)sna->debug_memory.cpu_bo_bytes);
17872
17873#ifdef VALGRIND_DO_ADDED_LEAK_CHECK
17874	VG(VALGRIND_DO_ADDED_LEAK_CHECK);
17875#endif
17876}
17877
17878#else
17879#define sna_accel_do_debug_memory(x) 0
17880static void sna_accel_debug_memory(struct sna *sna) { }
17881#endif
17882
17883static ShmFuncs shm_funcs = { sna_pixmap_create_shm, NULL };
17884
17885static PixmapPtr
17886sna_get_window_pixmap(WindowPtr window)
17887{
17888	return get_window_pixmap(window);
17889}
17890
17891static void
17892sna_set_window_pixmap(WindowPtr window, PixmapPtr pixmap)
17893{
17894	DBG(("%s: window=%ld, old pixmap=%ld new pixmap=%ld\n",
17895	     __FUNCTION__, window->drawable.id,
17896	     get_window_pixmap(window) ? get_window_pixmap(window)->drawable.serialNumber : 0,
17897	     pixmap->drawable.serialNumber));
17898
17899	sna_dri2_decouple_window(window);
17900
17901	*(PixmapPtr *)__get_private(window, sna_window_key) = pixmap;
17902}
17903
17904struct sna_visit_set_pixmap_window {
17905	PixmapPtr old, new;
17906};
17907
17908static int
17909sna_visit_set_window_pixmap(WindowPtr window, pointer data)
17910{
17911    struct sna_visit_set_pixmap_window *visit = data;
17912
17913    if (sna_get_window_pixmap(window) == visit->old) {
17914	    window->drawable.pScreen->SetWindowPixmap(window, visit->new);
17915	    return WT_WALKCHILDREN;
17916    }
17917
17918    return WT_DONTWALKCHILDREN;
17919}
17920
17921static void
17922migrate_dirty_tracking(PixmapPtr old_front, PixmapPtr new_front)
17923{
17924#if HAS_PIXMAP_SHARING
17925	ScreenPtr screen = old_front->drawable.pScreen;
17926	PixmapDirtyUpdatePtr dirty, safe;
17927
17928	xorg_list_for_each_entry_safe(dirty, safe, &screen->pixmap_dirty_list, ent) {
17929		assert(dirty->src == old_front);
17930		if ((PixmapPtr)dirty->src != old_front)
17931			continue;
17932
17933		DamageUnregister(&dirty->src->drawable, dirty->damage);
17934		DamageDestroy(dirty->damage);
17935
17936		dirty->damage = DamageCreate(NULL, NULL,
17937					     DamageReportNone,
17938					     TRUE, screen, screen);
17939		if (!dirty->damage) {
17940			xorg_list_del(&dirty->ent);
17941			free(dirty);
17942			continue;
17943		}
17944
17945		DamageRegister(&new_front->drawable, dirty->damage);
17946		dirty->src = (DrawablePtr)new_front;
17947	}
17948#endif
17949}
17950
17951static void
17952sna_set_screen_pixmap(PixmapPtr pixmap)
17953{
17954	ScreenPtr screen = pixmap->drawable.pScreen;
17955	PixmapPtr old_front = screen->devPrivate;
17956	WindowPtr root;
17957
17958	DBG(("%s: changing from pixmap=%ld to pixmap=%ld, (sna->front=%ld)\n",
17959	     __FUNCTION__,
17960	     old_front ? (long)old_front->drawable.serialNumber : 0,
17961	     pixmap ? (long)pixmap->drawable.serialNumber : 0,
17962	     to_sna_from_pixmap(pixmap)->front ? (long)to_sna_from_pixmap(pixmap)->front->drawable.serialNumber : 0));
17963
17964	assert(to_sna_from_pixmap(pixmap) == to_sna_from_screen(screen));
17965	assert(to_sna_from_pixmap(pixmap)->front == old_front);
17966
17967	if (old_front) {
17968		assert(to_sna_from_pixmap(old_front)->front == old_front);
17969		migrate_dirty_tracking(old_front, pixmap);
17970	}
17971
17972	root = get_root_window(screen);
17973	if (root) {
17974		struct sna_visit_set_pixmap_window visit = { old_front, pixmap };
17975		TraverseTree(root, sna_visit_set_window_pixmap, &visit);
17976		assert(fbGetWindowPixmap(root) == pixmap);
17977	}
17978
17979	to_sna_from_pixmap(pixmap)->front = pixmap;
17980	screen->devPrivate = pixmap;
17981	pixmap->refcnt++;
17982
17983	if (old_front)
17984		screen->DestroyPixmap(old_front);
17985}
17986
17987static Bool
17988sna_create_window(WindowPtr win)
17989{
17990	DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
17991	sna_set_window_pixmap(win, win->drawable.pScreen->devPrivate);
17992	return TRUE;
17993}
17994
17995static Bool
17996sna_map_window(WindowPtr win)
17997{
17998	return TRUE;
17999}
18000
18001static Bool
18002sna_position_window(WindowPtr win, int x, int y)
18003{
18004	return TRUE;
18005}
18006
18007static Bool
18008sna_unmap_window(WindowPtr win)
18009{
18010	return TRUE;
18011}
18012
18013static Bool
18014sna_destroy_window(WindowPtr win)
18015{
18016	DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
18017	sna_video_destroy_window(win);
18018	sna_dri2_destroy_window(win);
18019	return TRUE;
18020}
18021
18022static void
18023sna_query_best_size(int class,
18024		    unsigned short *width, unsigned short *height,
18025		    ScreenPtr screen)
18026{
18027	unsigned short w;
18028
18029	switch (class) {
18030	case CursorShape:
18031		if (*width > screen->width)
18032			*width = screen->width;
18033		if (*height > screen->height)
18034			*height = screen->height;
18035		break;
18036
18037	case TileShape:
18038	case StippleShape:
18039		w = *width;
18040		if ((w & (w - 1)) && w < FB_UNIT) {
18041			for (w = 1; w < *width; w <<= 1)
18042				;
18043			*width = w;
18044		}
18045		break;
18046	}
18047}
18048
18049static void sna_store_colors(ColormapPtr cmap, int n, xColorItem *def)
18050{
18051}
18052
18053static bool sna_picture_init(ScreenPtr screen)
18054{
18055	PictureScreenPtr ps;
18056
18057	DBG(("%s\n", __FUNCTION__));
18058
18059	if (!miPictureInit(screen, NULL, 0))
18060		return false;
18061
18062	ps = GetPictureScreen(screen);
18063	assert(ps != NULL);
18064	assert(ps->CreatePicture != NULL);
18065	assert(ps->DestroyPicture != NULL);
18066
18067	ps->Composite = sna_composite;
18068	ps->CompositeRects = sna_composite_rectangles;
18069	ps->Glyphs = sna_glyphs;
18070	if (xf86IsEntityShared(xf86ScreenToScrn(screen)->entityList[0]))
18071		ps->Glyphs = sna_glyphs__shared;
18072	ps->UnrealizeGlyph = sna_glyph_unrealize;
18073	ps->AddTraps = sna_add_traps;
18074	ps->Trapezoids = sna_composite_trapezoids;
18075#if HAS_PIXMAN_TRIANGLES
18076	ps->Triangles = sna_composite_triangles;
18077#if PICTURE_SCREEN_VERSION >= 2
18078	ps->TriStrip = sna_composite_tristrip;
18079	ps->TriFan = sna_composite_trifan;
18080#endif
18081#endif
18082
18083	return true;
18084}
18085
18086static bool sna_option_accel_none(struct sna *sna)
18087{
18088	const char *s;
18089
18090	if (wedged(sna))
18091		return true;
18092
18093	if (!xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_ENABLE, TRUE))
18094		return true;
18095
18096	if (sna->kgem.gen >= 0120)
18097		return true;
18098
18099	if (!intel_option_cast_to_bool(sna->Options,
18100				       OPTION_ACCEL_METHOD,
18101				       !IS_DEFAULT_ACCEL_METHOD(NOACCEL)))
18102		return false;
18103
18104#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
18105	s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD);
18106	if (s == NULL)
18107		return IS_DEFAULT_ACCEL_METHOD(NOACCEL);
18108
18109	return strcasecmp(s, "none") == 0;
18110#else
18111	return IS_DEFAULT_ACCEL_METHOD(NOACCEL);
18112#endif
18113}
18114
18115static bool sna_option_accel_blt(struct sna *sna)
18116{
18117	const char *s;
18118
18119	assert(sna->kgem.gen < 0120);
18120
18121	s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD);
18122	if (s == NULL)
18123		return false;
18124
18125	return strcasecmp(s, "blt") == 0;
18126}
18127
18128#if HAVE_NOTIFY_FD
18129static void sna_accel_notify(int fd, int ready, void *data)
18130{
18131	sna_mode_wakeup(data);
18132}
18133#endif
18134
18135bool sna_accel_init(ScreenPtr screen, struct sna *sna)
18136{
18137	const char *backend;
18138
18139	DBG(("%s\n", __FUNCTION__));
18140
18141	sna_font_key = AllocateFontPrivateIndex();
18142
18143	list_init(&sna->flush_pixmaps);
18144	list_init(&sna->active_pixmaps);
18145
18146	SetNotifyFd(sna->kgem.fd, sna_accel_notify, X_NOTIFY_READ, sna);
18147
18148#ifdef DEBUG_MEMORY
18149	sna->timer_expire[DEBUG_MEMORY_TIMER] = GetTimeInMillis()+ 10 * 1000;
18150#endif
18151
18152	screen->defColormap = FakeClientID(0);
18153	/* let CreateDefColormap do whatever it wants for pixels */
18154	screen->blackPixel = screen->whitePixel = (Pixel) 0;
18155	screen->QueryBestSize = sna_query_best_size;
18156	assert(screen->GetImage == NULL);
18157	screen->GetImage = sna_get_image;
18158	assert(screen->GetSpans == NULL);
18159	screen->GetSpans = sna_get_spans;
18160	assert(screen->CreateWindow == NULL);
18161	screen->CreateWindow = sna_create_window;
18162	assert(screen->DestroyWindow == NULL);
18163	screen->DestroyWindow = sna_destroy_window;
18164	screen->PositionWindow = sna_position_window;
18165	screen->ChangeWindowAttributes = sna_change_window_attributes;
18166	screen->RealizeWindow = sna_map_window;
18167	screen->UnrealizeWindow = sna_unmap_window;
18168	screen->CopyWindow = sna_copy_window;
18169	assert(screen->CreatePixmap == NULL);
18170	screen->CreatePixmap = sna_create_pixmap;
18171	assert(screen->DestroyPixmap == NULL);
18172	screen->DestroyPixmap = sna_destroy_pixmap;
18173#ifdef CREATE_PIXMAP_USAGE_SHARED
18174	screen->SharePixmapBacking = sna_share_pixmap_backing;
18175	screen->SetSharedPixmapBacking = sna_set_shared_pixmap_backing;
18176#endif
18177	screen->RealizeFont = sna_realize_font;
18178	screen->UnrealizeFont = sna_unrealize_font;
18179	assert(screen->CreateGC == NULL);
18180	screen->CreateGC = sna_create_gc;
18181	screen->CreateColormap = miInitializeColormap;
18182	screen->DestroyColormap = (void (*)(ColormapPtr)) NoopDDA;
18183	screen->InstallColormap = miInstallColormap;
18184	screen->UninstallColormap = miUninstallColormap;
18185	screen->ListInstalledColormaps = miListInstalledColormaps;
18186	screen->ResolveColor = miResolveColor;
18187	assert(screen->StoreColors == NULL);
18188	screen->StoreColors = sna_store_colors;
18189	screen->BitmapToRegion = fbBitmapToRegion;
18190
18191#if HAS_PIXMAP_SHARING
18192	screen->StartPixmapTracking = PixmapStartDirtyTracking;
18193	screen->StopPixmapTracking = PixmapStopDirtyTracking;
18194#endif
18195
18196	assert(screen->GetWindowPixmap == NULL);
18197	screen->GetWindowPixmap = sna_get_window_pixmap;
18198	assert(screen->SetWindowPixmap == NULL);
18199	screen->SetWindowPixmap = sna_set_window_pixmap;
18200
18201	screen->SetScreenPixmap = sna_set_screen_pixmap;
18202
18203	if (sna->kgem.has_userptr)
18204		ShmRegisterFuncs(screen, &shm_funcs);
18205	else
18206		ShmRegisterFbFuncs(screen);
18207
18208	if (!sna_picture_init(screen))
18209		return false;
18210
18211	backend = no_render_init(sna);
18212	if (sna_option_accel_none(sna)) {
18213		backend = "disabled";
18214		sna->kgem.wedged = true;
18215		sna_render_mark_wedged(sna);
18216	} else if (sna_option_accel_blt(sna))
18217		(void)backend;
18218	else if (sna->kgem.gen >= 0110)
18219		backend = gen9_render_init(sna, backend);
18220	else if (sna->kgem.gen >= 0100)
18221		backend = gen8_render_init(sna, backend);
18222	else if (sna->kgem.gen >= 070)
18223		backend = gen7_render_init(sna, backend);
18224	else if (sna->kgem.gen >= 060)
18225		backend = gen6_render_init(sna, backend);
18226	else if (sna->kgem.gen >= 050)
18227		backend = gen5_render_init(sna, backend);
18228	else if (sna->kgem.gen >= 040)
18229		backend = gen4_render_init(sna, backend);
18230	else if (sna->kgem.gen >= 030)
18231		backend = gen3_render_init(sna, backend);
18232	else if (sna->kgem.gen >= 020)
18233		backend = gen2_render_init(sna, backend);
18234
18235	DBG(("%s(backend=%s, prefer_gpu=%x)\n",
18236	     __FUNCTION__, backend, sna->render.prefer_gpu));
18237
18238	kgem_reset(&sna->kgem);
18239	sigtrap_init();
18240
18241	xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
18242		   "SNA initialized with %s backend\n",
18243		   backend);
18244
18245	return true;
18246}
18247
18248void sna_accel_create(struct sna *sna)
18249{
18250	ExtensionEntry *damage;
18251
18252	DBG(("%s\n", __FUNCTION__));
18253
18254	damage = CheckExtension("DAMAGE");
18255	if (damage)
18256		sna->damage_event = damage->eventBase + XDamageNotify;
18257
18258	if (!sna_glyphs_create(sna))
18259		goto fail;
18260
18261	if (!sna_gradients_create(sna))
18262		goto fail;
18263
18264	if (!sna_composite_create(sna))
18265		goto fail;
18266
18267	return;
18268
18269fail:
18270	xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
18271		   "Failed to allocate caches, disabling RENDER acceleration\n");
18272	no_render_init(sna);
18273}
18274
18275static void sna_shm_watch_flush(struct sna *sna, int enable)
18276{
18277	DBG(("%s: enable=%d\n", __FUNCTION__, enable));
18278	assert(enable);
18279
18280	if (sna->watch_shm_flush == 0) {
18281		DBG(("%s: installing shm watchers\n", __FUNCTION__));
18282		assert(enable > 0);
18283
18284		if (!AddCallback(&FlushCallback, sna_shm_flush_callback, sna))
18285			return;
18286
18287		sna->watch_shm_flush++;
18288	}
18289
18290	sna->watch_shm_flush += enable;
18291}
18292
18293void sna_watch_flush(struct sna *sna, int enable)
18294{
18295	DBG(("%s: enable=%d\n", __FUNCTION__, enable));
18296	assert(enable);
18297
18298	if (sna->watch_dri_flush == 0) {
18299		int err = 0;
18300
18301		DBG(("%s: installing watchers\n", __FUNCTION__));
18302		assert(enable > 0);
18303
18304		if (!sna->damage_event)
18305			return;
18306
18307		if (!AddCallback(&EventCallback, sna_event_callback, sna))
18308			err = 1;
18309
18310		if (!AddCallback(&FlushCallback, sna_flush_callback, sna))
18311			err = 1;
18312
18313		if (err) {
18314			xf86DrvMsg(sna->scrn->scrnIndex, X_Error,
18315				   "Failed to attach ourselves to the flush callbacks, expect missing synchronisation with DRI clients (e.g a compositor)\n");
18316		}
18317
18318		sna->watch_dri_flush++;
18319	}
18320
18321	sna->watch_dri_flush += enable;
18322}
18323
18324void sna_accel_leave(struct sna *sna)
18325{
18326	DBG(("%s\n", __FUNCTION__));
18327	sna_scanout_flush(sna);
18328
18329	/* as root we always have permission to render */
18330	if (geteuid() == 0)
18331		return;
18332
18333	/* as a user, we can only render now if we have a rendernode */
18334	if (intel_has_render_node(sna->dev))
18335		return;
18336
18337	/* no longer authorized to use our fd */
18338	DBG(("%s: dropping render privileges\n", __FUNCTION__));
18339
18340	kgem_submit(&sna->kgem);
18341	sna->kgem.wedged |= 2;
18342}
18343
18344void sna_accel_enter(struct sna *sna)
18345{
18346	DBG(("%s\n", __FUNCTION__));
18347	sna->kgem.wedged &= kgem_is_wedged(&sna->kgem);
18348	kgem_throttle(&sna->kgem);
18349}
18350
18351void sna_accel_close(struct sna *sna)
18352{
18353	DBG(("%s\n", __FUNCTION__));
18354
18355	sna_composite_close(sna);
18356	sna_gradients_close(sna);
18357	sna_glyphs_close(sna);
18358
18359	sna_pixmap_expire(sna);
18360
18361	DeleteCallback(&FlushCallback, sna_shm_flush_callback, sna);
18362	DeleteCallback(&FlushCallback, sna_flush_callback, sna);
18363	DeleteCallback(&EventCallback, sna_event_callback, sna);
18364	RemoveNotifyFd(sna->kgem.fd);
18365
18366	kgem_cleanup_cache(&sna->kgem);
18367}
18368
18369void sna_accel_block(struct sna *sna, struct timeval **tv)
18370{
18371	sigtrap_assert_inactive();
18372
18373	if (sna->kgem.need_retire)
18374		kgem_retire(&sna->kgem);
18375	kgem_retire__buffers(&sna->kgem);
18376
18377	if (sna->timer_active)
18378		UpdateCurrentTimeIf();
18379
18380	if (sna->kgem.nbatch &&
18381	    (sna->kgem.scanout_busy ||
18382	     kgem_ring_is_idle(&sna->kgem, sna->kgem.ring))) {
18383		DBG(("%s: GPU idle, flushing\n", __FUNCTION__));
18384		_kgem_submit(&sna->kgem);
18385	}
18386
18387	if (sna->mode.dirty)
18388		sna_crtc_config_notify(xf86ScrnToScreen(sna->scrn));
18389
18390restart:
18391	if (sna_scanout_do_flush(sna))
18392		sna_scanout_flush(sna);
18393	assert(sna_accel_scanout(sna) == NULL ||
18394	       !sna_accel_scanout(sna)->gpu_bo->needs_flush ||
18395	       sna->timer_active & (1<<(FLUSH_TIMER)));
18396
18397	if (sna_accel_do_throttle(sna))
18398		sna_accel_throttle(sna);
18399	assert(!sna->kgem.need_retire ||
18400	       sna->timer_active & (1<<(THROTTLE_TIMER)));
18401
18402	if (sna_accel_do_expire(sna))
18403		sna_accel_expire(sna);
18404	assert(!sna->kgem.need_expire ||
18405	       sna->timer_active & (1<<(EXPIRE_TIMER)));
18406
18407	if (sna_accel_do_debug_memory(sna))
18408		sna_accel_debug_memory(sna);
18409
18410	if (sna->watch_shm_flush == 1) {
18411		DBG(("%s: removing shm watchers\n", __FUNCTION__));
18412		DeleteCallback(&FlushCallback, sna_shm_flush_callback, sna);
18413		sna->watch_shm_flush = 0;
18414	}
18415
18416	if (sna->watch_dri_flush == 1) {
18417		DBG(("%s: removing dri watchers\n", __FUNCTION__));
18418		DeleteCallback(&FlushCallback, sna_flush_callback, sna);
18419		DeleteCallback(&EventCallback, sna_event_callback, sna);
18420		sna->watch_dri_flush = 0;
18421	}
18422
18423	if (sna->timer_active & 1) {
18424		int32_t timeout;
18425
18426		DBG(("%s: evaluating timers, active=%x\n",
18427		     __FUNCTION__, sna->timer_active));
18428
18429		timeout = sna->timer_expire[FLUSH_TIMER] - TIME;
18430		DBG(("%s: flush timer expires in %d [%d]\n",
18431		     __FUNCTION__, timeout, sna->timer_expire[FLUSH_TIMER]));
18432		if (timeout < 3)
18433			goto restart;
18434
18435		if (*tv == NULL) {
18436			*tv = &sna->timer_tv;
18437			goto set_tv;
18438		}
18439		if ((*tv)->tv_sec * 1000 + (*tv)->tv_usec / 1000 > timeout) {
18440set_tv:
18441			(*tv)->tv_sec = timeout / 1000;
18442			(*tv)->tv_usec = timeout % 1000 * 1000;
18443		}
18444	}
18445
18446	sna->kgem.scanout_busy = false;
18447
18448	if (FAULT_INJECTION && (rand() % FAULT_INJECTION) == 0) {
18449		DBG(("%s hardware acceleration\n",
18450		     sna->kgem.wedged ? "Re-enabling" : "Disabling"));
18451		kgem_submit(&sna->kgem);
18452		sna->kgem.wedged = !sna->kgem.wedged;
18453	}
18454}
18455
18456void sna_accel_free(struct sna *sna)
18457{
18458	DBG(("%s\n", __FUNCTION__));
18459	sigtrap_assert_inactive();
18460}
18461