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 <sys/time.h>
54#include <sys/mman.h>
55#include <unistd.h>
56
57#ifdef HAVE_VALGRIND
58#include <valgrind.h>
59#include <memcheck.h>
60#endif
61
62#define FAULT_INJECTION 0
63
64#define FORCE_INPLACE 0
65#define FORCE_FALLBACK 0
66#define FORCE_FLUSH 0
67#define FORCE_FULL_SYNC 0 /* https://bugs.freedesktop.org/show_bug.cgi?id=61628 */
68
69#define DEFAULT_TILING I915_TILING_X
70
71#define USE_INPLACE 1
72#define USE_SPANS 0 /* -1 force CPU, 1 force GPU */
73#define USE_CPU_BO 1
74#define USE_USERPTR_UPLOADS 1
75#define USE_USERPTR_DOWNLOADS 1
76#define USE_COW 1
77#define UNDO 1
78
79#define MIGRATE_ALL 0
80#define DBG_NO_PARTIAL_MOVE_TO_CPU 0
81#define DBG_NO_CPU_UPLOAD 0
82#define DBG_NO_CPU_DOWNLOAD 0
83
84#define ACCEL_FILL_SPANS 1
85#define ACCEL_SET_SPANS 1
86#define ACCEL_PUT_IMAGE 1
87#define ACCEL_GET_IMAGE 1
88#define ACCEL_COPY_AREA 1
89#define ACCEL_COPY_PLANE 1
90#define ACCEL_COPY_WINDOW 1
91#define ACCEL_POLY_POINT 1
92#define ACCEL_POLY_LINE 1
93#define ACCEL_POLY_SEGMENT 1
94#define ACCEL_POLY_RECTANGLE 1
95#define ACCEL_POLY_ARC 1
96#define ACCEL_POLY_FILL_POLYGON 1
97#define ACCEL_POLY_FILL_RECT 1
98#define ACCEL_POLY_FILL_ARC 1
99#define ACCEL_POLY_TEXT8 1
100#define ACCEL_POLY_TEXT16 1
101#define ACCEL_POLY_GLYPH 1
102#define ACCEL_IMAGE_TEXT8 1
103#define ACCEL_IMAGE_TEXT16 1
104#define ACCEL_IMAGE_GLYPH 1
105#define ACCEL_PUSH_PIXELS 1
106
107#define NO_TILE_8x8 0
108#define NO_STIPPLE_8x8 0
109
110#define IS_COW_OWNER(ptr) ((uintptr_t)(ptr) & 1)
111#define MAKE_COW_OWNER(ptr) ((void*)((uintptr_t)(ptr) | 1))
112#define COW(ptr) (void *)((uintptr_t)(ptr) & ~1)
113
114#define IS_CLIPPED	0x2
115#define RECTILINEAR	0x4
116#define OVERWRITES	0x8
117
118#if 0
119static void __sna_fallback_flush(DrawablePtr d)
120{
121	PixmapPtr pixmap = get_drawable_pixmap(d);
122	struct sna *sna = to_sna_from_pixmap(pixmap);
123	struct sna_pixmap *priv;
124	BoxRec box;
125	PixmapPtr tmp;
126	int i, j;
127	char *src, *dst;
128
129	DBG(("%s: uploading CPU damage...\n", __FUNCTION__));
130	priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ);
131	if (priv == NULL)
132		return;
133
134	DBG(("%s: downloading GPU damage...\n", __FUNCTION__));
135	if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
136		return;
137
138	box.x1 = box.y1 = 0;
139	box.x2 = pixmap->drawable.width;
140	box.y2 = pixmap->drawable.height;
141
142	tmp = sna_pixmap_create_unattached(pixmap->drawable.pScreen,
143					   pixmap->drawable.width,
144					   pixmap->drawable.height,
145					   pixmap->drawable.depth,
146					   0);
147
148	DBG(("%s: comparing with direct read...\n", __FUNCTION__));
149	sna_read_boxes(sna, tmp, priv->gpu_bo, &box, 1);
150
151	src = pixmap->devPrivate.ptr;
152	dst = tmp->devPrivate.ptr;
153	for (i = 0; i < tmp->drawable.height; i++) {
154		if (memcmp(src, dst, tmp->drawable.width * tmp->drawable.bitsPerPixel >> 3)) {
155			for (j = 0; src[j] == dst[j]; j++)
156				;
157			ERR(("mismatch at (%d, %d)\n",
158			     8*j / tmp->drawable.bitsPerPixel, i));
159			abort();
160		}
161		src += pixmap->devKind;
162		dst += tmp->devKind;
163	}
164	tmp->drawable.pScreen->DestroyPixmap(tmp);
165}
166#define FALLBACK_FLUSH(d) __sna_fallback_flush(d)
167#else
168#define FALLBACK_FLUSH(d)
169#endif
170
171static int sna_font_key;
172
173static const uint8_t copy_ROP[] = {
174	ROP_0,		/* GXclear */
175	ROP_DSa,	/* GXand */
176	ROP_SDna,	/* GXandReverse */
177	ROP_S,		/* GXcopy */
178	ROP_DSna,	/* GXandInverted */
179	ROP_D,		/* GXnoop */
180	ROP_DSx,	/* GXxor */
181	ROP_DSo,	/* GXor */
182	ROP_DSon,	/* GXnor */
183	ROP_DSxn,	/* GXequiv */
184	ROP_Dn,		/* GXinvert */
185	ROP_SDno,	/* GXorReverse */
186	ROP_Sn,		/* GXcopyInverted */
187	ROP_DSno,	/* GXorInverted */
188	ROP_DSan,	/* GXnand */
189	ROP_1		/* GXset */
190};
191static const uint8_t fill_ROP[] = {
192	ROP_0,
193	ROP_DPa,
194	ROP_PDna,
195	ROP_P,
196	ROP_DPna,
197	ROP_D,
198	ROP_DPx,
199	ROP_DPo,
200	ROP_DPon,
201	ROP_PDxn,
202	ROP_Dn,
203	ROP_PDno,
204	ROP_Pn,
205	ROP_DPno,
206	ROP_DPan,
207	ROP_1
208};
209
210static const GCOps sna_gc_ops;
211static const GCOps sna_gc_ops__cpu;
212static GCOps sna_gc_ops__tmp;
213static const GCFuncs sna_gc_funcs;
214static const GCFuncs sna_gc_funcs__cpu;
215
216static void
217sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect);
218
219static inline void region_set(RegionRec *r, const BoxRec *b)
220{
221	r->extents = *b;
222	r->data = NULL;
223}
224
225static inline bool region_maybe_clip(RegionRec *r, RegionRec *clip)
226{
227	if (clip->data && !RegionIntersect(r, r, clip))
228		return false;
229
230	return !box_empty(&r->extents);
231}
232
233static inline bool region_is_singular(const RegionRec *r)
234{
235	return r->data == NULL;
236}
237
238static inline bool region_is_unclipped(const RegionRec *r, int w, int h)
239{
240	return (region_is_singular(r) &&
241		w == r->extents.x2 - r->extents.x1 &&
242		h == r->extents.y2 - r->extents.y1);
243}
244
245typedef struct box32 {
246	int32_t x1, y1, x2, y2;
247} Box32Rec;
248
249#define PM_IS_SOLID(_draw, _pm) \
250	(((_pm) & FbFullMask((_draw)->depth)) == FbFullMask((_draw)->depth))
251
252#ifndef NDEBUG
253static void _assert_pixmap_contains_box(PixmapPtr pixmap, const BoxRec *box, const char *function)
254{
255	if (box->x1 < 0 || box->y1 < 0 ||
256	    box->x2 > pixmap->drawable.width ||
257	    box->y2 > pixmap->drawable.height)
258	{
259		FatalError("%s: damage box [(%d, %d), (%d, %d)] is beyond the pixmap=%ld size=%dx%d\n",
260			   function, box->x1, box->y1, box->x2, box->y2,
261			   pixmap->drawable.serialNumber,
262			   pixmap->drawable.width,
263			   pixmap->drawable.height);
264	}
265}
266
267static void
268_assert_pixmap_contains_damage(PixmapPtr pixmap, struct sna_damage *damage, const char *function)
269{
270	if (damage == NULL)
271		return;
272
273	_assert_pixmap_contains_box(pixmap, &DAMAGE_PTR(damage)->extents, function);
274}
275#define assert_pixmap_contains_damage(p,d) _assert_pixmap_contains_damage(p, d, __FUNCTION__)
276#else
277#define assert_pixmap_contains_damage(p,d)
278#endif
279
280#define __assert_pixmap_damage(p) do { \
281	struct sna_pixmap *priv__ = sna_pixmap(p); \
282	if (priv__) { \
283		assert(priv__->gpu_damage == NULL || priv__->gpu_bo); \
284		assert(priv__->gpu_bo == NULL || priv__->gpu_bo->refcnt); \
285		assert(priv__->cpu_bo == NULL || priv__->cpu_bo->refcnt); \
286		assert_pixmap_contains_damage(p, priv__->gpu_damage); \
287		assert_pixmap_contains_damage(p, priv__->cpu_damage); \
288		assert_pixmap_map(p, priv__); \
289	} \
290} while (0)
291
292#ifdef DEBUG_PIXMAP
293static void _assert_pixmap_contains_box_with_offset(PixmapPtr pixmap, const BoxRec *box, int dx, int dy, const char *function)
294{
295	BoxRec b = *box;
296	b.x1 += dx; b.x2 += dx;
297	b.y1 += dy; b.y2 += dy;
298	_assert_pixmap_contains_box(pixmap, &b, function);
299}
300
301static void _assert_pixmap_contains_boxes(PixmapPtr pixmap, const BoxRec *box, int n, int dx, int dy, const char *function)
302{
303	BoxRec extents;
304
305	extents = *box;
306	while (--n) {
307		++box;
308
309		if (box->x1 < extents.x1)
310			extents.x1 = box->x1;
311		if (box->x2 > extents.x2)
312			extents.x2 = box->x2;
313
314		if (box->y1 < extents.y1)
315			extents.y1 = box->y1;
316		if (box->y2 > extents.y2)
317			extents.y2 = box->y2;
318	}
319	extents.x1 += dx;
320	extents.x2 += dx;
321	extents.y1 += dy;
322	extents.y2 += dy;
323	_assert_pixmap_contains_box(pixmap, &extents, function);
324}
325
326
327static void _assert_pixmap_contains_points(PixmapPtr pixmap, const DDXPointRec *pt, int n, int dx, int dy, const char *function)
328{
329	BoxRec extents;
330
331	extents.x2 = extents.x1 = pt->x;
332	extents.y2 = extents.y1 = pt->y;
333	while (--n) {
334		++pt;
335
336		if (pt->x < extents.x1)
337			extents.x1 = pt->x;
338		else if (pt->x > extents.x2)
339			extents.x2 = pt->x;
340
341		if (pt->y < extents.y1)
342			extents.y1 = pt->y;
343		else if (pt->y > extents.y2)
344			extents.y2 = pt->y;
345	}
346	extents.x1 += dx;
347	extents.x2 += dx + 1;
348	extents.y1 += dy;
349	extents.y2 += dy + 1;
350	_assert_pixmap_contains_box(pixmap, &extents, function);
351}
352
353static void _assert_drawable_contains_box(DrawablePtr drawable, const BoxRec *box, const char *function)
354{
355	if (box->x1 < drawable->x ||
356	    box->y1 < drawable->y ||
357	    box->x2 > drawable->x + drawable->width ||
358	    box->y2 > drawable->y + drawable->height)
359	{
360		FatalError("%s: damage box is beyond the drawable: box=(%d, %d), (%d, %d), drawable=(%d, %d)x(%d, %d)\n",
361			   function,
362			   box->x1, box->y1, box->x2, box->y2,
363			   drawable->x, drawable->y,
364			   drawable->width, drawable->height);
365	}
366}
367
368static void assert_pixmap_damage(PixmapPtr p)
369{
370	struct sna_pixmap *priv;
371	RegionRec reg, cpu, gpu;
372
373	priv = sna_pixmap(p);
374	if (priv == NULL)
375		return;
376
377	__assert_pixmap_damage(p);
378
379	if (priv->clear) {
380		assert(DAMAGE_IS_ALL(priv->gpu_damage));
381		assert(priv->cpu_damage == NULL);
382	}
383
384	if (DAMAGE_IS_ALL(priv->gpu_damage) && DAMAGE_IS_ALL(priv->cpu_damage)) {
385		/* special upload buffer */
386		assert(priv->gpu_bo && priv->gpu_bo->proxy);
387		assert(priv->cpu_bo == NULL);
388		return;
389	}
390
391	assert(!DAMAGE_IS_ALL(priv->gpu_damage) || priv->cpu_damage == NULL);
392	assert(!DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL);
393
394	/* Avoid reducing damage to minimise interferrence */
395	RegionNull(&reg);
396	RegionNull(&gpu);
397	RegionNull(&cpu);
398
399	if (priv->gpu_damage)
400		_sna_damage_debug_get_region(DAMAGE_PTR(priv->gpu_damage), &gpu);
401
402	if (priv->cpu_damage)
403		_sna_damage_debug_get_region(DAMAGE_PTR(priv->cpu_damage), &cpu);
404
405	RegionIntersect(&reg, &cpu, &gpu);
406	assert(RegionNil(&reg));
407
408	RegionUninit(&reg);
409	RegionUninit(&gpu);
410	RegionUninit(&cpu);
411}
412
413#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__)
414#define assert_pixmap_contains_box_with_offset(p, b, dx, dy) _assert_pixmap_contains_box_with_offset(p, b, dx, dy, __FUNCTION__)
415#define assert_drawable_contains_box(d, b) _assert_drawable_contains_box(d, b, __FUNCTION__)
416#define assert_pixmap_contains_boxes(p, b, n, x, y) _assert_pixmap_contains_boxes(p, b, n, x, y, __FUNCTION__)
417#define assert_pixmap_contains_points(p, pt, n, x, y) _assert_pixmap_contains_points(p, pt, n, x, y, __FUNCTION__)
418
419#else
420#define assert_pixmap_contains_box(p, b)
421#define assert_pixmap_contains_box_with_offset(p, b, dx, dy)
422#define assert_pixmap_contains_boxes(p, b, n, x, y)
423#define assert_pixmap_contains_points(p, pt, n, x, y)
424#define assert_drawable_contains_box(d, b)
425#ifndef NDEBUG
426#define assert_pixmap_damage(p) __assert_pixmap_damage(p)
427#else
428#define assert_pixmap_damage(p)
429#endif
430#endif
431
432jmp_buf sigjmp[4];
433volatile sig_atomic_t sigtrap;
434
435static int sigtrap_handler(int sig)
436{
437	/* XXX rate-limited squawk? */
438	DBG(("%s(sig=%d) sigtrap=%d\n", __FUNCTION__, sig, sigtrap));
439	sna_threads_trap(sig);
440
441	if (sigtrap)
442		siglongjmp(sigjmp[--sigtrap], sig);
443
444	return -1;
445}
446
447static void sigtrap_init(void)
448{
449#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0)
450	OsRegisterSigWrapper(sigtrap_handler);
451#endif
452}
453
454inline static bool
455sna_fill_init_blt(struct sna_fill_op *fill,
456		  struct sna *sna,
457		  PixmapPtr pixmap,
458		  struct kgem_bo *bo,
459		  uint8_t alu,
460		  uint32_t pixel,
461		  unsigned flags)
462{
463	return sna->render.fill(sna, alu, pixmap, bo, pixel, flags, fill);
464}
465
466static bool
467sna_copy_init_blt(struct sna_copy_op *copy,
468		  struct sna *sna,
469		  PixmapPtr src, struct kgem_bo *src_bo,
470		  PixmapPtr dst, struct kgem_bo *dst_bo,
471		  uint8_t alu)
472{
473	memset(copy, 0, sizeof(*copy));
474	return sna->render.copy(sna, alu, src, src_bo, dst, dst_bo, copy);
475}
476
477static void sna_pixmap_free_gpu(struct sna *sna, struct sna_pixmap *priv)
478{
479	DBG(("%s: handle=%d (pinned? %d)\n", __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->pinned));
480	assert(priv->gpu_damage == NULL || priv->gpu_bo);
481
482	if (priv->cow)
483		sna_pixmap_undo_cow(sna, priv, MOVE_WRITE);
484	assert(priv->cow == NULL);
485
486	if (priv->move_to_gpu) {
487		sna_pixmap_discard_shadow_damage(priv, NULL);
488		priv->move_to_gpu(sna, priv, MOVE_WRITE);
489	}
490
491	sna_damage_destroy(&priv->gpu_damage);
492	priv->clear = false;
493
494	if (priv->gpu_bo) {
495		if (!priv->pinned) {
496			assert(!priv->flush);
497			assert(!priv->move_to_gpu);
498			sna_pixmap_unmap(priv->pixmap, priv);
499			kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
500			priv->gpu_bo = NULL;
501		} else
502			kgem_bo_undo(&sna->kgem, priv->gpu_bo);
503	}
504
505	/* and reset the upload counter */
506	priv->source_count = SOURCE_BIAS;
507}
508
509static bool must_check
510sna_pixmap_alloc_cpu(struct sna *sna,
511		     PixmapPtr pixmap,
512		     struct sna_pixmap *priv,
513		     unsigned flags)
514{
515	/* Restore after a GTT mapping? */
516	assert(priv->gpu_damage == NULL || priv->gpu_bo);
517	assert(!priv->shm);
518	if (priv->ptr)
519		goto done;
520
521	DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
522	assert(priv->stride);
523
524	if (priv->create & KGEM_CAN_CREATE_CPU) {
525		unsigned hint;
526
527		DBG(("%s: allocating CPU buffer (%dx%d)\n", __FUNCTION__,
528		     pixmap->drawable.width, pixmap->drawable.height));
529
530		hint = 0;
531		if ((flags & MOVE_ASYNC_HINT) == 0 &&
532		    ((flags & MOVE_READ) == 0 || (priv->gpu_damage && !priv->clear && !sna->kgem.has_llc)))
533			hint = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE;
534
535		priv->cpu_bo = kgem_create_cpu_2d(&sna->kgem,
536						  pixmap->drawable.width,
537						  pixmap->drawable.height,
538						  pixmap->drawable.bitsPerPixel,
539						  hint);
540		if (priv->cpu_bo) {
541			priv->ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo);
542			if (priv->ptr) {
543				DBG(("%s: allocated CPU handle=%d (snooped? %d)\n", __FUNCTION__,
544				     priv->cpu_bo->handle, priv->cpu_bo->snoop));
545				priv->stride = priv->cpu_bo->pitch;
546#ifdef DEBUG_MEMORY
547				sna->debug_memory.cpu_bo_allocs++;
548				sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo);
549#endif
550			} else {
551				kgem_bo_destroy(&sna->kgem, priv->cpu_bo);
552				priv->cpu_bo = NULL;
553			}
554		}
555	}
556
557	if (priv->ptr == NULL) {
558		DBG(("%s: allocating ordinary memory for shadow pixels [%d bytes]\n",
559		     __FUNCTION__, priv->stride * pixmap->drawable.height));
560		priv->ptr = malloc(priv->stride * pixmap->drawable.height);
561	}
562
563done:
564	assert(priv->stride);
565	assert(!priv->mapped);
566	pixmap->devPrivate.ptr = PTR(priv->ptr);
567	pixmap->devKind = priv->stride;
568	return priv->ptr != NULL;
569}
570
571static void __sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv)
572{
573	if (priv->cpu_bo) {
574		DBG(("%s: discarding CPU buffer, handle=%d, size=%d\n",
575		     __FUNCTION__, priv->cpu_bo->handle, kgem_bo_size(priv->cpu_bo)));
576#ifdef DEBUG_MEMORY
577		sna->debug_memory.cpu_bo_allocs--;
578		sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
579#endif
580		if (priv->cpu_bo->flush) {
581			assert(!priv->cpu_bo->reusable);
582			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
583			sna_accel_watch_flush(sna, -1);
584		}
585		kgem_bo_destroy(&sna->kgem, priv->cpu_bo);
586	} else if (!IS_STATIC_PTR(priv->ptr))
587		free(priv->ptr);
588}
589
590static bool sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv, bool active)
591{
592	if (active)
593		return false;
594
595	if (IS_STATIC_PTR(priv->ptr))
596		return false;
597
598	if (priv->ptr == NULL)
599		return true;
600
601	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, priv->pixmap->drawable.serialNumber));
602	__sna_pixmap_free_cpu(sna, priv);
603
604	priv->cpu_bo = NULL;
605	priv->ptr = NULL;
606
607	if (priv->mapped == MAPPED_NONE)
608		priv->pixmap->devPrivate.ptr = NULL;
609
610	return true;
611}
612
613static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap)
614{
615#if DEFAULT_TILING == I915_TILING_NONE
616	return I915_TILING_NONE;
617#elif DEFAULT_TILING == I915_TILING_X
618	return I915_TILING_X;
619#else
620	/* Try to avoid hitting the Y-tiling GTT mapping bug on 855GM */
621	if (sna->kgem.gen == 021)
622		return I915_TILING_X;
623
624	/* Only on later generations was the render pipeline
625	 * more flexible than the BLT. So on gen2/3, prefer to
626	 * keep large objects accessible through the BLT.
627	 */
628	if (sna->kgem.gen < 040 &&
629	    (pixmap->drawable.width  > sna->render.max_3d_size ||
630	     pixmap->drawable.height > sna->render.max_3d_size))
631		return I915_TILING_X;
632
633	if (sna_damage_is_all(&sna_pixmap(pixmap)->cpu_damage,
634			      pixmap->drawable.width,
635			      pixmap->drawable.height)) {
636		DBG(("%s: entire source is damaged, using Y-tiling\n",
637		     __FUNCTION__));
638		sna_damage_destroy(&sna_pixmap(priv)->gpu_damage);
639		return I915_TILING_Y;
640	}
641
642	return I915_TILING_Y;
643#endif
644}
645
646pure static uint32_t sna_pixmap_default_tiling(struct sna *sna, PixmapPtr pixmap)
647{
648	/* Also adjust tiling if it is not supported or likely to
649	 * slow us down,
650	 */
651	return kgem_choose_tiling(&sna->kgem,
652				  default_tiling(sna, pixmap),
653				  pixmap->drawable.width,
654				  pixmap->drawable.height,
655				  pixmap->drawable.bitsPerPixel);
656}
657
658struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling)
659{
660	struct sna_pixmap *priv = sna_pixmap(pixmap);
661	struct sna *sna = to_sna_from_pixmap(pixmap);
662	struct kgem_bo *bo;
663	BoxRec box;
664
665	DBG(("%s: changing tiling %d -> %d for %dx%d pixmap\n",
666	     __FUNCTION__, priv->gpu_bo->tiling, tiling,
667	     pixmap->drawable.width, pixmap->drawable.height));
668	assert(priv->gpu_damage == NULL || priv->gpu_bo);
669
670	if (priv->pinned) {
671		DBG(("%s: can't convert pinned bo\n", __FUNCTION__));
672		return NULL;
673	}
674
675	if (wedged(sna)) {
676		DBG(("%s: can't convert bo, wedged\n", __FUNCTION__));
677		return NULL;
678	}
679
680	assert_pixmap_damage(pixmap);
681	assert(!priv->move_to_gpu);
682
683	bo = kgem_create_2d(&sna->kgem,
684			    pixmap->drawable.width,
685			    pixmap->drawable.height,
686			    pixmap->drawable.bitsPerPixel,
687			    tiling, 0);
688	if (bo == NULL) {
689		DBG(("%s: allocation failed\n", __FUNCTION__));
690		return NULL;
691	}
692
693	box.x1 = box.y1 = 0;
694	box.x2 = pixmap->drawable.width;
695	box.y2 = pixmap->drawable.height;
696
697	if (!sna->render.copy_boxes(sna, GXcopy,
698				    &pixmap->drawable, priv->gpu_bo, 0, 0,
699				    &pixmap->drawable, bo, 0, 0,
700				    &box, 1, 0)) {
701		DBG(("%s: copy failed\n", __FUNCTION__));
702		kgem_bo_destroy(&sna->kgem, bo);
703		return NULL;
704	}
705
706	sna_pixmap_unmap(pixmap, priv);
707	kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
708
709	return priv->gpu_bo = bo;
710}
711
712static inline void sna_set_pixmap(PixmapPtr pixmap, struct sna_pixmap *sna)
713{
714	((void **)__get_private(pixmap, sna_pixmap_key))[1] = sna;
715	assert(sna_pixmap(pixmap) == sna);
716}
717
718static struct sna_pixmap *
719_sna_pixmap_init(struct sna_pixmap *priv, PixmapPtr pixmap)
720{
721	list_init(&priv->flush_list);
722	list_init(&priv->cow_list);
723	priv->source_count = SOURCE_BIAS;
724	priv->pixmap = pixmap;
725
726	return priv;
727}
728
729static struct sna_pixmap *
730_sna_pixmap_reset(PixmapPtr pixmap)
731{
732	struct sna_pixmap *priv;
733
734	assert(pixmap->drawable.type == DRAWABLE_PIXMAP);
735	assert(pixmap->drawable.class == 0);
736	assert(pixmap->drawable.x == 0);
737	assert(pixmap->drawable.y == 0);
738
739	priv = sna_pixmap(pixmap);
740	assert(priv != NULL);
741
742	memset(priv, 0, sizeof(*priv));
743	return _sna_pixmap_init(priv, pixmap);
744}
745
746static struct sna_pixmap *sna_pixmap_attach(PixmapPtr pixmap)
747{
748	struct sna_pixmap *priv;
749
750	priv = calloc(1, sizeof(*priv));
751	if (!priv)
752		return NULL;
753
754	sna_set_pixmap(pixmap, priv);
755	return _sna_pixmap_init(priv, pixmap);
756}
757
758struct sna_pixmap *sna_pixmap_attach_to_bo(PixmapPtr pixmap, struct kgem_bo *bo)
759{
760	struct sna_pixmap *priv;
761
762	assert(bo);
763	assert(bo->proxy == NULL);
764	assert(bo->unique_id);
765
766	priv = sna_pixmap_attach(pixmap);
767	if (!priv)
768		return NULL;
769
770	DBG(("%s: attaching %s handle=%d to pixmap=%ld\n",
771	     __FUNCTION__, bo->snoop ? "CPU" : "GPU", bo->handle, pixmap->drawable.serialNumber));
772
773	assert(!priv->mapped);
774	assert(!priv->move_to_gpu);
775
776	if (bo->snoop) {
777		priv->cpu_bo = bo;
778		sna_damage_all(&priv->cpu_damage, pixmap);
779	} else {
780		priv->gpu_bo = bo;
781		sna_damage_all(&priv->gpu_damage, pixmap);
782	}
783
784	return priv;
785}
786
787static int bits_per_pixel(int depth)
788{
789	switch (depth) {
790	case 1: return 1;
791	case 4:
792	case 8: return 8;
793	case 15:
794	case 16: return 16;
795	case 24:
796	case 30:
797	case 32: return 32;
798	default: return 0;
799	}
800}
801static PixmapPtr
802create_pixmap(struct sna *sna, ScreenPtr screen,
803	      int width, int height, int depth,
804	      unsigned usage_hint)
805{
806	PixmapPtr pixmap;
807	size_t datasize;
808	size_t stride;
809	int base, bpp;
810
811	bpp = bits_per_pixel(depth);
812	if (bpp == 0)
813		return NullPixmap;
814
815	stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
816	if (stride / 4 > 32767 || height > 32767)
817		return NullPixmap;
818
819	datasize = height * stride;
820	base = screen->totalPixmapSize;
821	if (datasize && base & 15) {
822		int adjust = 16 - (base & 15);
823		base += adjust;
824		datasize += adjust;
825	}
826
827	DBG(("%s: allocating pixmap %dx%d, depth=%d, size=%ld\n",
828	     __FUNCTION__, width, height, depth, (long)datasize));
829	pixmap = AllocatePixmap(screen, datasize);
830	if (!pixmap)
831		return NullPixmap;
832
833	((void **)__get_private(pixmap, sna_pixmap_key))[0] = sna;
834	assert(to_sna_from_pixmap(pixmap) == sna);
835
836	pixmap->drawable.type = DRAWABLE_PIXMAP;
837	pixmap->drawable.class = 0;
838	pixmap->drawable.pScreen = screen;
839	pixmap->drawable.depth = depth;
840	pixmap->drawable.bitsPerPixel = bpp;
841	pixmap->drawable.id = 0;
842	pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
843	pixmap->drawable.x = 0;
844	pixmap->drawable.y = 0;
845	pixmap->drawable.width = width;
846	pixmap->drawable.height = height;
847	pixmap->devKind = stride;
848	pixmap->refcnt = 1;
849	pixmap->devPrivate.ptr = datasize ? (char *)pixmap + base : NULL;
850
851#ifdef COMPOSITE
852	pixmap->screen_x = 0;
853	pixmap->screen_y = 0;
854#endif
855
856	pixmap->usage_hint = usage_hint;
857#if DEBUG_MEMORY
858	sna->debug_memory.pixmap_allocs++;
859#endif
860
861	DBG(("%s: serial=%ld, usage=%d, %dx%d\n",
862	     __FUNCTION__,
863	     pixmap->drawable.serialNumber,
864	     pixmap->usage_hint,
865	     pixmap->drawable.width,
866	     pixmap->drawable.height));
867
868	return pixmap;
869}
870
871static PixmapPtr
872__pop_freed_pixmap(struct sna *sna)
873{
874	PixmapPtr pixmap;
875
876	assert(sna->freed_pixmap);
877
878	pixmap = sna->freed_pixmap;
879	sna->freed_pixmap = pixmap->devPrivate.ptr;
880
881	assert(pixmap->refcnt == 0);
882	assert(sna_pixmap(pixmap));
883	assert(sna_pixmap(pixmap)->header);
884
885#if DEBUG_MEMORY
886	sna->debug_memory.pixmap_cached--;
887#endif
888
889	return pixmap;
890}
891
892inline static PixmapPtr
893create_pixmap_hdr(struct sna *sna, ScreenPtr screen,
894		  int width, int height, int depth, int usage,
895		  struct sna_pixmap **priv)
896{
897	PixmapPtr pixmap;
898
899	if (sna->freed_pixmap == NULL) {
900		pixmap = create_pixmap(sna, screen, 0, 0, depth, usage);
901		if (pixmap == NullPixmap)
902			return NullPixmap;
903
904		*priv = sna_pixmap_attach(pixmap);
905		if (!*priv) {
906			FreePixmap(pixmap);
907			return NullPixmap;
908		}
909	} else {
910		pixmap = __pop_freed_pixmap(sna);
911		*priv = _sna_pixmap_reset(pixmap);
912
913		assert(pixmap->drawable.type == DRAWABLE_PIXMAP);
914		assert(pixmap->drawable.class == 0);
915		assert(pixmap->drawable.pScreen == screen);
916		assert(pixmap->drawable.x == 0);
917		assert(pixmap->drawable.y == 0);
918
919		pixmap->drawable.id = 0;
920
921		pixmap->drawable.depth = depth;
922		pixmap->drawable.bitsPerPixel = bits_per_pixel(depth);
923		pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
924
925		pixmap->devKind = 0;
926		pixmap->devPrivate.ptr = NULL;
927
928#ifdef COMPOSITE
929		pixmap->screen_x = 0;
930		pixmap->screen_y = 0;
931#endif
932
933#if DEBUG_MEMORY
934		sna->debug_memory.pixmap_allocs++;
935#endif
936
937		pixmap->refcnt = 1;
938	}
939
940	DBG(("%s: pixmap=%ld, width=%d, height=%d, usage=%d\n", __FUNCTION__,
941	     pixmap->drawable.serialNumber, width, height, usage));
942	pixmap->drawable.width = width;
943	pixmap->drawable.height = height;
944	pixmap->usage_hint = usage;
945
946	(*priv)->header = true;
947	return pixmap;
948}
949
950static PixmapPtr
951sna_pixmap_create_shm(ScreenPtr screen,
952		      int width, int height, int depth,
953		      char *addr)
954{
955	struct sna *sna = to_sna_from_screen(screen);
956	int bpp = bits_per_pixel(depth);
957	int pitch = PixmapBytePad(width, depth);
958	struct sna_pixmap *priv;
959	PixmapPtr pixmap;
960
961	DBG(("%s(%dx%d, depth=%d, bpp=%d, pitch=%d)\n",
962	     __FUNCTION__, width, height, depth, bpp, pitch));
963
964	if (wedged(sna) || bpp == 0 || pitch*height < 4096) {
965fallback:
966		pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth);
967		if (pixmap == NULL)
968			return NULL;
969
970		if (!screen->ModifyPixmapHeader(pixmap, width, height, depth,
971						bpp, pitch, addr)) {
972			screen->DestroyPixmap(pixmap);
973			return NULL;
974		}
975
976		return pixmap;
977	}
978
979	pixmap = create_pixmap_hdr(sna, screen, width, height, depth, 0, &priv);
980	if (pixmap == NullPixmap) {
981		DBG(("%s: allocation failed\n", __FUNCTION__));
982		goto fallback;
983	}
984
985	priv->cpu_bo = kgem_create_map(&sna->kgem, addr, pitch*height, false);
986	if (priv->cpu_bo == NULL) {
987		DBG(("%s: mapping SHM segment failed\n", __FUNCTION__));
988		sna_pixmap_destroy(pixmap);
989		goto fallback;
990	}
991	priv->cpu_bo->pitch = pitch;
992	kgem_bo_mark_unreusable(priv->cpu_bo);
993	sna_accel_watch_flush(sna, 1);
994#ifdef DEBUG_MEMORY
995	sna->debug_memory.cpu_bo_allocs++;
996	sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo);
997#endif
998
999	/* Be wary as we cannot cache SHM Pixmap in our freed cache */
1000	priv->header = false;
1001	priv->cpu = true;
1002	priv->shm = true;
1003	priv->stride = pitch;
1004	priv->ptr = MAKE_STATIC_PTR(addr);
1005	sna_damage_all(&priv->cpu_damage, pixmap);
1006
1007	pixmap->devKind = pitch;
1008	pixmap->devPrivate.ptr = addr;
1009
1010	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
1011	     __FUNCTION__,
1012	     pixmap->drawable.serialNumber,
1013	     pixmap->drawable.width,
1014	     pixmap->drawable.height,
1015	     pixmap->usage_hint));
1016	return pixmap;
1017}
1018
1019PixmapPtr
1020sna_pixmap_create_unattached(ScreenPtr screen,
1021			     int width, int height, int depth)
1022{
1023	return create_pixmap(to_sna_from_screen(screen),
1024			     screen, width, height, depth,
1025			     -1);
1026}
1027
1028static PixmapPtr
1029sna_pixmap_create_scratch(ScreenPtr screen,
1030			  int width, int height, int depth,
1031			  uint32_t tiling)
1032{
1033	struct sna *sna = to_sna_from_screen(screen);
1034	struct sna_pixmap *priv;
1035	PixmapPtr pixmap;
1036	int bpp;
1037
1038	DBG(("%s(%d, %d, %d, tiling=%d)\n", __FUNCTION__,
1039	     width, height, depth, tiling));
1040
1041	bpp = bits_per_pixel(depth);
1042	if (tiling == I915_TILING_Y &&
1043	    (sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0)
1044		tiling = I915_TILING_X;
1045
1046	if (tiling == I915_TILING_Y &&
1047	    (width > sna->render.max_3d_size ||
1048	     height > sna->render.max_3d_size))
1049		tiling = I915_TILING_X;
1050
1051	tiling = kgem_choose_tiling(&sna->kgem, tiling, width, height, bpp);
1052
1053	/* you promise never to access this via the cpu... */
1054	pixmap = create_pixmap_hdr(sna, screen, width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH, &priv);
1055	if (pixmap == NullPixmap)
1056		return NullPixmap;
1057
1058	priv->stride = PixmapBytePad(width, depth);
1059
1060	priv->gpu_bo = kgem_create_2d(&sna->kgem,
1061				      width, height, bpp, tiling,
1062				      CREATE_TEMPORARY);
1063	if (priv->gpu_bo == NULL) {
1064		free(priv);
1065		FreePixmap(pixmap);
1066		return NullPixmap;
1067	}
1068
1069	sna_damage_all(&priv->gpu_damage, pixmap);
1070
1071	assert(to_sna_from_pixmap(pixmap) == sna);
1072	assert(pixmap->drawable.pScreen == screen);
1073	assert(pixmap->refcnt == 1);
1074
1075	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
1076	     __FUNCTION__,
1077	     pixmap->drawable.serialNumber,
1078	     pixmap->drawable.width,
1079	     pixmap->drawable.height,
1080	     pixmap->usage_hint));
1081	return pixmap;
1082}
1083
1084#ifdef CREATE_PIXMAP_USAGE_SHARED
1085static Bool
1086sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle)
1087{
1088	struct sna *sna = to_sna_from_pixmap(pixmap);
1089	struct sna_pixmap *priv;
1090	int fd;
1091
1092	DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
1093
1094	priv = sna_pixmap_move_to_gpu(pixmap,
1095				      MOVE_READ | MOVE_WRITE | __MOVE_DRI | __MOVE_PRIME | __MOVE_FORCE);
1096	if (priv == NULL)
1097		return FALSE;
1098
1099	assert(!priv->shm);
1100	assert(priv->gpu_bo);
1101	assert(priv->stride);
1102
1103	/* XXX negotiate format and stride restrictions */
1104	if (priv->gpu_bo->tiling != I915_TILING_NONE ||
1105	    priv->gpu_bo->pitch & 255) {
1106		struct kgem_bo *bo;
1107		BoxRec box;
1108
1109		DBG(("%s: removing tiling %d, and aligning pitch %d for %dx%d pixmap=%ld\n",
1110		     __FUNCTION__, priv->gpu_bo->tiling, priv->gpu_bo->pitch,
1111		     pixmap->drawable.width, pixmap->drawable.height,
1112		     pixmap->drawable.serialNumber));
1113
1114		if (priv->pinned) {
1115			DBG(("%s: can't convert pinned %x bo\n", __FUNCTION__,
1116			     priv->pinned));
1117			return FALSE;
1118		}
1119
1120		assert_pixmap_damage(pixmap);
1121
1122		bo = kgem_create_2d(&sna->kgem,
1123				    pixmap->drawable.width,
1124				    pixmap->drawable.height,
1125				    pixmap->drawable.bitsPerPixel,
1126				    I915_TILING_NONE,
1127				    CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT);
1128		if (bo == NULL) {
1129			DBG(("%s: allocation failed\n", __FUNCTION__));
1130			return FALSE;
1131		}
1132
1133		box.x1 = box.y1 = 0;
1134		box.x2 = pixmap->drawable.width;
1135		box.y2 = pixmap->drawable.height;
1136
1137		assert(!wedged(sna)); /* XXX */
1138		if (!sna->render.copy_boxes(sna, GXcopy,
1139					    &pixmap->drawable, priv->gpu_bo, 0, 0,
1140					    &pixmap->drawable, bo, 0, 0,
1141					    &box, 1, 0)) {
1142			DBG(("%s: copy failed\n", __FUNCTION__));
1143			kgem_bo_destroy(&sna->kgem, bo);
1144			return FALSE;
1145		}
1146
1147		sna_pixmap_unmap(pixmap, priv);
1148		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1149		priv->gpu_bo = bo;
1150	}
1151	assert(priv->gpu_bo->tiling == I915_TILING_NONE);
1152	assert((priv->gpu_bo->pitch & 255) == 0);
1153
1154	/* And export the bo->pitch via pixmap->devKind */
1155	if (!priv->mapped) {
1156		void *ptr;
1157
1158		ptr = kgem_bo_map__async(&sna->kgem, priv->gpu_bo);
1159		if (ptr == NULL)
1160			return FALSE;
1161
1162		pixmap->devPrivate.ptr = ptr;
1163		pixmap->devKind = priv->gpu_bo->pitch;
1164		priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
1165	}
1166	assert_pixmap_map(pixmap, priv);
1167
1168	fd = kgem_bo_export_to_prime(&sna->kgem, priv->gpu_bo);
1169	if (fd == -1)
1170		return FALSE;
1171
1172	priv->pinned |= PIN_PRIME;
1173
1174	*fd_handle = (void *)(intptr_t)fd;
1175	return TRUE;
1176}
1177
1178static Bool
1179sna_set_shared_pixmap_backing(PixmapPtr pixmap, void *fd_handle)
1180{
1181	struct sna *sna = to_sna_from_pixmap(pixmap);
1182	struct sna_pixmap *priv;
1183	struct kgem_bo *bo;
1184
1185	DBG(("%s: pixmap=%ld, size=%dx%d, depth=%d/%d, stride=%d\n",
1186	     __FUNCTION__, pixmap->drawable.serialNumber,
1187	     pixmap->drawable.width, pixmap->drawable.height,
1188	     pixmap->drawable.depth, pixmap->drawable.bitsPerPixel,
1189	     pixmap->devKind));
1190
1191	priv = sna_pixmap(pixmap);
1192	if (priv == NULL)
1193		return FALSE;
1194
1195	assert(!priv->pinned);
1196	assert(priv->gpu_bo == NULL);
1197	assert(priv->cpu_bo == NULL);
1198	assert(priv->cpu_damage == NULL);
1199	assert(priv->gpu_damage == NULL);
1200
1201	bo = kgem_create_for_prime(&sna->kgem,
1202				   (intptr_t)fd_handle,
1203				   pixmap->devKind * pixmap->drawable.height);
1204	if (bo == NULL)
1205		return FALSE;
1206
1207	sna_damage_all(&priv->gpu_damage, pixmap);
1208
1209	bo->pitch = pixmap->devKind;
1210	priv->stride = pixmap->devKind;
1211
1212	assert(!priv->mapped);
1213	priv->gpu_bo = bo;
1214	priv->pinned |= PIN_PRIME;
1215
1216	close((intptr_t)fd_handle);
1217	return TRUE;
1218}
1219
1220static PixmapPtr
1221sna_create_pixmap_shared(struct sna *sna, ScreenPtr screen,
1222			 int width, int height, int depth)
1223{
1224	PixmapPtr pixmap;
1225	struct sna_pixmap *priv;
1226
1227	DBG(("%s: width=%d, height=%d, depth=%d\n",
1228	     __FUNCTION__, width, height, depth));
1229
1230	/* Create a stub to be attached later */
1231	pixmap = create_pixmap_hdr(sna, screen,
1232				   width, height, depth, 0,
1233				   &priv);
1234	if (pixmap == NullPixmap)
1235		return NullPixmap;
1236
1237	assert(!priv->mapped);
1238	priv->stride = 0;
1239	priv->create = 0;
1240
1241	if (width|height) {
1242		priv->gpu_bo = kgem_create_2d(&sna->kgem,
1243					      width, height,
1244					      pixmap->drawable.bitsPerPixel,
1245					      I915_TILING_NONE,
1246					      CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT);
1247		if (priv->gpu_bo == NULL) {
1248			free(priv);
1249			FreePixmap(pixmap);
1250			return NullPixmap;
1251		}
1252
1253		/* minimal interface for sharing is linear, 256 byte pitch */
1254		assert(priv->gpu_bo->tiling == I915_TILING_NONE);
1255		assert((priv->gpu_bo->pitch & 255) == 0);
1256
1257		pixmap->devPrivate.ptr =
1258			kgem_bo_map__async(&sna->kgem, priv->gpu_bo);
1259		if (pixmap->devPrivate.ptr == NULL) {
1260			kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1261			free(priv);
1262			FreePixmap(pixmap);
1263			return FALSE;
1264		}
1265
1266		pixmap->devKind = priv->gpu_bo->pitch;
1267
1268		priv->stride = priv->gpu_bo->pitch;
1269		priv->mapped = pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
1270		assert_pixmap_map(pixmap, priv);
1271
1272		sna_damage_all(&priv->gpu_damage, pixmap);
1273	}
1274
1275	return pixmap;
1276}
1277#endif
1278
1279static PixmapPtr sna_create_pixmap(ScreenPtr screen,
1280				   int width, int height, int depth,
1281				   unsigned int usage)
1282{
1283	struct sna *sna = to_sna_from_screen(screen);
1284	PixmapPtr pixmap;
1285	struct sna_pixmap *priv;
1286	unsigned flags;
1287	int pad;
1288	void *ptr;
1289
1290	DBG(("%s(%d, %d, %d, usage=%x)\n", __FUNCTION__,
1291	     width, height, depth, usage));
1292
1293#ifdef CREATE_PIXMAP_USAGE_SHARED
1294	if (usage == CREATE_PIXMAP_USAGE_SHARED)
1295		return sna_create_pixmap_shared(sna, screen,
1296						width, height, depth);
1297#endif
1298
1299	if ((width|height) == 0) {
1300		usage = -1;
1301		goto fallback;
1302	}
1303	assert(width && height);
1304
1305	flags = kgem_can_create_2d(&sna->kgem, width, height, depth);
1306	if (flags == 0) {
1307		DBG(("%s: can not use GPU, just creating shadow\n",
1308		     __FUNCTION__));
1309		goto fallback;
1310	}
1311
1312	if (unlikely((sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0))
1313		flags &= ~KGEM_CAN_CREATE_GPU;
1314	if (wedged(sna))
1315		flags &= ~KGEM_CAN_CREATE_GTT;
1316
1317	DBG(("%s: usage=%d, flags=%x\n", __FUNCTION__, usage, flags));
1318	switch (usage) {
1319	case CREATE_PIXMAP_USAGE_SCRATCH:
1320		if (flags & KGEM_CAN_CREATE_GPU)
1321			return sna_pixmap_create_scratch(screen,
1322							 width, height, depth,
1323							 I915_TILING_X);
1324		else
1325			goto fallback;
1326
1327	case SNA_CREATE_SCRATCH:
1328		if (flags & (KGEM_CAN_CREATE_CPU | KGEM_CAN_CREATE_GPU))
1329			return sna_pixmap_create_scratch(screen,
1330							 width, height, depth,
1331							 I915_TILING_Y);
1332		else
1333			return NullPixmap;
1334	}
1335
1336	if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE)
1337		flags &= ~KGEM_CAN_CREATE_GPU;
1338	if (usage == CREATE_PIXMAP_USAGE_BACKING_PIXMAP)
1339		usage = 0;
1340
1341	pad = PixmapBytePad(width, depth);
1342	if (pad * height < 4096) {
1343		DBG(("%s: small buffer [%d], attaching to shadow pixmap\n",
1344		     __FUNCTION__, pad * height));
1345		pixmap = create_pixmap(sna, screen,
1346				       width, height, depth, usage);
1347		if (pixmap == NullPixmap)
1348			return NullPixmap;
1349
1350		ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr);
1351		pad = pixmap->devKind;
1352		flags &= ~(KGEM_CAN_CREATE_GPU | KGEM_CAN_CREATE_CPU);
1353
1354		priv = sna_pixmap_attach(pixmap);
1355		if (priv == NULL) {
1356			free(pixmap);
1357			goto fallback;
1358		}
1359	} else {
1360		DBG(("%s: creating GPU pixmap %dx%d, stride=%d, flags=%x\n",
1361		     __FUNCTION__, width, height, pad, flags));
1362
1363		pixmap = create_pixmap_hdr(sna, screen, width, height, depth, usage, &priv);
1364		if (pixmap == NullPixmap)
1365			return NullPixmap;
1366
1367		ptr = NULL;
1368	}
1369
1370	priv->stride = pad;
1371	priv->create = flags;
1372	priv->ptr = ptr;
1373
1374	assert(to_sna_from_pixmap(pixmap) == sna);
1375	assert(pixmap->drawable.pScreen == screen);
1376	assert(pixmap->refcnt == 1);
1377
1378	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
1379	     __FUNCTION__,
1380	     pixmap->drawable.serialNumber,
1381	     pixmap->drawable.width,
1382	     pixmap->drawable.height,
1383	     pixmap->usage_hint));
1384	return pixmap;
1385
1386fallback:
1387	return create_pixmap(sna, screen, width, height, depth, usage);
1388}
1389
1390void sna_add_flush_pixmap(struct sna *sna,
1391			  struct sna_pixmap *priv,
1392			  struct kgem_bo *bo)
1393{
1394	DBG(("%s: marking pixmap=%ld for flushing\n",
1395	     __FUNCTION__, priv->pixmap->drawable.serialNumber));
1396	assert(bo);
1397	assert(bo->flush);
1398	assert(priv->gpu_damage == NULL || priv->gpu_bo);
1399	list_move(&priv->flush_list, &sna->flush_pixmaps);
1400
1401	if (bo->exec == NULL && sna->kgem.nbatch && kgem_is_idle(&sna->kgem)) {
1402		DBG(("%s: new flush bo, flushing before\n", __FUNCTION__));
1403		_kgem_submit(&sna->kgem);
1404	}
1405}
1406
1407static void __sna_free_pixmap(struct sna *sna,
1408			      PixmapPtr pixmap,
1409			      struct sna_pixmap *priv)
1410{
1411	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber));
1412	list_del(&priv->flush_list);
1413
1414	assert(priv->gpu_damage == NULL);
1415	assert(priv->cpu_damage == NULL);
1416
1417	__sna_pixmap_free_cpu(sna, priv);
1418
1419	if (priv->flush)
1420		sna_accel_watch_flush(sna, -1);
1421
1422	if (priv->header) {
1423		assert(pixmap->drawable.pScreen == sna->scrn->pScreen);
1424		assert(!priv->shm);
1425		pixmap->devPrivate.ptr = sna->freed_pixmap;
1426		sna->freed_pixmap = pixmap;
1427#if DEBUG_MEMORY
1428		sna->debug_memory.pixmap_cached++;
1429#endif
1430	} else {
1431		free(priv);
1432		FreePixmap(pixmap);
1433	}
1434}
1435
1436static Bool sna_destroy_pixmap(PixmapPtr pixmap)
1437{
1438	struct sna *sna;
1439	struct sna_pixmap *priv;
1440
1441	assert(pixmap->refcnt > 0);
1442	if (--pixmap->refcnt)
1443		return TRUE;
1444
1445#if DEBUG_MEMORY
1446	to_sna_from_pixmap(pixmap)->debug_memory.pixmap_allocs--;
1447#endif
1448
1449	priv = sna_pixmap(pixmap);
1450	DBG(("%s: pixmap=%ld, attached?=%d\n",
1451	     __FUNCTION__, pixmap->drawable.serialNumber, priv != NULL));
1452	if (priv == NULL) {
1453		FreePixmap(pixmap);
1454		return TRUE;
1455	}
1456
1457	assert_pixmap_damage(pixmap);
1458	sna = to_sna_from_pixmap(pixmap);
1459
1460	sna_damage_destroy(&priv->gpu_damage);
1461	sna_damage_destroy(&priv->cpu_damage);
1462
1463	list_del(&priv->cow_list);
1464	if (priv->cow) {
1465		struct sna_cow *cow = COW(priv->cow);
1466		DBG(("%s: pixmap=%ld discarding cow, refcnt=%d\n",
1467		     __FUNCTION__, pixmap->drawable.serialNumber, cow->refcnt));
1468		assert(cow->refcnt);
1469		if (!--cow->refcnt)
1470			free(cow);
1471		priv->cow = NULL;
1472	} else
1473		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
1474
1475	if (priv->move_to_gpu)
1476		(void)priv->move_to_gpu(sna, priv, 0);
1477
1478	/* Always release the gpu bo back to the lower levels of caching */
1479	if (priv->gpu_bo) {
1480		sna_pixmap_unmap(pixmap, priv);
1481		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1482		priv->gpu_bo = NULL;
1483	}
1484
1485	if (priv->shm && kgem_bo_is_busy(priv->cpu_bo)) {
1486		DBG(("%s: deferring release of active SHM pixmap=%ld\n",
1487		     __FUNCTION__, pixmap->drawable.serialNumber));
1488		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
1489		kgem_bo_submit(&sna->kgem, priv->cpu_bo); /* XXX ShmDetach */
1490	} else
1491		__sna_free_pixmap(sna, pixmap, priv);
1492	return TRUE;
1493}
1494
1495void sna_pixmap_destroy(PixmapPtr pixmap)
1496{
1497	assert(pixmap->refcnt == 1);
1498	assert(sna_pixmap(pixmap) == NULL || sna_pixmap(pixmap)->header == true);
1499
1500	sna_destroy_pixmap(pixmap);
1501}
1502
1503static inline bool has_coherent_map(struct sna *sna,
1504				    struct kgem_bo *bo,
1505				    unsigned flags)
1506{
1507	assert(bo);
1508
1509	if (kgem_bo_mapped(&sna->kgem, bo))
1510		return true;
1511
1512	if (bo->tiling == I915_TILING_Y)
1513		return false;
1514
1515	return kgem_bo_can_map__cpu(&sna->kgem, bo, flags & MOVE_WRITE);
1516}
1517
1518static inline bool has_coherent_ptr(struct sna *sna, struct sna_pixmap *priv, unsigned flags)
1519{
1520	if (priv == NULL)
1521		return true;
1522
1523	if (flags & MOVE_ASYNC_HINT) {
1524		/* Not referencing the pointer itself, so do not care */
1525		return true;
1526	}
1527
1528	if (!priv->mapped) {
1529		if (!priv->cpu_bo)
1530			return true;
1531
1532		assert(!priv->cpu_bo->needs_flush);
1533		assert(priv->pixmap->devKind == priv->cpu_bo->pitch);
1534		return priv->pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu);
1535	}
1536
1537	assert(!priv->move_to_gpu || (flags & MOVE_WRITE) == 0);
1538
1539	assert_pixmap_map(priv->pixmap, priv);
1540	assert(priv->pixmap->devKind == priv->gpu_bo->pitch);
1541
1542	if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu)) {
1543		assert(priv->mapped == MAPPED_CPU);
1544
1545		if (priv->gpu_bo->tiling != I915_TILING_NONE)
1546			return false;
1547
1548		return flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE);
1549	}
1550
1551	if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__gtt)) {
1552		assert(priv->mapped == MAPPED_GTT);
1553
1554		if (priv->gpu_bo->tiling == I915_TILING_Y && sna->kgem.gen == 0x21)
1555			return false;
1556
1557		return true;
1558	}
1559
1560	return false;
1561}
1562
1563static inline bool pixmap_inplace(struct sna *sna,
1564				  PixmapPtr pixmap,
1565				  struct sna_pixmap *priv,
1566				  unsigned flags)
1567{
1568	if (FORCE_INPLACE)
1569		return FORCE_INPLACE > 0;
1570
1571	if (wedged(sna) && !priv->pinned) {
1572		DBG(("%s: no, wedged and unpinned; pull pixmap back to CPU\n", __FUNCTION__));
1573		return false;
1574	}
1575
1576	if (priv->move_to_gpu && flags & MOVE_WRITE)
1577		return false;
1578
1579	if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) {
1580		if ((flags & (MOVE_WRITE | MOVE_READ)) == (MOVE_WRITE | MOVE_READ)) {
1581			DBG(("%s: no, GPU bo is busy\n", __FUNCTION__));
1582			return false;
1583		}
1584
1585		if ((flags & MOVE_READ) == 0) {
1586			DBG(("%s: %s, GPU bo is busy, but not reading\n", __FUNCTION__, priv->pinned ? "no" : "yes"));
1587			return !priv->pinned;
1588		}
1589	}
1590
1591	if (priv->mapped) {
1592		DBG(("%s: %s, already mapped\n", __FUNCTION__, has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no"));
1593		return has_coherent_map(sna, priv->gpu_bo, flags);
1594	}
1595
1596	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) {
1597		DBG(("%s: yes, has CPU bo and is active on CPU\n", __FUNCTION__));
1598		return true;
1599	}
1600
1601	if (priv->cpu_bo && priv->cpu) {
1602		DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__));
1603		return false;
1604	}
1605
1606	if (flags & MOVE_READ &&
1607	    (priv->cpu || priv->cpu_damage || priv->gpu_damage == NULL)) {
1608		DBG(("%s:, no, reading and has CPU damage\n", __FUNCTION__));
1609		return false;
1610	}
1611
1612	return (priv->stride * pixmap->drawable.height >> 12) >
1613		sna->kgem.half_cpu_cache_pages;
1614}
1615
1616static bool sna_pixmap_alloc_gpu(struct sna *sna,
1617				 PixmapPtr pixmap,
1618				 struct sna_pixmap *priv,
1619				 unsigned flags)
1620{
1621	uint32_t tiling;
1622
1623	/* Use tiling by default, but disable per user request */
1624	if (pixmap->usage_hint == SNA_CREATE_FB && (sna->flags & SNA_LINEAR_FB) == 0) {
1625		flags |= CREATE_SCANOUT;
1626		tiling = kgem_choose_tiling(&sna->kgem,
1627					    -I915_TILING_X,
1628					    pixmap->drawable.width,
1629					    pixmap->drawable.height,
1630					    pixmap->drawable.bitsPerPixel);
1631	} else
1632		tiling = sna_pixmap_default_tiling(sna, pixmap);
1633
1634	DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
1635
1636	priv->gpu_bo = kgem_create_2d(&sna->kgem,
1637				      pixmap->drawable.width,
1638				      pixmap->drawable.height,
1639				      pixmap->drawable.bitsPerPixel,
1640				      tiling, flags);
1641	return priv->gpu_bo != NULL;
1642}
1643
1644static bool
1645sna_pixmap_create_mappable_gpu(PixmapPtr pixmap,
1646			       bool can_replace)
1647{
1648	struct sna *sna = to_sna_from_pixmap(pixmap);
1649	struct sna_pixmap *priv = sna_pixmap(pixmap);
1650
1651	if (wedged(sna))
1652		goto out;
1653
1654	if ((priv->create & KGEM_CAN_CREATE_GTT) == 0)
1655		goto out;
1656
1657	assert_pixmap_damage(pixmap);
1658
1659	if (can_replace && priv->gpu_bo &&
1660	    (!kgem_bo_can_map(&sna->kgem, priv->gpu_bo) ||
1661	     __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) {
1662		if (priv->pinned)
1663			return false;
1664
1665		DBG(("%s: discard busy GPU bo\n", __FUNCTION__));
1666		sna_pixmap_free_gpu(sna, priv);
1667	}
1668
1669	if (priv->gpu_bo == NULL) {
1670		assert_pixmap_damage(pixmap);
1671		assert(priv->gpu_damage == NULL);
1672		sna_pixmap_alloc_gpu(sna, pixmap, priv, CREATE_GTT_MAP | CREATE_INACTIVE);
1673	}
1674
1675out:
1676	if (priv->gpu_bo == NULL)
1677		return false;
1678
1679	return (kgem_bo_can_map(&sna->kgem, priv->gpu_bo) &&
1680		!kgem_bo_is_busy(priv->gpu_bo));
1681}
1682
1683static inline bool gpu_bo_download(struct sna *sna,
1684				   struct sna_pixmap *priv,
1685				   int n, const BoxRec *box,
1686				   bool idle)
1687{
1688	char *src;
1689
1690	if (!USE_INPLACE)
1691		return false;
1692
1693	switch (priv->gpu_bo->tiling) {
1694	case I915_TILING_Y:
1695		return false;
1696	case I915_TILING_X:
1697		if (!sna->kgem.memcpy_from_tiled_x)
1698			return false;
1699	default:
1700		break;
1701	}
1702
1703	if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC))
1704		return false;
1705
1706	if (idle) {
1707		if (__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
1708			return false;
1709
1710		if (priv->cpu_bo && __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo))
1711			return false;
1712	}
1713
1714	src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
1715	if (src == NULL)
1716		return false;
1717
1718	kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC);
1719
1720	if (priv->cpu_bo)
1721		kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
1722	assert(has_coherent_ptr(sna, priv, MOVE_WRITE));
1723
1724	if (sigtrap_get())
1725		return false;
1726
1727	if (priv->gpu_bo->tiling) {
1728		int bpp = priv->pixmap->drawable.bitsPerPixel;
1729		void *dst = priv->pixmap->devPrivate.ptr;
1730		int dst_pitch = priv->pixmap->devKind;
1731
1732		DBG(("%s: download through a tiled CPU map\n", __FUNCTION__));
1733		do {
1734			DBG(("%s: box (%d, %d), (%d, %d)\n",
1735			     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
1736			memcpy_from_tiled_x(&sna->kgem, src, dst, bpp,
1737					    priv->gpu_bo->pitch, dst_pitch,
1738					    box->x1, box->y1,
1739					    box->x1, box->y1,
1740					    box->x2 - box->x1, box->y2 - box->y1);
1741			box++;
1742		} while (--n);
1743	} else {
1744		int bpp = priv->pixmap->drawable.bitsPerPixel;
1745		void *dst = priv->pixmap->devPrivate.ptr;
1746		int dst_pitch = priv->pixmap->devKind;
1747
1748		DBG(("%s: download through a linear CPU map\n", __FUNCTION__));
1749		do {
1750			DBG(("%s: box (%d, %d), (%d, %d)\n",
1751			     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
1752			memcpy_blt(src, dst, bpp,
1753				   priv->gpu_bo->pitch, dst_pitch,
1754				   box->x1, box->y1,
1755				   box->x1, box->y1,
1756				   box->x2 - box->x1, box->y2 - box->y1);
1757			box++;
1758		} while (--n);
1759	}
1760
1761	sigtrap_put();
1762	return true;
1763}
1764
1765static inline bool cpu_bo_download(struct sna *sna,
1766				   struct sna_pixmap *priv,
1767				   int n, const BoxRec *box)
1768{
1769	if (DBG_NO_CPU_DOWNLOAD)
1770		return false;
1771
1772	if (wedged(sna))
1773		return false;
1774
1775	if (priv->cpu_bo == NULL || !sna->kgem.can_blt_cpu)
1776		return false;
1777
1778	if (!kgem_bo_is_busy(priv->gpu_bo) && !kgem_bo_is_busy(priv->cpu_bo)) {
1779		/* Is it worth detiling? */
1780		assert(box[0].y1 < box[n-1].y2);
1781		if (kgem_bo_can_map(&sna->kgem, priv->gpu_bo) &&
1782		    (box[n-1].y2 - box[0].y1 - 1) * priv->gpu_bo->pitch < 4096) {
1783			DBG(("%s: no, tiny transfer (height=%d, pitch=%d) expect to read inplace\n",
1784			     __FUNCTION__, box[n-1].y2-box[0].y1, priv->gpu_bo->pitch));
1785			return false;
1786		}
1787	}
1788
1789	DBG(("%s: using GPU write to CPU bo for download from GPU\n", __FUNCTION__));
1790	return sna->render.copy_boxes(sna, GXcopy,
1791				      &priv->pixmap->drawable, priv->gpu_bo, 0, 0,
1792				      &priv->pixmap->drawable, priv->cpu_bo, 0, 0,
1793				      box, n, COPY_LAST);
1794}
1795
1796static void download_boxes(struct sna *sna,
1797			   struct sna_pixmap *priv,
1798			   int n, const BoxRec *box)
1799{
1800	bool ok;
1801
1802	DBG(("%s: nbox=%d\n", __FUNCTION__, n));
1803
1804	ok = gpu_bo_download(sna, priv, n, box, true);
1805	if (!ok)
1806		ok = cpu_bo_download(sna, priv, n, box);
1807	if (!ok)
1808		ok = gpu_bo_download(sna, priv, n, box, false);
1809	if (!ok) {
1810		if (priv->cpu_bo)
1811			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
1812		assert(priv->mapped == MAPPED_NONE);
1813		assert(has_coherent_ptr(sna, priv, MOVE_WRITE));
1814		sna_read_boxes(sna, priv->pixmap, priv->gpu_bo, box, n);
1815	}
1816}
1817
1818static inline bool use_cpu_bo_for_upload(struct sna *sna,
1819					 struct sna_pixmap *priv,
1820					 unsigned flags)
1821{
1822	if (DBG_NO_CPU_UPLOAD)
1823		return false;
1824
1825	if (wedged(sna))
1826		return false;
1827
1828	if (priv->cpu_bo == NULL)
1829		return false;
1830
1831	DBG(("%s? flags=%x, gpu busy?=%d, cpu busy?=%d\n", __FUNCTION__,
1832	     flags,
1833	     kgem_bo_is_busy(priv->gpu_bo),
1834	     kgem_bo_is_busy(priv->cpu_bo)));
1835
1836	if (!priv->cpu)
1837		return true;
1838
1839	if (flags & (MOVE_WRITE | MOVE_ASYNC_HINT))
1840		return true;
1841
1842	if (priv->gpu_bo->tiling)
1843		return true;
1844
1845	return kgem_bo_is_busy(priv->gpu_bo) || kgem_bo_is_busy(priv->cpu_bo);
1846}
1847
1848bool
1849sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags)
1850{
1851	struct sna_cow *cow = COW(priv->cow);
1852
1853	DBG(("%s: pixmap=%ld, handle=%d [refcnt=%d], cow refcnt=%d, flags=%x\n",
1854	     __FUNCTION__,
1855	     priv->pixmap->drawable.serialNumber,
1856	     priv->gpu_bo->handle,
1857	     priv->gpu_bo->refcnt,
1858	     cow->refcnt,
1859	     flags));
1860
1861	assert(priv->gpu_bo == cow->bo);
1862	assert(cow->refcnt);
1863
1864	if (flags && (flags & MOVE_WRITE) == 0 && IS_COW_OWNER(priv->cow))
1865		return true;
1866
1867	if (!IS_COW_OWNER(priv->cow))
1868		list_del(&priv->cow_list);
1869
1870	if (!--cow->refcnt) {
1871		DBG(("%s: freeing cow\n", __FUNCTION__));
1872		assert(list_is_empty(&cow->list));
1873		free(cow);
1874	} else if (IS_COW_OWNER(priv->cow) && priv->pinned) {
1875		PixmapPtr pixmap = priv->pixmap;
1876		struct kgem_bo *bo;
1877		BoxRec box;
1878
1879		DBG(("%s: copying the Holy cow\n", __FUNCTION__));
1880
1881		box.x1 = box.y1 = 0;
1882		box.x2 = pixmap->drawable.width;
1883		box.y2 = pixmap->drawable.height;
1884
1885		bo = kgem_create_2d(&sna->kgem,
1886				    box.x2, box.y2,
1887				    pixmap->drawable.bitsPerPixel,
1888				    sna_pixmap_default_tiling(sna, pixmap),
1889				    0);
1890		if (bo == NULL) {
1891			cow->refcnt++;
1892			DBG(("%s: allocation failed\n", __FUNCTION__));
1893			return false;
1894		}
1895
1896		if (!sna->render.copy_boxes(sna, GXcopy,
1897					    &pixmap->drawable, priv->gpu_bo, 0, 0,
1898					    &pixmap->drawable, bo, 0, 0,
1899					    &box, 1, 0)) {
1900			DBG(("%s: copy failed\n", __FUNCTION__));
1901			kgem_bo_destroy(&sna->kgem, bo);
1902			cow->refcnt++;
1903			return false;
1904		}
1905
1906		assert(!list_is_empty(&cow->list));
1907		while (!list_is_empty(&cow->list)) {
1908			struct sna_pixmap *clone;
1909
1910			clone = list_first_entry(&cow->list,
1911						 struct sna_pixmap, cow_list);
1912			list_del(&clone->cow_list);
1913
1914			assert(clone->gpu_bo == cow->bo);
1915			sna_pixmap_unmap(clone->pixmap, clone);
1916			kgem_bo_destroy(&sna->kgem, clone->gpu_bo);
1917			clone->gpu_bo = kgem_bo_reference(bo);
1918		}
1919		cow->bo = bo;
1920		kgem_bo_destroy(&sna->kgem, bo);
1921	} else {
1922		struct kgem_bo *bo = NULL;
1923
1924		if (flags & MOVE_READ) {
1925			PixmapPtr pixmap = priv->pixmap;
1926			unsigned create, tiling;
1927			BoxRec box;
1928
1929			DBG(("%s: copying cow\n", __FUNCTION__));
1930
1931			box.x1 = box.y1 = 0;
1932			box.x2 = pixmap->drawable.width;
1933			box.y2 = pixmap->drawable.height;
1934
1935			if (flags & __MOVE_PRIME) {
1936				create = CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT;
1937				tiling = I915_TILING_NONE;
1938			} else {
1939				create = 0;
1940				tiling = sna_pixmap_default_tiling(sna, pixmap);
1941			}
1942
1943			bo = kgem_create_2d(&sna->kgem,
1944					    box.x2, box.y2,
1945					    pixmap->drawable.bitsPerPixel,
1946					    tiling, create);
1947			if (bo == NULL) {
1948				cow->refcnt++;
1949				DBG(("%s: allocation failed\n", __FUNCTION__));
1950				return false;
1951			}
1952
1953			if (!sna->render.copy_boxes(sna, GXcopy,
1954						    &pixmap->drawable, priv->gpu_bo, 0, 0,
1955						    &pixmap->drawable, bo, 0, 0,
1956						    &box, 1, 0)) {
1957				DBG(("%s: copy failed\n", __FUNCTION__));
1958				kgem_bo_destroy(&sna->kgem, bo);
1959				cow->refcnt++;
1960				return false;
1961			}
1962		}
1963
1964		assert(priv->gpu_bo);
1965		sna_pixmap_unmap(priv->pixmap, priv);
1966		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1967		priv->gpu_bo = bo;
1968	}
1969
1970	priv->cow = NULL;
1971	return true;
1972}
1973
1974static bool
1975sna_pixmap_make_cow(struct sna *sna,
1976		    struct sna_pixmap *src_priv,
1977		    struct sna_pixmap *dst_priv)
1978{
1979	struct sna_cow *cow;
1980
1981	assert(src_priv->gpu_bo);
1982
1983	if (!USE_COW)
1984		return false;
1985
1986	if (src_priv->gpu_bo->proxy)
1987		return false;
1988
1989	DBG(("%s: make cow src=%ld, dst=%ld, handle=%d (already cow? src=%d, dst=%d)\n",
1990	     __FUNCTION__,
1991	     src_priv->pixmap->drawable.serialNumber,
1992	     dst_priv->pixmap->drawable.serialNumber,
1993	     src_priv->gpu_bo->handle,
1994	     src_priv->cow ? IS_COW_OWNER(src_priv->cow) ? 1 : -1 : 0,
1995	     dst_priv->cow ? IS_COW_OWNER(dst_priv->cow) ? 1 : -1 : 0));
1996
1997	if (dst_priv->pinned) {
1998		DBG(("%s: can't cow, dst_pinned=%x\n",
1999		     __FUNCTION__, dst_priv->pinned));
2000		return false;
2001	}
2002
2003	assert(dst_priv->move_to_gpu == NULL);
2004	assert(!dst_priv->flush);
2005	assert(list_is_empty(&dst_priv->cow_list));
2006
2007	cow = COW(src_priv->cow);
2008	if (cow == NULL) {
2009		cow = malloc(sizeof(*cow));
2010		if (cow == NULL)
2011			return false;
2012
2013		list_init(&cow->list);
2014
2015		cow->bo = src_priv->gpu_bo;
2016		cow->refcnt = 1;
2017
2018		DBG(("%s: moo! attaching source cow to pixmap=%ld, handle=%d\n",
2019		     __FUNCTION__,
2020		     src_priv->pixmap->drawable.serialNumber,
2021		     cow->bo->handle));
2022
2023		src_priv->cow = MAKE_COW_OWNER(cow);
2024	}
2025
2026	if (cow == COW(dst_priv->cow)) {
2027		assert(dst_priv->gpu_bo == cow->bo);
2028		return true;
2029	}
2030
2031	if (dst_priv->cow)
2032		sna_pixmap_undo_cow(sna, dst_priv, 0);
2033
2034	if (dst_priv->gpu_bo) {
2035		sna_pixmap_unmap(dst_priv->pixmap, dst_priv);
2036		kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo);
2037	}
2038	assert(!dst_priv->mapped);
2039	dst_priv->gpu_bo = kgem_bo_reference(cow->bo);
2040	dst_priv->cow = cow;
2041	list_add(&dst_priv->cow_list, &cow->list);
2042	cow->refcnt++;
2043
2044	DBG(("%s: moo! attaching clone to pixmap=%ld (source=%ld, handle=%d)\n",
2045	     __FUNCTION__,
2046	     dst_priv->pixmap->drawable.serialNumber,
2047	     src_priv->pixmap->drawable.serialNumber,
2048	     cow->bo->handle));
2049
2050	return true;
2051}
2052
2053static inline bool operate_inplace(struct sna_pixmap *priv, unsigned flags)
2054{
2055	if (!USE_INPLACE)
2056		return false;
2057
2058	if ((flags & MOVE_INPLACE_HINT) == 0) {
2059		DBG(("%s: no, inplace operation not suitable\n", __FUNCTION__));
2060		return false;
2061	}
2062
2063	assert((flags & MOVE_ASYNC_HINT) == 0 || (priv->create & KGEM_CAN_CREATE_LARGE));
2064
2065	if (priv->move_to_gpu && flags & MOVE_WRITE) {
2066		DBG(("%s: no, has pending move-to-gpu\n", __FUNCTION__));
2067		return false;
2068	}
2069
2070	if (priv->cow && flags & MOVE_WRITE) {
2071		DBG(("%s: no, has COW\n", __FUNCTION__));
2072		return false;
2073	}
2074
2075	if ((priv->create & KGEM_CAN_CREATE_GTT) == 0) {
2076		DBG(("%s: no, not accessible via GTT\n", __FUNCTION__));
2077		return false;
2078	}
2079
2080	if ((priv->gpu_damage == NULL || priv->cpu_damage) && flags & MOVE_READ) {
2081		DBG(("%s: no, has CPU damage and requires readback\n", __FUNCTION__));
2082		return false;
2083	}
2084
2085	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) {
2086		DBG(("%s: yes, CPU is busy\n", __FUNCTION__));
2087		return true;
2088	}
2089
2090	if (priv->create & KGEM_CAN_CREATE_LARGE) {
2091		DBG(("%s: large object, has GPU? %d\n",
2092		     __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0));
2093		return priv->gpu_bo != NULL;
2094	}
2095
2096	if (flags & MOVE_WRITE && priv->gpu_bo&&kgem_bo_is_busy(priv->gpu_bo)) {
2097		DBG(("%s: no, GPU is busy, so stage write\n", __FUNCTION__));
2098		return false;
2099	}
2100
2101	return true;
2102}
2103
2104bool
2105_sna_pixmap_move_to_cpu(PixmapPtr pixmap, unsigned int flags)
2106{
2107	struct sna *sna = to_sna_from_pixmap(pixmap);
2108	struct sna_pixmap *priv;
2109
2110	DBG(("%s(pixmap=%ld, %dx%d, flags=%x)\n", __FUNCTION__,
2111	     pixmap->drawable.serialNumber,
2112	     pixmap->drawable.width,
2113	     pixmap->drawable.height,
2114	     flags));
2115
2116	assert(flags & (MOVE_READ | MOVE_WRITE));
2117	assert_pixmap_damage(pixmap);
2118
2119	priv = sna_pixmap(pixmap);
2120	if (priv == NULL) {
2121		DBG(("%s: not attached\n", __FUNCTION__));
2122		return true;
2123	}
2124
2125	DBG(("%s: gpu_bo=%d, gpu_damage=%p, cpu_damage=%p, is-clear?=%d\n",
2126	     __FUNCTION__,
2127	     priv->gpu_bo ? priv->gpu_bo->handle : 0,
2128	     priv->gpu_damage, priv->cpu_damage, priv->clear));
2129
2130	assert(priv->gpu_damage == NULL || priv->gpu_bo);
2131
2132	if ((flags & MOVE_READ) == 0 && UNDO) {
2133		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
2134		if (priv->move_to_gpu)
2135			sna_pixmap_discard_shadow_damage(priv, NULL);
2136	}
2137
2138	if (kgem_bo_discard_cache(priv->gpu_bo, flags & MOVE_WRITE)) {
2139		assert(DAMAGE_IS_ALL(priv->cpu_damage));
2140		if (DAMAGE_IS_ALL(priv->gpu_damage)) {
2141			DBG(("%s: using magical upload buffer\n", __FUNCTION__));
2142			goto skip;
2143		}
2144
2145		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
2146		assert(priv->gpu_damage == NULL);
2147		assert(!priv->pinned);
2148		assert(!priv->mapped);
2149		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
2150		priv->gpu_bo = NULL;
2151	}
2152
2153	if (DAMAGE_IS_ALL(priv->cpu_damage)) {
2154		DBG(("%s: CPU all-damaged\n", __FUNCTION__));
2155		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage));
2156		assert(priv->gpu_damage == NULL || (flags & MOVE_WRITE) == 0);
2157		goto done;
2158	}
2159
2160	if (USE_INPLACE && (flags & MOVE_READ) == 0 && !(priv->cow || priv->move_to_gpu)) {
2161		assert(flags & MOVE_WRITE);
2162		DBG(("%s: no readback, discarding gpu damage [%d], pending clear[%d]\n",
2163		     __FUNCTION__, priv->gpu_damage != NULL, priv->clear));
2164
2165		if ((priv->gpu_bo || priv->create & KGEM_CAN_CREATE_GPU) &&
2166		    pixmap_inplace(sna, pixmap, priv, flags) &&
2167		    sna_pixmap_create_mappable_gpu(pixmap, true)) {
2168			void *ptr;
2169
2170			DBG(("%s: write inplace\n", __FUNCTION__));
2171			assert(!priv->shm);
2172			assert(priv->cow == NULL);
2173			assert(priv->move_to_gpu == NULL);
2174			assert(priv->gpu_bo->exec == NULL);
2175			assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL);
2176
2177			ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo);
2178			if (ptr == NULL)
2179				goto skip_inplace_map;
2180
2181			pixmap->devPrivate.ptr = ptr;
2182			pixmap->devKind = priv->gpu_bo->pitch;
2183			priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
2184			assert(has_coherent_ptr(sna, priv, flags));
2185
2186			assert(priv->gpu_bo->proxy == NULL);
2187			sna_damage_all(&priv->gpu_damage, pixmap);
2188			sna_damage_destroy(&priv->cpu_damage);
2189			priv->clear = false;
2190			list_del(&priv->flush_list);
2191
2192			assert(!priv->shm);
2193			assert(priv->cpu_bo == NULL || !priv->cpu_bo->flush);
2194			sna_pixmap_free_cpu(sna, priv, priv->cpu);
2195			priv->cpu &= priv->mapped == MAPPED_CPU;
2196
2197			assert_pixmap_damage(pixmap);
2198			return true;
2199		}
2200
2201skip_inplace_map:
2202		sna_damage_destroy(&priv->gpu_damage);
2203		priv->clear = false;
2204		if ((flags & MOVE_ASYNC_HINT) == 0 &&
2205		    priv->cpu_bo && !priv->cpu_bo->flush &&
2206		    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2207			DBG(("%s: discarding busy CPU bo\n", __FUNCTION__));
2208			assert(!priv->shm);
2209			assert(priv->gpu_bo == NULL || priv->gpu_damage == NULL);
2210
2211			sna_damage_destroy(&priv->cpu_damage);
2212			sna_pixmap_free_cpu(sna, priv, false);
2213
2214			assert(priv->mapped == MAPPED_NONE);
2215			if (!sna_pixmap_alloc_cpu(sna, pixmap, priv, 0))
2216				return false;
2217			assert(priv->mapped == MAPPED_NONE);
2218			assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2219
2220			goto mark_damage;
2221		}
2222	}
2223
2224	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2225
2226	if (operate_inplace(priv, flags) &&
2227	    pixmap_inplace(sna, pixmap, priv, flags) &&
2228	    sna_pixmap_create_mappable_gpu(pixmap, (flags & MOVE_READ) == 0)) {
2229		void *ptr;
2230
2231		DBG(("%s: try to operate inplace (GTT)\n", __FUNCTION__));
2232		assert(priv->gpu_bo);
2233		assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
2234		assert(!priv->move_to_gpu);
2235		assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2236		assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL);
2237		/* XXX only sync for writes? */
2238		kgem_bo_submit(&sna->kgem, priv->gpu_bo);
2239		assert(priv->gpu_bo->exec == NULL);
2240
2241		ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo);
2242		if (ptr != NULL) {
2243			pixmap->devPrivate.ptr = ptr;
2244			pixmap->devKind = priv->gpu_bo->pitch;
2245			priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
2246			assert(has_coherent_ptr(sna, priv, flags));
2247
2248			if (flags & MOVE_WRITE) {
2249				assert(priv->gpu_bo->proxy == NULL);
2250				sna_damage_all(&priv->gpu_damage, pixmap);
2251				sna_damage_destroy(&priv->cpu_damage);
2252				sna_pixmap_free_cpu(sna, priv, priv->cpu);
2253				list_del(&priv->flush_list);
2254				priv->clear = false;
2255			}
2256			priv->cpu &= priv->mapped == MAPPED_CPU;
2257
2258			assert_pixmap_damage(pixmap);
2259			DBG(("%s: operate inplace (GTT)\n", __FUNCTION__));
2260			return true;
2261		}
2262	}
2263
2264	sna_pixmap_unmap(pixmap, priv);
2265
2266	if (USE_INPLACE &&
2267	    (flags & MOVE_WRITE ? (void *)priv->gpu_bo : (void *)priv->gpu_damage) && priv->cpu_damage == NULL &&
2268	    priv->gpu_bo->tiling == I915_TILING_NONE &&
2269	    (flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE)) &&
2270	    ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 ||
2271	     (!priv->cow && !priv->move_to_gpu && !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)))) {
2272		void *ptr;
2273
2274		DBG(("%s: try to operate inplace (CPU)\n", __FUNCTION__));
2275		assert(priv->gpu_bo);
2276		assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
2277		assert(priv->move_to_gpu == NULL || (flags & MOVE_WRITE) == 0);
2278		assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2279
2280		assert(!priv->mapped);
2281		assert(priv->gpu_bo->tiling == I915_TILING_NONE);
2282
2283		ptr = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
2284		if (ptr != NULL) {
2285			pixmap->devPrivate.ptr = ptr;
2286			pixmap->devKind = priv->gpu_bo->pitch;
2287			priv->mapped = MAPPED_CPU;
2288			assert(has_coherent_ptr(sna, priv, flags));
2289
2290			if (flags & MOVE_WRITE) {
2291				assert(priv->gpu_bo->proxy == NULL);
2292				sna_damage_all(&priv->gpu_damage, pixmap);
2293				sna_damage_destroy(&priv->cpu_damage);
2294				sna_pixmap_free_cpu(sna, priv, priv->cpu);
2295				list_del(&priv->flush_list);
2296				priv->clear = false;
2297				priv->cpu = true;
2298			}
2299
2300			assert(pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu));
2301			kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo,
2302					       FORCE_FULL_SYNC || flags & MOVE_WRITE);
2303			assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo));
2304			assert_pixmap_damage(pixmap);
2305			assert(has_coherent_ptr(sna, priv, flags));
2306			DBG(("%s: operate inplace (CPU)\n", __FUNCTION__));
2307			return true;
2308		}
2309	}
2310
2311	assert(priv->mapped == MAPPED_NONE);
2312	if (((flags & MOVE_READ) == 0 || priv->clear) &&
2313	    priv->cpu_bo && !priv->cpu_bo->flush &&
2314	    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2315		assert(!priv->shm);
2316		sna_pixmap_free_cpu(sna, priv, false);
2317	}
2318
2319	assert(priv->mapped == MAPPED_NONE);
2320	if (pixmap->devPrivate.ptr == NULL &&
2321	    !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags))
2322		return false;
2323	assert(priv->mapped == MAPPED_NONE);
2324	assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2325
2326	if (flags & MOVE_READ) {
2327		if (priv->clear) {
2328			DBG(("%s: applying clear [%08x] size=%dx%d, stride=%d (total=%d)\n",
2329			     __FUNCTION__, priv->clear_color, pixmap->drawable.width, pixmap->drawable.height,
2330			     pixmap->devKind, pixmap->devKind * pixmap->drawable.height));
2331
2332			if (priv->cpu_bo) {
2333				if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) &&
2334				    sna->render.fill_one(sna,
2335							  pixmap, priv->cpu_bo, priv->clear_color,
2336							  0, 0,
2337							  pixmap->drawable.width,
2338							  pixmap->drawable.height,
2339							  GXcopy))
2340					goto clear_done;
2341
2342				DBG(("%s: syncing CPU bo\n", __FUNCTION__));
2343				kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
2344				assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
2345			}
2346
2347			assert(pixmap->devKind);
2348			if (priv->clear_color == 0 ||
2349			    pixmap->drawable.bitsPerPixel == 8 ||
2350			    priv->clear_color == (1 << pixmap->drawable.depth) - 1) {
2351				memset(pixmap->devPrivate.ptr, priv->clear_color,
2352				       (size_t)pixmap->devKind * pixmap->drawable.height);
2353			} else {
2354				pixman_fill(pixmap->devPrivate.ptr,
2355					    pixmap->devKind/sizeof(uint32_t),
2356					    pixmap->drawable.bitsPerPixel,
2357					    0, 0,
2358					    pixmap->drawable.width,
2359					    pixmap->drawable.height,
2360					    priv->clear_color);
2361			}
2362
2363clear_done:
2364			sna_damage_all(&priv->cpu_damage, pixmap);
2365			sna_pixmap_free_gpu(sna, priv);
2366			assert(priv->gpu_damage == NULL);
2367			assert(priv->clear == false);
2368		}
2369
2370		if (priv->gpu_damage) {
2371			const BoxRec *box;
2372			int n;
2373
2374			DBG(("%s: flushing GPU damage\n", __FUNCTION__));
2375			assert(priv->gpu_bo);
2376
2377			n = sna_damage_get_boxes(priv->gpu_damage, &box);
2378			if (n) {
2379				if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ)) {
2380					DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
2381					return false;
2382				}
2383
2384				download_boxes(sna, priv, n, box);
2385			}
2386
2387			__sna_damage_destroy(DAMAGE_PTR(priv->gpu_damage));
2388			priv->gpu_damage = NULL;
2389		}
2390	}
2391
2392	if (flags & MOVE_WRITE || priv->create & KGEM_CAN_CREATE_LARGE) {
2393mark_damage:
2394		DBG(("%s: marking as damaged\n", __FUNCTION__));
2395		sna_damage_all(&priv->cpu_damage, pixmap);
2396		sna_pixmap_free_gpu(sna, priv);
2397		assert(priv->gpu_damage == NULL);
2398		assert(priv->clear == false);
2399
2400		if (priv->flush) {
2401			assert(!priv->shm);
2402			sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
2403		}
2404	}
2405
2406done:
2407	if (flags & MOVE_WRITE) {
2408		assert(DAMAGE_IS_ALL(priv->cpu_damage));
2409		assert(priv->gpu_damage == NULL);
2410		assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
2411		if (priv->cow)
2412			sna_pixmap_undo_cow(sna, priv, 0);
2413		if (priv->gpu_bo && priv->gpu_bo->rq == NULL) {
2414			DBG(("%s: discarding idle GPU bo\n", __FUNCTION__));
2415			sna_pixmap_free_gpu(sna, priv);
2416		}
2417		priv->source_count = SOURCE_BIAS;
2418	}
2419
2420	if (priv->cpu_bo) {
2421		if ((flags & MOVE_ASYNC_HINT) == 0) {
2422			DBG(("%s: syncing CPU bo\n", __FUNCTION__));
2423			assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
2424			kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo,
2425					       FORCE_FULL_SYNC || flags & MOVE_WRITE);
2426			assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo));
2427		}
2428	}
2429skip:
2430	priv->cpu |= (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE;
2431	assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2432	assert(pixmap->devKind);
2433	assert_pixmap_damage(pixmap);
2434	assert(has_coherent_ptr(sna, sna_pixmap(pixmap), flags));
2435	return true;
2436}
2437
2438static bool
2439region_overlaps_damage(const RegionRec *region,
2440		       struct sna_damage *damage,
2441		       int dx, int dy)
2442{
2443	const BoxRec *re, *de;
2444
2445	DBG(("%s?\n", __FUNCTION__));
2446
2447	if (damage == NULL)
2448		return false;
2449
2450	if (DAMAGE_IS_ALL(damage))
2451		return true;
2452
2453	re = &region->extents;
2454	de = &DAMAGE_PTR(damage)->extents;
2455	DBG(("%s: region (%d, %d), (%d, %d), damage (%d, %d), (%d, %d)\n",
2456	     __FUNCTION__,
2457	     re->x1, re->y1, re->x2, re->y2,
2458	     de->x1, de->y1, de->x2, de->y2));
2459
2460	return (re->x1 + dx < de->x2 && re->x2 + dx > de->x1 &&
2461		re->y1 + dy < de->y2 && re->y2 + dy > de->y1);
2462}
2463
2464static inline bool region_inplace(struct sna *sna,
2465				  PixmapPtr pixmap,
2466				  RegionPtr region,
2467				  struct sna_pixmap *priv,
2468				  unsigned flags)
2469{
2470	assert_pixmap_damage(pixmap);
2471
2472	if (FORCE_INPLACE)
2473		return FORCE_INPLACE > 0;
2474
2475	if (wedged(sna) && !priv->pinned)
2476		return false;
2477
2478	if (priv->gpu_damage &&
2479	    (priv->clear || (flags & MOVE_READ) == 0) &&
2480	    kgem_bo_is_busy(priv->gpu_bo))
2481		return false;
2482
2483	if (flags & MOVE_READ &&
2484	    (priv->cpu ||
2485	     priv->gpu_damage == NULL ||
2486	     region_overlaps_damage(region, priv->cpu_damage, 0, 0))) {
2487		DBG(("%s: no, uncovered CPU damage pending\n", __FUNCTION__));
2488		return false;
2489	}
2490
2491	if (priv->mapped) {
2492		DBG(("%s: %s, already mapped, continuing\n", __FUNCTION__,
2493		     has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no"));
2494		return has_coherent_map(sna, priv->gpu_bo, flags);
2495	}
2496
2497	if (priv->flush) {
2498		DBG(("%s: yes, exported via dri, will flush\n", __FUNCTION__));
2499		return true;
2500	}
2501
2502	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
2503		DBG(("%s: yes, already wholly damaged on the GPU\n", __FUNCTION__));
2504		assert(priv->gpu_bo);
2505		return true;
2506	}
2507
2508	if (priv->cpu_bo && priv->cpu) {
2509		DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__));
2510		return false;
2511	}
2512
2513	DBG(("%s: (%dx%d), inplace? %d\n",
2514	     __FUNCTION__,
2515	     region->extents.x2 - region->extents.x1,
2516	     region->extents.y2 - region->extents.y1,
2517	     ((int)(region->extents.x2 - region->extents.x1) *
2518	      (int)(region->extents.y2 - region->extents.y1) *
2519	      pixmap->drawable.bitsPerPixel >> 12)
2520	     >= sna->kgem.half_cpu_cache_pages));
2521	return ((int)(region->extents.x2 - region->extents.x1) *
2522		(int)(region->extents.y2 - region->extents.y1) *
2523		pixmap->drawable.bitsPerPixel >> 12)
2524		>= sna->kgem.half_cpu_cache_pages;
2525}
2526
2527static bool cpu_clear_boxes(struct sna *sna,
2528			    PixmapPtr pixmap,
2529			    struct sna_pixmap *priv,
2530			    const BoxRec *box, int n)
2531{
2532	struct sna_fill_op fill;
2533
2534	if (!sna_fill_init_blt(&fill, sna,
2535			       pixmap, priv->cpu_bo,
2536			       GXcopy, priv->clear_color,
2537			       FILL_BOXES)) {
2538		DBG(("%s: unsupported fill\n",
2539		     __FUNCTION__));
2540		return false;
2541	}
2542
2543	fill.boxes(sna, &fill, box, n);
2544	fill.done(sna, &fill);
2545	return true;
2546}
2547
2548bool
2549sna_drawable_move_region_to_cpu(DrawablePtr drawable,
2550				RegionPtr region,
2551				unsigned flags)
2552{
2553	PixmapPtr pixmap = get_drawable_pixmap(drawable);
2554	struct sna *sna = to_sna_from_pixmap(pixmap);
2555	struct sna_pixmap *priv;
2556	int16_t dx, dy;
2557
2558	DBG(("%s(pixmap=%ld (%dx%d), [(%d, %d), (%d, %d)], flags=%x)\n",
2559	     __FUNCTION__, pixmap->drawable.serialNumber,
2560	     pixmap->drawable.width, pixmap->drawable.height,
2561	     RegionExtents(region)->x1, RegionExtents(region)->y1,
2562	     RegionExtents(region)->x2, RegionExtents(region)->y2,
2563	     flags));
2564
2565	assert_pixmap_damage(pixmap);
2566	if (flags & MOVE_WRITE) {
2567		assert_drawable_contains_box(drawable, &region->extents);
2568	}
2569	assert(flags & (MOVE_WRITE | MOVE_READ));
2570
2571	if (box_empty(&region->extents))
2572		return true;
2573
2574	if (MIGRATE_ALL || DBG_NO_PARTIAL_MOVE_TO_CPU) {
2575		if (!region_subsumes_pixmap(region, pixmap))
2576			flags |= MOVE_READ;
2577		return _sna_pixmap_move_to_cpu(pixmap, flags);
2578	}
2579
2580	priv = sna_pixmap(pixmap);
2581	if (priv == NULL) {
2582		DBG(("%s: not attached to pixmap %ld (depth %d)\n",
2583		     __FUNCTION__, pixmap->drawable.serialNumber, pixmap->drawable.depth));
2584		return true;
2585	}
2586
2587	assert(priv->gpu_damage == NULL || priv->gpu_bo);
2588
2589	if (kgem_bo_discard_cache(priv->gpu_bo, flags & MOVE_WRITE)) {
2590		assert(DAMAGE_IS_ALL(priv->cpu_damage));
2591		if (DAMAGE_IS_ALL(priv->gpu_damage)) {
2592			DBG(("%s: using magical upload buffer\n", __FUNCTION__));
2593			goto skip;
2594		}
2595
2596		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
2597		assert(priv->gpu_damage == NULL);
2598		assert(!priv->pinned);
2599		assert(!priv->mapped);
2600		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
2601		priv->gpu_bo = NULL;
2602	}
2603
2604	if (sna_damage_is_all(&priv->cpu_damage,
2605			      pixmap->drawable.width,
2606			      pixmap->drawable.height)) {
2607		bool discard_gpu = priv->cpu;
2608
2609		DBG(("%s: pixmap=%ld all damaged on CPU\n",
2610		     __FUNCTION__, pixmap->drawable.serialNumber));
2611		assert(!priv->clear);
2612
2613		sna_damage_destroy(&priv->gpu_damage);
2614
2615		if ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 &&
2616		    priv->cpu_bo && !priv->cpu_bo->flush &&
2617		    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2618			DBG(("%s: active CPU bo replacing\n", __FUNCTION__));
2619			assert(!priv->shm);
2620			assert(!IS_STATIC_PTR(priv->ptr));
2621
2622			if (!region_subsumes_pixmap(region, pixmap)) {
2623				DBG(("%s: partial replacement\n", __FUNCTION__));
2624				if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
2625					RegionTranslate(region, dx, dy);
2626
2627				if (sna->kgem.has_llc && !priv->pinned &&
2628				    sna_pixmap_default_tiling(sna, pixmap) == I915_TILING_NONE) {
2629#ifdef DEBUG_MEMORY
2630					sna->debug_memory.cpu_bo_allocs--;
2631					sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
2632#endif
2633					DBG(("%s: promoting CPU bo to GPU bo\n", __FUNCTION__));
2634					if (priv->gpu_bo)
2635						sna_pixmap_free_gpu(sna, priv);
2636					priv->gpu_bo = priv->cpu_bo;
2637					priv->cpu_bo = NULL;
2638					priv->ptr = NULL;
2639					pixmap->devPrivate.ptr = NULL;
2640
2641					priv->gpu_damage = priv->cpu_damage;
2642					priv->cpu_damage = NULL;
2643
2644					sna_damage_subtract(&priv->gpu_damage, region);
2645					discard_gpu = false;
2646				} else {
2647					DBG(("%s: pushing surrounding damage to GPU bo\n", __FUNCTION__));
2648					sna_damage_subtract(&priv->cpu_damage, region);
2649					assert(priv->cpu_damage);
2650					if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) {
2651						sna_pixmap_free_cpu(sna, priv, false);
2652						if (priv->flush)
2653							sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
2654
2655						assert(priv->cpu_damage == NULL);
2656						sna_damage_all(&priv->gpu_damage, pixmap);
2657						sna_damage_subtract(&priv->gpu_damage, region);
2658						discard_gpu = false;
2659					}
2660				}
2661				sna_damage_add_to_pixmap(&priv->cpu_damage, region, pixmap);
2662
2663				if (dx | dy)
2664					RegionTranslate(region, -dx, -dy);
2665			} else
2666				sna_pixmap_free_cpu(sna, priv, false);
2667		}
2668
2669		if (flags & MOVE_WRITE && discard_gpu)
2670			sna_pixmap_free_gpu(sna, priv);
2671
2672		sna_pixmap_unmap(pixmap, priv);
2673		assert(priv->mapped == MAPPED_NONE);
2674		if (pixmap->devPrivate.ptr == NULL &&
2675		    !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags))
2676			return false;
2677		assert(priv->mapped == MAPPED_NONE);
2678		assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2679
2680		goto out;
2681	}
2682
2683	if (USE_INPLACE &&
2684	    (priv->create & KGEM_CAN_CREATE_LARGE ||
2685	     ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 &&
2686	      (priv->flush ||
2687	       (flags & MOVE_WHOLE_HINT && whole_pixmap_inplace(pixmap)) ||
2688	       box_inplace(pixmap, &region->extents))))) {
2689		DBG(("%s: marking for inplace hint (%d, %d)\n",
2690		     __FUNCTION__, priv->flush, box_inplace(pixmap, &region->extents)));
2691		flags |= MOVE_INPLACE_HINT;
2692	}
2693
2694	if (region_subsumes_pixmap(region, pixmap)) {
2695		DBG(("%s: region (%d, %d), (%d, %d) + (%d, %d) subsumes pixmap (%dx%d)\n",
2696		       __FUNCTION__,
2697		       region->extents.x1,
2698		       region->extents.y1,
2699		       region->extents.x2,
2700		       region->extents.y2,
2701		       get_drawable_dx(drawable), get_drawable_dy(drawable),
2702		       pixmap->drawable.width,
2703		       pixmap->drawable.height));
2704		return _sna_pixmap_move_to_cpu(pixmap, flags);
2705	}
2706
2707	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2708
2709	if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
2710		DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy));
2711		RegionTranslate(region, dx, dy);
2712	}
2713
2714	if (priv->move_to_gpu) {
2715		DBG(("%s: applying move-to-gpu override\n", __FUNCTION__));
2716		if ((flags & MOVE_READ) == 0)
2717			sna_pixmap_discard_shadow_damage(priv, region);
2718		if (!priv->move_to_gpu(sna, priv, MOVE_READ)) {
2719			DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
2720			return NULL;
2721		}
2722	}
2723
2724	if (operate_inplace(priv, flags) &&
2725	    region_inplace(sna, pixmap, region, priv, flags) &&
2726	    sna_pixmap_create_mappable_gpu(pixmap, false)) {
2727		void *ptr;
2728
2729		DBG(("%s: try to operate inplace\n", __FUNCTION__));
2730		assert(priv->gpu_bo);
2731		assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
2732		assert(priv->move_to_gpu == NULL || (flags & MOVE_WRITE) == 0);
2733		assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2734
2735		/* XXX only sync for writes? */
2736		kgem_bo_submit(&sna->kgem, priv->gpu_bo);
2737		assert(priv->gpu_bo->exec == NULL);
2738
2739		ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo);
2740		if (ptr != NULL) {
2741			pixmap->devPrivate.ptr = ptr;
2742			pixmap->devKind = priv->gpu_bo->pitch;
2743			priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
2744			assert(has_coherent_ptr(sna, priv, flags));
2745
2746			if (flags & MOVE_WRITE) {
2747				if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
2748					assert(!priv->clear);
2749					sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap);
2750					if (sna_damage_is_all(&priv->gpu_damage,
2751							      pixmap->drawable.width,
2752							      pixmap->drawable.height)) {
2753						DBG(("%s: replaced entire pixmap, destroying CPU shadow\n",
2754						     __FUNCTION__));
2755						sna_damage_destroy(&priv->cpu_damage);
2756						list_del(&priv->flush_list);
2757					} else
2758						sna_damage_subtract(&priv->cpu_damage,
2759								    region);
2760				}
2761				priv->clear = false;
2762			}
2763			priv->cpu &= priv->mapped == MAPPED_CPU;
2764			assert_pixmap_damage(pixmap);
2765			if (dx | dy)
2766				RegionTranslate(region, -dx, -dy);
2767			DBG(("%s: operate inplace\n", __FUNCTION__));
2768			return true;
2769		}
2770	}
2771
2772	if (priv->clear && flags & MOVE_WRITE) {
2773		DBG(("%s: pending clear, moving whole pixmap for partial write\n", __FUNCTION__));
2774demote_to_cpu:
2775		if (dx | dy)
2776			RegionTranslate(region, -dx, -dy);
2777		return _sna_pixmap_move_to_cpu(pixmap, flags | MOVE_READ);
2778	}
2779
2780	if (flags & MOVE_WHOLE_HINT) {
2781		DBG(("%s: region (%d, %d), (%d, %d) marked with WHOLE hint, pixmap %dx%d\n",
2782		       __FUNCTION__,
2783		       region->extents.x1,
2784		       region->extents.y1,
2785		       region->extents.x2,
2786		       region->extents.y2,
2787		       pixmap->drawable.width,
2788		       pixmap->drawable.height));
2789move_to_cpu:
2790		if ((flags & MOVE_READ) == 0)
2791			sna_damage_subtract(&priv->gpu_damage, region);
2792		goto demote_to_cpu;
2793	}
2794
2795	sna_pixmap_unmap(pixmap, priv);
2796
2797	if (USE_INPLACE &&
2798	    priv->gpu_damage &&
2799	    priv->gpu_bo->tiling == I915_TILING_NONE &&
2800	    ((priv->cow == NULL && priv->move_to_gpu == NULL) || (flags & MOVE_WRITE) == 0) &&
2801	    (DAMAGE_IS_ALL(priv->gpu_damage) ||
2802	     sna_damage_contains_box__no_reduce(priv->gpu_damage,
2803						&region->extents)) &&
2804	    kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE) &&
2805	    ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 ||
2806	     !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) {
2807		void *ptr;
2808
2809		DBG(("%s: try to operate inplace (CPU), read? %d, write? %d\n",
2810		     __FUNCTION__, !!(flags & MOVE_READ), !!(flags & MOVE_WRITE)));
2811		assert(priv->gpu_bo);
2812		assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2813		assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
2814		assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
2815
2816		ptr = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
2817		if (ptr != NULL) {
2818			pixmap->devPrivate.ptr = ptr;
2819			pixmap->devKind = priv->gpu_bo->pitch;
2820			priv->mapped = MAPPED_CPU;
2821			assert(has_coherent_ptr(sna, priv, flags));
2822
2823			if (flags & MOVE_WRITE) {
2824				if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
2825					assert(!priv->clear);
2826					sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap);
2827					if (sna_damage_is_all(&priv->gpu_damage,
2828							      pixmap->drawable.width,
2829							      pixmap->drawable.height)) {
2830						DBG(("%s: replaced entire pixmap, destroying CPU shadow\n",
2831						     __FUNCTION__));
2832						sna_damage_destroy(&priv->cpu_damage);
2833						list_del(&priv->flush_list);
2834					} else
2835						sna_damage_subtract(&priv->cpu_damage,
2836								    region);
2837				}
2838				priv->clear = false;
2839			}
2840			assert_pixmap_damage(pixmap);
2841
2842			kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo,
2843					       FORCE_FULL_SYNC || flags & MOVE_WRITE);
2844			priv->cpu = true;
2845
2846			assert_pixmap_map(pixmap, priv);
2847			assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo));
2848			if (dx | dy)
2849				RegionTranslate(region, -dx, -dy);
2850			DBG(("%s: operate inplace (CPU)\n", __FUNCTION__));
2851			return true;
2852		}
2853	}
2854
2855	if ((priv->clear || (flags & MOVE_READ) == 0) &&
2856	    priv->cpu_bo && !priv->cpu_bo->flush &&
2857	    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2858		sna_damage_subtract(&priv->cpu_damage, region);
2859		if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) {
2860			assert(priv->gpu_bo);
2861			sna_damage_all(&priv->gpu_damage, pixmap);
2862			sna_pixmap_free_cpu(sna, priv, false);
2863		}
2864	}
2865
2866	assert(priv->mapped == MAPPED_NONE);
2867	if (pixmap->devPrivate.ptr == NULL &&
2868	    !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags)) {
2869		DBG(("%s: CPU bo allocation failed, trying full move-to-cpu\n", __FUNCTION__));
2870		goto move_to_cpu;
2871	}
2872	assert(priv->mapped == MAPPED_NONE);
2873	assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2874
2875	if (priv->gpu_bo == NULL) {
2876		assert(priv->gpu_damage == NULL);
2877		goto done;
2878	}
2879
2880	assert(priv->gpu_bo->proxy == NULL);
2881
2882	if ((flags & MOVE_READ) == 0) {
2883		assert(flags & MOVE_WRITE);
2884		sna_damage_subtract(&priv->gpu_damage, region);
2885		priv->clear = false;
2886		goto done;
2887	}
2888
2889	if (priv->clear) {
2890		int n = region_num_rects(region);
2891		const BoxRec *box = region_rects(region);
2892
2893		assert(DAMAGE_IS_ALL(priv->gpu_damage));
2894		assert(priv->cpu_damage == NULL);
2895
2896		DBG(("%s: pending clear, doing partial fill\n", __FUNCTION__));
2897		if (priv->cpu_bo) {
2898			if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) &&
2899			    cpu_clear_boxes(sna, pixmap, priv, box, n))
2900				goto clear_done;
2901
2902			DBG(("%s: syncing CPU bo\n", __FUNCTION__));
2903			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
2904			assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
2905		}
2906
2907		assert(pixmap->devKind);
2908		do {
2909			pixman_fill(pixmap->devPrivate.ptr,
2910				    pixmap->devKind/sizeof(uint32_t),
2911				    pixmap->drawable.bitsPerPixel,
2912				    box->x1, box->y1,
2913				    box->x2 - box->x1,
2914				    box->y2 - box->y1,
2915				    priv->clear_color);
2916			box++;
2917		} while (--n);
2918
2919clear_done:
2920		if (flags & MOVE_WRITE ||
2921		    region->extents.x2 - region->extents.x1 > 1 ||
2922		    region->extents.y2 - region->extents.y1 > 1) {
2923			sna_damage_subtract(&priv->gpu_damage, region);
2924			priv->clear = false;
2925		}
2926		goto done;
2927	}
2928
2929	if (priv->gpu_damage &&
2930	    (DAMAGE_IS_ALL(priv->gpu_damage) ||
2931	     sna_damage_overlaps_box(priv->gpu_damage, &region->extents))) {
2932		DBG(("%s: region (%dx%d) overlaps gpu damage\n",
2933		     __FUNCTION__,
2934		     region->extents.x2 - region->extents.x1,
2935		     region->extents.y2 - region->extents.y1));
2936		assert(priv->gpu_bo);
2937
2938		if (priv->cpu_damage == NULL) {
2939			if ((flags & MOVE_WRITE) == 0 &&
2940			    region->extents.x2 - region->extents.x1 == 1 &&
2941			    region->extents.y2 - region->extents.y1 == 1) {
2942				/*  Often associated with synchronisation, KISS */
2943				DBG(("%s: single pixel read\n", __FUNCTION__));
2944				sna_read_boxes(sna, pixmap, priv->gpu_bo,
2945					       &region->extents, 1);
2946				goto done;
2947			}
2948		} else {
2949			if (DAMAGE_IS_ALL(priv->cpu_damage) ||
2950			    sna_damage_contains_box__no_reduce(priv->cpu_damage,
2951							       &region->extents)) {
2952				assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_OUT);
2953				assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_IN);
2954
2955				DBG(("%s: region already in CPU damage\n",
2956				     __FUNCTION__));
2957				goto already_damaged;
2958			}
2959		}
2960
2961		if (sna_damage_contains_box(&priv->gpu_damage,
2962					    &region->extents) != PIXMAN_REGION_OUT) {
2963			RegionRec want, *r = region;
2964
2965			DBG(("%s: region (%dx%d) intersects gpu damage\n",
2966			     __FUNCTION__,
2967			     region->extents.x2 - region->extents.x1,
2968			     region->extents.y2 - region->extents.y1));
2969
2970			if ((flags & MOVE_WRITE) == 0 &&
2971			    region->extents.x2 - region->extents.x1 == 1 &&
2972			    region->extents.y2 - region->extents.y1 == 1) {
2973				sna_read_boxes(sna, pixmap, priv->gpu_bo,
2974					       &region->extents, 1);
2975				goto done;
2976			}
2977
2978			/* Expand the region to move 32x32 pixel blocks at a
2979			 * time, as we assume that we will continue writing
2980			 * afterwards and so aim to coallesce subsequent
2981			 * reads.
2982			 */
2983			if (flags & MOVE_WRITE) {
2984				int n = region_num_rects(region), i;
2985				const BoxRec *boxes = region_rects(region);
2986				BoxPtr blocks;
2987
2988				blocks = NULL;
2989				if (priv->cpu_damage == NULL)
2990					blocks = malloc(sizeof(BoxRec) * n);
2991				if (blocks) {
2992					for (i = 0; i < n; i++) {
2993						blocks[i].x1 = boxes[i].x1 & ~31;
2994						if (blocks[i].x1 < 0)
2995							blocks[i].x1 = 0;
2996
2997						blocks[i].x2 = (boxes[i].x2 + 31) & ~31;
2998						if (blocks[i].x2 > pixmap->drawable.width)
2999							blocks[i].x2 = pixmap->drawable.width;
3000
3001						blocks[i].y1 = boxes[i].y1 & ~31;
3002						if (blocks[i].y1 < 0)
3003							blocks[i].y1 = 0;
3004
3005						blocks[i].y2 = (boxes[i].y2 + 31) & ~31;
3006						if (blocks[i].y2 > pixmap->drawable.height)
3007							blocks[i].y2 = pixmap->drawable.height;
3008					}
3009					if (pixman_region_init_rects(&want, blocks, i))
3010						r = &want;
3011					free(blocks);
3012				}
3013			}
3014
3015			if (region_subsumes_damage(r, priv->gpu_damage)) {
3016				const BoxRec *box;
3017				int n;
3018
3019				DBG(("%s: region wholly contains damage\n",
3020				     __FUNCTION__));
3021
3022				n = sna_damage_get_boxes(priv->gpu_damage, &box);
3023				if (n)
3024					download_boxes(sna, priv, n, box);
3025
3026				sna_damage_destroy(&priv->gpu_damage);
3027			} else if (DAMAGE_IS_ALL(priv->gpu_damage) ||
3028				   sna_damage_contains_box__no_reduce(priv->gpu_damage,
3029								      &r->extents)) {
3030
3031				DBG(("%s: region wholly inside damage\n",
3032				     __FUNCTION__));
3033
3034				assert(sna_damage_contains_box(&priv->gpu_damage, &r->extents) == PIXMAN_REGION_IN);
3035				assert(sna_damage_contains_box(&priv->cpu_damage, &r->extents) == PIXMAN_REGION_OUT);
3036
3037				download_boxes(sna, priv,
3038					       region_num_rects(r),
3039					       region_rects(r));
3040				sna_damage_subtract(&priv->gpu_damage, r);
3041			} else {
3042				RegionRec need;
3043
3044				pixman_region_init(&need);
3045				if (sna_damage_intersect(priv->gpu_damage, r, &need)) {
3046					DBG(("%s: region intersects damage\n",
3047					     __FUNCTION__));
3048
3049					download_boxes(sna, priv,
3050						       region_num_rects(&need),
3051						       region_rects(&need));
3052					sna_damage_subtract(&priv->gpu_damage, r);
3053					RegionUninit(&need);
3054				}
3055			}
3056			if (r == &want)
3057				pixman_region_fini(&want);
3058		}
3059	}
3060
3061done:
3062	if ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE) {
3063		DBG(("%s: applying cpu damage\n", __FUNCTION__));
3064		assert(!DAMAGE_IS_ALL(priv->cpu_damage));
3065		assert_pixmap_contains_box(pixmap, RegionExtents(region));
3066		sna_damage_add_to_pixmap(&priv->cpu_damage, region, pixmap);
3067		sna_damage_reduce_all(&priv->cpu_damage, pixmap);
3068		if (DAMAGE_IS_ALL(priv->cpu_damage)) {
3069			DBG(("%s: replaced entire pixmap\n", __FUNCTION__));
3070			sna_pixmap_free_gpu(sna, priv);
3071		}
3072		if (priv->flush) {
3073			assert(!priv->shm);
3074			sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
3075		}
3076	}
3077
3078already_damaged:
3079	if (dx | dy)
3080		RegionTranslate(region, -dx, -dy);
3081
3082out:
3083	if (flags & MOVE_WRITE) {
3084		assert(!DAMAGE_IS_ALL(priv->gpu_damage));
3085		priv->source_count = SOURCE_BIAS;
3086		assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
3087		assert(priv->gpu_bo || priv->gpu_damage == NULL);
3088		assert(!priv->flush || !list_is_empty(&priv->flush_list));
3089		assert(!priv->clear);
3090	}
3091	if ((flags & MOVE_ASYNC_HINT) == 0 && priv->cpu_bo) {
3092		DBG(("%s: syncing cpu bo\n", __FUNCTION__));
3093		assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
3094		kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo,
3095				       FORCE_FULL_SYNC || flags & MOVE_WRITE);
3096		assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo));
3097	}
3098skip:
3099	priv->cpu |= (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE;
3100	assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
3101	assert(pixmap->devKind);
3102	assert_pixmap_damage(pixmap);
3103	assert(has_coherent_ptr(sna, priv, flags));
3104	return true;
3105}
3106
3107bool
3108sna_drawable_move_to_cpu(DrawablePtr drawable, unsigned flags)
3109{
3110	RegionRec region;
3111	PixmapPtr pixmap;
3112	int16_t dx, dy;
3113
3114	if (drawable->type == DRAWABLE_PIXMAP)
3115		return sna_pixmap_move_to_cpu((PixmapPtr)drawable, flags);
3116
3117	pixmap = get_window_pixmap((WindowPtr)drawable);
3118	get_drawable_deltas(drawable, pixmap, &dx, &dy);
3119
3120	DBG(("%s: (%d, %d)x(%d, %d) + (%d, %d), flags=%x\n",
3121	     __FUNCTION__,
3122	     drawable->x, drawable->y,
3123	     drawable->width, drawable->height,
3124	     dx, dy, flags));
3125
3126	region.extents.x1 = drawable->x + dx;
3127	region.extents.y1 = drawable->y + dy;
3128	region.extents.x2 = region.extents.x1 + drawable->width;
3129	region.extents.y2 = region.extents.y1 + drawable->height;
3130	region.data = NULL;
3131
3132	if (region.extents.x1 < 0)
3133		region.extents.x1 = 0;
3134	if (region.extents.y1 < 0)
3135		region.extents.y1 = 0;
3136	if (region.extents.x2 > pixmap->drawable.width)
3137		region.extents.x2 = pixmap->drawable.width;
3138	if (region.extents.y2 > pixmap->drawable.height)
3139		region.extents.y2 = pixmap->drawable.height;
3140
3141	if (box_empty(&region.extents))
3142		return true;
3143
3144	return sna_drawable_move_region_to_cpu(&pixmap->drawable, &region, flags);
3145}
3146
3147pure static bool alu_overwrites(uint8_t alu)
3148{
3149	switch (alu) {
3150	case GXclear:
3151	case GXcopy:
3152	case GXcopyInverted:
3153	case GXset:
3154		return true;
3155	default:
3156		return false;
3157	}
3158}
3159
3160inline static bool drawable_gc_inplace_hint(DrawablePtr draw, GCPtr gc)
3161{
3162	if (!alu_overwrites(gc->alu))
3163		return false;
3164
3165	if (!PM_IS_SOLID(draw, gc->planemask))
3166		return false;
3167
3168	if (gc->fillStyle == FillStippled)
3169		return false;
3170
3171	return true;
3172}
3173
3174inline static unsigned
3175drawable_gc_flags(DrawablePtr draw, GCPtr gc, bool partial)
3176{
3177	assert(sna_gc(gc)->changes == 0);
3178
3179	if (gc->fillStyle == FillStippled) {
3180		DBG(("%s: read due to fill %d\n",
3181		     __FUNCTION__, gc->fillStyle));
3182		return MOVE_READ | MOVE_WRITE;
3183	}
3184
3185	if (fb_gc(gc)->and | fb_gc(gc)->bgand) {
3186		DBG(("%s: read due to rrop %d:%x\n",
3187		     __FUNCTION__, gc->alu, (unsigned)fb_gc(gc)->and));
3188		return MOVE_READ | MOVE_WRITE;
3189	}
3190
3191	DBG(("%s: try operating on drawable inplace [hint? %d]\n",
3192	     __FUNCTION__, drawable_gc_inplace_hint(draw, gc)));
3193
3194	return (partial ? MOVE_READ : 0) | MOVE_WRITE | MOVE_INPLACE_HINT;
3195}
3196
3197static inline struct sna_pixmap *
3198sna_pixmap_mark_active(struct sna *sna, struct sna_pixmap *priv)
3199{
3200	assert(priv->gpu_bo);
3201	DBG(("%s: pixmap=%ld, handle=%u\n", __FUNCTION__,
3202	     priv->pixmap->drawable.serialNumber,
3203	     priv->gpu_bo->handle));
3204	return priv;
3205}
3206
3207inline static struct sna_pixmap *
3208__sna_pixmap_for_gpu(struct sna *sna, PixmapPtr pixmap, unsigned flags)
3209{
3210	struct sna_pixmap *priv;
3211
3212	if ((flags & __MOVE_FORCE) == 0 && wedged(sna))
3213		return NULL;
3214
3215	priv = sna_pixmap(pixmap);
3216	if (priv == NULL) {
3217		DBG(("%s: not attached\n", __FUNCTION__));
3218		if ((flags & __MOVE_DRI) == 0)
3219			return NULL;
3220
3221		if (pixmap->usage_hint == -1) {
3222			DBG(("%s: not promoting SHM Pixmap for DRI\n", __FUNCTION__));
3223			return NULL;
3224		}
3225
3226		DBG(("%s: forcing the creation on the GPU\n", __FUNCTION__));
3227
3228		priv = sna_pixmap_attach(pixmap);
3229		if (priv == NULL)
3230			return NULL;
3231
3232		sna_damage_all(&priv->cpu_damage, pixmap);
3233
3234		assert(priv->gpu_bo == NULL);
3235		assert(priv->gpu_damage == NULL);
3236	}
3237
3238	return priv;
3239}
3240
3241struct sna_pixmap *
3242sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int flags)
3243{
3244	struct sna *sna = to_sna_from_pixmap(pixmap);
3245	struct sna_pixmap *priv;
3246	RegionRec i, r;
3247
3248	DBG(("%s: pixmap=%ld box=(%d, %d), (%d, %d), flags=%x\n",
3249	     __FUNCTION__, pixmap->drawable.serialNumber,
3250	     box->x1, box->y1, box->x2, box->y2, flags));
3251
3252	priv = __sna_pixmap_for_gpu(sna, pixmap, flags);
3253	if (priv == NULL)
3254		return NULL;
3255
3256	assert(box->x2 > box->x1 && box->y2 > box->y1);
3257	assert_pixmap_damage(pixmap);
3258	assert_pixmap_contains_box(pixmap, box);
3259	assert(priv->gpu_damage == NULL || priv->gpu_bo);
3260
3261	if ((flags & MOVE_READ) == 0)
3262		sna_damage_subtract_box(&priv->cpu_damage, box);
3263
3264	if (priv->move_to_gpu) {
3265		unsigned int hint;
3266
3267		DBG(("%s: applying move-to-gpu override\n", __FUNCTION__));
3268		hint = flags | MOVE_READ;
3269		if ((flags & MOVE_READ) == 0) {
3270			RegionRec region;
3271
3272			region.extents = *box;
3273			region.data = NULL;
3274			sna_pixmap_discard_shadow_damage(priv, &region);
3275			if (region_subsumes_pixmap(&region, pixmap))
3276				hint &= ~MOVE_READ;
3277		} else {
3278			if (priv->cpu_damage)
3279				hint |= MOVE_WRITE;
3280		}
3281		if (!priv->move_to_gpu(sna, priv, hint)) {
3282			DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
3283			return NULL;
3284		}
3285	}
3286
3287	if (priv->cow) {
3288		unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE);
3289
3290		if ((flags & MOVE_READ) == 0) {
3291			if (priv->gpu_damage) {
3292				r.extents = *box;
3293				r.data = NULL;
3294				if (!region_subsumes_damage(&r, priv->gpu_damage))
3295					cow |= MOVE_READ;
3296			}
3297		} else {
3298			if (priv->cpu_damage) {
3299				r.extents = *box;
3300				r.data = NULL;
3301				if (region_overlaps_damage(&r, priv->cpu_damage, 0, 0))
3302					cow |= MOVE_WRITE;
3303			}
3304		}
3305
3306		if (cow) {
3307			if (!sna_pixmap_undo_cow(sna, priv, cow))
3308				return NULL;
3309
3310			if (priv->gpu_bo == NULL)
3311				sna_damage_destroy(&priv->gpu_damage);
3312		}
3313	}
3314
3315	if (sna_damage_is_all(&priv->gpu_damage,
3316			      pixmap->drawable.width,
3317			      pixmap->drawable.height)) {
3318		assert(priv->gpu_bo);
3319		assert(priv->gpu_bo->proxy == NULL);
3320		sna_damage_destroy(&priv->cpu_damage);
3321		list_del(&priv->flush_list);
3322		goto done;
3323	}
3324
3325	if (kgem_bo_discard_cache(priv->gpu_bo, flags & (MOVE_WRITE | __MOVE_FORCE))) {
3326		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
3327		assert(DAMAGE_IS_ALL(priv->cpu_damage));
3328		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */
3329		assert(!priv->pinned);
3330		assert(!priv->mapped);
3331		sna_damage_destroy(&priv->gpu_damage);
3332		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
3333		priv->gpu_bo = NULL;
3334	}
3335
3336	sna_damage_reduce(&priv->cpu_damage);
3337	assert_pixmap_damage(pixmap);
3338
3339	if (priv->cpu_damage == NULL) {
3340		list_del(&priv->flush_list);
3341		return sna_pixmap_move_to_gpu(pixmap, MOVE_READ | flags);
3342	}
3343
3344	if (priv->gpu_bo == NULL) {
3345		assert(priv->gpu_damage == NULL);
3346
3347		if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU)
3348			sna_pixmap_alloc_gpu(sna, pixmap, priv, CREATE_INACTIVE);
3349
3350		if (priv->gpu_bo == NULL)
3351			return NULL;
3352
3353		DBG(("%s: created gpu bo\n", __FUNCTION__));
3354	}
3355
3356	if (priv->gpu_bo->proxy) {
3357		DBG(("%s: reusing cached upload\n", __FUNCTION__));
3358		assert((flags & MOVE_WRITE) == 0);
3359		assert(priv->gpu_damage == NULL);
3360		return priv;
3361	}
3362
3363	if (priv->shm) {
3364		assert(!priv->flush);
3365		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
3366	}
3367
3368	assert(priv->cpu_damage);
3369	region_set(&r, box);
3370	if (MIGRATE_ALL || region_subsumes_damage(&r, priv->cpu_damage)) {
3371		bool ok = false;
3372		int n;
3373
3374		n = sna_damage_get_boxes(priv->cpu_damage, &box);
3375		assert(n);
3376		if (use_cpu_bo_for_upload(sna, priv, 0)) {
3377			DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__));
3378			ok = sna->render.copy_boxes(sna, GXcopy,
3379						    &pixmap->drawable, priv->cpu_bo, 0, 0,
3380						    &pixmap->drawable, priv->gpu_bo, 0, 0,
3381						    box, n, 0);
3382		}
3383		if (!ok) {
3384			sna_pixmap_unmap(pixmap, priv);
3385			if (pixmap->devPrivate.ptr == NULL)
3386				return NULL;
3387
3388			assert(pixmap->devKind);
3389			if (n == 1 && !priv->pinned &&
3390			    box->x1 <= 0 && box->y1 <= 0 &&
3391			    box->x2 >= pixmap->drawable.width &&
3392			    box->y2 >= pixmap->drawable.height) {
3393				ok = sna_replace(sna, pixmap,
3394						 pixmap->devPrivate.ptr,
3395						 pixmap->devKind);
3396			} else {
3397				ok = sna_write_boxes(sna, pixmap,
3398						     priv->gpu_bo, 0, 0,
3399						     pixmap->devPrivate.ptr,
3400						     pixmap->devKind,
3401						     0, 0,
3402						     box, n);
3403			}
3404			if (!ok)
3405				return NULL;
3406		}
3407
3408		sna_damage_destroy(&priv->cpu_damage);
3409	} else if (DAMAGE_IS_ALL(priv->cpu_damage) ||
3410		   sna_damage_contains_box__no_reduce(priv->cpu_damage, box)) {
3411		bool ok = false;
3412
3413		assert(sna_damage_contains_box(&priv->gpu_damage, box) == PIXMAN_REGION_OUT);
3414		assert(sna_damage_contains_box(&priv->cpu_damage, box) == PIXMAN_REGION_IN);
3415
3416		if (use_cpu_bo_for_upload(sna, priv, 0)) {
3417			DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__));
3418			ok = sna->render.copy_boxes(sna, GXcopy,
3419						    &pixmap->drawable, priv->cpu_bo, 0, 0,
3420						    &pixmap->drawable, priv->gpu_bo, 0, 0,
3421						    box, 1, 0);
3422		}
3423		if (!ok) {
3424			sna_pixmap_unmap(pixmap, priv);
3425			if (pixmap->devPrivate.ptr != NULL) {
3426				assert(pixmap->devKind);
3427				ok = sna_write_boxes(sna, pixmap,
3428						priv->gpu_bo, 0, 0,
3429						pixmap->devPrivate.ptr,
3430						pixmap->devKind,
3431						0, 0,
3432						box, 1);
3433			}
3434		}
3435		if (!ok)
3436			return NULL;
3437
3438		sna_damage_subtract(&priv->cpu_damage, &r);
3439	} else if (sna_damage_intersect(priv->cpu_damage, &r, &i)) {
3440		int n = region_num_rects(&i);
3441		bool ok;
3442
3443		box = region_rects(&i);
3444		ok = false;
3445		if (use_cpu_bo_for_upload(sna, priv, 0)) {
3446			DBG(("%s: using CPU bo for upload to GPU, %d boxes\n", __FUNCTION__, n));
3447			ok = sna->render.copy_boxes(sna, GXcopy,
3448						    &pixmap->drawable, priv->cpu_bo, 0, 0,
3449						    &pixmap->drawable, priv->gpu_bo, 0, 0,
3450						    box, n, 0);
3451		}
3452		if (!ok) {
3453			sna_pixmap_unmap(pixmap, priv);
3454			if (pixmap->devPrivate.ptr != NULL) {
3455				assert(pixmap->devKind);
3456				ok = sna_write_boxes(sna, pixmap,
3457						priv->gpu_bo, 0, 0,
3458						pixmap->devPrivate.ptr,
3459						pixmap->devKind,
3460						0, 0,
3461						box, n);
3462			}
3463		}
3464		if (!ok)
3465			return NULL;
3466
3467		sna_damage_subtract(&priv->cpu_damage, &r);
3468		RegionUninit(&i);
3469	}
3470
3471done:
3472	if (priv->cpu_damage == NULL && priv->flush)
3473		list_del(&priv->flush_list);
3474	if (flags & MOVE_WRITE) {
3475		priv->clear = false;
3476		if (!DAMAGE_IS_ALL(priv->gpu_damage) &&
3477		    priv->cpu_damage == NULL &&
3478		    (box_covers_pixmap(pixmap, &r.extents) ||
3479		     box_inplace(pixmap, &r.extents))) {
3480			DBG(("%s: large operation on undamaged, discarding CPU shadow\n",
3481			     __FUNCTION__));
3482			assert(priv->gpu_bo);
3483			assert(priv->gpu_bo->proxy == NULL);
3484			if (sna_pixmap_free_cpu(sna, priv, priv->cpu)) {
3485				DBG(("%s: large operation on undamaged, promoting to full GPU\n",
3486				     __FUNCTION__));
3487				sna_damage_all(&priv->gpu_damage, pixmap);
3488			}
3489		}
3490		if (DAMAGE_IS_ALL(priv->gpu_damage)) {
3491			sna_pixmap_free_cpu(sna, priv, priv->cpu);
3492			sna_damage_destroy(&priv->cpu_damage);
3493			list_del(&priv->flush_list);
3494		}
3495		priv->cpu = false;
3496	}
3497
3498	assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0);
3499	return sna_pixmap_mark_active(sna, priv);
3500}
3501
3502struct kgem_bo *
3503sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box,
3504		    struct sna_damage ***damage)
3505{
3506	PixmapPtr pixmap = get_drawable_pixmap(drawable);
3507	struct sna_pixmap *priv = sna_pixmap(pixmap);
3508	struct sna *sna;
3509	RegionRec region;
3510	int16_t dx, dy;
3511	int ret;
3512
3513	DBG(("%s pixmap=%ld, box=((%d, %d), (%d, %d)), flags=%x...\n",
3514	     __FUNCTION__,
3515	     pixmap->drawable.serialNumber,
3516	     box->x1, box->y1, box->x2, box->y2,
3517	     flags));
3518
3519	assert(box->x2 > box->x1 && box->y2 > box->y1);
3520	assert(pixmap->refcnt);
3521	assert_pixmap_damage(pixmap);
3522	assert_drawable_contains_box(drawable, box);
3523
3524	if (priv == NULL) {
3525		DBG(("%s: not attached\n", __FUNCTION__));
3526		return NULL;
3527	}
3528
3529	if (priv->cow) {
3530		unsigned cow = MOVE_WRITE | MOVE_READ;
3531
3532		if (flags & IGNORE_DAMAGE) {
3533			if (priv->gpu_damage) {
3534				region.extents = *box;
3535				if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3536					region.extents.x1 += dx;
3537					region.extents.x2 += dx;
3538					region.extents.y1 += dy;
3539					region.extents.y2 += dy;
3540				}
3541				region.data = NULL;
3542				if (region_subsumes_damage(&region,
3543							   priv->gpu_damage))
3544					cow &= ~MOVE_READ;
3545			} else
3546				cow &= ~MOVE_READ;
3547		}
3548
3549		if (!sna_pixmap_undo_cow(to_sna_from_pixmap(pixmap), priv, cow))
3550			return NULL;
3551
3552		if (priv->gpu_bo == NULL)
3553			sna_damage_destroy(&priv->gpu_damage);
3554	}
3555
3556	if (kgem_bo_discard_cache(priv->gpu_bo, true)) {
3557		DBG(("%s: cached upload proxy, discard and revert to GPU\n", __FUNCTION__));
3558		assert(DAMAGE_IS_ALL(priv->cpu_damage));
3559		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */
3560		assert(!priv->pinned);
3561		assert(!priv->mapped);
3562		sna_damage_destroy(&priv->gpu_damage);
3563		kgem_bo_destroy(&to_sna_from_pixmap(pixmap)->kgem,
3564				priv->gpu_bo);
3565		priv->gpu_bo = NULL;
3566		goto use_cpu_bo;
3567	}
3568
3569	if (priv->flush) {
3570		DBG(("%s: exported target, set PREFER_GPU\n", __FUNCTION__));
3571		flags |= PREFER_GPU;
3572	}
3573	if (priv->shm) {
3574		DBG(("%s: shm target, discard PREFER_GPU\n", __FUNCTION__));
3575		flags &= ~PREFER_GPU;
3576	}
3577	if (priv->pinned) {
3578		DBG(("%s: pinned, never REPLACES\n", __FUNCTION__));
3579		flags &= ~REPLACES;
3580	}
3581	if (priv->cpu && (flags & (FORCE_GPU | IGNORE_DAMAGE)) == 0) {
3582		DBG(("%s: last on cpu and needs damage, discard PREFER_GPU\n", __FUNCTION__));
3583		flags &= ~PREFER_GPU;
3584	}
3585
3586	if ((flags & (PREFER_GPU | IGNORE_DAMAGE)) == IGNORE_DAMAGE) {
3587		if (priv->gpu_bo && (box_covers_pixmap(pixmap, box) || box_inplace(pixmap, box))) {
3588			DBG(("%s: not reading damage and large, set PREFER_GPU\n", __FUNCTION__));
3589			flags |= PREFER_GPU;
3590		}
3591	}
3592
3593	DBG(("%s: flush=%d, shm=%d, cpu=%d => flags=%x\n",
3594	     __FUNCTION__, priv->flush, priv->shm, priv->cpu, flags));
3595
3596	if ((flags & PREFER_GPU) == 0 &&
3597	    (flags & (REPLACES | IGNORE_DAMAGE) || !priv->gpu_damage || !kgem_bo_is_busy(priv->gpu_bo))) {
3598		DBG(("%s: try cpu as GPU bo is idle\n", __FUNCTION__));
3599		goto use_cpu_bo;
3600	}
3601
3602	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
3603		DBG(("%s: use GPU fast path (all-damaged)\n", __FUNCTION__));
3604		assert(priv->cpu_damage == NULL);
3605		assert(priv->gpu_bo);
3606		assert(priv->gpu_bo->proxy == NULL);
3607		goto use_gpu_bo;
3608	}
3609
3610	if (DAMAGE_IS_ALL(priv->cpu_damage)) {
3611		assert(priv->gpu_damage == NULL);
3612		if ((flags & FORCE_GPU) == 0 || priv->cpu_bo) {
3613			DBG(("%s: use CPU fast path (all-damaged), and not forced-gpu\n",
3614			     __FUNCTION__));
3615			goto use_cpu_bo;
3616		}
3617	}
3618
3619	DBG(("%s: gpu? %d, damaged? %d; cpu? %d, damaged? %d\n", __FUNCTION__,
3620	     priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->gpu_damage != NULL,
3621	     priv->cpu_bo ? priv->cpu_bo->handle : 0, priv->cpu_damage != NULL));
3622	if (priv->gpu_bo == NULL) {
3623		unsigned int move;
3624
3625		if ((flags & FORCE_GPU) == 0 &&
3626		    (priv->create & KGEM_CAN_CREATE_GPU) == 0) {
3627			DBG(("%s: untiled, will not force allocation\n",
3628			     __FUNCTION__));
3629			goto use_cpu_bo;
3630		}
3631
3632		if ((flags & IGNORE_DAMAGE) == 0) {
3633			if (priv->cpu_bo) {
3634				if (to_sna_from_pixmap(pixmap)->kgem.can_blt_cpu) {
3635					if (kgem_bo_is_busy(priv->cpu_bo)) {
3636						DBG(("%s: already using CPU bo, will not force allocation\n",
3637						     __FUNCTION__));
3638						goto use_cpu_bo;
3639					}
3640
3641					if ((flags & RENDER_GPU) == 0) {
3642						DBG(("%s: prefer cpu", __FUNCTION__));
3643						goto use_cpu_bo;
3644					}
3645				} else {
3646					if (kgem_bo_is_busy(priv->cpu_bo)) {
3647						DBG(("%s: CPU bo active, must force allocation\n",
3648						     __FUNCTION__));
3649						goto create_gpu_bo;
3650					}
3651				}
3652			}
3653
3654			if ((flags & FORCE_GPU) == 0 && priv->cpu_damage) {
3655				if ((flags & PREFER_GPU) == 0) {
3656					DBG(("%s: already damaged and prefer cpu",
3657					     __FUNCTION__));
3658					goto use_cpu_bo;
3659				}
3660
3661				if (!box_inplace(pixmap, box)) {
3662					DBG(("%s: damaged with a small operation, will not force allocation\n",
3663					     __FUNCTION__));
3664					goto use_cpu_bo;
3665				}
3666			}
3667		} else if (priv->cpu_damage) {
3668			region.extents = *box;
3669			if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3670				region.extents.x1 += dx;
3671				region.extents.x2 += dx;
3672				region.extents.y1 += dy;
3673				region.extents.y2 += dy;
3674			}
3675			region.data = NULL;
3676
3677			sna_damage_subtract(&priv->cpu_damage, &region);
3678			if (priv->cpu_damage == NULL) {
3679				list_del(&priv->flush_list);
3680				priv->cpu = false;
3681			}
3682		}
3683
3684create_gpu_bo:
3685		move = MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT;
3686		if (flags & FORCE_GPU)
3687			move |= __MOVE_FORCE;
3688		if (!sna_pixmap_move_to_gpu(pixmap, move))
3689			goto use_cpu_bo;
3690
3691		DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__));
3692		goto done;
3693	}
3694
3695
3696	region.extents = *box;
3697	if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3698		region.extents.x1 += dx;
3699		region.extents.x2 += dx;
3700		region.extents.y1 += dy;
3701		region.extents.y2 += dy;
3702	}
3703	region.data = NULL;
3704
3705	DBG(("%s extents (%d, %d), (%d, %d)\n", __FUNCTION__,
3706	     region.extents.x1, region.extents.y1,
3707	     region.extents.x2, region.extents.y2));
3708
3709	if (priv->gpu_damage) {
3710		assert(priv->gpu_bo);
3711		if (!priv->cpu_damage || flags & IGNORE_DAMAGE) {
3712			if (flags & REPLACES || box_covers_pixmap(pixmap, &region.extents)) {
3713				unsigned int move;
3714
3715				if (flags & IGNORE_DAMAGE)
3716					move = MOVE_WRITE;
3717				else
3718					move = MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT;
3719
3720				if (sna_pixmap_move_to_gpu(pixmap, move))
3721					goto use_gpu_bo;
3722			}
3723
3724			if (DAMAGE_IS_ALL(priv->gpu_damage) ||
3725			    sna_damage_contains_box__no_reduce(priv->gpu_damage,
3726							       &region.extents)) {
3727				DBG(("%s: region wholly contained within GPU damage\n",
3728				     __FUNCTION__));
3729				assert(sna_damage_contains_box(&priv->gpu_damage, &region.extents) == PIXMAN_REGION_IN);
3730				assert(sna_damage_contains_box(&priv->cpu_damage, &region.extents) == PIXMAN_REGION_OUT);
3731				goto use_gpu_bo;
3732			} else {
3733				DBG(("%s: partial GPU damage with no CPU damage, continuing to use GPU\n",
3734				     __FUNCTION__));
3735				goto move_to_gpu;
3736			}
3737		}
3738
3739		ret = sna_damage_contains_box(&priv->gpu_damage, &region.extents);
3740		if (ret == PIXMAN_REGION_IN) {
3741			DBG(("%s: region wholly contained within GPU damage\n",
3742			     __FUNCTION__));
3743			goto use_gpu_bo;
3744		}
3745
3746		if (ret != PIXMAN_REGION_OUT) {
3747			DBG(("%s: region partially contained within GPU damage\n",
3748			     __FUNCTION__));
3749			goto move_to_gpu;
3750		}
3751	}
3752
3753	if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_damage) {
3754		ret = sna_damage_contains_box(&priv->cpu_damage, &region.extents);
3755		if (ret == PIXMAN_REGION_IN) {
3756			DBG(("%s: region wholly contained within CPU damage\n",
3757			     __FUNCTION__));
3758			goto use_cpu_bo;
3759		}
3760
3761		if (box_inplace(pixmap, box)) {
3762			DBG(("%s: forcing inplace\n", __FUNCTION__));
3763			goto move_to_gpu;
3764		}
3765
3766		if (ret != PIXMAN_REGION_OUT) {
3767			DBG(("%s: region partially contained within CPU damage\n",
3768			     __FUNCTION__));
3769			goto use_cpu_bo;
3770		}
3771	}
3772
3773move_to_gpu:
3774	if (!sna_pixmap_move_area_to_gpu(pixmap, &region.extents,
3775					 flags & IGNORE_DAMAGE ? MOVE_WRITE : MOVE_READ | MOVE_WRITE)) {
3776		DBG(("%s: failed to move-to-gpu, fallback\n", __FUNCTION__));
3777		assert(priv->gpu_bo == NULL);
3778		goto use_cpu_bo;
3779	}
3780
3781done:
3782	assert(priv->move_to_gpu == NULL);
3783	assert(priv->gpu_bo != NULL);
3784	assert(priv->gpu_bo->refcnt);
3785	if (sna_damage_is_all(&priv->gpu_damage,
3786			      pixmap->drawable.width,
3787			      pixmap->drawable.height)) {
3788		sna_damage_destroy(&priv->cpu_damage);
3789		list_del(&priv->flush_list);
3790		*damage = NULL;
3791	} else
3792		*damage = &priv->gpu_damage;
3793
3794	DBG(("%s: using GPU bo with damage? %d\n",
3795	     __FUNCTION__, *damage != NULL));
3796	assert(*damage == NULL || !DAMAGE_IS_ALL(*damage));
3797	assert(priv->gpu_bo->proxy == NULL);
3798	assert(priv->clear == false);
3799	assert(priv->cpu == false);
3800	assert(!priv->shm);
3801	return priv->gpu_bo;
3802
3803use_gpu_bo:
3804	if (priv->move_to_gpu) {
3805		unsigned hint = MOVE_READ | MOVE_WRITE;
3806
3807		sna = to_sna_from_pixmap(pixmap);
3808
3809		DBG(("%s: applying move-to-gpu override\n", __FUNCTION__));
3810		if (flags & IGNORE_DAMAGE) {
3811			region.extents = *box;
3812			region.data = NULL;
3813			if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3814				region.extents.x1 += dx;
3815				region.extents.x2 += dx;
3816				region.extents.y1 += dy;
3817				region.extents.y2 += dy;
3818			}
3819			sna_pixmap_discard_shadow_damage(priv, &region);
3820			if (region_subsumes_pixmap(&region, pixmap)) {
3821				DBG(("%s: discarding move-to-gpu READ for subsumed pixmap\n", __FUNCTION__));
3822				hint = MOVE_WRITE;
3823			}
3824		}
3825
3826		if (!priv->move_to_gpu(sna, priv, hint)) {
3827			DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
3828			goto use_cpu_bo;
3829		}
3830	}
3831
3832	if (priv->shm) {
3833		assert(!priv->flush);
3834		list_move(&priv->flush_list, &sna->flush_pixmaps);
3835	}
3836
3837	DBG(("%s: using whole GPU bo\n", __FUNCTION__));
3838	assert(priv->gpu_bo != NULL);
3839	assert(priv->gpu_bo->refcnt);
3840	assert(priv->gpu_bo->proxy == NULL);
3841	assert(priv->gpu_damage);
3842	priv->cpu = false;
3843	priv->clear = false;
3844	*damage = NULL;
3845	return priv->gpu_bo;
3846
3847use_cpu_bo:
3848	if (!USE_CPU_BO || priv->cpu_bo == NULL) {
3849		if ((flags & FORCE_GPU) == 0) {
3850			DBG(("%s: no CPU bo, and GPU not forced\n", __FUNCTION__));
3851			return NULL;
3852		}
3853
3854		flags &= ~FORCE_GPU;
3855
3856		region.extents = *box;
3857		if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3858			region.extents.x1 += dx;
3859			region.extents.x2 += dx;
3860			region.extents.y1 += dy;
3861			region.extents.y2 += dy;
3862		}
3863		region.data = NULL;
3864
3865		if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, &region,
3866						     (flags & IGNORE_DAMAGE ? 0 : MOVE_READ) | MOVE_WRITE | MOVE_ASYNC_HINT) ||
3867		    priv->cpu_bo == NULL) {
3868			DBG(("%s: did not create CPU bo\n", __FUNCTION__));
3869cpu_fail:
3870			if (priv->gpu_bo)
3871				goto move_to_gpu;
3872
3873			return NULL;
3874		}
3875	}
3876
3877	assert(priv->cpu_bo->refcnt);
3878
3879	sna = to_sna_from_pixmap(pixmap);
3880	if ((flags & FORCE_GPU) == 0 &&
3881	    !__kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
3882		DBG(("%s: has CPU bo, but is idle and acceleration not forced\n",
3883		     __FUNCTION__));
3884		return NULL;
3885	}
3886
3887	region.extents = *box;
3888	if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3889		region.extents.x1 += dx;
3890		region.extents.x2 += dx;
3891		region.extents.y1 += dy;
3892		region.extents.y2 += dy;
3893	}
3894	region.data = NULL;
3895
3896	if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) {
3897		DBG(("%s: both CPU and GPU are busy, prefer to use the GPU\n",
3898		     __FUNCTION__));
3899		goto move_to_gpu;
3900	}
3901
3902	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
3903
3904	if (flags & RENDER_GPU) {
3905		flags &= ~RENDER_GPU;
3906
3907		if ((flags & IGNORE_DAMAGE) == 0 && priv->gpu_damage) {
3908			DBG(("%s: prefer to use GPU bo for rendering whilst reading from GPU damage\n", __FUNCTION__));
3909
3910prefer_gpu_bo:
3911			if (priv->gpu_bo == NULL) {
3912				if ((flags & FORCE_GPU) == 0) {
3913					DBG(("%s: untiled, will not force allocation\n",
3914					     __FUNCTION__));
3915					return NULL;
3916				}
3917
3918				if (flags & IGNORE_DAMAGE) {
3919					sna_damage_subtract(&priv->cpu_damage, &region);
3920					if (priv->cpu_damage == NULL) {
3921						list_del(&priv->flush_list);
3922						priv->cpu = false;
3923					}
3924				}
3925
3926				if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE))
3927					return NULL;
3928
3929				sna_damage_all(&priv->gpu_damage, pixmap);
3930
3931				DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__));
3932				goto done;
3933			}
3934			goto move_to_gpu;
3935		}
3936
3937		if ((priv->cpu_damage == NULL || flags & IGNORE_DAMAGE)) {
3938			if (priv->gpu_bo && priv->gpu_bo->tiling) {
3939				DBG(("%s: prefer to use GPU bo for rendering large pixmaps\n", __FUNCTION__));
3940				goto prefer_gpu_bo;
3941			}
3942
3943			if (priv->cpu_bo->pitch >= 4096) {
3944				DBG(("%s: prefer to use GPU bo for rendering wide pixmaps\n", __FUNCTION__));
3945				goto prefer_gpu_bo;
3946			}
3947		}
3948
3949		if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_bo->snoop) {
3950			DBG(("%s: prefer to use GPU bo for reading from snooped target bo\n", __FUNCTION__));
3951			goto prefer_gpu_bo;
3952		}
3953
3954		if (!sna->kgem.can_blt_cpu) {
3955			DBG(("%s: can't render to CPU bo, try to use GPU bo\n", __FUNCTION__));
3956			goto prefer_gpu_bo;
3957		}
3958	}
3959
3960	if (!sna->kgem.can_blt_cpu)
3961		goto cpu_fail;
3962
3963	if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, &region,
3964					     (flags & IGNORE_DAMAGE ? 0 : MOVE_READ) | MOVE_WRITE | MOVE_ASYNC_HINT)) {
3965		DBG(("%s: failed to move-to-cpu, fallback\n", __FUNCTION__));
3966		goto cpu_fail;
3967	}
3968
3969	if (priv->shm) {
3970		assert(!priv->flush);
3971		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
3972
3973		/* As we may have flushed and retired,, recheck for busy bo */
3974		if ((flags & FORCE_GPU) == 0 && !kgem_bo_is_busy(priv->cpu_bo))
3975			return NULL;
3976	}
3977	if (priv->flush) {
3978		assert(!priv->shm);
3979		sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
3980	}
3981
3982	if (sna_damage_is_all(&priv->cpu_damage,
3983			      pixmap->drawable.width,
3984			      pixmap->drawable.height)) {
3985		sna_damage_destroy(&priv->gpu_damage);
3986		*damage = NULL;
3987	} else {
3988		assert(!DAMAGE_IS_ALL(priv->cpu_damage));
3989		if (priv->cpu_damage &&
3990		    sna_damage_contains_box__no_reduce(priv->cpu_damage,
3991						       &region.extents)) {
3992			assert(sna_damage_contains_box(&priv->gpu_damage, &region.extents) == PIXMAN_REGION_OUT);
3993			assert(sna_damage_contains_box(&priv->cpu_damage, &region.extents) == PIXMAN_REGION_IN);
3994			*damage = NULL;
3995		} else
3996			*damage = &priv->cpu_damage;
3997	}
3998
3999	DBG(("%s: using CPU bo with damage? %d\n",
4000	     __FUNCTION__, *damage != NULL));
4001	assert(damage == NULL || !DAMAGE_IS_ALL(*damage));
4002	assert(priv->clear == false);
4003	priv->cpu = false;
4004	return priv->cpu_bo;
4005}
4006
4007PixmapPtr
4008sna_pixmap_create_upload(ScreenPtr screen,
4009			 int width, int height, int depth,
4010			 unsigned flags)
4011{
4012	struct sna *sna = to_sna_from_screen(screen);
4013	PixmapPtr pixmap;
4014	struct sna_pixmap *priv;
4015	void *ptr;
4016
4017	DBG(("%s(%d, %d, %d, flags=%x)\n", __FUNCTION__,
4018	     width, height, depth, flags));
4019	assert(width);
4020	assert(height);
4021
4022	if (depth == 1)
4023		return create_pixmap(sna, screen, width, height, depth,
4024				     CREATE_PIXMAP_USAGE_SCRATCH);
4025
4026	pixmap = create_pixmap_hdr(sna, screen,
4027				   width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH,
4028				   &priv);
4029	if (!pixmap)
4030		return NullPixmap;
4031
4032	priv->gpu_bo = kgem_create_buffer_2d(&sna->kgem,
4033					     width, height,
4034					     pixmap->drawable.bitsPerPixel,
4035					     flags, &ptr);
4036	if (!priv->gpu_bo) {
4037		free(priv);
4038		FreePixmap(pixmap);
4039		return NullPixmap;
4040	}
4041
4042	/* Marking both the shadow and the GPU bo is a little dubious,
4043	 * but will work so long as we always check before doing the
4044	 * transfer.
4045	 */
4046	sna_damage_all(&priv->gpu_damage, pixmap);
4047	sna_damage_all(&priv->cpu_damage, pixmap);
4048
4049	pixmap->devKind = priv->gpu_bo->pitch;
4050	pixmap->devPrivate.ptr = ptr;
4051	priv->ptr = MAKE_STATIC_PTR(ptr);
4052	priv->stride = priv->gpu_bo->pitch;
4053	priv->create = 0;
4054
4055	pixmap->usage_hint = 0;
4056	if (!kgem_buffer_is_inplace(priv->gpu_bo))
4057		pixmap->usage_hint = 1;
4058
4059	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
4060	     __FUNCTION__,
4061	     pixmap->drawable.serialNumber,
4062	     pixmap->drawable.width,
4063	     pixmap->drawable.height,
4064	     pixmap->usage_hint));
4065	return pixmap;
4066}
4067
4068static bool can_convert_to_gpu(struct sna_pixmap *priv, unsigned flags)
4069{
4070	assert(priv->gpu_bo == NULL);
4071
4072	if (priv->cpu_bo == NULL)
4073		return false;
4074
4075	if (priv->shm)
4076		return false;
4077
4078	/* Linear scanout have a restriction that their pitch must be
4079	 * 64 byte aligned. Force the creation of a proper GPU bo if
4080	 * this CPU bo is not suitable for scanout.
4081	 */
4082	if (priv->pixmap->usage_hint == SNA_CREATE_FB || flags & __MOVE_SCANOUT)
4083		if (priv->cpu_bo->pitch & 63)
4084			return false;
4085
4086	if (flags & __MOVE_PRIME)
4087		if (priv->cpu_bo->pitch & 255)
4088			return false;
4089
4090	return true;
4091}
4092
4093struct sna_pixmap *
4094sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
4095{
4096	struct sna *sna = to_sna_from_pixmap(pixmap);
4097	struct sna_pixmap *priv;
4098	const BoxRec *box;
4099	int n;
4100
4101	DBG(("%s(pixmap=%ld, usage=%d), flags=%x\n",
4102	     __FUNCTION__,
4103	     pixmap->drawable.serialNumber,
4104	     pixmap->usage_hint,
4105	     flags));
4106
4107	priv = __sna_pixmap_for_gpu(sna, pixmap, flags);
4108	if (priv == NULL)
4109		return NULL;
4110
4111	assert_pixmap_damage(pixmap);
4112
4113	if (priv->move_to_gpu &&
4114	    !priv->move_to_gpu(sna, priv, flags | ((priv->cpu_damage && (flags & MOVE_READ)) ? MOVE_WRITE : 0))) {
4115		DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
4116		return NULL;
4117	}
4118
4119	if ((flags & MOVE_READ) == 0 && UNDO)
4120		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
4121
4122	if (priv->cow) {
4123		unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE);
4124		if (flags & MOVE_READ && priv->cpu_damage)
4125			cow |= MOVE_WRITE;
4126		if (cow) {
4127			if (!sna_pixmap_undo_cow(sna, priv, cow))
4128				return NULL;
4129
4130			if (priv->gpu_bo == NULL)
4131				sna_damage_destroy(&priv->gpu_damage);
4132		}
4133	}
4134
4135	if (sna_damage_is_all(&priv->gpu_damage,
4136			      pixmap->drawable.width,
4137			      pixmap->drawable.height)) {
4138		DBG(("%s: already all-damaged\n", __FUNCTION__));
4139		assert(DAMAGE_IS_ALL(priv->gpu_damage));
4140		assert(priv->gpu_bo);
4141		assert(priv->gpu_bo->proxy == NULL);
4142		assert_pixmap_map(pixmap, priv);
4143		sna_damage_destroy(&priv->cpu_damage);
4144		list_del(&priv->flush_list);
4145		goto active;
4146	}
4147
4148	if ((flags & MOVE_READ) == 0)
4149		sna_damage_destroy(&priv->cpu_damage);
4150
4151	sna_damage_reduce(&priv->cpu_damage);
4152	assert_pixmap_damage(pixmap);
4153	DBG(("%s: CPU damage? %d\n", __FUNCTION__, priv->cpu_damage != NULL));
4154	if (priv->gpu_bo == NULL ||
4155	    kgem_bo_discard_cache(priv->gpu_bo, flags & (MOVE_WRITE | __MOVE_FORCE))) {
4156		struct kgem_bo *proxy;
4157
4158		proxy = priv->gpu_bo;
4159		priv->gpu_bo = NULL;
4160
4161		DBG(("%s: creating GPU bo (%dx%d@%d), create=%x\n",
4162		     __FUNCTION__,
4163		     pixmap->drawable.width,
4164		     pixmap->drawable.height,
4165		     pixmap->drawable.bitsPerPixel,
4166		     priv->create));
4167		assert(!priv->mapped);
4168		assert(list_is_empty(&priv->flush_list));
4169
4170		if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU) {
4171			bool is_linear;
4172
4173			assert(pixmap->drawable.width > 0);
4174			assert(pixmap->drawable.height > 0);
4175			assert(pixmap->drawable.bitsPerPixel >= 8);
4176
4177			if (flags & __MOVE_PRIME) {
4178				assert((flags & __MOVE_TILED) == 0);
4179				is_linear = true;
4180			} else {
4181				is_linear = sna_pixmap_default_tiling(sna, pixmap) == I915_TILING_NONE;
4182				if (is_linear && flags & __MOVE_TILED) {
4183					DBG(("%s: not creating linear GPU bo\n",
4184					     __FUNCTION__));
4185					return NULL;
4186				}
4187			}
4188
4189			if (is_linear &&
4190			    can_convert_to_gpu(priv, flags) &&
4191			    kgem_bo_convert_to_gpu(&sna->kgem, priv->cpu_bo, flags)) {
4192				assert(!priv->mapped);
4193				assert(!IS_STATIC_PTR(priv->ptr));
4194#ifdef DEBUG_MEMORY
4195				sna->debug_memory.cpu_bo_allocs--;
4196				sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
4197#endif
4198				priv->gpu_bo = priv->cpu_bo;
4199				priv->cpu_bo = NULL;
4200				priv->ptr = NULL;
4201				pixmap->devPrivate.ptr = NULL;
4202				sna_damage_all(&priv->gpu_damage, pixmap);
4203				sna_damage_destroy(&priv->cpu_damage);
4204			} else {
4205				unsigned create = 0;
4206				if (flags & MOVE_INPLACE_HINT || (priv->cpu_damage && priv->cpu_bo == NULL))
4207					create = CREATE_GTT_MAP | CREATE_INACTIVE;
4208				if (flags & __MOVE_PRIME)
4209					create |= CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT;
4210
4211				sna_pixmap_alloc_gpu(sna, pixmap, priv, create);
4212			}
4213		}
4214
4215		if (priv->gpu_bo == NULL) {
4216			DBG(("%s: not creating GPU bo\n", __FUNCTION__));
4217			assert(priv->gpu_damage == NULL);
4218			priv->gpu_bo = proxy;
4219			if (proxy)
4220				sna_damage_all(&priv->cpu_damage, pixmap);
4221			return NULL;
4222		}
4223
4224		if (proxy) {
4225			DBG(("%s: promoting upload proxy handle=%d to GPU\n", __FUNCTION__, proxy->handle));
4226
4227			if (priv->cpu_damage &&
4228			    sna->render.copy_boxes(sna, GXcopy,
4229						   &pixmap->drawable, proxy, 0, 0,
4230						   &pixmap->drawable, priv->gpu_bo, 0, 0,
4231						   region_rects(DAMAGE_REGION(priv->cpu_damage)),
4232						   region_num_rects(DAMAGE_REGION(priv->cpu_damage)),
4233						   0))
4234				sna_damage_destroy(&priv->cpu_damage);
4235
4236			kgem_bo_destroy(&sna->kgem, proxy);
4237		}
4238
4239		if (flags & MOVE_WRITE && priv->cpu_damage == NULL) {
4240			/* Presume that we will only ever write to the GPU
4241			 * bo. Readbacks are expensive but fairly constant
4242			 * in cost for all sizes i.e. it is the act of
4243			 * synchronisation that takes the most time. This is
4244			 * mitigated by avoiding fallbacks in the first place.
4245			 */
4246			assert(priv->gpu_bo);
4247			assert(priv->gpu_bo->proxy == NULL);
4248			sna_damage_all(&priv->gpu_damage, pixmap);
4249			DBG(("%s: marking as all-damaged for GPU\n",
4250			     __FUNCTION__));
4251			goto active;
4252		}
4253	}
4254
4255	if (priv->gpu_bo->proxy) {
4256		DBG(("%s: reusing cached upload\n", __FUNCTION__));
4257		assert((flags & MOVE_WRITE) == 0);
4258		assert(priv->gpu_damage == NULL);
4259		return priv;
4260	}
4261
4262	if (priv->cpu_damage == NULL)
4263		goto done;
4264
4265	if (DAMAGE_IS_ALL(priv->cpu_damage) && priv->cpu_bo &&
4266	    !priv->pinned && !priv->shm &&
4267	    priv->gpu_bo->tiling == I915_TILING_NONE &&
4268	    kgem_bo_convert_to_gpu(&sna->kgem, priv->cpu_bo, flags)) {
4269		assert(!priv->mapped);
4270		assert(!IS_STATIC_PTR(priv->ptr));
4271#ifdef DEBUG_MEMORY
4272		sna->debug_memory.cpu_bo_allocs--;
4273		sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
4274#endif
4275		sna_pixmap_free_gpu(sna, priv);
4276		priv->gpu_bo = priv->cpu_bo;
4277		priv->cpu_bo = NULL;
4278		priv->ptr = NULL;
4279		pixmap->devPrivate.ptr = NULL;
4280		sna_damage_all(&priv->gpu_damage, pixmap);
4281		sna_damage_destroy(&priv->cpu_damage);
4282		goto done;
4283	}
4284
4285	if (priv->shm) {
4286		assert(!priv->flush);
4287		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
4288	}
4289
4290	n = sna_damage_get_boxes(priv->cpu_damage, &box);
4291	assert(n);
4292	if (n) {
4293		bool ok;
4294
4295		assert_pixmap_contains_damage(pixmap, priv->cpu_damage);
4296		DBG(("%s: uploading %d damage boxes\n", __FUNCTION__, n));
4297
4298		ok = false;
4299		if (use_cpu_bo_for_upload(sna, priv, flags)) {
4300			DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__));
4301			ok = sna->render.copy_boxes(sna, GXcopy,
4302						    &pixmap->drawable, priv->cpu_bo, 0, 0,
4303						    &pixmap->drawable, priv->gpu_bo, 0, 0,
4304						    box, n, 0);
4305		}
4306		if (!ok) {
4307			sna_pixmap_unmap(pixmap, priv);
4308			if (pixmap->devPrivate.ptr == NULL)
4309				return NULL;
4310
4311			assert(pixmap->devKind);
4312			if (n == 1 && !priv->pinned &&
4313			    (box->x2 - box->x1) >= pixmap->drawable.width &&
4314			    (box->y2 - box->y1) >= pixmap->drawable.height) {
4315				ok = sna_replace(sna, pixmap,
4316						 pixmap->devPrivate.ptr,
4317						 pixmap->devKind);
4318			} else {
4319				ok = sna_write_boxes(sna, pixmap,
4320						     priv->gpu_bo, 0, 0,
4321						     pixmap->devPrivate.ptr,
4322						     pixmap->devKind,
4323						     0, 0,
4324						     box, n);
4325			}
4326			if (!ok)
4327				return NULL;
4328		}
4329	}
4330
4331	__sna_damage_destroy(DAMAGE_PTR(priv->cpu_damage));
4332	priv->cpu_damage = NULL;
4333
4334	/* For large bo, try to keep only a single copy around */
4335	if (priv->create & KGEM_CAN_CREATE_LARGE || flags & MOVE_SOURCE_HINT) {
4336		DBG(("%s: disposing of system copy for large/source\n",
4337		     __FUNCTION__));
4338		assert(!priv->shm);
4339		assert(priv->gpu_bo);
4340		assert(priv->gpu_bo->proxy == NULL);
4341		sna_damage_all(&priv->gpu_damage, pixmap);
4342		sna_pixmap_free_cpu(sna, priv,
4343				    (priv->create & KGEM_CAN_CREATE_LARGE) ? false : priv->cpu);
4344	}
4345done:
4346	list_del(&priv->flush_list);
4347
4348	sna_damage_reduce_all(&priv->gpu_damage, pixmap);
4349	if (DAMAGE_IS_ALL(priv->gpu_damage))
4350		sna_pixmap_free_cpu(sna, priv, priv->cpu);
4351
4352active:
4353	if (flags & MOVE_WRITE) {
4354		priv->clear = false;
4355		priv->cpu = false;
4356	}
4357	assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0);
4358	return sna_pixmap_mark_active(sna, priv);
4359}
4360
4361static bool must_check sna_validate_pixmap(DrawablePtr draw, PixmapPtr pixmap)
4362{
4363	DBG(("%s: target bpp=%d, source bpp=%d\n",
4364	     __FUNCTION__, draw->bitsPerPixel, pixmap->drawable.bitsPerPixel));
4365
4366	if (draw->bitsPerPixel == pixmap->drawable.bitsPerPixel &&
4367	    FbEvenTile(pixmap->drawable.width *
4368		       pixmap->drawable.bitsPerPixel)) {
4369		DBG(("%s: flushing pixmap\n", __FUNCTION__));
4370		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
4371			return false;
4372
4373		fbPadPixmap(pixmap);
4374	}
4375
4376	return true;
4377}
4378
4379static bool must_check sna_gc_move_to_cpu(GCPtr gc,
4380					  DrawablePtr drawable,
4381					  RegionPtr region)
4382{
4383	struct sna_gc *sgc = sna_gc(gc);
4384	long changes = sgc->changes;
4385
4386	DBG(("%s(%p) changes=%lx\n", __FUNCTION__, gc, changes));
4387	assert(drawable);
4388	assert(region);
4389
4390	assert(gc->ops == (GCOps *)&sna_gc_ops);
4391	gc->ops = (GCOps *)&sna_gc_ops__cpu;
4392
4393	assert(gc->funcs);
4394	sgc->old_funcs = gc->funcs;
4395	gc->funcs = (GCFuncs *)&sna_gc_funcs__cpu;
4396
4397	assert(gc->pCompositeClip);
4398	sgc->priv = gc->pCompositeClip;
4399	gc->pCompositeClip = region;
4400
4401#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0)
4402	if (gc->clientClipType == CT_PIXMAP) {
4403		PixmapPtr clip = gc->clientClip;
4404		gc->clientClip = region_from_bitmap(gc->pScreen, clip);
4405		gc->pScreen->DestroyPixmap(clip);
4406		gc->clientClipType = gc->clientClip ? CT_REGION : CT_NONE;
4407		changes |= GCClipMask;
4408	} else
4409		changes &= ~GCClipMask;
4410#else
4411	changes &= ~GCClipMask;
4412#endif
4413
4414	if (changes || drawable->serialNumber != (sgc->serial & DRAWABLE_SERIAL_BITS)) {
4415		long tmp = gc->serialNumber;
4416		gc->serialNumber = sgc->serial;
4417
4418		if (fb_gc(gc)->bpp != drawable->bitsPerPixel) {
4419			changes |= GCStipple | GCForeground | GCBackground | GCPlaneMask;
4420			fb_gc(gc)->bpp = drawable->bitsPerPixel;
4421		}
4422
4423		if (changes & GCTile && !gc->tileIsPixel) {
4424			DBG(("%s: flushing tile pixmap\n", __FUNCTION__));
4425			if (!sna_validate_pixmap(drawable, gc->tile.pixmap))
4426				return false;
4427		}
4428
4429		if (changes & GCStipple && gc->stipple) {
4430			DBG(("%s: flushing stipple pixmap\n", __FUNCTION__));
4431			if (!sna_validate_pixmap(drawable, gc->stipple))
4432				return false;
4433		}
4434
4435		fbValidateGC(gc, changes, drawable);
4436		gc->serialNumber = tmp;
4437	}
4438	sgc->changes = 0;
4439
4440	switch (gc->fillStyle) {
4441	case FillTiled:
4442		DBG(("%s: moving tile to cpu\n", __FUNCTION__));
4443		return sna_drawable_move_to_cpu(&gc->tile.pixmap->drawable, MOVE_READ);
4444	case FillStippled:
4445	case FillOpaqueStippled:
4446		DBG(("%s: moving stipple to cpu\n", __FUNCTION__));
4447		return sna_drawable_move_to_cpu(&gc->stipple->drawable, MOVE_READ);
4448	default:
4449		return true;
4450	}
4451}
4452
4453static void sna_gc_move_to_gpu(GCPtr gc)
4454{
4455	DBG(("%s(%p)\n", __FUNCTION__, gc));
4456
4457	assert(gc->ops == (GCOps *)&sna_gc_ops__cpu);
4458	assert(gc->funcs == (GCFuncs *)&sna_gc_funcs__cpu);
4459
4460	gc->ops = (GCOps *)&sna_gc_ops;
4461	gc->funcs = (GCFuncs *)sna_gc(gc)->old_funcs;
4462	assert(gc->funcs);
4463	gc->pCompositeClip = sna_gc(gc)->priv;
4464	assert(gc->pCompositeClip);
4465}
4466
4467static inline bool clip_box(BoxPtr box, GCPtr gc)
4468{
4469	const BoxRec *clip;
4470	bool clipped;
4471
4472	assert(gc->pCompositeClip);
4473	clip = &gc->pCompositeClip->extents;
4474
4475	clipped = !region_is_singular(gc->pCompositeClip);
4476	if (box->x1 < clip->x1)
4477		box->x1 = clip->x1, clipped = true;
4478	if (box->x2 > clip->x2)
4479		box->x2 = clip->x2, clipped = true;
4480
4481	if (box->y1 < clip->y1)
4482		box->y1 = clip->y1, clipped = true;
4483	if (box->y2 > clip->y2)
4484		box->y2 = clip->y2, clipped = true;
4485
4486	return clipped;
4487}
4488
4489static inline void translate_box(BoxPtr box, DrawablePtr d)
4490{
4491	box->x1 += d->x;
4492	box->x2 += d->x;
4493
4494	box->y1 += d->y;
4495	box->y2 += d->y;
4496}
4497
4498static inline bool trim_and_translate_box(BoxPtr box, DrawablePtr d, GCPtr gc)
4499{
4500	translate_box(box, d);
4501	return clip_box(box, gc);
4502}
4503
4504static inline bool box32_clip(Box32Rec *box, GCPtr gc)
4505{
4506	bool clipped = !region_is_singular(gc->pCompositeClip);
4507	const BoxRec *clip = &gc->pCompositeClip->extents;
4508
4509	if (box->x1 < clip->x1)
4510		box->x1 = clip->x1, clipped = true;
4511	if (box->x2 > clip->x2)
4512		box->x2 = clip->x2, clipped = true;
4513
4514	if (box->y1 < clip->y1)
4515		box->y1 = clip->y1, clipped = true;
4516	if (box->y2 > clip->y2)
4517		box->y2 = clip->y2, clipped = true;
4518
4519	return clipped;
4520}
4521
4522static inline void box32_translate(Box32Rec *box, DrawablePtr d)
4523{
4524	box->x1 += d->x;
4525	box->x2 += d->x;
4526
4527	box->y1 += d->y;
4528	box->y2 += d->y;
4529}
4530
4531static inline bool box32_trim_and_translate(Box32Rec *box, DrawablePtr d, GCPtr gc)
4532{
4533	box32_translate(box, d);
4534	return box32_clip(box, gc);
4535}
4536
4537static inline void box_add_pt(BoxPtr box, int16_t x, int16_t y)
4538{
4539	if (box->x1 > x)
4540		box->x1 = x;
4541	else if (box->x2 < x)
4542		box->x2 = x;
4543
4544	if (box->y1 > y)
4545		box->y1 = y;
4546	else if (box->y2 < y)
4547		box->y2 = y;
4548}
4549
4550static inline bool box32_to_box16(const Box32Rec *b32, BoxRec *b16)
4551{
4552	b16->x1 = b32->x1;
4553	b16->y1 = b32->y1;
4554	b16->x2 = b32->x2;
4555	b16->y2 = b32->y2;
4556
4557	return b16->x2 > b16->x1 && b16->y2 > b16->y1;
4558}
4559
4560static inline void box32_add_rect(Box32Rec *box, const xRectangle *r)
4561{
4562	int32_t v;
4563
4564	v = r->x;
4565	if (box->x1 > v)
4566		box->x1 = v;
4567	v += r->width;
4568	if (box->x2 < v)
4569		box->x2 = v;
4570
4571	v = r->y;
4572	if (box->y1 > v)
4573		box->y1 = v;
4574	v += r->height;
4575	if (box->y2 < v)
4576		box->y2 = v;
4577}
4578
4579static bool
4580can_create_upload_tiled_x(struct sna *sna,
4581			  PixmapPtr pixmap,
4582			  struct sna_pixmap *priv,
4583			  bool replaces)
4584{
4585	if (priv->shm || (priv->cpu && !replaces))
4586		return false;
4587
4588	if ((priv->create & KGEM_CAN_CREATE_GPU) == 0)
4589		return false;
4590
4591	if (sna->kgem.has_llc)
4592		return true;
4593
4594	if (!sna->kgem.has_wc_mmap && sna_pixmap_default_tiling(sna, pixmap))
4595		return false;
4596
4597	return true;
4598}
4599
4600static bool
4601create_upload_tiled_x(struct sna *sna,
4602		      PixmapPtr pixmap,
4603		      struct sna_pixmap *priv,
4604		      bool replaces)
4605{
4606	unsigned create;
4607
4608	if (!can_create_upload_tiled_x(sna, pixmap, priv, replaces))
4609		return false;
4610
4611	assert(priv->gpu_bo == NULL);
4612	assert(priv->gpu_damage == NULL);
4613
4614	if (sna->kgem.has_llc)
4615		create = CREATE_CPU_MAP | CREATE_INACTIVE;
4616	else if (sna->kgem.has_wc_mmap)
4617		create = CREATE_GTT_MAP | CREATE_INACTIVE;
4618	else
4619		create = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_CACHED;
4620
4621	return sna_pixmap_alloc_gpu(sna, pixmap, priv, create);
4622}
4623
4624static bool can_upload__tiled_x(struct kgem *kgem, struct kgem_bo *bo)
4625{
4626	return kgem_bo_can_map__cpu(kgem, bo, true) || kgem->has_wc_mmap;
4627}
4628
4629static bool
4630try_upload__tiled_x(PixmapPtr pixmap, RegionRec *region,
4631		    int x, int y, int w, int  h, char *bits, int stride)
4632{
4633	struct sna *sna = to_sna_from_pixmap(pixmap);
4634	struct sna_pixmap *priv = sna_pixmap(pixmap);
4635	const BoxRec *box;
4636	uint8_t *dst;
4637	int n;
4638
4639	if (!can_upload__tiled_x(&sna->kgem, priv->gpu_bo)) {
4640		DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__));
4641		return false;
4642	}
4643
4644	if (!sna_pixmap_move_area_to_gpu(pixmap, &region->extents,
4645					 MOVE_WRITE | (region->data ? MOVE_READ : 0)))
4646		return false;
4647
4648	if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 &&
4649	    __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
4650		return false;
4651
4652	if (kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true)) {
4653		dst = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
4654		if (dst == NULL)
4655			return false;
4656
4657		kgem_bo_sync__cpu(&sna->kgem, priv->gpu_bo);
4658	} else {
4659		dst = kgem_bo_map__wc(&sna->kgem, priv->gpu_bo);
4660		if (dst == NULL)
4661			return false;
4662
4663		kgem_bo_sync__gtt(&sna->kgem, priv->gpu_bo);
4664	}
4665
4666	box = region_rects(region);
4667	n = region_num_rects(region);
4668
4669	DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n));
4670
4671	if (sigtrap_get())
4672		return false;
4673
4674	if (priv->gpu_bo->tiling) {
4675		do {
4676			DBG(("%s: copy tiled box (%d, %d)->(%d, %d)x(%d, %d)\n",
4677			     __FUNCTION__,
4678			     box->x1 - x, box->y1 - y,
4679			     box->x1, box->y1,
4680			     box->x2 - box->x1, box->y2 - box->y1));
4681
4682			assert(box->x2 > box->x1);
4683			assert(box->y2 > box->y1);
4684
4685			assert(box->x1 >= 0);
4686			assert(box->y1 >= 0);
4687			assert(box->x2 <= pixmap->drawable.width);
4688			assert(box->y2 <= pixmap->drawable.height);
4689
4690			assert(box->x1 - x >= 0);
4691			assert(box->y1 - y >= 0);
4692			assert(box->x2 - x <= w);
4693			assert(box->y2 - y <= h);
4694
4695			memcpy_to_tiled_x(&sna->kgem, bits, dst,
4696					  pixmap->drawable.bitsPerPixel,
4697					  stride, priv->gpu_bo->pitch,
4698					  box->x1 - x, box->y1 - y,
4699					  box->x1, box->y1,
4700					  box->x2 - box->x1, box->y2 - box->y1);
4701			box++;
4702		} while (--n);
4703	} else {
4704		do {
4705			DBG(("%s: copy lined box (%d, %d)->(%d, %d)x(%d, %d)\n",
4706			     __FUNCTION__,
4707			     box->x1 - x, box->y1 - y,
4708			     box->x1, box->y1,
4709			     box->x2 - box->x1, box->y2 - box->y1));
4710
4711			assert(box->x2 > box->x1);
4712			assert(box->y2 > box->y1);
4713
4714			assert(box->x1 >= 0);
4715			assert(box->y1 >= 0);
4716			assert(box->x2 <= pixmap->drawable.width);
4717			assert(box->y2 <= pixmap->drawable.height);
4718
4719			assert(box->x1 - x >= 0);
4720			assert(box->y1 - y >= 0);
4721			assert(box->x2 - x <= w);
4722			assert(box->y2 - y <= h);
4723
4724			memcpy_blt(bits, dst,
4725				   pixmap->drawable.bitsPerPixel,
4726				   stride, priv->gpu_bo->pitch,
4727				   box->x1 - x, box->y1 - y,
4728				   box->x1, box->y1,
4729				   box->x2 - box->x1, box->y2 - box->y1);
4730			box++;
4731		} while (--n);
4732
4733		if (!priv->shm) {
4734			pixmap->devPrivate.ptr = dst;
4735			pixmap->devKind = priv->gpu_bo->pitch;
4736			if (dst == MAP(priv->gpu_bo->map__cpu)) {
4737				priv->mapped = MAPPED_CPU;
4738				priv->cpu = true;
4739			} else
4740				priv->mapped = MAPPED_GTT;
4741			assert_pixmap_map(pixmap, priv);
4742		}
4743	}
4744
4745	sigtrap_put();
4746	return true;
4747}
4748
4749static bool
4750try_upload__inplace(PixmapPtr pixmap, RegionRec *region,
4751		    int x, int y, int w, int  h, char *bits, int stride)
4752{
4753	struct sna *sna = to_sna_from_pixmap(pixmap);
4754	struct sna_pixmap *priv = sna_pixmap(pixmap);
4755	bool ignore_cpu = false;
4756	bool replaces;
4757	const BoxRec *box;
4758	uint8_t *dst;
4759	int n;
4760
4761	if (!USE_INPLACE)
4762		return false;
4763
4764	assert(priv);
4765
4766	if (priv->shm && priv->gpu_damage == NULL)
4767		return false;
4768
4769	replaces = region_subsumes_pixmap(region, pixmap);
4770
4771	DBG(("%s: bo? %d, can map? %d, replaces? %d\n", __FUNCTION__,
4772	     priv->gpu_bo != NULL,
4773	     priv->gpu_bo ? kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true) : 0,
4774	     replaces));
4775
4776	if (kgem_bo_discard_cache(priv->gpu_bo, true)) {
4777		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
4778		assert(DAMAGE_IS_ALL(priv->cpu_damage));
4779		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */
4780		assert(!priv->pinned);
4781		assert(!priv->mapped);
4782		sna_damage_destroy(&priv->gpu_damage);
4783		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
4784		priv->gpu_bo = NULL;
4785	}
4786
4787	if (priv->gpu_bo && replaces) {
4788		if (UNDO) kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
4789		if (can_create_upload_tiled_x(sna, pixmap, priv, true) &&
4790		    (priv->cow ||
4791		     __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo) ||
4792		     !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))) {
4793			DBG(("%s: discarding unusable target bo (busy? %d, mappable? %d)\n", __FUNCTION__,
4794			     kgem_bo_is_busy(priv->gpu_bo),
4795			     kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true)));
4796			sna_pixmap_free_gpu(sna, priv);
4797			ignore_cpu = true;
4798		}
4799	}
4800	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
4801
4802	if (priv->cow ||
4803	    (priv->move_to_gpu && !sna_pixmap_discard_shadow_damage(priv, replaces ? NULL : region))) {
4804		DBG(("%s: no, has pending COW? %d or move-to-gpu? %d\n",
4805		     __FUNCTION__, priv->cow != NULL, priv->move_to_gpu != NULL));
4806		return false;
4807	}
4808
4809	if (priv->gpu_damage &&
4810	    region_subsumes_damage(region, priv->gpu_damage)) {
4811		if (UNDO) kgem_bo_undo(&sna->kgem, priv->gpu_bo);
4812		if (can_create_upload_tiled_x(sna, pixmap, priv, priv->cpu_damage == NULL) &&
4813		    (__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo) ||
4814		     !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))) {
4815			DBG(("%s: discarding unusable partial target bo (busy? %d, mappable? %d)\n", __FUNCTION__,
4816			     kgem_bo_is_busy(priv->gpu_bo),
4817			     kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true)));
4818			sna_pixmap_free_gpu(sna, priv);
4819			ignore_cpu = priv->cpu_damage == NULL;
4820			if (priv->ptr)
4821				sna_damage_all(&priv->cpu_damage, pixmap);
4822		}
4823	}
4824
4825	if (priv->gpu_bo == NULL &&
4826	    !create_upload_tiled_x(sna, pixmap, priv, ignore_cpu))
4827		return false;
4828
4829	DBG(("%s: tiling=%d\n", __FUNCTION__, priv->gpu_bo->tiling));
4830	switch (priv->gpu_bo->tiling) {
4831	case I915_TILING_Y:
4832		break;
4833	case I915_TILING_X:
4834		if (!sna->kgem.memcpy_to_tiled_x)
4835			break;
4836	default:
4837		if (try_upload__tiled_x(pixmap, region, x, y, w, h, bits, stride))
4838			goto done;
4839		break;
4840	}
4841
4842	if (priv->gpu_damage == NULL && !box_inplace(pixmap, &region->extents)) {
4843		DBG(("%s: no, too small to bother with using the GTT\n", __FUNCTION__));
4844		return false;
4845	}
4846
4847	if (!kgem_bo_can_map(&sna->kgem, priv->gpu_bo)) {
4848		DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__));
4849		return false;
4850	}
4851
4852	if (!sna_pixmap_move_area_to_gpu(pixmap, &region->extents,
4853					 MOVE_WRITE | (region->data ? MOVE_READ : 0)))
4854		return false;
4855
4856	if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 &&
4857	    __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
4858		return false;
4859
4860	dst = kgem_bo_map(&sna->kgem, priv->gpu_bo);
4861	if (dst == NULL)
4862		return false;
4863
4864	pixmap->devPrivate.ptr = dst;
4865	pixmap->devKind = priv->gpu_bo->pitch;
4866	priv->mapped = dst == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
4867	assert(has_coherent_ptr(sna, priv, MOVE_WRITE));
4868
4869	box = region_rects(region);
4870	n = region_num_rects(region);
4871
4872	DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n));
4873
4874	if (sigtrap_get())
4875		return false;
4876
4877	do {
4878		DBG(("%s: copy lined box (%d, %d)->(%d, %d)x(%d, %d)\n",
4879		     __FUNCTION__,
4880		     box->x1 - x, box->y1 - y,
4881		     box->x1, box->y1,
4882		     box->x2 - box->x1, box->y2 - box->y1));
4883
4884		assert(box->x2 > box->x1);
4885		assert(box->y2 > box->y1);
4886
4887		assert(box->x1 >= 0);
4888		assert(box->y1 >= 0);
4889		assert(box->x2 <= pixmap->drawable.width);
4890		assert(box->y2 <= pixmap->drawable.height);
4891
4892		assert(box->x1 - x >= 0);
4893		assert(box->y1 - y >= 0);
4894		assert(box->x2 - x <= w);
4895		assert(box->y2 - y <= h);
4896
4897		memcpy_blt(bits, dst,
4898			   pixmap->drawable.bitsPerPixel,
4899			   stride, priv->gpu_bo->pitch,
4900			   box->x1 - x, box->y1 - y,
4901			   box->x1, box->y1,
4902			   box->x2 - box->x1, box->y2 - box->y1);
4903		box++;
4904	} while (--n);
4905
4906	sigtrap_put();
4907
4908done:
4909	if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
4910		if (replaces) {
4911			sna_damage_all(&priv->gpu_damage, pixmap);
4912		} else {
4913			sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap);
4914			sna_damage_reduce_all(&priv->gpu_damage, pixmap);
4915		}
4916		if (DAMAGE_IS_ALL(priv->gpu_damage))
4917			sna_damage_destroy(&priv->cpu_damage);
4918		else
4919			sna_damage_subtract(&priv->cpu_damage, region);
4920
4921		if (priv->cpu_damage == NULL) {
4922			list_del(&priv->flush_list);
4923			sna_damage_all(&priv->gpu_damage, pixmap);
4924		}
4925
4926		if (priv->shm)
4927			sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
4928	}
4929
4930	assert(!priv->clear);
4931	return true;
4932}
4933
4934static bool
4935try_upload__blt(PixmapPtr pixmap, RegionRec *region,
4936		int x, int y, int w, int  h, char *bits, int stride)
4937{
4938	struct sna *sna = to_sna_from_pixmap(pixmap);
4939	struct sna_pixmap *priv;
4940	struct kgem_bo *src_bo;
4941	bool ok;
4942
4943	if (!sna->kgem.has_userptr || !USE_USERPTR_UPLOADS)
4944		return false;
4945
4946	priv = sna_pixmap(pixmap);
4947	assert(priv);
4948	assert(priv->gpu_bo);
4949	assert(priv->gpu_bo->proxy == NULL);
4950
4951	if (priv->cpu_damage &&
4952	    (DAMAGE_IS_ALL(priv->cpu_damage) ||
4953	     sna_damage_contains_box__no_reduce(priv->cpu_damage,
4954						&region->extents)) &&
4955	    !box_inplace(pixmap, &region->extents)) {
4956		DBG(("%s: no, damage on CPU and too small\n", __FUNCTION__));
4957		return false;
4958	}
4959
4960	src_bo = kgem_create_map(&sna->kgem, bits, stride * h, true);
4961	if (src_bo == NULL)
4962		return false;
4963
4964	src_bo->pitch = stride;
4965	kgem_bo_mark_unreusable(src_bo);
4966
4967	if (!sna_pixmap_move_area_to_gpu(pixmap, &region->extents,
4968					 MOVE_WRITE | MOVE_ASYNC_HINT | (region->data ? MOVE_READ : 0))) {
4969		kgem_bo_destroy(&sna->kgem, src_bo);
4970		return false;
4971	}
4972
4973	DBG(("%s: upload(%d, %d, %d, %d) x %d through a temporary map\n",
4974	     __FUNCTION__, x, y, w, h, region_num_rects(region)));
4975
4976	if (sigtrap_get() == 0) {
4977		ok = sna->render.copy_boxes(sna, GXcopy,
4978					    &pixmap->drawable, src_bo, -x, -y,
4979					    &pixmap->drawable, priv->gpu_bo, 0, 0,
4980					    region_rects(region),
4981					    region_num_rects(region),
4982					    COPY_LAST);
4983		sigtrap_put();
4984	} else
4985		ok = false;
4986
4987	kgem_bo_sync__cpu(&sna->kgem, src_bo);
4988	assert(src_bo->rq == NULL);
4989	kgem_bo_destroy(&sna->kgem, src_bo);
4990
4991	if (!ok) {
4992		DBG(("%s: copy failed!\n", __FUNCTION__));
4993		return false;
4994	}
4995
4996	if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
4997		assert(!priv->clear);
4998		if (region_subsumes_drawable(region, &pixmap->drawable)) {
4999			sna_damage_all(&priv->gpu_damage, pixmap);
5000		} else {
5001			sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap);
5002			sna_damage_reduce_all(&priv->gpu_damage, pixmap);
5003		}
5004		if (DAMAGE_IS_ALL(priv->gpu_damage))
5005			sna_damage_destroy(&priv->cpu_damage);
5006		else
5007			sna_damage_subtract(&priv->cpu_damage, region);
5008		if (priv->cpu_damage == NULL) {
5009			list_del(&priv->flush_list);
5010			if (sna_pixmap_free_cpu(sna, priv, priv->cpu))
5011				sna_damage_all(&priv->gpu_damage, pixmap);
5012		}
5013	}
5014	priv->cpu = false;
5015	priv->clear = false;
5016
5017	return true;
5018}
5019
5020static bool ignore_cpu_damage(struct sna *sna, struct sna_pixmap *priv, const RegionRec *region)
5021{
5022	if (region_subsumes_pixmap(region, priv->pixmap))
5023		return true;
5024
5025	if (priv->cpu_damage != NULL) {
5026		if (DAMAGE_IS_ALL(priv->cpu_damage))
5027			return false;
5028
5029		if (!box_inplace(priv->pixmap, &region->extents))
5030			return false;
5031
5032		if (sna_damage_contains_box__no_reduce(priv->cpu_damage, &region->extents))
5033			return false;
5034	}
5035
5036	return priv->gpu_bo == NULL || !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo);
5037
5038}
5039
5040static bool
5041try_upload__fast(PixmapPtr pixmap, RegionRec *region,
5042		 int x, int y, int w, int  h, char *bits, int stride)
5043{
5044	struct sna *sna = to_sna_from_pixmap(pixmap);
5045	struct sna_pixmap *priv;
5046
5047	if (wedged(sna))
5048		return false;
5049
5050	priv = sna_pixmap(pixmap);
5051	if (priv == NULL)
5052		return false;
5053
5054	if (ignore_cpu_damage(sna, priv, region)) {
5055		DBG(("%s: ignore existing cpu damage (if any)\n", __FUNCTION__));
5056		if (try_upload__inplace(pixmap, region, x, y, w, h, bits, stride))
5057			return true;
5058	}
5059
5060	if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL || priv->cpu) {
5061		DBG(("%s: no, no gpu damage\n", __FUNCTION__));
5062		return false;
5063	}
5064
5065	assert(priv->gpu_bo);
5066	assert(priv->gpu_bo->proxy == NULL);
5067
5068	if (try_upload__blt(pixmap, region, x, y, w, h, bits, stride))
5069		return true;
5070
5071	if (try_upload__inplace(pixmap, region, x, y, w, h, bits, stride))
5072		return true;
5073
5074	return false;
5075}
5076
5077static bool
5078sna_put_zpixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
5079		    int x, int y, int w, int  h, char *bits, int stride)
5080{
5081	PixmapPtr pixmap = get_drawable_pixmap(drawable);
5082	unsigned int hint;
5083	const BoxRec *box;
5084	int16_t dx, dy;
5085	int n;
5086
5087	assert_pixmap_contains_box(pixmap, RegionExtents(region));
5088
5089	if (gc->alu != GXcopy)
5090		return false;
5091
5092	if (drawable->depth < 8)
5093		return false;
5094
5095	get_drawable_deltas(drawable, pixmap, &dx, &dy);
5096	x += dx + drawable->x;
5097	y += dy + drawable->y;
5098	assert(region->extents.x1 >= x);
5099	assert(region->extents.y1 >= y);
5100	assert(region->extents.x2 <= x + w);
5101	assert(region->extents.y2 <= y + h);
5102
5103	if (try_upload__fast(pixmap, region, x, y, w, h, bits, stride))
5104		return true;
5105
5106	hint = MOVE_WRITE;
5107	if (region_is_unclipped(region, pixmap->drawable.width, h) &&
5108	    (h+1)*stride > 65536) {
5109		DBG(("%s: segmented, unclipped large upload (%d bytes), marking WHOLE_HINT\n",
5110		     __FUNCTION__, h*stride));
5111		hint |= MOVE_WHOLE_HINT;
5112	}
5113
5114	if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, region, hint))
5115		return false;
5116
5117	if (sigtrap_get())
5118		return false;
5119
5120	/* Region is pre-clipped and translated into pixmap space */
5121	box = region_rects(region);
5122	n = region_num_rects(region);
5123	DBG(("%s: upload(%d, %d, %d, %d) x %d boxes\n", __FUNCTION__, x, y, w, h, n));
5124	do {
5125		DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n",
5126		     __FUNCTION__,
5127		     box->x1 - x, box->y1 - y,
5128		     box->x1, box->y1,
5129		     box->x2 - box->x1, box->y2 - box->y1));
5130
5131		assert(box->x2 > box->x1);
5132		assert(box->y2 > box->y1);
5133
5134		assert(box->x1 >= 0);
5135		assert(box->y1 >= 0);
5136		assert(box->x2 <= pixmap->drawable.width);
5137		assert(box->y2 <= pixmap->drawable.height);
5138
5139		assert(box->x1 - x >= 0);
5140		assert(box->y1 - y >= 0);
5141		assert(box->x2 - x <= w);
5142		assert(box->y2 - y <= h);
5143
5144		assert(has_coherent_ptr(to_sna_from_pixmap(pixmap), sna_pixmap(pixmap), MOVE_WRITE));
5145		assert(pixmap->devKind);
5146		memcpy_blt(bits, pixmap->devPrivate.ptr,
5147			   pixmap->drawable.bitsPerPixel,
5148			   stride, pixmap->devKind,
5149			   box->x1 - x, box->y1 - y,
5150			   box->x1, box->y1,
5151			   box->x2 - box->x1, box->y2 - box->y1);
5152		box++;
5153	} while (--n);
5154
5155	sigtrap_put();
5156	assert_pixmap_damage(pixmap);
5157	return true;
5158}
5159
5160static inline uint8_t byte_reverse(uint8_t b)
5161{
5162	return ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
5163}
5164
5165static inline uint8_t blt_depth(int depth)
5166{
5167	switch (depth) {
5168	case 8: return 0;
5169	case 15: return 0x2;
5170	case 16: return 0x1;
5171	default: return 0x3;
5172	}
5173}
5174
5175static bool
5176sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
5177		     int x, int y, int w, int  h, char *bits)
5178{
5179	PixmapPtr pixmap = get_drawable_pixmap(drawable);
5180	struct sna *sna = to_sna_from_pixmap(pixmap);
5181	struct sna_damage **damage;
5182	struct kgem_bo *bo;
5183	const BoxRec *box;
5184	int16_t dx, dy;
5185	int n;
5186	uint8_t rop = copy_ROP[gc->alu];
5187
5188	bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU,
5189				 &region->extents, &damage);
5190	if (bo == NULL)
5191		return false;
5192
5193	if (bo->tiling == I915_TILING_Y) {
5194		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
5195		assert(bo == __sna_pixmap_get_bo(pixmap));
5196		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
5197		if (bo == NULL) {
5198			DBG(("%s: fallback -- unable to change tiling\n",
5199			     __FUNCTION__));
5200			return false;
5201		}
5202	}
5203
5204	if (!kgem_bo_can_blt(&sna->kgem, bo))
5205		return false;
5206
5207	assert_pixmap_contains_box(pixmap, RegionExtents(region));
5208	if (damage)
5209		sna_damage_add_to_pixmap(damage, region, pixmap);
5210	assert_pixmap_damage(pixmap);
5211
5212	DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h));
5213
5214	get_drawable_deltas(drawable, pixmap, &dx, &dy);
5215	x += dx + drawable->x;
5216	y += dy + drawable->y;
5217
5218	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
5219	assert(kgem_bo_can_blt(&sna->kgem, bo));
5220
5221	/* Region is pre-clipped and translated into pixmap space */
5222	box = region_rects(region);
5223	n = region_num_rects(region);
5224	do {
5225		int bx1 = (box->x1 - x) & ~7;
5226		int bx2 = (box->x2 - x + 7) & ~7;
5227		int bw = (bx2 - bx1)/8;
5228		int bh = box->y2 - box->y1;
5229		int bstride = ALIGN(bw, 2);
5230		struct kgem_bo *upload;
5231		void *ptr;
5232
5233		if (!kgem_check_batch(&sna->kgem, 10) ||
5234		    !kgem_check_bo_fenced(&sna->kgem, bo) ||
5235		    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
5236			kgem_submit(&sna->kgem);
5237			if (!kgem_check_bo_fenced(&sna->kgem, bo))
5238				return false;
5239			_kgem_set_mode(&sna->kgem, KGEM_BLT);
5240		}
5241
5242		upload = kgem_create_buffer(&sna->kgem,
5243					    bstride*bh,
5244					    KGEM_BUFFER_WRITE_INPLACE,
5245					    &ptr);
5246		if (!upload)
5247			break;
5248
5249
5250		if (sigtrap_get() == 0) {
5251			int src_stride = BitmapBytePad(w);
5252			uint8_t *dst = ptr;
5253			uint8_t *src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8;
5254			uint32_t *b;
5255
5256			bstride -= bw;
5257			src_stride -= bw;
5258
5259			do {
5260				int i = bw;
5261				assert(src >= (uint8_t *)bits);
5262				do {
5263					*dst++ = byte_reverse(*src++);
5264				} while (--i);
5265				assert(src <= (uint8_t *)bits + BitmapBytePad(w) * h);
5266				assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload));
5267				dst += bstride;
5268				src += src_stride;
5269			} while (--bh);
5270
5271			assert(sna->kgem.mode == KGEM_BLT);
5272			if (sna->kgem.gen >= 0100) {
5273				b = sna->kgem.batch + sna->kgem.nbatch;
5274				b[0] = XY_MONO_SRC_COPY | 3 << 20 | 8;
5275				b[0] |= ((box->x1 - x) & 7) << 17;
5276				b[1] = bo->pitch;
5277				if (bo->tiling) {
5278					b[0] |= BLT_DST_TILED;
5279					b[1] >>= 2;
5280				}
5281				b[1] |= blt_depth(drawable->depth) << 24;
5282				b[1] |= rop << 16;
5283				b[2] = box->y1 << 16 | box->x1;
5284				b[3] = box->y2 << 16 | box->x2;
5285				*(uint64_t *)(b+4) =
5286					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
5287							I915_GEM_DOMAIN_RENDER << 16 |
5288							I915_GEM_DOMAIN_RENDER |
5289							KGEM_RELOC_FENCED,
5290							0);
5291				*(uint64_t *)(b+6) =
5292					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
5293							I915_GEM_DOMAIN_RENDER << 16 |
5294							KGEM_RELOC_FENCED,
5295							0);
5296				b[8] = gc->bgPixel;
5297				b[9] = gc->fgPixel;
5298
5299				sna->kgem.nbatch += 10;
5300			} else {
5301				b = sna->kgem.batch + sna->kgem.nbatch;
5302				b[0] = XY_MONO_SRC_COPY | 3 << 20 | 6;
5303				b[0] |= ((box->x1 - x) & 7) << 17;
5304				b[1] = bo->pitch;
5305				if (sna->kgem.gen >= 040 && bo->tiling) {
5306					b[0] |= BLT_DST_TILED;
5307					b[1] >>= 2;
5308				}
5309				b[1] |= blt_depth(drawable->depth) << 24;
5310				b[1] |= rop << 16;
5311				b[2] = box->y1 << 16 | box->x1;
5312				b[3] = box->y2 << 16 | box->x2;
5313				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
5314						I915_GEM_DOMAIN_RENDER << 16 |
5315						I915_GEM_DOMAIN_RENDER |
5316						KGEM_RELOC_FENCED,
5317						0);
5318				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
5319						I915_GEM_DOMAIN_RENDER << 16 |
5320						KGEM_RELOC_FENCED,
5321						0);
5322				b[6] = gc->bgPixel;
5323				b[7] = gc->fgPixel;
5324
5325				sna->kgem.nbatch += 8;
5326			}
5327			sigtrap_put();
5328		}
5329		kgem_bo_destroy(&sna->kgem, upload);
5330
5331		box++;
5332	} while (--n);
5333
5334	sna->blt_state.fill_bo = 0;
5335	return true;
5336}
5337
5338static bool
5339sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
5340		     int x, int y, int w, int  h, int left,char *bits)
5341{
5342	PixmapPtr pixmap = get_drawable_pixmap(drawable);
5343	struct sna *sna = to_sna_from_pixmap(pixmap);
5344	struct sna_damage **damage;
5345	struct kgem_bo *bo;
5346	int16_t dx, dy;
5347	unsigned i, skip;
5348
5349	if (gc->alu != GXcopy)
5350		return false;
5351
5352	bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU,
5353				 &region->extents, &damage);
5354	if (bo == NULL)
5355		return false;
5356
5357	if (bo->tiling == I915_TILING_Y) {
5358		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
5359		assert(bo == __sna_pixmap_get_bo(pixmap));
5360		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
5361		if (bo == NULL) {
5362			DBG(("%s: fallback -- unable to change tiling\n",
5363			     __FUNCTION__));
5364			return false;
5365		}
5366	}
5367
5368	if (!kgem_bo_can_blt(&sna->kgem, bo))
5369		return false;
5370
5371	assert_pixmap_contains_box(pixmap, RegionExtents(region));
5372	if (damage)
5373		sna_damage_add_to_pixmap(damage, region, pixmap);
5374	assert_pixmap_damage(pixmap);
5375
5376	DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h));
5377
5378	get_drawable_deltas(drawable, pixmap, &dx, &dy);
5379	x += dx + drawable->x;
5380	y += dy + drawable->y;
5381
5382	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
5383	assert(kgem_bo_can_blt(&sna->kgem, bo));
5384
5385	skip = h * BitmapBytePad(w + left);
5386	for (i = 1 << (gc->depth-1); i; i >>= 1, bits += skip) {
5387		const BoxRec *box = region_rects(region);
5388		int n = region_num_rects(region);
5389
5390		if ((gc->planemask & i) == 0)
5391			continue;
5392
5393		/* Region is pre-clipped and translated into pixmap space */
5394		do {
5395			int bx1 = (box->x1 - x) & ~7;
5396			int bx2 = (box->x2 - x + 7) & ~7;
5397			int bw = (bx2 - bx1)/8;
5398			int bh = box->y2 - box->y1;
5399			int bstride = ALIGN(bw, 2);
5400			struct kgem_bo *upload;
5401			void *ptr;
5402
5403			if (!kgem_check_batch(&sna->kgem, 14) ||
5404			    !kgem_check_bo_fenced(&sna->kgem, bo) ||
5405			    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
5406				kgem_submit(&sna->kgem);
5407				if (!kgem_check_bo_fenced(&sna->kgem, bo))
5408					return false;
5409				_kgem_set_mode(&sna->kgem, KGEM_BLT);
5410			}
5411
5412			upload = kgem_create_buffer(&sna->kgem,
5413						    bstride*bh,
5414						    KGEM_BUFFER_WRITE_INPLACE,
5415						    &ptr);
5416			if (!upload)
5417				break;
5418
5419			if (sigtrap_get() == 0) {
5420				int src_stride = BitmapBytePad(w);
5421				uint8_t *src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8;
5422				uint8_t *dst = ptr;
5423				uint32_t *b;
5424
5425				bstride -= bw;
5426				src_stride -= bw;
5427				do {
5428					int j = bw;
5429					assert(src >= (uint8_t *)bits);
5430					do {
5431						*dst++ = byte_reverse(*src++);
5432					} while (--j);
5433					assert(src <= (uint8_t *)bits + BitmapBytePad(w) * h);
5434					assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload));
5435					dst += bstride;
5436					src += src_stride;
5437				} while (--bh);
5438
5439				assert(sna->kgem.mode == KGEM_BLT);
5440				if (sna->kgem.gen >= 0100) {
5441					assert(sna->kgem.mode == KGEM_BLT);
5442					b = sna->kgem.batch + sna->kgem.nbatch;
5443					b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20 | 12;
5444					b[0] |= ((box->x1 - x) & 7) << 17;
5445					b[1] = bo->pitch;
5446					if (bo->tiling) {
5447						b[0] |= BLT_DST_TILED;
5448						b[1] >>= 2;
5449					}
5450					b[1] |= 1 << 31; /* solid pattern */
5451					b[1] |= blt_depth(drawable->depth) << 24;
5452					b[1] |= 0xce << 16; /* S or (D and !P) */
5453					b[2] = box->y1 << 16 | box->x1;
5454					b[3] = box->y2 << 16 | box->x2;
5455					*(uint64_t *)(b+4) =
5456						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
5457								I915_GEM_DOMAIN_RENDER << 16 |
5458								I915_GEM_DOMAIN_RENDER |
5459								KGEM_RELOC_FENCED,
5460								0);
5461					*(uint64_t *)(b+6) =
5462						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
5463								I915_GEM_DOMAIN_RENDER << 16 |
5464								KGEM_RELOC_FENCED,
5465								0);
5466					b[8] = 0;
5467					b[9] = i;
5468					b[10] = i;
5469					b[11] = i;
5470					b[12] = -1;
5471					b[13] = -1;
5472					sna->kgem.nbatch += 14;
5473				} else {
5474					b = sna->kgem.batch + sna->kgem.nbatch;
5475					b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20 | 10;
5476					b[0] |= ((box->x1 - x) & 7) << 17;
5477					b[1] = bo->pitch;
5478					if (sna->kgem.gen >= 040 && bo->tiling) {
5479						b[0] |= BLT_DST_TILED;
5480						b[1] >>= 2;
5481					}
5482					b[1] |= 1 << 31; /* solid pattern */
5483					b[1] |= blt_depth(drawable->depth) << 24;
5484					b[1] |= 0xce << 16; /* S or (D and !P) */
5485					b[2] = box->y1 << 16 | box->x1;
5486					b[3] = box->y2 << 16 | box->x2;
5487					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
5488							I915_GEM_DOMAIN_RENDER << 16 |
5489							I915_GEM_DOMAIN_RENDER |
5490							KGEM_RELOC_FENCED,
5491							0);
5492					b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
5493							I915_GEM_DOMAIN_RENDER << 16 |
5494							KGEM_RELOC_FENCED,
5495							0);
5496					b[6] = 0;
5497					b[7] = i;
5498					b[8] = i;
5499					b[9] = i;
5500					b[10] = -1;
5501					b[11] = -1;
5502					sna->kgem.nbatch += 12;
5503				}
5504				sigtrap_put();
5505			}
5506			kgem_bo_destroy(&sna->kgem, upload);
5507
5508			box++;
5509		} while (--n);
5510	}
5511
5512	sna->blt_state.fill_bo = 0;
5513	return true;
5514}
5515
5516static void
5517sna_put_image(DrawablePtr drawable, GCPtr gc, int depth,
5518	      int x, int y, int w, int h, int left, int format,
5519	      char *bits)
5520{
5521	PixmapPtr pixmap = get_drawable_pixmap(drawable);
5522	struct sna *sna = to_sna_from_pixmap(pixmap);
5523	struct sna_pixmap *priv = sna_pixmap(pixmap);
5524	RegionRec region;
5525	int16_t dx, dy;
5526
5527	DBG(("%s((%d, %d)x(%d, %d), depth=%d, format=%d)\n",
5528	     __FUNCTION__, x, y, w, h, depth, format));
5529
5530	if (w == 0 || h == 0)
5531		return;
5532
5533	region.extents.x1 = x + drawable->x;
5534	region.extents.y1 = y + drawable->y;
5535	region.extents.x2 = region.extents.x1 + w;
5536	region.extents.y2 = region.extents.y1 + h;
5537	region.data = NULL;
5538
5539	if (!region_is_singular(gc->pCompositeClip) ||
5540	    gc->pCompositeClip->extents.x1 > region.extents.x1 ||
5541	    gc->pCompositeClip->extents.y1 > region.extents.y1 ||
5542	    gc->pCompositeClip->extents.x2 < region.extents.x2 ||
5543	    gc->pCompositeClip->extents.y2 < region.extents.y2) {
5544		if (!RegionIntersect(&region, &region, gc->pCompositeClip) ||
5545		    box_empty(&region.extents))
5546			return;
5547	}
5548
5549	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
5550		RegionTranslate(&region, dx, dy);
5551
5552	if (priv == NULL) {
5553		DBG(("%s: fallback -- unattached(%d, %d, %d, %d)\n",
5554		     __FUNCTION__, x, y, w, h));
5555		goto fallback;
5556	}
5557
5558	if (FORCE_FALLBACK)
5559		goto fallback;
5560
5561	if (wedged(sna))
5562		goto fallback;
5563
5564	if (!ACCEL_PUT_IMAGE)
5565		goto fallback;
5566
5567	switch (format) {
5568	case ZPixmap:
5569		if (!PM_IS_SOLID(drawable, gc->planemask))
5570			goto fallback;
5571
5572		if (sna_put_zpixmap_blt(drawable, gc, &region,
5573					x, y, w, h,
5574					bits, PixmapBytePad(w, depth)))
5575			return;
5576		break;
5577
5578	case XYBitmap:
5579		if (!PM_IS_SOLID(drawable, gc->planemask))
5580			goto fallback;
5581
5582		if (sna_put_xybitmap_blt(drawable, gc, &region,
5583					 x, y, w, h,
5584					 bits))
5585			return;
5586		break;
5587
5588	case XYPixmap:
5589		if (sna_put_xypixmap_blt(drawable, gc, &region,
5590					 x, y, w, h, left,
5591					 bits))
5592			return;
5593		break;
5594
5595	default:
5596		return;
5597	}
5598
5599fallback:
5600	DBG(("%s: fallback\n", __FUNCTION__));
5601	RegionTranslate(&region, -dx, -dy);
5602
5603	if (!sna_gc_move_to_cpu(gc, drawable, &region))
5604		goto out;
5605	if (!sna_drawable_move_region_to_cpu(drawable, &region,
5606					      format == XYPixmap ?
5607					      MOVE_READ | MOVE_WRITE :
5608					      drawable_gc_flags(drawable, gc, false)))
5609		goto out;
5610
5611	if (sigtrap_get() == 0) {
5612		DBG(("%s: fbPutImage(%d, %d, %d, %d)\n",
5613		     __FUNCTION__, x, y, w, h));
5614		fbPutImage(drawable, gc, depth, x, y, w, h, left, format, bits);
5615		FALLBACK_FLUSH(drawable);
5616		sigtrap_put();
5617	}
5618out:
5619	sna_gc_move_to_gpu(gc);
5620	RegionUninit(&region);
5621}
5622
5623static bool
5624source_contains_region(struct sna_damage *damage,
5625		       const RegionRec *region, int16_t dx, int16_t dy)
5626{
5627	BoxRec box;
5628
5629	if (DAMAGE_IS_ALL(damage))
5630		return true;
5631
5632	if (damage == NULL)
5633		return false;
5634
5635	box = region->extents;
5636	box.x1 += dx;
5637	box.x2 += dx;
5638	box.y1 += dy;
5639	box.y2 += dy;
5640	return sna_damage_contains_box__no_reduce(damage, &box);
5641}
5642
5643static bool
5644move_to_gpu(PixmapPtr pixmap, struct sna_pixmap *priv,
5645	    RegionRec *region, int16_t dx, int16_t dy,
5646	    uint8_t alu, bool dst_is_gpu)
5647{
5648	int w = region->extents.x2 - region->extents.x1;
5649	int h = region->extents.y2 - region->extents.y1;
5650	int count;
5651
5652	assert_pixmap_map(pixmap, priv);
5653	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
5654		assert(priv->gpu_bo);
5655		return true;
5656	}
5657
5658	if (dst_is_gpu && priv->cpu_bo && priv->cpu_damage) {
5659		DBG(("%s: can use CPU bo? cpu_damage=%d, gpu_damage=%d, cpu hint=%d\n",
5660		     __FUNCTION__,
5661		     priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0,
5662		     priv->gpu_damage ? DAMAGE_IS_ALL(priv->gpu_damage) ? -1 : 1 : 0,
5663		     priv->cpu));
5664		if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL)
5665			return false;
5666
5667		if (priv->cpu &&
5668		    source_contains_region(priv->cpu_damage, region, dx, dy))
5669			return false;
5670	}
5671
5672	if (priv->gpu_bo) {
5673		DBG(("%s: has gpu bo (cpu damage?=%d, cpu=%d, gpu tiling=%d)\n",
5674		     __FUNCTION__,
5675		     priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0,
5676		     priv->cpu, priv->gpu_bo->tiling));
5677
5678		if (priv->cpu_damage == NULL)
5679			return true;
5680
5681		if (alu != GXcopy)
5682			return true;
5683
5684		if (!priv->cpu)
5685			return true;
5686
5687		if (priv->gpu_bo->tiling)
5688			return true;
5689
5690		RegionTranslate(region, dx, dy);
5691		count = region_subsumes_damage(region, priv->cpu_damage);
5692		RegionTranslate(region, -dx, -dy);
5693		if (count)
5694			return true;
5695	} else {
5696		if ((priv->create & KGEM_CAN_CREATE_GPU) == 0)
5697			return false;
5698		if (priv->shm)
5699			return false;
5700	}
5701
5702	count = priv->source_count++;
5703	if (priv->cpu_bo) {
5704		if (priv->cpu_bo->flush && count > SOURCE_BIAS)
5705			return true;
5706
5707		if (sna_pixmap_default_tiling(to_sna_from_pixmap(pixmap), pixmap) == I915_TILING_NONE)
5708			return false;
5709
5710		if (priv->cpu)
5711			return false;
5712
5713		return count > SOURCE_BIAS;
5714	} else {
5715		if (w == pixmap->drawable.width && h == pixmap->drawable.height)
5716			return count > SOURCE_BIAS;
5717
5718		return count * w*h >= (SOURCE_BIAS+2) * (int)pixmap->drawable.width * pixmap->drawable.height;
5719	}
5720}
5721
5722static const BoxRec *
5723reorder_boxes(const BoxRec *box, int n, int dx, int dy)
5724{
5725	const BoxRec *next, *base;
5726	BoxRec *new;
5727
5728	DBG(("%s x %d dx=%d, dy=%d\n", __FUNCTION__, n, dx, dy));
5729
5730	if (dy <= 0 && dx <= 0) {
5731		BoxRec *tmp;
5732
5733		new = malloc(sizeof(BoxRec) * n);
5734		if (new == NULL)
5735			return NULL;
5736
5737		tmp = new;
5738		next = box + n;
5739		do {
5740			*tmp++ = *--next;
5741		} while (next != box);
5742	} else if (dy < 0) {
5743		new = malloc(sizeof(BoxRec) * n);
5744		if (new == NULL)
5745			return NULL;
5746
5747		base = next = box + n - 1;
5748		while (base >= box) {
5749			const BoxRec *tmp;
5750
5751			while (next >= box && base->y1 == next->y1)
5752				next--;
5753			tmp = next + 1;
5754			while (tmp <= base)
5755				*new++ = *tmp++;
5756			base = next;
5757		}
5758		new -= n;
5759	} else {
5760		new = malloc(sizeof(BoxRec) * n);
5761		if (!new)
5762			return NULL;
5763
5764		base = next = box;
5765		while (base < box + n) {
5766			const BoxRec *tmp;
5767
5768			while (next < box + n && next->y1 == base->y1)
5769				next++;
5770			tmp = next;
5771			while (tmp != base)
5772				*new++ = *--tmp;
5773			base = next;
5774		}
5775		new -= n;
5776	}
5777
5778	return new;
5779}
5780
5781static void
5782sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
5783		    RegionPtr region,int dx, int dy,
5784		    Pixel bitplane, void *closure)
5785{
5786	PixmapPtr pixmap = get_drawable_pixmap(src);
5787	struct sna *sna = to_sna_from_pixmap(pixmap);
5788	struct sna_pixmap *priv = sna_pixmap(pixmap);
5789	const BoxRec *box = region_rects(region);
5790	int n = region_num_rects(region);
5791	int alu = gc ? gc->alu : GXcopy;
5792	int16_t tx, ty, sx, sy;
5793
5794	assert(pixmap == get_drawable_pixmap(dst));
5795
5796	assert(region_num_rects(region));
5797	if (((dx | dy) == 0 && alu == GXcopy))
5798		return;
5799
5800	if (n > 1 && (dx | dy) < 0) {
5801		box = reorder_boxes(box, n, dx, dy);
5802		if (box == NULL)
5803			return;
5804	}
5805
5806	DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d, pix.size=%dx%d)\n",
5807	     __FUNCTION__, n,
5808	     region->extents.x1, region->extents.y1,
5809	     region->extents.x2, region->extents.y2,
5810	     dx, dy, alu,
5811	     pixmap->drawable.width, pixmap->drawable.height));
5812
5813	get_drawable_deltas(dst, pixmap, &tx, &ty);
5814	get_drawable_deltas(src, pixmap, &sx, &sy);
5815	sx += dx;
5816	sy += dy;
5817
5818	if (priv == NULL || DAMAGE_IS_ALL(priv->cpu_damage)) {
5819		DBG(("%s: unattached, or all damaged on CPU\n", __FUNCTION__));
5820		goto fallback;
5821	}
5822
5823	if (priv->gpu_damage || (priv->cpu_damage == NULL && priv->gpu_bo)) {
5824		assert(priv->gpu_bo);
5825
5826		if (alu == GXcopy && priv->clear)
5827			goto free_boxes;
5828
5829		assert(priv->gpu_bo->proxy == NULL);
5830		if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT)) {
5831			DBG(("%s: fallback - not a pure copy and failed to move dst to GPU\n",
5832			     __FUNCTION__));
5833			goto fallback;
5834		}
5835		assert(priv->cpu_damage == NULL);
5836
5837		if (!sna->render.copy_boxes(sna, alu,
5838					    &pixmap->drawable, priv->gpu_bo, sx, sy,
5839					    &pixmap->drawable, priv->gpu_bo, tx, ty,
5840					    box, n, 0)) {
5841			DBG(("%s: fallback - accelerated copy boxes failed\n",
5842			     __FUNCTION__));
5843			goto fallback;
5844		}
5845
5846		if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
5847			assert(!priv->clear);
5848			if (sna_pixmap_free_cpu(sna, priv, false)) {
5849				sna_damage_all(&priv->gpu_damage, pixmap);
5850			} else {
5851				RegionTranslate(region, tx, ty);
5852				sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap);
5853			}
5854		}
5855		assert_pixmap_damage(pixmap);
5856	} else {
5857fallback:
5858		DBG(("%s: fallback\n", __FUNCTION__));
5859		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE))
5860			goto free_boxes;
5861
5862		if (alu == GXcopy && pixmap->drawable.bitsPerPixel >= 8) {
5863			assert(pixmap->devKind);
5864			if (sigtrap_get() == 0) {
5865				FbBits *dst_bits, *src_bits;
5866				int stride = pixmap->devKind;
5867				int bpp = pixmap->drawable.bitsPerPixel;
5868				int i;
5869
5870				dst_bits = (FbBits *)
5871					((char *)pixmap->devPrivate.ptr +
5872					 ty * stride + tx * bpp / 8);
5873				src_bits = (FbBits *)
5874					((char *)pixmap->devPrivate.ptr +
5875					 sy * stride + sx * bpp / 8);
5876
5877				for (i = 0; i < n; i++)
5878					memmove_box(src_bits, dst_bits,
5879						    bpp, stride, box+i,
5880						    dx, dy);
5881				sigtrap_put();
5882			}
5883		} else {
5884			if (gc && !sna_gc_move_to_cpu(gc, dst, region))
5885				goto out;
5886
5887			if (sigtrap_get() == 0) {
5888				miCopyRegion(src, dst, gc,
5889					     region, dx, dy,
5890					     fbCopyNtoN, 0, NULL);
5891				sigtrap_put();
5892			}
5893
5894			if (gc)
5895out:
5896				sna_gc_move_to_gpu(gc);
5897		}
5898	}
5899
5900free_boxes:
5901	if (box != region_rects(region))
5902		free((void *)box);
5903}
5904
5905static inline bool
5906sna_pixmap_is_gpu(PixmapPtr pixmap)
5907{
5908	struct sna_pixmap *priv = sna_pixmap(pixmap);
5909
5910	if (priv == NULL || priv->clear)
5911		return false;
5912
5913	if (DAMAGE_IS_ALL(priv->gpu_damage) ||
5914	    (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo) && !priv->gpu_bo->proxy))
5915		return true;
5916
5917	return priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo);
5918}
5919
5920static int
5921copy_prefer_gpu(struct sna *sna,
5922		struct sna_pixmap *dst_priv,
5923		struct sna_pixmap *src_priv,
5924		RegionRec *region,
5925		int16_t dx, int16_t dy)
5926{
5927	assert(dst_priv);
5928
5929	if (wedged(sna) && !dst_priv->pinned)
5930		return 0;
5931
5932	if (src_priv == NULL) {
5933		DBG(("%s: source unattached, use cpu\n", __FUNCTION__));
5934		return 0;
5935	}
5936
5937	if (src_priv->clear) {
5938		DBG(("%s: source is clear, don't force use of GPU\n", __FUNCTION__));
5939		return 0;
5940	}
5941
5942	if (src_priv->gpu_damage &&
5943	    !source_contains_region(src_priv->cpu_damage, region, dx, dy)) {
5944		DBG(("%s: source has gpu damage, force gpu? %d\n",
5945		     __FUNCTION__, src_priv->cpu_damage == NULL));
5946		assert(src_priv->gpu_bo);
5947		return src_priv->cpu_damage ? PREFER_GPU : PREFER_GPU | FORCE_GPU;
5948	}
5949
5950	if (src_priv->cpu_bo && kgem_bo_is_busy(src_priv->cpu_bo)) {
5951		DBG(("%s: source has busy CPU bo, force gpu\n", __FUNCTION__));
5952		return PREFER_GPU | FORCE_GPU;
5953	}
5954
5955	if (source_contains_region(src_priv->cpu_damage, region, dx, dy))
5956		return src_priv->cpu_bo && kgem_is_idle(&sna->kgem);
5957
5958	DBG(("%s: source has GPU bo? %d\n",
5959	     __FUNCTION__, src_priv->gpu_bo != NULL));
5960	return src_priv->gpu_bo != NULL;
5961}
5962
5963static bool use_shm_bo(struct sna *sna,
5964		       struct kgem_bo *bo,
5965		       struct sna_pixmap *priv,
5966		       int alu, bool replaces)
5967{
5968	if (priv == NULL || priv->cpu_bo == NULL) {
5969		DBG(("%s: no, not attached\n", __FUNCTION__));
5970		return false;
5971	}
5972
5973	if (!priv->shm && !priv->cpu) {
5974		DBG(("%s: yes, ordinary CPU bo\n", __FUNCTION__));
5975		return true;
5976	}
5977
5978	if (alu != GXcopy) {
5979		DBG(("%s: yes, complex alu=%d\n", __FUNCTION__, alu));
5980		return true;
5981	}
5982
5983	if (!replaces && __kgem_bo_is_busy(&sna->kgem, bo)) {
5984		DBG(("%s: yes, dst is busy\n", __FUNCTION__));
5985		return true;
5986	}
5987
5988	if (priv->cpu_bo->needs_flush &&
5989	    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
5990		DBG(("%s: yes, src is busy\n", __FUNCTION__));
5991		return true;
5992	}
5993
5994	return false;
5995}
5996
5997static bool
5998sna_damage_contains_box__no_reduce__offset(struct sna_damage *damage,
5999					   const BoxRec *extents,
6000					   int16_t dx, int16_t dy)
6001{
6002	BoxRec _extents;
6003
6004	if (dx | dy) {
6005		_extents.x1 = extents->x1 + dx;
6006		_extents.x2 = extents->x2 + dx;
6007		_extents.y1 = extents->y1 + dy;
6008		_extents.y2 = extents->y2 + dy;
6009		extents = &_extents;
6010	}
6011
6012	return sna_damage_contains_box__no_reduce(damage, extents);
6013}
6014
6015static bool
6016sna_copy_boxes__inplace(struct sna *sna, RegionPtr region, int alu,
6017			PixmapPtr src_pixmap, struct sna_pixmap *src_priv,
6018			int dx, int dy,
6019			PixmapPtr dst_pixmap, struct sna_pixmap *dst_priv,
6020			bool replaces)
6021{
6022	const BoxRec *box;
6023	char *ptr;
6024	int n;
6025
6026	assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel);
6027
6028	if (alu != GXcopy) {
6029		DBG(("%s - no, complex alu [%d]\n", __FUNCTION__, alu));
6030		return false;
6031	}
6032
6033	if (!USE_INPLACE) {
6034		DBG(("%s - no, compile time disabled\n", __FUNCTION__));
6035		return false;
6036	}
6037
6038	if (dst_priv == src_priv) {
6039		DBG(("%s - no, dst == src\n", __FUNCTION__));
6040		return false;
6041	}
6042
6043	if (src_priv == NULL || src_priv->gpu_bo == NULL) {
6044		if (dst_priv && dst_priv->gpu_bo)
6045			goto upload_inplace;
6046
6047		DBG(("%s - no, no src or dst GPU bo\n", __FUNCTION__));
6048		return false;
6049	}
6050
6051	switch (src_priv->gpu_bo->tiling) {
6052	case I915_TILING_Y:
6053		DBG(("%s - no, bad src tiling [Y]\n", __FUNCTION__));
6054		return false;
6055	case I915_TILING_X:
6056		if (!sna->kgem.memcpy_from_tiled_x) {
6057			DBG(("%s - no, bad src tiling [X]\n", __FUNCTION__));
6058			return false;
6059		}
6060	default:
6061		break;
6062	}
6063
6064	if (src_priv->move_to_gpu && !src_priv->move_to_gpu(sna, src_priv, MOVE_READ)) {
6065		DBG(("%s - no, pending src move-to-gpu failed\n", __FUNCTION__));
6066		return false;
6067	}
6068
6069	if (!kgem_bo_can_map__cpu(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC)) {
6070		DBG(("%s - no, cannot map src for reads into the CPU\n", __FUNCTION__));
6071		return false;
6072	}
6073
6074	if (src_priv->gpu_damage == NULL ||
6075	    !(DAMAGE_IS_ALL(src_priv->gpu_damage) ||
6076	      sna_damage_contains_box__no_reduce__offset(src_priv->gpu_damage,
6077							 &region->extents,
6078							 dx, dy))) {
6079		DBG(("%s - no, src is not damaged on the GPU\n", __FUNCTION__));
6080		return false;
6081	}
6082
6083	assert(sna_damage_contains_box__offset(&src_priv->gpu_damage, &region->extents, dx, dy) == PIXMAN_REGION_IN);
6084	assert(sna_damage_contains_box__offset(&src_priv->cpu_damage, &region->extents, dx, dy) == PIXMAN_REGION_OUT);
6085
6086	ptr = kgem_bo_map__cpu(&sna->kgem, src_priv->gpu_bo);
6087	if (ptr == NULL) {
6088		DBG(("%s - no, map failed\n", __FUNCTION__));
6089		return false;
6090	}
6091
6092	if (dst_priv &&
6093	    !sna_drawable_move_region_to_cpu(&dst_pixmap->drawable,
6094					     region, MOVE_WRITE | MOVE_INPLACE_HINT)) {
6095		DBG(("%s - no, dst sync failed\n", __FUNCTION__));
6096		return false;
6097	}
6098
6099	kgem_bo_sync__cpu_full(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC);
6100
6101	box = region_rects(region);
6102	n = region_num_rects(region);
6103	if (src_priv->gpu_bo->tiling) {
6104		DBG(("%s: copy from a tiled CPU map\n", __FUNCTION__));
6105		assert(dst_pixmap->devKind);
6106		do {
6107			memcpy_from_tiled_x(&sna->kgem, ptr, dst_pixmap->devPrivate.ptr,
6108					    src_pixmap->drawable.bitsPerPixel,
6109					    src_priv->gpu_bo->pitch,
6110					    dst_pixmap->devKind,
6111					    box->x1 + dx, box->y1 + dy,
6112					    box->x1, box->y1,
6113					    box->x2 - box->x1, box->y2 - box->y1);
6114			box++;
6115		} while (--n);
6116	} else {
6117		DBG(("%s: copy from a linear CPU map\n", __FUNCTION__));
6118		assert(dst_pixmap->devKind);
6119		do {
6120			memcpy_blt(ptr, dst_pixmap->devPrivate.ptr,
6121				   src_pixmap->drawable.bitsPerPixel,
6122				   src_priv->gpu_bo->pitch,
6123				   dst_pixmap->devKind,
6124				   box->x1 + dx, box->y1 + dy,
6125				   box->x1, box->y1,
6126				   box->x2 - box->x1, box->y2 - box->y1);
6127			box++;
6128		} while (--n);
6129
6130		if (!src_priv->shm) {
6131			assert(ptr == MAP(src_priv->gpu_bo->map__cpu));
6132			src_pixmap->devPrivate.ptr = ptr;
6133			src_pixmap->devKind = src_priv->gpu_bo->pitch;
6134			src_priv->mapped = MAPPED_CPU;
6135			assert_pixmap_map(src_pixmap, src_priv);
6136			src_priv->cpu = true;
6137		}
6138	}
6139
6140	return true;
6141
6142upload_inplace:
6143	switch (dst_priv->gpu_bo->tiling) {
6144	case I915_TILING_Y:
6145		DBG(("%s - no, bad dst tiling [Y]\n", __FUNCTION__));
6146		return false;
6147	case I915_TILING_X:
6148		if (!sna->kgem.memcpy_to_tiled_x) {
6149			DBG(("%s - no, bad dst tiling [X]\n", __FUNCTION__));
6150			return false;
6151		}
6152	default:
6153		break;
6154	}
6155
6156	if (dst_priv->move_to_gpu) {
6157		DBG(("%s - no, pending dst move-to-gpu\n", __FUNCTION__));
6158		return false;
6159	}
6160
6161	if (!can_upload__tiled_x(&sna->kgem, dst_priv->gpu_bo) ||
6162	    __kgem_bo_is_busy(&sna->kgem, dst_priv->gpu_bo)) {
6163		if (replaces && !dst_priv->pinned) {
6164			unsigned create;
6165			struct kgem_bo *bo;
6166
6167			create = CREATE_CPU_MAP | CREATE_INACTIVE;
6168			if (dst_priv->gpu_bo->scanout)
6169				create |= CREATE_SCANOUT;
6170
6171			bo = kgem_create_2d(&sna->kgem,
6172					    dst_pixmap->drawable.width,
6173					    dst_pixmap->drawable.height,
6174					    dst_pixmap->drawable.bitsPerPixel,
6175					    dst_priv->gpu_bo->tiling,
6176					    create);
6177			if (bo == NULL)
6178				return false;
6179
6180			sna_pixmap_unmap(dst_pixmap, dst_priv);
6181			kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo);
6182			dst_priv->gpu_bo = bo;
6183		} else {
6184			DBG(("%s - no, dst is busy\n", __FUNCTION__));
6185			return false;
6186		}
6187
6188		if (!can_upload__tiled_x(&sna->kgem, dst_priv->gpu_bo)) {
6189			DBG(("%s - no, cannot map dst for reads into the CPU\n", __FUNCTION__));
6190			return false;
6191		}
6192	}
6193
6194	if (src_priv &&
6195	    !sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
6196					     region, MOVE_READ)) {
6197		DBG(("%s - no, src sync failed\n", __FUNCTION__));
6198		return false;
6199	}
6200
6201	if (kgem_bo_can_map__cpu(&sna->kgem, dst_priv->gpu_bo, true)) {
6202		ptr = kgem_bo_map__cpu(&sna->kgem, dst_priv->gpu_bo);
6203		if (ptr == NULL) {
6204			DBG(("%s - no, map failed\n", __FUNCTION__));
6205			return false;
6206		}
6207
6208		kgem_bo_sync__cpu(&sna->kgem, dst_priv->gpu_bo);
6209	} else {
6210		ptr = kgem_bo_map__wc(&sna->kgem, dst_priv->gpu_bo);
6211		if (ptr == NULL) {
6212			DBG(("%s - no, map failed\n", __FUNCTION__));
6213			return false;
6214		}
6215
6216		kgem_bo_sync__gtt(&sna->kgem, dst_priv->gpu_bo);
6217	}
6218
6219	if (!DAMAGE_IS_ALL(dst_priv->gpu_damage)) {
6220		assert(!dst_priv->clear);
6221		sna_damage_add_to_pixmap(&dst_priv->gpu_damage, region, dst_pixmap);
6222		if (sna_damage_is_all(&dst_priv->gpu_damage,
6223				      dst_pixmap->drawable.width,
6224				      dst_pixmap->drawable.height)) {
6225			DBG(("%s: replaced entire pixmap, destroying CPU shadow\n",
6226			     __FUNCTION__));
6227			sna_damage_destroy(&dst_priv->cpu_damage);
6228			list_del(&dst_priv->flush_list);
6229		} else
6230			sna_damage_subtract(&dst_priv->cpu_damage,
6231					    region);
6232	}
6233	dst_priv->clear = false;
6234
6235	assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
6236
6237	box = region_rects(region);
6238	n = region_num_rects(region);
6239	if (dst_priv->gpu_bo->tiling) {
6240		DBG(("%s: copy to a tiled CPU map\n", __FUNCTION__));
6241		assert(dst_priv->gpu_bo->tiling == I915_TILING_X);
6242		assert(src_pixmap->devKind);
6243		do {
6244			memcpy_to_tiled_x(&sna->kgem, src_pixmap->devPrivate.ptr, ptr,
6245					  src_pixmap->drawable.bitsPerPixel,
6246					  src_pixmap->devKind,
6247					  dst_priv->gpu_bo->pitch,
6248					  box->x1 + dx, box->y1 + dy,
6249					  box->x1, box->y1,
6250					  box->x2 - box->x1, box->y2 - box->y1);
6251			box++;
6252		} while (--n);
6253	} else {
6254		DBG(("%s: copy to a linear CPU map\n", __FUNCTION__));
6255		assert(src_pixmap->devKind);
6256		do {
6257			memcpy_blt(src_pixmap->devPrivate.ptr, ptr,
6258				   src_pixmap->drawable.bitsPerPixel,
6259				   src_pixmap->devKind,
6260				   dst_priv->gpu_bo->pitch,
6261				   box->x1 + dx, box->y1 + dy,
6262				   box->x1, box->y1,
6263				   box->x2 - box->x1, box->y2 - box->y1);
6264			box++;
6265		} while (--n);
6266
6267		if (!dst_priv->shm) {
6268			assert(ptr == MAP(dst_priv->gpu_bo->map__cpu));
6269			dst_pixmap->devPrivate.ptr = ptr;
6270			dst_pixmap->devKind = dst_priv->gpu_bo->pitch;
6271			dst_priv->mapped = MAPPED_CPU;
6272			assert_pixmap_map(dst_pixmap, dst_priv);
6273			dst_priv->cpu = true;
6274		}
6275	}
6276
6277	return true;
6278}
6279
6280static void discard_cpu_damage(struct sna *sna, struct sna_pixmap *priv)
6281{
6282	if (priv->cpu_damage == NULL && !priv->shm)
6283		return;
6284
6285	DBG(("%s: discarding existing CPU damage\n", __FUNCTION__));
6286
6287	if (kgem_bo_discard_cache(priv->gpu_bo, true)) {
6288		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
6289		assert(DAMAGE_IS_ALL(priv->cpu_damage));
6290		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */
6291		assert(!priv->pinned);
6292		assert(!priv->mapped);
6293		sna_damage_destroy(&priv->gpu_damage);
6294		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
6295		priv->gpu_bo = NULL;
6296	}
6297
6298	sna_damage_destroy(&priv->cpu_damage);
6299	list_del(&priv->flush_list);
6300
6301	if (priv->gpu_bo && sna_pixmap_free_cpu(sna, priv, priv->cpu))
6302		sna_damage_all(&priv->gpu_damage, priv->pixmap);
6303	priv->cpu = false;
6304}
6305
6306static void
6307sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
6308	       RegionPtr region, int dx, int dy,
6309	       Pixel bitplane, void *closure)
6310{
6311	PixmapPtr src_pixmap = get_drawable_pixmap(src);
6312	struct sna_pixmap *src_priv = sna_pixmap(src_pixmap);
6313	PixmapPtr dst_pixmap = get_drawable_pixmap(dst);
6314	struct sna_pixmap *dst_priv = sna_pixmap(dst_pixmap);
6315	struct sna *sna = to_sna_from_pixmap(src_pixmap);
6316	struct sna_damage **damage;
6317	struct kgem_bo *bo;
6318	int16_t src_dx, src_dy;
6319	int16_t dst_dx, dst_dy;
6320	const BoxRec *box = region_rects(region);
6321	int n = region_num_rects(region);
6322	int alu = gc->alu;
6323	int stride, bpp;
6324	char *bits;
6325	bool replaces;
6326
6327	assert(region_num_rects(region));
6328
6329	if (src_pixmap == dst_pixmap)
6330		return sna_self_copy_boxes(src, dst, gc,
6331					   region, dx, dy,
6332					   bitplane, closure);
6333
6334	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",
6335	     __FUNCTION__, n,
6336	     box[0].x1, box[0].y1, box[0].x2, box[0].y2,
6337	     src_pixmap->drawable.serialNumber, dx, dy,
6338	     dst_pixmap->drawable.serialNumber, get_drawable_dx(dst), get_drawable_dy(dst),
6339	     alu,
6340	     src_pixmap->drawable.width, src_pixmap->drawable.height,
6341	     dst_pixmap->drawable.width, dst_pixmap->drawable.height));
6342
6343	assert_pixmap_damage(dst_pixmap);
6344	assert_pixmap_damage(src_pixmap);
6345
6346	bpp = dst_pixmap->drawable.bitsPerPixel;
6347
6348	if (get_drawable_deltas(dst, dst_pixmap, &dst_dx, &dst_dy))
6349		RegionTranslate(region, dst_dx, dst_dy);
6350	get_drawable_deltas(src, src_pixmap, &src_dx, &src_dy);
6351	src_dx += dx - dst_dx;
6352	src_dy += dy - dst_dy;
6353
6354	assert_pixmap_contains_box(dst_pixmap, RegionExtents(region));
6355	assert_pixmap_contains_box_with_offset(src_pixmap,
6356					       RegionExtents(region),
6357					       src_dx, src_dy);
6358
6359	replaces = n == 1 &&
6360		alu_overwrites(alu) &&
6361		box->x1 <= 0 &&
6362		box->y1 <= 0 &&
6363		box->x2 >= dst_pixmap->drawable.width &&
6364		box->y2 >= dst_pixmap->drawable.height;
6365
6366	DBG(("%s: dst=(priv=%p, gpu_bo=%d, cpu_bo=%d), src=(priv=%p, gpu_bo=%d, cpu_bo=%d), replaces=%d\n",
6367	     __FUNCTION__,
6368	     dst_priv,
6369	     dst_priv && dst_priv->gpu_bo ? dst_priv->gpu_bo->handle : 0,
6370	     dst_priv && dst_priv->cpu_bo ? dst_priv->cpu_bo->handle : 0,
6371	     src_priv,
6372	     src_priv && src_priv->gpu_bo ? src_priv->gpu_bo->handle : 0,
6373	     src_priv && src_priv->cpu_bo ? src_priv->cpu_bo->handle : 0,
6374	     replaces));
6375
6376	if (dst_priv == NULL) {
6377		DBG(("%s: unattached dst failed, fallback\n", __FUNCTION__));
6378		goto fallback;
6379	}
6380
6381	if (alu == GXcopy &&
6382	    src_priv && src_priv->cow &&
6383	    COW(src_priv->cow) == COW(dst_priv->cow)) {
6384		if ((dx | dy) == 0) {
6385			DBG(("%s: ignoring cow for no op\n",
6386			     __FUNCTION__));
6387			return;
6388		} else if (IS_COW_OWNER(dst_priv->cow)) {
6389			/* XXX hack for firefox -- subsequent uses of src will be corrupt! */
6390			DBG(("%s: ignoring cow reference for cousin copy\n",
6391			     __FUNCTION__));
6392			assert(src_priv->cpu_damage == NULL);
6393			assert(dst_priv->move_to_gpu == NULL);
6394			bo = dst_priv->gpu_bo;
6395			damage = NULL;
6396		} else
6397			goto discard_cow;
6398	} else {
6399		unsigned hint;
6400discard_cow:
6401		hint = copy_prefer_gpu(sna, dst_priv, src_priv, region, src_dx, src_dy);
6402		if (replaces) {
6403			discard_cpu_damage(sna, dst_priv);
6404			hint |= REPLACES | IGNORE_DAMAGE;
6405		} else if (alu_overwrites(alu)) {
6406			if (region->data == NULL)
6407				hint |= IGNORE_DAMAGE;
6408			if (dst_priv->cpu_damage &&
6409			    region_subsumes_damage(region,
6410						   dst_priv->cpu_damage))
6411				discard_cpu_damage(sna, dst_priv);
6412		}
6413		bo = sna_drawable_use_bo(&dst_pixmap->drawable, hint,
6414					 &region->extents, &damage);
6415	}
6416	if (bo) {
6417		if (alu == GXset || alu == GXclear || (src_priv && src_priv->clear)) {
6418			uint32_t color;
6419
6420			if (alu == GXset)
6421				color = (1 << dst_pixmap->drawable.depth) - 1;
6422			else if (alu == GXclear)
6423				color = 0;
6424			else
6425				color = src_priv->clear_color;
6426			DBG(("%s: applying src clear [%08x] to dst\n",
6427			     __FUNCTION__, src_priv->clear_color));
6428
6429			if (n == 1) {
6430				if (replaces && UNDO)
6431					kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
6432
6433				if (!sna->render.fill_one(sna,
6434							  dst_pixmap, bo, color,
6435							  box->x1, box->y1,
6436							  box->x2, box->y2,
6437							  alu)) {
6438					DBG(("%s: unsupported fill\n",
6439					     __FUNCTION__));
6440					goto fallback;
6441				}
6442
6443				if (replaces && bo == dst_priv->gpu_bo) {
6444					DBG(("%s: marking dst handle=%d as all clear [%08x]\n",
6445					     __FUNCTION__,
6446					     dst_priv->gpu_bo->handle,
6447					     src_priv->clear_color));
6448					dst_priv->clear = true;
6449					dst_priv->clear_color = color;
6450					sna_damage_all(&dst_priv->gpu_damage, dst_pixmap);
6451					sna_damage_destroy(&dst_priv->cpu_damage);
6452					list_del(&dst_priv->flush_list);
6453					return;
6454				}
6455			} else {
6456				struct sna_fill_op fill;
6457
6458				if (!sna_fill_init_blt(&fill, sna,
6459						       dst_pixmap, bo,
6460						       alu, color,
6461						       FILL_BOXES)) {
6462					DBG(("%s: unsupported fill\n",
6463					     __FUNCTION__));
6464					goto fallback;
6465				}
6466
6467				fill.boxes(sna, &fill, box, n);
6468				fill.done(sna, &fill);
6469			}
6470
6471			if (damage)
6472				sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6473			return;
6474		}
6475
6476		if (src_priv &&
6477		    move_to_gpu(src_pixmap, src_priv, region, src_dx, src_dy, alu, bo == dst_priv->gpu_bo) &&
6478		    sna_pixmap_move_to_gpu(src_pixmap, MOVE_READ | MOVE_ASYNC_HINT)) {
6479			DBG(("%s: move whole src_pixmap to GPU and copy\n",
6480			     __FUNCTION__));
6481			if (replaces && UNDO)
6482				kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
6483
6484			if (replaces &&
6485			    src_pixmap->drawable.width == dst_pixmap->drawable.width &&
6486			    src_pixmap->drawable.height == dst_pixmap->drawable.height) {
6487				assert(src_pixmap->drawable.depth == dst_pixmap->drawable.depth);
6488				assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel);
6489				if (sna_pixmap_make_cow(sna, src_priv, dst_priv)) {
6490					assert(dst_priv->gpu_bo == src_priv->gpu_bo);
6491					sna_damage_all(&dst_priv->gpu_damage, dst_pixmap);
6492					sna_damage_destroy(&dst_priv->cpu_damage);
6493					list_del(&dst_priv->flush_list);
6494					if (dst_priv->shm)
6495						sna_add_flush_pixmap(sna, dst_priv, dst_priv->cpu_bo);
6496					return;
6497				}
6498			}
6499			if (!sna->render.copy_boxes(sna, alu,
6500						    &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy,
6501						    &dst_pixmap->drawable, bo, 0, 0,
6502						    box, n, 0)) {
6503				DBG(("%s: fallback - accelerated copy boxes failed\n",
6504				     __FUNCTION__));
6505				goto fallback;
6506			}
6507
6508			if (damage)
6509				sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6510			return;
6511		}
6512
6513		if (src_priv &&
6514		    region_overlaps_damage(region, src_priv->gpu_damage,
6515					   src_dx, src_dy)) {
6516			BoxRec area;
6517
6518			DBG(("%s: region overlaps GPU damage, upload and copy\n",
6519			     __FUNCTION__));
6520
6521			area = region->extents;
6522			area.x1 += src_dx;
6523			area.x2 += src_dx;
6524			area.y1 += src_dy;
6525			area.y2 += src_dy;
6526
6527			if (!sna_pixmap_move_area_to_gpu(src_pixmap, &area,
6528							 MOVE_READ | MOVE_ASYNC_HINT)) {
6529				DBG(("%s: move-to-gpu(src) failed, fallback\n", __FUNCTION__));
6530				goto fallback;
6531			}
6532
6533			if (replaces && UNDO)
6534				kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
6535
6536			if (!sna->render.copy_boxes(sna, alu,
6537						    &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy,
6538						    &dst_pixmap->drawable, bo, 0, 0,
6539						    box, n, 0)) {
6540				DBG(("%s: fallback - accelerated copy boxes failed\n",
6541				     __FUNCTION__));
6542				goto fallback;
6543			}
6544
6545			if (damage)
6546				sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6547			return;
6548		}
6549
6550		if (bo != dst_priv->gpu_bo)
6551			goto fallback;
6552
6553		if (use_shm_bo(sna, bo, src_priv, alu, replaces && !dst_priv->pinned)) {
6554			bool ret;
6555
6556			DBG(("%s: region overlaps CPU damage, copy from CPU bo (shm? %d)\n",
6557			     __FUNCTION__, src_priv->shm));
6558
6559			assert(bo != dst_priv->cpu_bo);
6560
6561			RegionTranslate(region, src_dx, src_dy);
6562			ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
6563							      region,
6564							      MOVE_READ | MOVE_ASYNC_HINT);
6565			RegionTranslate(region, -src_dx, -src_dy);
6566			if (!ret) {
6567				DBG(("%s: move-to-cpu(src) failed, fallback\n", __FUNCTION__));
6568				goto fallback;
6569			}
6570
6571			if (replaces && UNDO)
6572				kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
6573
6574			if (src_priv->shm) {
6575				assert(!src_priv->flush);
6576				sna_add_flush_pixmap(sna, src_priv, src_priv->cpu_bo);
6577			}
6578
6579			if (!sna->render.copy_boxes(sna, alu,
6580						    &src_pixmap->drawable, src_priv->cpu_bo, src_dx, src_dy,
6581						    &dst_pixmap->drawable, bo, 0, 0,
6582						    box, n, src_priv->shm ? COPY_LAST : 0)) {
6583				DBG(("%s: fallback - accelerated copy boxes failed\n",
6584				     __FUNCTION__));
6585				goto fallback;
6586			}
6587
6588			if (damage)
6589				sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6590			return;
6591		}
6592
6593		if (src_priv) {
6594			bool ret;
6595
6596			RegionTranslate(region, src_dx, src_dy);
6597			ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
6598							      region, MOVE_READ);
6599			RegionTranslate(region, -src_dx, -src_dy);
6600			if (!ret) {
6601				DBG(("%s: move-to-cpu(src) failed, fallback\n", __FUNCTION__));
6602				goto fallback;
6603			}
6604
6605			assert(!src_priv->mapped);
6606			if (src_pixmap->devPrivate.ptr == NULL)
6607				/* uninitialised!*/
6608				return;
6609		}
6610
6611		if (USE_USERPTR_UPLOADS &&
6612		    sna->kgem.has_userptr &&
6613		    (alu != GXcopy ||
6614		     (box_inplace(src_pixmap, &region->extents) &&
6615		      __kgem_bo_is_busy(&sna->kgem, bo)))) {
6616			struct kgem_bo *src_bo;
6617			bool ok = false;
6618
6619			DBG(("%s: upload through a temporary map\n",
6620			     __FUNCTION__));
6621
6622			assert(src_pixmap->devKind);
6623			src_bo = kgem_create_map(&sna->kgem,
6624						 src_pixmap->devPrivate.ptr,
6625						 src_pixmap->devKind * src_pixmap->drawable.height,
6626						 true);
6627			if (src_bo) {
6628				src_bo->pitch = src_pixmap->devKind;
6629				kgem_bo_mark_unreusable(src_bo);
6630
6631				ok = sna->render.copy_boxes(sna, alu,
6632							    &src_pixmap->drawable, src_bo, src_dx, src_dy,
6633							    &dst_pixmap->drawable, bo, 0, 0,
6634							    box, n, COPY_LAST);
6635
6636				kgem_bo_sync__cpu(&sna->kgem, src_bo);
6637				assert(src_bo->rq == NULL);
6638				kgem_bo_destroy(&sna->kgem, src_bo);
6639			}
6640
6641			if (ok) {
6642				if (damage)
6643					sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6644				return;
6645			}
6646		}
6647
6648		if (alu != GXcopy) {
6649			PixmapPtr tmp;
6650			struct kgem_bo *src_bo;
6651			int i;
6652
6653			assert(src_pixmap->drawable.depth != 1);
6654
6655			DBG(("%s: creating temporary source upload for non-copy alu [%d]\n",
6656			     __FUNCTION__, alu));
6657
6658			tmp = sna_pixmap_create_upload(src->pScreen,
6659						       region->extents.x2 - region->extents.x1,
6660						       region->extents.y2 - region->extents.y1,
6661						       src->depth,
6662						       KGEM_BUFFER_WRITE_INPLACE);
6663			if (tmp == NullPixmap)
6664				return;
6665
6666			src_bo = __sna_pixmap_get_bo(tmp);
6667			assert(src_bo != NULL);
6668
6669			dx = -region->extents.x1;
6670			dy = -region->extents.y1;
6671			for (i = 0; i < n; i++) {
6672				assert(box[i].x1 + src_dx >= 0);
6673				assert(box[i].y1 + src_dy >= 0);
6674				assert(box[i].x2 + src_dx <= src_pixmap->drawable.width);
6675				assert(box[i].y2 + src_dy <= src_pixmap->drawable.height);
6676
6677				assert(box[i].x1 + dx >= 0);
6678				assert(box[i].y1 + dy >= 0);
6679				assert(box[i].x2 + dx <= tmp->drawable.width);
6680				assert(box[i].y2 + dy <= tmp->drawable.height);
6681
6682				assert(has_coherent_ptr(sna, sna_pixmap(src_pixmap), MOVE_READ));
6683				assert(has_coherent_ptr(sna, sna_pixmap(tmp), MOVE_WRITE));
6684				assert(src_pixmap->devKind);
6685				assert(tmp->devKind);
6686				memcpy_blt(src_pixmap->devPrivate.ptr,
6687					   tmp->devPrivate.ptr,
6688					   src_pixmap->drawable.bitsPerPixel,
6689					   src_pixmap->devKind,
6690					   tmp->devKind,
6691					   box[i].x1 + src_dx,
6692					   box[i].y1 + src_dy,
6693					   box[i].x1 + dx,
6694					   box[i].y1 + dy,
6695					   box[i].x2 - box[i].x1,
6696					   box[i].y2 - box[i].y1);
6697			}
6698
6699			if (n == 1 &&
6700			    tmp->drawable.width == src_pixmap->drawable.width &&
6701			    tmp->drawable.height == src_pixmap->drawable.height) {
6702				DBG(("%s: caching upload for src bo\n",
6703				     __FUNCTION__));
6704				assert(src_priv->gpu_damage == NULL);
6705				assert(src_priv->gpu_bo == NULL);
6706				kgem_proxy_bo_attach(src_bo, &src_priv->gpu_bo);
6707			}
6708
6709			if (!sna->render.copy_boxes(sna, alu,
6710						    &tmp->drawable, src_bo, dx, dy,
6711						    &dst_pixmap->drawable, bo, 0, 0,
6712						    box, n, 0)) {
6713				DBG(("%s: fallback - accelerated copy boxes failed\n",
6714				     __FUNCTION__));
6715				tmp->drawable.pScreen->DestroyPixmap(tmp);
6716				goto fallback;
6717			}
6718			tmp->drawable.pScreen->DestroyPixmap(tmp);
6719
6720			if (damage)
6721				sna_damage_add_to_pixmap(damage, region, dst_pixmap);
6722			return;
6723		} else {
6724			DBG(("%s: dst is on the GPU, src is on the CPU, uploading into dst\n",
6725			     __FUNCTION__));
6726
6727			assert(src_pixmap->devKind);
6728			if (!dst_priv->pinned && replaces) {
6729				stride = src_pixmap->devKind;
6730				bits = src_pixmap->devPrivate.ptr;
6731				bits += (src_dy + box->y1) * stride + (src_dx + box->x1) * bpp / 8;
6732
6733				if (!sna_replace(sna, dst_pixmap, bits, stride)) {
6734					DBG(("%s: replace failed, fallback\n", __FUNCTION__));
6735					goto fallback;
6736				}
6737			} else {
6738				assert(!DAMAGE_IS_ALL(dst_priv->cpu_damage));
6739				if (!sna_write_boxes(sna, dst_pixmap,
6740						     dst_priv->gpu_bo, 0, 0,
6741						     src_pixmap->devPrivate.ptr,
6742						     src_pixmap->devKind,
6743						     src_dx, src_dy,
6744						     box, n)) {
6745					DBG(("%s: write failed, fallback\n", __FUNCTION__));
6746					goto fallback;
6747				}
6748			}
6749
6750			assert(dst_priv->clear == false);
6751			dst_priv->cpu = false;
6752			if (damage) {
6753				assert(!dst_priv->clear);
6754				assert(dst_priv->gpu_bo);
6755				assert(dst_priv->gpu_bo->proxy == NULL);
6756				assert(*damage == dst_priv->gpu_damage);
6757				if (replaces) {
6758					sna_damage_destroy(&dst_priv->cpu_damage);
6759					sna_damage_all(&dst_priv->gpu_damage, dst_pixmap);
6760					list_del(&dst_priv->flush_list);
6761				} else
6762					sna_damage_add(&dst_priv->gpu_damage,
6763						       region);
6764				assert_pixmap_damage(dst_pixmap);
6765			}
6766		}
6767
6768		return;
6769	}
6770
6771fallback:
6772	if (alu == GXcopy && src_priv && src_priv->clear) {
6773		DBG(("%s: copying clear [%08x]\n",
6774		     __FUNCTION__, src_priv->clear_color));
6775
6776		if (dst_priv) {
6777			if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable,
6778							     region,
6779							     MOVE_WRITE | MOVE_INPLACE_HINT))
6780				return;
6781		}
6782
6783		assert(dst_pixmap->devPrivate.ptr);
6784		assert(dst_pixmap->devKind);
6785		do {
6786			pixman_fill(dst_pixmap->devPrivate.ptr,
6787				    dst_pixmap->devKind/sizeof(uint32_t),
6788				    dst_pixmap->drawable.bitsPerPixel,
6789				    box->x1, box->y1,
6790				    box->x2 - box->x1,
6791				    box->y2 - box->y1,
6792				    src_priv->clear_color);
6793			box++;
6794		} while (--n);
6795	} else if (!sna_copy_boxes__inplace(sna, region, alu,
6796					    src_pixmap, src_priv,
6797					    src_dx, src_dy,
6798					    dst_pixmap, dst_priv,
6799					    replaces)) {
6800		FbBits *dst_bits, *src_bits;
6801		int dst_stride, src_stride;
6802
6803		DBG(("%s: fallback -- src=(%d, %d), dst=(%d, %d)\n",
6804		     __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy));
6805		if (src_priv) {
6806			unsigned mode;
6807
6808			RegionTranslate(region, src_dx, src_dy);
6809
6810			assert_pixmap_contains_box(src_pixmap,
6811						   RegionExtents(region));
6812
6813			mode = MOVE_READ;
6814			if (!sna->kgem.can_blt_cpu ||
6815			    (src_priv->cpu_bo == NULL &&
6816			     (src_priv->create & KGEM_CAN_CREATE_CPU) == 0))
6817				mode |= MOVE_INPLACE_HINT;
6818
6819			if (!sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
6820							     region, mode))
6821				return;
6822
6823			RegionTranslate(region, -src_dx, -src_dy);
6824		}
6825		assert(src_priv == sna_pixmap(src_pixmap));
6826
6827		if (dst_priv) {
6828			unsigned mode;
6829
6830			if (alu_overwrites(alu))
6831				mode = MOVE_WRITE | MOVE_INPLACE_HINT;
6832			else
6833				mode = MOVE_WRITE | MOVE_READ;
6834			if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable,
6835							     region, mode))
6836				return;
6837		}
6838		assert(dst_priv == sna_pixmap(dst_pixmap));
6839
6840		assert(dst_pixmap->devKind);
6841		assert(src_pixmap->devKind);
6842		dst_stride = dst_pixmap->devKind;
6843		src_stride = src_pixmap->devKind;
6844
6845		if (alu == GXcopy && bpp >= 8) {
6846			dst_bits = (FbBits *)dst_pixmap->devPrivate.ptr;
6847			src_bits = (FbBits *)
6848				((char *)src_pixmap->devPrivate.ptr +
6849				 src_dy * src_stride + src_dx * bpp / 8);
6850
6851			do {
6852				DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n",
6853				     __FUNCTION__,
6854				     box->x1, box->y1,
6855				     box->x2 - box->x1,
6856				     box->y2 - box->y1,
6857				     src_dx, src_dy,
6858				     src_stride, dst_stride));
6859
6860				assert(box->x1 >= 0);
6861				assert(box->y1 >= 0);
6862				assert(box->x2 <= dst_pixmap->drawable.width);
6863				assert(box->y2 <= dst_pixmap->drawable.height);
6864
6865				assert(box->x1 + src_dx >= 0);
6866				assert(box->y1 + src_dy >= 0);
6867				assert(box->x2 + src_dx <= src_pixmap->drawable.width);
6868				assert(box->y2 + src_dy <= src_pixmap->drawable.height);
6869				assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
6870				assert(has_coherent_ptr(sna, dst_priv, MOVE_WRITE));
6871				assert(src_stride);
6872				assert(dst_stride);
6873				memcpy_blt(src_bits, dst_bits, bpp,
6874					   src_stride, dst_stride,
6875					   box->x1, box->y1,
6876					   box->x1, box->y1,
6877					   box->x2 - box->x1,
6878					   box->y2 - box->y1);
6879				box++;
6880			} while (--n);
6881		} else {
6882			DBG(("%s: fallback -- miCopyRegion\n", __FUNCTION__));
6883
6884			RegionTranslate(region, -dst_dx, -dst_dy);
6885
6886			if (sna_gc_move_to_cpu(gc, dst, region) &&
6887			    sigtrap_get() == 0) {
6888				miCopyRegion(src, dst, gc,
6889					     region, dx, dy,
6890					     fbCopyNtoN, 0, NULL);
6891				sigtrap_put();
6892			}
6893
6894			sna_gc_move_to_gpu(gc);
6895		}
6896	}
6897}
6898
6899typedef void (*sna_copy_func)(DrawablePtr src, DrawablePtr dst, GCPtr gc,
6900			      RegionPtr region, int dx, int dy,
6901			      Pixel bitPlane, void *closure);
6902
6903static inline bool box_equal(const BoxRec *a, const BoxRec *b)
6904{
6905	return *(const uint64_t *)a == *(const uint64_t *)b;
6906}
6907
6908static inline bool has_clip(GCPtr gc)
6909{
6910#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0)
6911	return gc->clientClipType != CT_NONE;
6912#else
6913	return gc->clientClip != NULL;
6914#endif
6915}
6916
6917static RegionPtr
6918sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc,
6919	    int sx, int sy,
6920	    int width, int height,
6921	    int dx, int dy,
6922	    sna_copy_func copy, Pixel bitPlane, void *closure)
6923{
6924	RegionPtr clip;
6925	RegionRec region;
6926	BoxRec src_extents;
6927	bool expose;
6928
6929	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n",
6930	     __FUNCTION__, sx, sy, dx, dy, width, height));
6931
6932	/* Short cut for unmapped windows */
6933	if (dst->type == DRAWABLE_WINDOW && !((WindowPtr)dst)->realized) {
6934		DBG(("%s: unmapped\n", __FUNCTION__));
6935		return NULL;
6936	}
6937
6938	SourceValidate(src, sx, sy, width, height, gc->subWindowMode);
6939
6940	sx += src->x;
6941	sy += src->y;
6942
6943	dx += dst->x;
6944	dy += dst->y;
6945
6946	DBG(("%s: after drawable: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n",
6947	     __FUNCTION__, sx, sy, dx, dy, width, height));
6948
6949	region.extents.x1 = dx;
6950	region.extents.y1 = dy;
6951	region.extents.x2 = bound(dx, width);
6952	region.extents.y2 = bound(dy, height);
6953	region.data = NULL;
6954
6955	DBG(("%s: dst extents (%d, %d), (%d, %d), dst clip extents (%d, %d), (%d, %d), dst size=%dx%d\n", __FUNCTION__,
6956	     region.extents.x1, region.extents.y1,
6957	     region.extents.x2, region.extents.y2,
6958	     gc->pCompositeClip->extents.x1, gc->pCompositeClip->extents.y1,
6959	     gc->pCompositeClip->extents.x2, gc->pCompositeClip->extents.y2,
6960	     dst->width, dst->height));
6961
6962	if (!box_intersect(&region.extents, &gc->pCompositeClip->extents)) {
6963		DBG(("%s: dst clipped out\n", __FUNCTION__));
6964		return NULL;
6965	}
6966
6967	DBG(("%s: clipped dst extents (%d, %d), (%d, %d)\n", __FUNCTION__,
6968	     region.extents.x1, region.extents.y1,
6969	     region.extents.x2, region.extents.y2));
6970	assert_drawable_contains_box(dst, &region.extents);
6971
6972	region.extents.x1 = clamp(region.extents.x1, sx - dx);
6973	region.extents.x2 = clamp(region.extents.x2, sx - dx);
6974	region.extents.y1 = clamp(region.extents.y1, sy - dy);
6975	region.extents.y2 = clamp(region.extents.y2, sy - dy);
6976
6977	src_extents = region.extents;
6978	expose = true;
6979
6980	DBG(("%s: unclipped src extents (%d, %d), (%d, %d)\n", __FUNCTION__,
6981	     region.extents.x1, region.extents.y1,
6982	     region.extents.x2, region.extents.y2));
6983
6984	if (region.extents.x1 < src->x)
6985		region.extents.x1 = src->x;
6986	if (region.extents.y1 < src->y)
6987		region.extents.y1 = src->y;
6988	if (region.extents.x2 > src->x + (int) src->width)
6989		region.extents.x2 = src->x + (int) src->width;
6990	if (region.extents.y2 > src->y + (int) src->height)
6991		region.extents.y2 = src->y + (int) src->height;
6992
6993	DBG(("%s: clipped src extents (%d, %d), (%d, %d)\n", __FUNCTION__,
6994	     region.extents.x1, region.extents.y1,
6995	     region.extents.x2, region.extents.y2));
6996	if (box_empty(&region.extents)) {
6997		DBG(("%s: src clipped out\n", __FUNCTION__));
6998		return NULL;
6999	}
7000
7001	/* Compute source clip region */
7002	if (src->type == DRAWABLE_PIXMAP) {
7003		if (src == dst && !has_clip(gc)) {
7004			DBG(("%s: pixmap -- using gc clip\n", __FUNCTION__));
7005			clip = gc->pCompositeClip;
7006		} else {
7007			DBG(("%s: pixmap -- no source clipping\n", __FUNCTION__));
7008			expose = false;
7009			clip = NULL;
7010		}
7011	} else {
7012		WindowPtr w = (WindowPtr)src;
7013		if (gc->subWindowMode == IncludeInferiors) {
7014			DBG(("%s: window -- include inferiors\n", __FUNCTION__));
7015
7016			if (w->winSize.data)
7017				RegionIntersect(&region, &region, &w->winSize);
7018			else
7019				box_intersect(&region.extents, &w->winSize.extents);
7020			clip = &w->borderClip;
7021		} else {
7022			DBG(("%s: window -- clip by children\n", __FUNCTION__));
7023			clip = &w->clipList;
7024		}
7025	}
7026	if (clip != NULL) {
7027		if (clip->data == NULL) {
7028			box_intersect(&region.extents, &clip->extents);
7029			if (box_equal(&src_extents, &region.extents))
7030				expose = false;
7031		} else
7032			RegionIntersect(&region, &region, clip);
7033	}
7034	DBG(("%s: src extents (%d, %d), (%d, %d) x %d\n", __FUNCTION__,
7035	     region.extents.x1, region.extents.y1,
7036	     region.extents.x2, region.extents.y2,
7037	     region_num_rects(&region)));
7038
7039	RegionTranslate(&region, dx-sx, dy-sy);
7040	if (gc->pCompositeClip->data)
7041		RegionIntersect(&region, &region, gc->pCompositeClip);
7042	DBG(("%s: copy region (%d, %d), (%d, %d) x %d + (%d, %d)\n",
7043	     __FUNCTION__,
7044	     region.extents.x1, region.extents.y1,
7045	     region.extents.x2, region.extents.y2,
7046	     region_num_rects(&region),
7047	     sx-dx, sy-dy));
7048
7049	if (!box_empty(&region.extents))
7050		copy(src, dst, gc, &region, sx-dx, sy-dy, bitPlane, closure);
7051	assert(gc->pCompositeClip != &region);
7052	RegionUninit(&region);
7053
7054	/* Pixmap sources generate a NoExposed (we return NULL to do this) */
7055	clip = NULL;
7056	if (expose && gc->fExpose)
7057		clip = miHandleExposures(src, dst, gc,
7058					 sx - src->x, sy - src->y,
7059					 width, height,
7060					 dx - dst->x, dy - dst->y,
7061					 (unsigned long) bitPlane);
7062	return clip;
7063}
7064
7065static void
7066sna_fallback_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
7067			RegionPtr region, int dx, int dy,
7068			Pixel bitplane, void *closure)
7069{
7070	DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d\n",
7071	     __FUNCTION__, region_num_rects(region),
7072	     region->extents.x1, region->extents.y1,
7073	     region->extents.x2, region->extents.y2,
7074	     dx, dy, gc->alu));
7075
7076	if (!sna_gc_move_to_cpu(gc, dst, region))
7077		goto out;
7078
7079	RegionTranslate(region, dx, dy);
7080	if (!sna_drawable_move_region_to_cpu(src, region, MOVE_READ))
7081		goto out;
7082	RegionTranslate(region, -dx, -dy);
7083
7084	if (src == dst ||
7085	    get_drawable_pixmap(src) == get_drawable_pixmap(dst)) {
7086		DBG(("%s: self-copy\n", __FUNCTION__));
7087		if (!sna_drawable_move_to_cpu(dst, MOVE_WRITE | MOVE_READ))
7088			goto out;
7089	} else {
7090		if (!sna_drawable_move_region_to_cpu(dst, region,
7091						     drawable_gc_flags(dst, gc, false)))
7092			goto out;
7093	}
7094
7095	if (sigtrap_get() == 0) {
7096		miCopyRegion(src, dst, gc,
7097			     region, dx, dy,
7098			     fbCopyNtoN, 0, NULL);
7099		FALLBACK_FLUSH(dst);
7100		sigtrap_put();
7101	}
7102out:
7103	sna_gc_move_to_gpu(gc);
7104}
7105
7106static RegionPtr
7107sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
7108	      int src_x, int src_y,
7109	      int width, int height,
7110	      int dst_x, int dst_y)
7111{
7112	struct sna *sna = to_sna_from_drawable(dst);
7113	sna_copy_func copy;
7114
7115	if (gc->planemask == 0)
7116		return NULL;
7117
7118	DBG(("%s: src=(%d, %d)x(%d, %d)+(%d, %d) -> dst=(%d, %d)+(%d, %d); alu=%d, pm=%lx, depth=%d\n",
7119	     __FUNCTION__,
7120	     src_x, src_y, width, height, src->x, src->y,
7121	     dst_x, dst_y, dst->x, dst->y,
7122	     gc->alu, gc->planemask, gc->depth));
7123
7124	if (FORCE_FALLBACK || !ACCEL_COPY_AREA || wedged(sna) ||
7125	    !PM_IS_SOLID(dst, gc->planemask) || gc->depth < 8)
7126		copy = sna_fallback_copy_boxes;
7127	else if (src == dst)
7128		copy = sna_self_copy_boxes;
7129	else
7130		copy = sna_copy_boxes;
7131
7132	return sna_do_copy(src, dst, gc,
7133			   src_x, src_y,
7134			   width, height,
7135			   dst_x, dst_y,
7136			   copy, 0, NULL);
7137}
7138
7139static const BoxRec *
7140find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y)
7141{
7142    const BoxRec *mid;
7143
7144    if (end == begin)
7145	return end;
7146
7147    if (end - begin == 1) {
7148	if (begin->y2 > y)
7149	    return begin;
7150	else
7151	    return end;
7152    }
7153
7154    mid = begin + (end - begin) / 2;
7155    if (mid->y2 > y)
7156	/* If no box is found in [begin, mid], the function
7157	 * will return @mid, which is then known to be the
7158	 * correct answer.
7159	 */
7160	return find_clip_box_for_y(begin, mid, y);
7161    else
7162	return find_clip_box_for_y(mid, end, y);
7163}
7164
7165struct sna_fill_spans {
7166	struct sna *sna;
7167	PixmapPtr pixmap;
7168	RegionRec region;
7169	unsigned flags;
7170	uint32_t phase;
7171	struct kgem_bo *bo;
7172	struct sna_damage **damage;
7173	int16_t dx, dy;
7174	void *op;
7175};
7176
7177static void
7178sna_poly_point__cpu(DrawablePtr drawable, GCPtr gc,
7179		    int mode, int n, DDXPointPtr pt)
7180{
7181	fbPolyPoint(drawable, gc, mode, n, pt, -1);
7182}
7183
7184static void
7185sna_poly_point__fill(DrawablePtr drawable, GCPtr gc,
7186		     int mode, int n, DDXPointPtr pt)
7187{
7188	struct sna_fill_spans *data = sna_gc(gc)->priv;
7189	struct sna_fill_op *op = data->op;
7190	BoxRec box[512];
7191	DDXPointRec last;
7192
7193	DBG(("%s: count=%d\n", __FUNCTION__, n));
7194	if (n == 0)
7195		return;
7196
7197	last.x = drawable->x + data->dx;
7198	last.y = drawable->y + data->dy;
7199	if (op->points && mode != CoordModePrevious) {
7200		op->points(data->sna, op, last.x, last.y, pt, n);
7201	} else do {
7202		BoxRec *b = box;
7203		unsigned nbox = n;
7204		if (nbox > ARRAY_SIZE(box))
7205			nbox = ARRAY_SIZE(box);
7206		n -= nbox;
7207		do {
7208			*(DDXPointRec *)b = *pt++;
7209
7210			b->x1 += last.x;
7211			b->y1 += last.y;
7212			if (mode == CoordModePrevious)
7213				last = *(DDXPointRec *)b;
7214
7215			b->x2 = b->x1 + 1;
7216			b->y2 = b->y1 + 1;
7217			b++;
7218		} while (--nbox);
7219		op->boxes(data->sna, op, box, b - box);
7220	} while (n);
7221}
7222
7223static void
7224sna_poly_point__gpu(DrawablePtr drawable, GCPtr gc,
7225		     int mode, int n, DDXPointPtr pt)
7226{
7227	struct sna_fill_spans *data = sna_gc(gc)->priv;
7228	struct sna_fill_op fill;
7229	BoxRec box[512];
7230	DDXPointRec last;
7231
7232	if (!sna_fill_init_blt(&fill,
7233			       data->sna, data->pixmap,
7234			       data->bo, gc->alu, gc->fgPixel,
7235			       FILL_POINTS))
7236		return;
7237
7238	DBG(("%s: count=%d\n", __FUNCTION__, n));
7239
7240	last.x = drawable->x;
7241	last.y = drawable->y;
7242	while (n) {
7243		BoxRec *b = box;
7244		unsigned nbox = n;
7245		if (nbox > ARRAY_SIZE(box))
7246			nbox = ARRAY_SIZE(box);
7247		n -= nbox;
7248		do {
7249			*(DDXPointRec *)b = *pt++;
7250
7251			b->x1 += last.x;
7252			b->y1 += last.y;
7253			if (mode == CoordModePrevious)
7254				last = *(DDXPointRec *)b;
7255
7256			if (RegionContainsPoint(&data->region,
7257						b->x1, b->y1, NULL)) {
7258				b->x1 += data->dx;
7259				b->y1 += data->dy;
7260				b->x2 = b->x1 + 1;
7261				b->y2 = b->y1 + 1;
7262				b++;
7263			}
7264		} while (--nbox);
7265		if (b != box)
7266			fill.boxes(data->sna, &fill, box, b - box);
7267	}
7268	fill.done(data->sna, &fill);
7269}
7270
7271static void
7272sna_poly_point__fill_clip_extents(DrawablePtr drawable, GCPtr gc,
7273				  int mode, int n, DDXPointPtr pt)
7274{
7275	struct sna_fill_spans *data = sna_gc(gc)->priv;
7276	struct sna_fill_op *op = data->op;
7277	const BoxRec *extents = &data->region.extents;
7278	BoxRec box[512], *b = box;
7279	const BoxRec *const last_box = b + ARRAY_SIZE(box);
7280	DDXPointRec last;
7281
7282	DBG(("%s: count=%d\n", __FUNCTION__, n));
7283
7284	last.x = drawable->x + data->dx;
7285	last.y = drawable->y + data->dy;
7286	while (n--) {
7287		*(DDXPointRec *)b = *pt++;
7288
7289		b->x1 += last.x;
7290		b->y1 += last.y;
7291		if (mode == CoordModePrevious)
7292			last = *(DDXPointRec *)b;
7293
7294		if (b->x1 >= extents->x1 && b->x1 < extents->x2 &&
7295		    b->y1 >= extents->y1 && b->y1 < extents->y2) {
7296			b->x2 = b->x1 + 1;
7297			b->y2 = b->y1 + 1;
7298			if (++b == last_box) {
7299				op->boxes(data->sna, op, box, last_box - box);
7300				b = box;
7301			}
7302		}
7303	}
7304	if (b != box)
7305		op->boxes(data->sna, op, box, b - box);
7306}
7307
7308static void
7309sna_poly_point__fill_clip_boxes(DrawablePtr drawable, GCPtr gc,
7310				int mode, int n, DDXPointPtr pt)
7311{
7312	struct sna_fill_spans *data = sna_gc(gc)->priv;
7313	struct sna_fill_op *op = data->op;
7314	RegionRec *clip = &data->region;
7315	BoxRec box[512], *b = box;
7316	const BoxRec *const last_box = b + ARRAY_SIZE(box);
7317	DDXPointRec last;
7318
7319	DBG(("%s: count=%d\n", __FUNCTION__, n));
7320
7321	last.x = drawable->x + data->dx;
7322	last.y = drawable->y + data->dy;
7323	while (n--) {
7324		*(DDXPointRec *)b = *pt++;
7325
7326		b->x1 += last.x;
7327		b->y1 += last.y;
7328		if (mode == CoordModePrevious)
7329			last = *(DDXPointRec *)b;
7330
7331		if (RegionContainsPoint(clip, b->x1, b->y1, NULL)) {
7332			b->x2 = b->x1 + 1;
7333			b->y2 = b->y1 + 1;
7334			if (++b == last_box) {
7335				op->boxes(data->sna, op, box, last_box - box);
7336				b = box;
7337			}
7338		}
7339	}
7340	if (b != box)
7341		op->boxes(data->sna, op, box, b - box);
7342}
7343
7344static void
7345sna_poly_point__dash(DrawablePtr drawable, GCPtr gc,
7346		     int mode, int n, DDXPointPtr pt)
7347{
7348	struct sna_fill_spans *data = sna_gc(gc)->priv;
7349	if (data->phase == gc->fgPixel)
7350		sna_poly_point__fill(drawable, gc, mode, n, pt);
7351}
7352
7353static void
7354sna_poly_point__dash_clip_extents(DrawablePtr drawable, GCPtr gc,
7355				  int mode, int n, DDXPointPtr pt)
7356{
7357	struct sna_fill_spans *data = sna_gc(gc)->priv;
7358	if (data->phase == gc->fgPixel)
7359		sna_poly_point__fill_clip_extents(drawable, gc, mode, n, pt);
7360}
7361
7362static void
7363sna_poly_point__dash_clip_boxes(DrawablePtr drawable, GCPtr gc,
7364				  int mode, int n, DDXPointPtr pt)
7365{
7366	struct sna_fill_spans *data = sna_gc(gc)->priv;
7367	if (data->phase == gc->fgPixel)
7368		sna_poly_point__fill_clip_boxes(drawable, gc, mode, n, pt);
7369}
7370
7371static void
7372sna_fill_spans__fill(DrawablePtr drawable,
7373		     GCPtr gc, int n,
7374		     DDXPointPtr pt, int *width, int sorted)
7375{
7376	struct sna_fill_spans *data = sna_gc(gc)->priv;
7377	struct sna_fill_op *op = data->op;
7378	BoxRec box[512];
7379
7380	DBG(("%s: alu=%d, fg=%08lx, count=%d\n",
7381	     __FUNCTION__, gc->alu, gc->fgPixel, n));
7382
7383	while (n) {
7384		BoxRec *b = box;
7385		int nbox = n;
7386		if (nbox > ARRAY_SIZE(box))
7387			nbox = ARRAY_SIZE(box);
7388		n -= nbox;
7389		do {
7390			*(DDXPointRec *)b = *pt++;
7391			b->x2 = b->x1 + (int)*width++;
7392			b->y2 = b->y1 + 1;
7393			DBG(("%s: (%d, %d), (%d, %d)\n",
7394			     __FUNCTION__, b->x1, b->y1, b->x2, b->y2));
7395			assert(b->x1 >= drawable->x);
7396			assert(b->x2 <= drawable->x + drawable->width);
7397			assert(b->y1 >= drawable->y);
7398			assert(b->y2 <= drawable->y + drawable->height);
7399			if (b->x2 > b->x1) {
7400				if (b != box &&
7401				    b->y1 == b[-1].y2 &&
7402				    b->x1 == b[-1].x1 &&
7403				    b->x2 == b[-1].x2)
7404					b[-1].y2 = b->y2;
7405				else
7406					b++;
7407			}
7408		} while (--nbox);
7409		if (b != box)
7410			op->boxes(data->sna, op, box, b - box);
7411	}
7412}
7413
7414static void
7415sna_fill_spans__dash(DrawablePtr drawable,
7416		     GCPtr gc, int n,
7417		     DDXPointPtr pt, int *width, int sorted)
7418{
7419	struct sna_fill_spans *data = sna_gc(gc)->priv;
7420	if (data->phase == gc->fgPixel)
7421		sna_fill_spans__fill(drawable, gc, n, pt, width, sorted);
7422}
7423
7424static void
7425sna_fill_spans__fill_offset(DrawablePtr drawable,
7426			    GCPtr gc, int n,
7427			    DDXPointPtr pt, int *width, int sorted)
7428{
7429	struct sna_fill_spans *data = sna_gc(gc)->priv;
7430	struct sna_fill_op *op = data->op;
7431	BoxRec box[512];
7432
7433	DBG(("%s: alu=%d, fg=%08lx\n", __FUNCTION__, gc->alu, gc->fgPixel));
7434
7435	while (n) {
7436		BoxRec *b = box;
7437		int nbox = n;
7438		if (nbox > ARRAY_SIZE(box))
7439			nbox = ARRAY_SIZE(box);
7440		n -= nbox;
7441		do {
7442			*(DDXPointRec *)b = *pt++;
7443			b->x1 += data->dx;
7444			b->y1 += data->dy;
7445			b->x2 = b->x1 + (int)*width++;
7446			b->y2 = b->y1 + 1;
7447			if (b->x2 > b->x1)
7448				b++;
7449		} while (--nbox);
7450		if (b != box)
7451			op->boxes(data->sna, op, box, b - box);
7452	}
7453}
7454
7455static void
7456sna_fill_spans__dash_offset(DrawablePtr drawable,
7457			    GCPtr gc, int n,
7458			    DDXPointPtr pt, int *width, int sorted)
7459{
7460	struct sna_fill_spans *data = sna_gc(gc)->priv;
7461	if (data->phase == gc->fgPixel)
7462		sna_fill_spans__fill_offset(drawable, gc, n, pt, width, sorted);
7463}
7464
7465static void
7466sna_fill_spans__fill_clip_extents(DrawablePtr drawable,
7467				  GCPtr gc, int n,
7468				  DDXPointPtr pt, int *width, int sorted)
7469{
7470	struct sna_fill_spans *data = sna_gc(gc)->priv;
7471	struct sna_fill_op *op = data->op;
7472	const BoxRec *extents = &data->region.extents;
7473	BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box);
7474
7475	DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n",
7476	     __FUNCTION__, gc->alu, gc->fgPixel, n,
7477	     extents->x1, extents->y1,
7478	     extents->x2, extents->y2));
7479
7480	while (n--) {
7481		DBG(("%s: [%d] pt=(%d, %d), width=%d\n",
7482		     __FUNCTION__, n, pt->x, pt->y, *width));
7483		*(DDXPointRec *)b = *pt++;
7484		b->x2 = b->x1 + (int)*width++;
7485		b->y2 = b->y1 + 1;
7486		if (box_intersect(b, extents)) {
7487			DBG(("%s: [%d] clipped=(%d, %d), (%d, %d)\n",
7488			     __FUNCTION__, n, b->x1, b->y1, b->x2, b->y2));
7489			if (data->dx|data->dy) {
7490				b->x1 += data->dx; b->x2 += data->dx;
7491				b->y1 += data->dy; b->y2 += data->dy;
7492			}
7493			if (b != box &&
7494			    b->y1 == b[-1].y2 &&
7495			    b->x1 == b[-1].x1 &&
7496			    b->x2 == b[-1].x2) {
7497				b[-1].y2 = b->y2;
7498			} else if (++b == last_box) {
7499				op->boxes(data->sna, op, box, last_box - box);
7500				b = box;
7501			}
7502		}
7503	}
7504	if (b != box)
7505		op->boxes(data->sna, op, box, b - box);
7506}
7507
7508static void
7509sna_fill_spans__dash_clip_extents(DrawablePtr drawable,
7510				  GCPtr gc, int n,
7511				  DDXPointPtr pt, int *width, int sorted)
7512{
7513	struct sna_fill_spans *data = sna_gc(gc)->priv;
7514	if (data->phase == gc->fgPixel)
7515		sna_fill_spans__fill_clip_extents(drawable, gc, n, pt, width, sorted);
7516}
7517
7518static void
7519sna_fill_spans__fill_clip_boxes(DrawablePtr drawable,
7520				GCPtr gc, int n,
7521				DDXPointPtr pt, int *width, int sorted)
7522{
7523	struct sna_fill_spans *data = sna_gc(gc)->priv;
7524	struct sna_fill_op *op = data->op;
7525	BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box);
7526	const BoxRec * const clip_start = RegionBoxptr(&data->region);
7527	const BoxRec * const clip_end = clip_start + data->region.data->numRects;
7528
7529	DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n",
7530	     __FUNCTION__, gc->alu, gc->fgPixel, n,
7531	     data->region.extents.x1, data->region.extents.y1,
7532	     data->region.extents.x2, data->region.extents.y2));
7533
7534	while (n--) {
7535		int16_t X1 = pt->x;
7536		int16_t y = pt->y;
7537		int16_t X2 = X1 + (int)*width;
7538		const BoxRec *c;
7539
7540		pt++;
7541		width++;
7542
7543		if (y < data->region.extents.y1 || data->region.extents.y2 <= y)
7544			continue;
7545
7546		if (X1 < data->region.extents.x1)
7547			X1 = data->region.extents.x1;
7548
7549		if (X2 > data->region.extents.x2)
7550			X2 = data->region.extents.x2;
7551
7552		if (X1 >= X2)
7553			continue;
7554
7555		c = find_clip_box_for_y(clip_start, clip_end, y);
7556		while (c != clip_end) {
7557			if (y + 1 <= c->y1 || X2 <= c->x1)
7558				break;
7559
7560			if (X1 >= c->x2) {
7561				c++;
7562				continue;
7563			}
7564
7565			b->x1 = c->x1;
7566			b->x2 = c->x2;
7567			c++;
7568
7569			if (b->x1 < X1)
7570				b->x1 = X1;
7571			if (b->x2 > X2)
7572				b->x2 = X2;
7573			if (b->x2 <= b->x1)
7574				continue;
7575
7576			b->x1 += data->dx;
7577			b->x2 += data->dx;
7578			b->y1 = y + data->dy;
7579			b->y2 = b->y1 + 1;
7580			if (++b == last_box) {
7581				op->boxes(data->sna, op, box, last_box - box);
7582				b = box;
7583			}
7584		}
7585	}
7586	if (b != box)
7587		op->boxes(data->sna, op, box, b - box);
7588}
7589
7590static void
7591sna_fill_spans__dash_clip_boxes(DrawablePtr drawable,
7592				GCPtr gc, int n,
7593				DDXPointPtr pt, int *width, int sorted)
7594{
7595	struct sna_fill_spans *data = sna_gc(gc)->priv;
7596	if (data->phase == gc->fgPixel)
7597		sna_fill_spans__fill_clip_boxes(drawable, gc, n, pt, width, sorted);
7598}
7599
7600static bool
7601sna_fill_spans_blt(DrawablePtr drawable,
7602		   struct kgem_bo *bo, struct sna_damage **damage,
7603		   GCPtr gc, uint32_t pixel,
7604		   int n, DDXPointPtr pt, int *width, int sorted,
7605		   const BoxRec *extents, unsigned clipped)
7606{
7607	PixmapPtr pixmap = get_drawable_pixmap(drawable);
7608	struct sna *sna = to_sna_from_pixmap(pixmap);
7609	int16_t dx, dy;
7610	struct sna_fill_op fill;
7611	BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box);
7612	static void * const jump[] = {
7613		&&no_damage,
7614		&&damage,
7615		&&no_damage_clipped,
7616		&&damage_clipped,
7617	};
7618	unsigned v;
7619
7620	DBG(("%s: alu=%d, fg=%08lx, damge=%p, clipped?=%d\n",
7621	     __FUNCTION__, gc->alu, gc->fgPixel, damage, clipped));
7622
7623	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_SPANS))
7624		return false;
7625
7626	get_drawable_deltas(drawable, pixmap, &dx, &dy);
7627
7628	v = (damage != NULL) | clipped;
7629	goto *jump[v];
7630
7631no_damage:
7632	if (dx|dy) {
7633		do {
7634			int nbox = n;
7635			if (nbox > last_box - box)
7636				nbox = last_box - box;
7637			n -= nbox;
7638			do {
7639				*(DDXPointRec *)b = *pt++;
7640				b->x1 += dx;
7641				b->y1 += dy;
7642				b->x2 = b->x1 + (int)*width++;
7643				b->y2 = b->y1 + 1;
7644				b++;
7645			} while (--nbox);
7646			fill.boxes(sna, &fill, box, b - box);
7647			b = box;
7648		} while (n);
7649	} else {
7650		do {
7651			int nbox = n;
7652			if (nbox > last_box - box)
7653				nbox = last_box - box;
7654			n -= nbox;
7655			do {
7656				*(DDXPointRec *)b = *pt++;
7657				b->x2 = b->x1 + (int)*width++;
7658				b->y2 = b->y1 + 1;
7659				b++;
7660			} while (--nbox);
7661			fill.boxes(sna, &fill, box, b - box);
7662			b = box;
7663		} while (n);
7664	}
7665	goto done;
7666
7667damage:
7668	do {
7669		*(DDXPointRec *)b = *pt++;
7670		b->x1 += dx;
7671		b->y1 += dy;
7672		b->x2 = b->x1 + (int)*width++;
7673		b->y2 = b->y1 + 1;
7674
7675		if (++b == last_box) {
7676			assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0);
7677			fill.boxes(sna, &fill, box, last_box - box);
7678			sna_damage_add_boxes(damage, box, last_box - box, 0, 0);
7679			b = box;
7680		}
7681	} while (--n);
7682	if (b != box) {
7683		assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
7684		fill.boxes(sna, &fill, box, b - box);
7685		sna_damage_add_boxes(damage, box, b - box, 0, 0);
7686	}
7687	goto done;
7688
7689no_damage_clipped:
7690	{
7691		RegionRec clip;
7692
7693		region_set(&clip, extents);
7694		if (!region_maybe_clip(&clip, gc->pCompositeClip))
7695			return true;
7696
7697		assert(dx + clip.extents.x1 >= 0);
7698		assert(dy + clip.extents.y1 >= 0);
7699		assert(dx + clip.extents.x2 <= pixmap->drawable.width);
7700		assert(dy + clip.extents.y2 <= pixmap->drawable.height);
7701
7702		DBG(("%s: clip %d x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n",
7703		     __FUNCTION__,
7704		     region_num_rects(&clip),
7705		     clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2,
7706		     n, pt->x, pt->y));
7707
7708		if (clip.data == NULL) {
7709			do {
7710				*(DDXPointRec *)b = *pt++;
7711				b->x2 = b->x1 + (int)*width++;
7712				b->y2 = b->y1 + 1;
7713
7714				if (box_intersect(b, &clip.extents)) {
7715					if (dx|dy) {
7716						b->x1 += dx; b->x2 += dx;
7717						b->y1 += dy; b->y2 += dy;
7718					}
7719					if (++b == last_box) {
7720						fill.boxes(sna, &fill, box, last_box - box);
7721						b = box;
7722					}
7723				}
7724			} while (--n);
7725		} else {
7726			const BoxRec * const clip_start = RegionBoxptr(&clip);
7727			const BoxRec * const clip_end = clip_start + clip.data->numRects;
7728			do {
7729				int16_t X1 = pt->x;
7730				int16_t y = pt->y;
7731				int16_t X2 = X1 + (int)*width;
7732				const BoxRec *c;
7733
7734				pt++;
7735				width++;
7736
7737				if (y < extents->y1 || extents->y2 <= y)
7738					continue;
7739
7740				if (X1 < extents->x1)
7741					X1 = extents->x1;
7742
7743				if (X2 > extents->x2)
7744					X2 = extents->x2;
7745
7746				if (X1 >= X2)
7747					continue;
7748
7749				c = find_clip_box_for_y(clip_start,
7750							clip_end,
7751							y);
7752				while (c != clip_end) {
7753					if (y + 1 <= c->y1 || X2 <= c->x1)
7754						break;
7755
7756					if (X1 >= c->x2) {
7757						c++;
7758						continue;
7759					}
7760
7761					b->x1 = c->x1;
7762					b->x2 = c->x2;
7763					c++;
7764
7765					if (b->x1 < X1)
7766						b->x1 = X1;
7767					if (b->x2 > X2)
7768						b->x2 = X2;
7769					if (b->x2 <= b->x1)
7770						continue;
7771
7772					b->x1 += dx;
7773					b->x2 += dx;
7774					b->y1 = y + dy;
7775					b->y2 = b->y1 + 1;
7776					if (++b == last_box) {
7777						fill.boxes(sna, &fill, box, last_box - box);
7778						b = box;
7779					}
7780				}
7781			} while (--n);
7782			RegionUninit(&clip);
7783		}
7784		if (b != box)
7785			fill.boxes(sna, &fill, box, b - box);
7786		goto done;
7787	}
7788
7789damage_clipped:
7790	{
7791		RegionRec clip;
7792
7793		region_set(&clip, extents);
7794		if (!region_maybe_clip(&clip, gc->pCompositeClip))
7795			return true;
7796
7797		assert(dx + clip.extents.x1 >= 0);
7798		assert(dy + clip.extents.y1 >= 0);
7799		assert(dx + clip.extents.x2 <= pixmap->drawable.width);
7800		assert(dy + clip.extents.y2 <= pixmap->drawable.height);
7801
7802		DBG(("%s: clip %d x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n",
7803		     __FUNCTION__,
7804		     region_num_rects(&clip),
7805		     clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2,
7806		     n, pt->x, pt->y));
7807
7808		if (clip.data == NULL) {
7809			do {
7810				*(DDXPointRec *)b = *pt++;
7811				b->x2 = b->x1 + (int)*width++;
7812				b->y2 = b->y1 + 1;
7813
7814				if (box_intersect(b, &clip.extents)) {
7815					b->x1 += dx;
7816					b->x2 += dx;
7817					b->y1 += dy;
7818					b->y2 += dy;
7819					if (++b == last_box) {
7820						assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
7821						fill.boxes(sna, &fill, box, last_box - box);
7822						sna_damage_add_boxes(damage, box, b - box, 0, 0);
7823						b = box;
7824					}
7825				}
7826			} while (--n);
7827		} else {
7828			const BoxRec * const clip_start = RegionBoxptr(&clip);
7829			const BoxRec * const clip_end = clip_start + clip.data->numRects;
7830			do {
7831				int16_t X1 = pt->x;
7832				int16_t y = pt->y;
7833				int16_t X2 = X1 + (int)*width;
7834				const BoxRec *c;
7835
7836				pt++;
7837				width++;
7838
7839				if (y < extents->y1 || extents->y2 <= y)
7840					continue;
7841
7842				if (X1 < extents->x1)
7843					X1 = extents->x1;
7844
7845				if (X2 > extents->x2)
7846					X2 = extents->x2;
7847
7848				if (X1 >= X2)
7849					continue;
7850
7851				c = find_clip_box_for_y(clip_start,
7852							clip_end,
7853							y);
7854				while (c != clip_end) {
7855					if (y + 1 <= c->y1 || X2 <= c->x1)
7856						break;
7857
7858					if (X1 >= c->x2) {
7859						c++;
7860						continue;
7861					}
7862
7863					b->x1 = c->x1;
7864					b->x2 = c->x2;
7865					c++;
7866
7867					if (b->x1 < X1)
7868						b->x1 = X1;
7869					if (b->x2 > X2)
7870						b->x2 = X2;
7871					if (b->x2 <= b->x1)
7872						continue;
7873
7874					b->x1 += dx;
7875					b->x2 += dx;
7876					b->y1 = y + dy;
7877					b->y2 = b->y1 + 1;
7878					if (++b == last_box) {
7879						assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0);
7880						fill.boxes(sna, &fill, box, last_box - box);
7881						sna_damage_add_boxes(damage, box, last_box - box, 0, 0);
7882						b = box;
7883					}
7884				}
7885			} while (--n);
7886			RegionUninit(&clip);
7887		}
7888		if (b != box) {
7889			assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
7890			fill.boxes(sna, &fill, box, b - box);
7891			sna_damage_add_boxes(damage, box, b - box, 0, 0);
7892		}
7893		goto done;
7894	}
7895
7896done:
7897	fill.done(sna, &fill);
7898	assert_pixmap_damage(pixmap);
7899	return true;
7900}
7901
7902static bool
7903sna_poly_fill_rect_tiled_blt(DrawablePtr drawable,
7904			     struct kgem_bo *bo,
7905			     struct sna_damage **damage,
7906			     GCPtr gc, int n, xRectangle *rect,
7907			     const BoxRec *extents, unsigned clipped);
7908
7909static bool
7910sna_poly_fill_rect_stippled_blt(DrawablePtr drawable,
7911				struct kgem_bo *bo,
7912				struct sna_damage **damage,
7913				GCPtr gc, int n, xRectangle *rect,
7914				const BoxRec *extents, unsigned clipped);
7915
7916static inline bool
7917gc_is_solid(GCPtr gc, uint32_t *color)
7918{
7919	assert(FbFullMask(gc->depth) == (FbFullMask(gc->depth) & gc->planemask));
7920
7921	if (gc->alu == GXclear) {
7922		*color = 0;
7923		return true;
7924	}
7925	if (gc->alu == GXset) {
7926		*color = (1 << gc->depth) - 1;
7927		return true;
7928	}
7929
7930	if (gc->fillStyle == FillSolid ||
7931	    (gc->fillStyle == FillTiled && gc->tileIsPixel) ||
7932	    (gc->fillStyle == FillOpaqueStippled && gc->bgPixel == gc->fgPixel)) {
7933		*color = gc->fillStyle == FillTiled ? gc->tile.pixel : gc->fgPixel;
7934		return true;
7935	}
7936
7937	return false;
7938}
7939
7940static void
7941sna_fill_spans__gpu(DrawablePtr drawable, GCPtr gc, int n,
7942		    DDXPointPtr pt, int *width, int sorted)
7943{
7944	struct sna_fill_spans *data = sna_gc(gc)->priv;
7945	uint32_t color;
7946
7947	DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n",
7948	     __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted));
7949
7950	assert(PM_IS_SOLID(drawable, gc->planemask));
7951	if (n == 0)
7952		return;
7953
7954	/* The mi routines do not attempt to keep the spans it generates
7955	 * within the clip, so we must run them through the clipper.
7956	 */
7957
7958	if (gc_is_solid(gc, &color)) {
7959		sna_fill_spans_blt(drawable,
7960				   data->bo, NULL,
7961				   gc, color, n, pt, width, sorted,
7962				   &data->region.extents, 2);
7963	} else {
7964		/* Try converting these to a set of rectangles instead */
7965		xRectangle *rect;
7966		int i;
7967
7968		DBG(("%s: converting to rectagnles\n", __FUNCTION__));
7969
7970		rect = malloc (n * sizeof (xRectangle));
7971		if (rect == NULL)
7972			return;
7973
7974		for (i = 0; i < n; i++) {
7975			rect[i].x = pt[i].x - drawable->x;
7976			rect[i].width = width[i];
7977			rect[i].y = pt[i].y - drawable->y;
7978			rect[i].height = 1;
7979		}
7980
7981		if (gc->fillStyle == FillTiled) {
7982			(void)sna_poly_fill_rect_tiled_blt(drawable,
7983							   data->bo, NULL,
7984							   gc, n, rect,
7985							   &data->region.extents, 2);
7986		} else {
7987			(void)sna_poly_fill_rect_stippled_blt(drawable,
7988							      data->bo, NULL,
7989							      gc, n, rect,
7990							      &data->region.extents, 2);
7991		}
7992		free (rect);
7993	}
7994}
7995
7996static unsigned
7997sna_spans_extents(DrawablePtr drawable, GCPtr gc,
7998		  int n, DDXPointPtr pt, int *width,
7999		  BoxPtr out)
8000{
8001	BoxRec box;
8002	bool clipped = false;
8003
8004	if (n == 0)
8005		return 0;
8006
8007	box.x1 = pt->x;
8008	box.x2 = box.x1 + *width;
8009	box.y2 = box.y1 = pt->y;
8010
8011	while (--n) {
8012		pt++;
8013		width++;
8014		if (box.x1 > pt->x)
8015			box.x1 = pt->x;
8016		if (box.x2 < pt->x + *width)
8017			box.x2 = pt->x + *width;
8018
8019		if (box.y1 > pt->y)
8020			box.y1 = pt->y;
8021		else if (box.y2 < pt->y)
8022			box.y2 = pt->y;
8023	}
8024	box.y2++;
8025
8026	if (gc)
8027		clipped = clip_box(&box, gc);
8028	if (box_empty(&box))
8029		return 0;
8030
8031	*out = box;
8032	return 1 | clipped << 1;
8033}
8034
8035static void
8036sna_fill_spans(DrawablePtr drawable, GCPtr gc, int n,
8037	       DDXPointPtr pt, int *width, int sorted)
8038{
8039	PixmapPtr pixmap = get_drawable_pixmap(drawable);
8040	struct sna *sna = to_sna_from_pixmap(pixmap);
8041	struct sna_damage **damage;
8042	struct kgem_bo *bo;
8043	RegionRec region;
8044	unsigned flags;
8045	uint32_t color;
8046
8047	DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n",
8048	     __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted));
8049
8050	flags = sna_spans_extents(drawable, gc, n, pt, width, &region.extents);
8051	if (flags == 0)
8052		return;
8053
8054	DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__,
8055	     region.extents.x1, region.extents.y1,
8056	     region.extents.x2, region.extents.y2));
8057
8058	if (FORCE_FALLBACK)
8059		goto fallback;
8060
8061	if (!ACCEL_FILL_SPANS)
8062		goto fallback;
8063
8064	if (wedged(sna)) {
8065		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
8066		goto fallback;
8067	}
8068
8069	DBG(("%s: fillStyle=%x [%d], mask=%lx [%d]\n", __FUNCTION__,
8070	     gc->fillStyle, gc->fillStyle == FillSolid,
8071	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask)));
8072	if (!PM_IS_SOLID(drawable, gc->planemask))
8073		goto fallback;
8074
8075	bo = sna_drawable_use_bo(drawable, PREFER_GPU,
8076				 &region.extents, &damage);
8077	if (bo) {
8078		if (gc_is_solid(gc, &color)) {
8079			DBG(("%s: trying solid fill [alu=%d, pixel=%08lx] blt paths\n",
8080			     __FUNCTION__, gc->alu, gc->fgPixel));
8081
8082			sna_fill_spans_blt(drawable,
8083					   bo, damage,
8084					   gc, color, n, pt, width, sorted,
8085					   &region.extents, flags & IS_CLIPPED);
8086		} else {
8087			/* Try converting these to a set of rectangles instead */
8088			xRectangle *rect;
8089			int i;
8090
8091			DBG(("%s: converting to rectagnles\n", __FUNCTION__));
8092
8093			rect = malloc (n * sizeof (xRectangle));
8094			if (rect == NULL)
8095				return;
8096
8097			for (i = 0; i < n; i++) {
8098				rect[i].x = pt[i].x - drawable->x;
8099				rect[i].width = width[i];
8100				rect[i].y = pt[i].y - drawable->y;
8101				rect[i].height = 1;
8102			}
8103
8104			if (gc->fillStyle == FillTiled) {
8105				i = sna_poly_fill_rect_tiled_blt(drawable,
8106								 bo, damage,
8107								 gc, n, rect,
8108								 &region.extents, flags & IS_CLIPPED);
8109			} else {
8110				i = sna_poly_fill_rect_stippled_blt(drawable,
8111								    bo, damage,
8112								    gc, n, rect,
8113								    &region.extents, flags & IS_CLIPPED);
8114			}
8115			free (rect);
8116
8117			if (i)
8118				return;
8119		}
8120	}
8121
8122fallback:
8123	DBG(("%s: fallback\n", __FUNCTION__));
8124	region.data = NULL;
8125	if (!region_maybe_clip(&region, gc->pCompositeClip))
8126		return;
8127
8128	if (!sna_gc_move_to_cpu(gc, drawable, &region))
8129		goto out;
8130	if (!sna_drawable_move_region_to_cpu(drawable, &region,
8131					     drawable_gc_flags(drawable, gc, n > 1)))
8132		goto out;
8133
8134	if (sigtrap_get() == 0) {
8135		DBG(("%s: fbFillSpans\n", __FUNCTION__));
8136		fbFillSpans(drawable, gc, n, pt, width, sorted);
8137		FALLBACK_FLUSH(drawable);
8138		sigtrap_put();
8139	}
8140out:
8141	sna_gc_move_to_gpu(gc);
8142	RegionUninit(&region);
8143}
8144
8145static void
8146sna_set_spans(DrawablePtr drawable, GCPtr gc, char *src,
8147	      DDXPointPtr pt, int *width, int n, int sorted)
8148{
8149	RegionRec region;
8150
8151	if (sna_spans_extents(drawable, gc, n, pt, width, &region.extents) == 0)
8152		return;
8153
8154	DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__,
8155	     region.extents.x1, region.extents.y1,
8156	     region.extents.x2, region.extents.y2));
8157
8158	if (FORCE_FALLBACK)
8159		goto fallback;
8160
8161	if (!ACCEL_SET_SPANS)
8162		goto fallback;
8163
8164fallback:
8165	region.data = NULL;
8166	if (!region_maybe_clip(&region, gc->pCompositeClip))
8167		return;
8168
8169	if (!sna_gc_move_to_cpu(gc, drawable, &region))
8170		goto out;
8171	if (!sna_drawable_move_region_to_cpu(drawable, &region,
8172					     drawable_gc_flags(drawable, gc, n > 1)))
8173		goto out;
8174
8175	if (sigtrap_get() == 0) {
8176		DBG(("%s: fbSetSpans\n", __FUNCTION__));
8177		fbSetSpans(drawable, gc, src, pt, width, n, sorted);
8178		FALLBACK_FLUSH(drawable);
8179		sigtrap_put();
8180	}
8181out:
8182	sna_gc_move_to_gpu(gc);
8183	RegionUninit(&region);
8184}
8185
8186struct sna_copy_plane {
8187	struct sna_damage **damage;
8188	struct kgem_bo *bo;
8189};
8190
8191static void
8192sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
8193		    RegionRec *region, int sx, int sy,
8194		    Pixel bitplane, void *closure)
8195{
8196	PixmapPtr pixmap = get_drawable_pixmap(drawable);
8197	struct sna *sna = to_sna_from_pixmap(pixmap);
8198	struct sna_copy_plane *arg = closure;
8199	PixmapPtr bitmap = (PixmapPtr)_bitmap;
8200	uint32_t br00, br13;
8201	int16_t dx, dy;
8202	const BoxRec *box;
8203	int n;
8204
8205	DBG(("%s: plane=%x (%d,%d),(%d,%d)xld\n",
8206	     __FUNCTION__, (unsigned)bitplane,
8207	     region->extents.x1, region->extents.y1,
8208	     region->extents.x2, region->extents.y2,
8209	     region_num_rects(region)));
8210
8211	box = region_rects(region);
8212	n = region_num_rects(region);
8213	assert(n);
8214
8215	get_drawable_deltas(drawable, pixmap, &dx, &dy);
8216	assert_pixmap_contains_boxes(pixmap, box, n, dx, dy);
8217
8218	br00 = 3 << 20;
8219	br13 = arg->bo->pitch;
8220	if (sna->kgem.gen >= 040 && arg->bo->tiling) {
8221		br00 |= BLT_DST_TILED;
8222		br13 >>= 2;
8223	}
8224	br13 |= blt_depth(drawable->depth) << 24;
8225	br13 |= copy_ROP[gc->alu] << 16;
8226
8227	kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo);
8228	assert(kgem_bo_can_blt(&sna->kgem, arg->bo));
8229	do {
8230		int bx1 = (box->x1 + sx) & ~7;
8231		int bx2 = (box->x2 + sx + 7) & ~7;
8232		int bw = (bx2 - bx1)/8;
8233		int bh = box->y2 - box->y1;
8234		int bstride = ALIGN(bw, 2);
8235		int src_stride;
8236		uint8_t *dst, *src;
8237		uint32_t *b;
8238
8239		DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n",
8240		     __FUNCTION__,
8241		     box->x1, box->y1,
8242		     box->x2, box->y2,
8243		     sx, sy, bx1, bx2));
8244
8245		src_stride = bstride*bh;
8246		assert(src_stride > 0);
8247		if (src_stride <= 128) {
8248			src_stride = ALIGN(src_stride, 8) / 4;
8249			assert(src_stride <= 32);
8250			if (!kgem_check_batch(&sna->kgem, 8+src_stride) ||
8251			    !kgem_check_bo_fenced(&sna->kgem, arg->bo) ||
8252			    !kgem_check_reloc(&sna->kgem, 1)) {
8253				kgem_submit(&sna->kgem);
8254				if (!kgem_check_bo_fenced(&sna->kgem, arg->bo))
8255					return; /* XXX fallback? */
8256				_kgem_set_mode(&sna->kgem, KGEM_BLT);
8257			}
8258
8259			assert(sna->kgem.mode == KGEM_BLT);
8260			if (sna->kgem.gen >= 0100) {
8261				b = sna->kgem.batch + sna->kgem.nbatch;
8262				b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00;
8263				b[0] |= ((box->x1 + sx) & 7) << 17;
8264				b[1] = br13;
8265				b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8266				b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8267				*(uint64_t *)(b+4) =
8268					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8269							 I915_GEM_DOMAIN_RENDER << 16 |
8270							 I915_GEM_DOMAIN_RENDER |
8271							 KGEM_RELOC_FENCED,
8272							 0);
8273				b[5] = gc->bgPixel;
8274				b[6] = gc->fgPixel;
8275
8276				dst = (uint8_t *)&b[8];
8277				sna->kgem.nbatch += 8 + src_stride;
8278			} else {
8279				b = sna->kgem.batch + sna->kgem.nbatch;
8280				b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
8281				b[0] |= ((box->x1 + sx) & 7) << 17;
8282				b[1] = br13;
8283				b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8284				b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8285				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8286						      I915_GEM_DOMAIN_RENDER << 16 |
8287						      I915_GEM_DOMAIN_RENDER |
8288						      KGEM_RELOC_FENCED,
8289						      0);
8290				b[5] = gc->bgPixel;
8291				b[6] = gc->fgPixel;
8292
8293				dst = (uint8_t *)&b[7];
8294				sna->kgem.nbatch += 7 + src_stride;
8295			}
8296
8297			assert(bitmap->devKind);
8298			src_stride = bitmap->devKind;
8299			src = bitmap->devPrivate.ptr;
8300			src += (box->y1 + sy) * src_stride + bx1/8;
8301			src_stride -= bstride;
8302			do {
8303				int i = bstride;
8304				assert(src >= (uint8_t *)bitmap->devPrivate.ptr);
8305				do {
8306					*dst++ = byte_reverse(*src++);
8307					*dst++ = byte_reverse(*src++);
8308					i -= 2;
8309				} while (i);
8310				assert(src <= (uint8_t *)bitmap->devPrivate.ptr + bitmap->devKind * bitmap->drawable.height);
8311				src += src_stride;
8312			} while (--bh);
8313		} else {
8314			struct kgem_bo *upload;
8315			void *ptr;
8316
8317			if (!kgem_check_batch(&sna->kgem, 10) ||
8318			    !kgem_check_bo_fenced(&sna->kgem, arg->bo) ||
8319			    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
8320				kgem_submit(&sna->kgem);
8321				if (!kgem_check_bo_fenced(&sna->kgem, arg->bo))
8322					return; /* XXX fallback? */
8323				_kgem_set_mode(&sna->kgem, KGEM_BLT);
8324			}
8325
8326			upload = kgem_create_buffer(&sna->kgem,
8327						    bstride*bh,
8328						    KGEM_BUFFER_WRITE_INPLACE,
8329						    &ptr);
8330			if (!upload)
8331				break;
8332
8333			if (sigtrap_get() == 0) {
8334				assert(sna->kgem.mode == KGEM_BLT);
8335				b = sna->kgem.batch + sna->kgem.nbatch;
8336				if (sna->kgem.gen >= 0100) {
8337					b[0] = XY_MONO_SRC_COPY | br00 | 8;
8338					b[0] |= ((box->x1 + sx) & 7) << 17;
8339					b[1] = br13;
8340					b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8341					b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8342					*(uint64_t *)(b+4) =
8343						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8344								I915_GEM_DOMAIN_RENDER << 16 |
8345								I915_GEM_DOMAIN_RENDER |
8346								KGEM_RELOC_FENCED,
8347								0);
8348					*(uint64_t *)(b+6) =
8349						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
8350								I915_GEM_DOMAIN_RENDER << 16 |
8351								KGEM_RELOC_FENCED,
8352								0);
8353					b[8] = gc->bgPixel;
8354					b[9] = gc->fgPixel;
8355
8356					sna->kgem.nbatch += 10;
8357				} else {
8358					b[0] = XY_MONO_SRC_COPY | br00 | 6;
8359					b[0] |= ((box->x1 + sx) & 7) << 17;
8360					b[1] = br13;
8361					b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8362					b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8363					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8364							I915_GEM_DOMAIN_RENDER << 16 |
8365							I915_GEM_DOMAIN_RENDER |
8366							KGEM_RELOC_FENCED,
8367							0);
8368					b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
8369							I915_GEM_DOMAIN_RENDER << 16 |
8370							KGEM_RELOC_FENCED,
8371							0);
8372					b[6] = gc->bgPixel;
8373					b[7] = gc->fgPixel;
8374
8375					sna->kgem.nbatch += 8;
8376				}
8377
8378				dst = ptr;
8379				assert(bitmap->devKind);
8380				src_stride = bitmap->devKind;
8381				src = bitmap->devPrivate.ptr;
8382				src += (box->y1 + sy) * src_stride + bx1/8;
8383				src_stride -= bstride;
8384				do {
8385					int i = bstride;
8386					assert(src >= (uint8_t *)bitmap->devPrivate.ptr);
8387					do {
8388						*dst++ = byte_reverse(*src++);
8389						*dst++ = byte_reverse(*src++);
8390						i -= 2;
8391					} while (i);
8392					assert(src <= (uint8_t *)bitmap->devPrivate.ptr + bitmap->devKind * bitmap->drawable.height);
8393					assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload));
8394					src += src_stride;
8395				} while (--bh);
8396
8397				sigtrap_put();
8398			}
8399
8400			kgem_bo_destroy(&sna->kgem, upload);
8401		}
8402
8403		box++;
8404	} while (--n);
8405
8406	if (arg->damage) {
8407		RegionTranslate(region, dx, dy);
8408		sna_damage_add_to_pixmap(arg->damage, region, pixmap);
8409	}
8410	assert_pixmap_damage(pixmap);
8411	sna->blt_state.fill_bo = 0;
8412}
8413
8414static void
8415sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc,
8416		   RegionPtr region, int sx, int sy,
8417		   Pixel bitplane, void *closure)
8418{
8419	PixmapPtr dst_pixmap = get_drawable_pixmap(drawable);
8420	PixmapPtr src_pixmap = get_drawable_pixmap(source);
8421	struct sna *sna = to_sna_from_pixmap(dst_pixmap);
8422	struct sna_copy_plane *arg = closure;
8423	int16_t dx, dy;
8424	int bit = ffs(bitplane) - 1;
8425	uint32_t br00, br13;
8426	const BoxRec *box = region_rects(region);
8427	int n = region_num_rects(region);
8428
8429	DBG(("%s: plane=%x [%d] x%d\n", __FUNCTION__,
8430	     (unsigned)bitplane, bit, n));
8431
8432	if (n == 0)
8433		return;
8434
8435	if (get_drawable_deltas(source, src_pixmap, &dx, &dy))
8436		sx += dx, sy += dy;
8437
8438	get_drawable_deltas(drawable, dst_pixmap, &dx, &dy);
8439	assert_pixmap_contains_boxes(dst_pixmap, box, n, dx, dy);
8440
8441	br00 = XY_MONO_SRC_COPY | 3 << 20;
8442	br13 = arg->bo->pitch;
8443	if (sna->kgem.gen >= 040 && arg->bo->tiling) {
8444		br00 |= BLT_DST_TILED;
8445		br13 >>= 2;
8446	}
8447	br13 |= blt_depth(drawable->depth) << 24;
8448	br13 |= copy_ROP[gc->alu] << 16;
8449
8450	kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo);
8451	assert(kgem_bo_can_blt(&sna->kgem, arg->bo));
8452	do {
8453		int bx1 = (box->x1 + sx) & ~7;
8454		int bx2 = (box->x2 + sx + 7) & ~7;
8455		int bw = (bx2 - bx1)/8;
8456		int bh = box->y2 - box->y1;
8457		int bstride = ALIGN(bw, 2);
8458		struct kgem_bo *upload;
8459		void *ptr;
8460
8461		DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n",
8462		     __FUNCTION__,
8463		     box->x1, box->y1,
8464		     box->x2, box->y2,
8465		     sx, sy, bx1, bx2));
8466
8467		if (!kgem_check_batch(&sna->kgem, 10) ||
8468		    !kgem_check_bo_fenced(&sna->kgem, arg->bo) ||
8469		    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
8470			kgem_submit(&sna->kgem);
8471			if (!kgem_check_bo_fenced(&sna->kgem, arg->bo))
8472				return; /* XXX fallback? */
8473			_kgem_set_mode(&sna->kgem, KGEM_BLT);
8474		}
8475
8476		upload = kgem_create_buffer(&sna->kgem,
8477					    bstride*bh,
8478					    KGEM_BUFFER_WRITE_INPLACE,
8479					    &ptr);
8480		if (!upload)
8481			break;
8482
8483		if (sigtrap_get() == 0) {
8484			uint32_t *b;
8485
8486			assert(src_pixmap->devKind);
8487			switch (source->bitsPerPixel) {
8488			case 32:
8489				{
8490					uint32_t *src = src_pixmap->devPrivate.ptr;
8491					int src_stride = src_pixmap->devKind/sizeof(uint32_t);
8492					uint8_t *dst = ptr;
8493
8494					src += (box->y1 + sy) * src_stride;
8495					src += bx1;
8496
8497					src_stride -= bw * 8;
8498					bstride -= bw;
8499
8500					do {
8501						int i = bw;
8502						do {
8503							uint8_t v = 0;
8504
8505							v |= ((*src++ >> bit) & 1) << 7;
8506							v |= ((*src++ >> bit) & 1) << 6;
8507							v |= ((*src++ >> bit) & 1) << 5;
8508							v |= ((*src++ >> bit) & 1) << 4;
8509							v |= ((*src++ >> bit) & 1) << 3;
8510							v |= ((*src++ >> bit) & 1) << 2;
8511							v |= ((*src++ >> bit) & 1) << 1;
8512							v |= ((*src++ >> bit) & 1) << 0;
8513
8514							*dst++ = v;
8515						} while (--i);
8516						dst += bstride;
8517						src += src_stride;
8518					} while (--bh);
8519					break;
8520				}
8521			case 16:
8522				{
8523					uint16_t *src = src_pixmap->devPrivate.ptr;
8524					int src_stride = src_pixmap->devKind/sizeof(uint16_t);
8525					uint8_t *dst = ptr;
8526
8527					src += (box->y1 + sy) * src_stride;
8528					src += bx1;
8529
8530					src_stride -= bw * 8;
8531					bstride -= bw;
8532
8533					do {
8534						int i = bw;
8535						do {
8536							uint8_t v = 0;
8537
8538							v |= ((*src++ >> bit) & 1) << 7;
8539							v |= ((*src++ >> bit) & 1) << 6;
8540							v |= ((*src++ >> bit) & 1) << 5;
8541							v |= ((*src++ >> bit) & 1) << 4;
8542							v |= ((*src++ >> bit) & 1) << 3;
8543							v |= ((*src++ >> bit) & 1) << 2;
8544							v |= ((*src++ >> bit) & 1) << 1;
8545							v |= ((*src++ >> bit) & 1) << 0;
8546
8547							*dst++ = v;
8548						} while (--i);
8549						dst += bstride;
8550						src += src_stride;
8551					} while (--bh);
8552					break;
8553				}
8554			default:
8555				assert(0);
8556			case 8:
8557				{
8558					uint8_t *src = src_pixmap->devPrivate.ptr;
8559					int src_stride = src_pixmap->devKind/sizeof(uint8_t);
8560					uint8_t *dst = ptr;
8561
8562					src += (box->y1 + sy) * src_stride;
8563					src += bx1;
8564
8565					src_stride -= bw * 8;
8566					bstride -= bw;
8567
8568					do {
8569						int i = bw;
8570						do {
8571							uint8_t v = 0;
8572
8573							v |= ((*src++ >> bit) & 1) << 7;
8574							v |= ((*src++ >> bit) & 1) << 6;
8575							v |= ((*src++ >> bit) & 1) << 5;
8576							v |= ((*src++ >> bit) & 1) << 4;
8577							v |= ((*src++ >> bit) & 1) << 3;
8578							v |= ((*src++ >> bit) & 1) << 2;
8579							v |= ((*src++ >> bit) & 1) << 1;
8580							v |= ((*src++ >> bit) & 1) << 0;
8581
8582							*dst++ = v;
8583						} while (--i);
8584						dst += bstride;
8585						src += src_stride;
8586					} while (--bh);
8587					break;
8588				}
8589			}
8590
8591			assert(sna->kgem.mode == KGEM_BLT);
8592			b = sna->kgem.batch + sna->kgem.nbatch;
8593			if (sna->kgem.gen >= 0100) {
8594				b[0] = br00 | ((box->x1 + sx) & 7) << 17 | 8;
8595				b[1] = br13;
8596				b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8597				b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8598				*(uint64_t *)(b+4) =
8599					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8600							I915_GEM_DOMAIN_RENDER << 16 |
8601							I915_GEM_DOMAIN_RENDER |
8602							KGEM_RELOC_FENCED,
8603							0);
8604				*(uint64_t *)(b+6) =
8605					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
8606							I915_GEM_DOMAIN_RENDER << 16 |
8607							KGEM_RELOC_FENCED,
8608							0);
8609				b[8] = gc->bgPixel;
8610				b[9] = gc->fgPixel;
8611
8612				sna->kgem.nbatch += 10;
8613			} else {
8614				b[0] = br00 | ((box->x1 + sx) & 7) << 17 | 6;
8615				b[1] = br13;
8616				b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8617				b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8618				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8619						I915_GEM_DOMAIN_RENDER << 16 |
8620						I915_GEM_DOMAIN_RENDER |
8621						KGEM_RELOC_FENCED,
8622						0);
8623				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
8624						I915_GEM_DOMAIN_RENDER << 16 |
8625						KGEM_RELOC_FENCED,
8626						0);
8627				b[6] = gc->bgPixel;
8628				b[7] = gc->fgPixel;
8629
8630				sna->kgem.nbatch += 8;
8631			}
8632			sigtrap_put();
8633		}
8634		kgem_bo_destroy(&sna->kgem, upload);
8635
8636		box++;
8637	} while (--n);
8638
8639	if (arg->damage) {
8640		RegionTranslate(region, dx, dy);
8641		sna_damage_add_to_pixmap(arg->damage, region, dst_pixmap);
8642	}
8643	assert_pixmap_damage(dst_pixmap);
8644	sna->blt_state.fill_bo = 0;
8645}
8646
8647static RegionPtr
8648sna_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc,
8649	       int src_x, int src_y,
8650	       int w, int h,
8651	       int dst_x, int dst_y,
8652	       unsigned long bit)
8653{
8654	PixmapPtr pixmap = get_drawable_pixmap(dst);
8655	struct sna *sna = to_sna_from_pixmap(pixmap);
8656	RegionRec region, *ret = NULL;
8657	struct sna_copy_plane arg;
8658
8659	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=%dx%d\n", __FUNCTION__,
8660	     src_x, src_y, dst_x, dst_y, w, h));
8661
8662	if (gc->planemask == 0)
8663		goto empty;
8664
8665	if (src->bitsPerPixel == 1 && (bit&1) == 0)
8666		goto empty;
8667
8668	region.extents.x1 = dst_x + dst->x;
8669	region.extents.y1 = dst_y + dst->y;
8670	region.extents.x2 = region.extents.x1 + w;
8671	region.extents.y2 = region.extents.y1 + h;
8672	region.data = NULL;
8673	RegionIntersect(&region, &region, gc->pCompositeClip);
8674
8675	DBG(("%s: dst extents (%d, %d), (%d, %d)\n",
8676	     __FUNCTION__,
8677	     region.extents.x1, region.extents.y1,
8678	     region.extents.x2, region.extents.y2));
8679
8680	{
8681		RegionRec clip;
8682
8683		clip.extents.x1 = src->x - (src->x + src_x) + (dst->x + dst_x);
8684		clip.extents.y1 = src->y - (src->y + src_y) + (dst->y + dst_y);
8685		clip.extents.x2 = clip.extents.x1 + src->width;
8686		clip.extents.y2 = clip.extents.y1 + src->height;
8687		clip.data = NULL;
8688
8689		DBG(("%s: src extents (%d, %d), (%d, %d)\n",
8690		     __FUNCTION__,
8691		     clip.extents.x1, clip.extents.y1,
8692		     clip.extents.x2, clip.extents.y2));
8693
8694		RegionIntersect(&region, &region, &clip);
8695	}
8696	DBG(("%s: dst^src extents (%d, %d), (%d, %d)\n",
8697	     __FUNCTION__,
8698	     region.extents.x1, region.extents.y1,
8699	     region.extents.x2, region.extents.y2));
8700	if (box_empty(&region.extents))
8701		goto empty;
8702
8703	RegionTranslate(&region,
8704			src_x - dst_x - dst->x + src->x,
8705			src_y - dst_y - dst->y + src->y);
8706
8707	if (!sna_drawable_move_region_to_cpu(src, &region, MOVE_READ))
8708		goto out;
8709
8710	RegionTranslate(&region,
8711			-(src_x - dst_x - dst->x + src->x),
8712			-(src_y - dst_y - dst->y + src->y));
8713
8714	if (FORCE_FALLBACK)
8715		goto fallback;
8716
8717	if (!ACCEL_COPY_PLANE)
8718		goto fallback;
8719
8720	if (wedged(sna))
8721		goto fallback;
8722
8723	if (!PM_IS_SOLID(dst, gc->planemask))
8724		goto fallback;
8725
8726	arg.bo = sna_drawable_use_bo(dst, PREFER_GPU,
8727				     &region.extents, &arg.damage);
8728	if (arg.bo) {
8729		if (arg.bo->tiling == I915_TILING_Y) {
8730			assert(arg.bo == __sna_pixmap_get_bo(pixmap));
8731			arg.bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
8732			if (arg.bo == NULL) {
8733				DBG(("%s: fallback -- unable to change tiling\n",
8734				     __FUNCTION__));
8735				goto fallback;
8736			}
8737		}
8738
8739		if (!kgem_bo_can_blt(&sna->kgem, arg.bo))
8740			return false;
8741
8742		RegionUninit(&region);
8743		return sna_do_copy(src, dst, gc,
8744				   src_x, src_y,
8745				   w, h,
8746				   dst_x, dst_y,
8747				   src->depth == 1 ? sna_copy_bitmap_blt : sna_copy_plane_blt,
8748				   (Pixel)bit, &arg);
8749	}
8750
8751fallback:
8752	DBG(("%s: fallback\n", __FUNCTION__));
8753	if (!sna_gc_move_to_cpu(gc, dst, &region))
8754		goto out;
8755	if (!sna_drawable_move_region_to_cpu(dst, &region,
8756					     drawable_gc_flags(dst, gc, false)))
8757		goto out;
8758
8759	if (sigtrap_get() == 0) {
8760		DBG(("%s: fbCopyPlane(%d, %d, %d, %d, %d,%d) %x\n",
8761		     __FUNCTION__, src_x, src_y, w, h, dst_x, dst_y, (unsigned)bit));
8762		ret = miDoCopy(src, dst, gc,
8763			       src_x, src_y, w, h, dst_x, dst_y,
8764			       src->bitsPerPixel > 1 ? fbCopyNto1 : fbCopy1toN,
8765			       bit, 0);
8766		FALLBACK_FLUSH(dst);
8767		sigtrap_put();
8768	}
8769out:
8770	sna_gc_move_to_gpu(gc);
8771	RegionUninit(&region);
8772	return ret;
8773empty:
8774	return miHandleExposures(src, dst, gc,
8775				 src_x, src_y,
8776				 w, h,
8777				 dst_x, dst_y, bit);
8778}
8779
8780static bool
8781sna_poly_point_blt(DrawablePtr drawable,
8782		   struct kgem_bo *bo,
8783		   struct sna_damage **damage,
8784		   GCPtr gc, int mode, int n, DDXPointPtr pt,
8785		   bool clipped)
8786{
8787	PixmapPtr pixmap = get_drawable_pixmap(drawable);
8788	struct sna *sna = to_sna_from_pixmap(pixmap);
8789	BoxRec box[512], *b = box, * const last_box = box + ARRAY_SIZE(box);
8790	struct sna_fill_op fill;
8791	DDXPointRec last;
8792	int16_t dx, dy;
8793
8794	DBG(("%s: alu=%d, pixel=%08lx, clipped?=%d\n",
8795	     __FUNCTION__, gc->alu, gc->fgPixel, clipped));
8796
8797	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_POINTS))
8798		return false;
8799
8800	get_drawable_deltas(drawable, pixmap, &dx, &dy);
8801
8802	last.x = drawable->x;
8803	last.y = drawable->y;
8804
8805	if (!clipped) {
8806		last.x += dx;
8807		last.y += dy;
8808
8809		assert_pixmap_contains_points(pixmap, pt, n, last.x, last.y);
8810		sna_damage_add_points(damage, pt, n, last.x, last.y);
8811		if (fill.points && mode != CoordModePrevious) {
8812			fill.points(sna, &fill, last.x, last.y, pt, n);
8813		} else {
8814			do {
8815				unsigned nbox = n;
8816				if (nbox > ARRAY_SIZE(box))
8817					nbox = ARRAY_SIZE(box);
8818				n -= nbox;
8819				do {
8820					*(DDXPointRec *)b = *pt++;
8821
8822					b->x1 += last.x;
8823					b->y1 += last.y;
8824					if (mode == CoordModePrevious)
8825						last = *(DDXPointRec *)b;
8826
8827					b->x2 = b->x1 + 1;
8828					b->y2 = b->y1 + 1;
8829					b++;
8830				} while (--nbox);
8831				fill.boxes(sna, &fill, box, b - box);
8832				b = box;
8833			} while (n);
8834		}
8835	} else {
8836		RegionPtr clip = gc->pCompositeClip;
8837
8838		while (n--) {
8839			int x, y;
8840
8841			x = pt->x;
8842			y = pt->y;
8843			pt++;
8844			if (mode == CoordModePrevious) {
8845				x += last.x;
8846				y += last.y;
8847				last.x = x;
8848				last.y = y;
8849			} else {
8850				x += drawable->x;
8851				y += drawable->y;
8852			}
8853
8854			if (RegionContainsPoint(clip, x, y, NULL)) {
8855				b->x1 = x + dx;
8856				b->y1 = y + dy;
8857				b->x2 = b->x1 + 1;
8858				b->y2 = b->y1 + 1;
8859				if (++b == last_box){
8860					assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0);
8861					fill.boxes(sna, &fill, box, last_box - box);
8862					if (damage)
8863						sna_damage_add_boxes(damage, box, last_box-box, 0, 0);
8864					b = box;
8865				}
8866			}
8867		}
8868		if (b != box){
8869			assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
8870			fill.boxes(sna, &fill, box, b - box);
8871			if (damage)
8872				sna_damage_add_boxes(damage, box, b-box, 0, 0);
8873		}
8874	}
8875	fill.done(sna, &fill);
8876	assert_pixmap_damage(pixmap);
8877	return true;
8878}
8879
8880static unsigned
8881sna_poly_point_extents(DrawablePtr drawable, GCPtr gc,
8882		       int mode, int n, DDXPointPtr pt, BoxPtr out)
8883{
8884	BoxRec box;
8885	bool clipped;
8886
8887	if (n == 0)
8888		return 0;
8889
8890	box.x2 = box.x1 = pt->x;
8891	box.y2 = box.y1 = pt->y;
8892	if (mode == CoordModePrevious) {
8893		DDXPointRec last = *pt++;
8894		while (--n) {
8895			last.x += pt->x;
8896			last.y += pt->y;
8897			pt++;
8898			box_add_pt(&box, last.x, last.y);
8899		}
8900	} else {
8901		--n; ++pt;
8902		while (n >= 8) {
8903			box_add_pt(&box, pt[0].x, pt[0].y);
8904			box_add_pt(&box, pt[1].x, pt[1].y);
8905			box_add_pt(&box, pt[2].x, pt[2].y);
8906			box_add_pt(&box, pt[3].x, pt[3].y);
8907			box_add_pt(&box, pt[4].x, pt[4].y);
8908			box_add_pt(&box, pt[5].x, pt[5].y);
8909			box_add_pt(&box, pt[6].x, pt[6].y);
8910			box_add_pt(&box, pt[7].x, pt[7].y);
8911			pt += 8;
8912			n -= 8;
8913		}
8914		if (n & 4) {
8915			box_add_pt(&box, pt[0].x, pt[0].y);
8916			box_add_pt(&box, pt[1].x, pt[1].y);
8917			box_add_pt(&box, pt[2].x, pt[2].y);
8918			box_add_pt(&box, pt[3].x, pt[3].y);
8919			pt += 4;
8920		}
8921		if (n & 2) {
8922			box_add_pt(&box, pt[0].x, pt[0].y);
8923			box_add_pt(&box, pt[1].x, pt[1].y);
8924			pt += 2;
8925		}
8926		if (n & 1)
8927			box_add_pt(&box, pt[0].x, pt[0].y);
8928	}
8929	box.x2++;
8930	box.y2++;
8931
8932	clipped = trim_and_translate_box(&box, drawable, gc);
8933	if (box_empty(&box))
8934		return 0;
8935
8936	*out = box;
8937	return 1 | clipped << 1;
8938}
8939
8940static void
8941sna_poly_point(DrawablePtr drawable, GCPtr gc,
8942	       int mode, int n, DDXPointPtr pt)
8943{
8944	PixmapPtr pixmap = get_drawable_pixmap(drawable);
8945	struct sna *sna = to_sna_from_pixmap(pixmap);
8946	RegionRec region;
8947	unsigned flags;
8948
8949	DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d)\n",
8950	     __FUNCTION__, mode, n, pt[0].x, pt[0].y));
8951
8952	flags = sna_poly_point_extents(drawable, gc, mode, n, pt, &region.extents);
8953	if (flags == 0)
8954		return;
8955
8956	DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
8957	     region.extents.x1, region.extents.y1,
8958	     region.extents.x2, region.extents.y2,
8959	     flags));
8960
8961	if (FORCE_FALLBACK)
8962		goto fallback;
8963
8964	if (!ACCEL_POLY_POINT)
8965		goto fallback;
8966
8967	if (wedged(sna)) {
8968		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
8969		goto fallback;
8970	}
8971
8972	if (PM_IS_SOLID(drawable, gc->planemask)) {
8973		struct sna_damage **damage;
8974		struct kgem_bo *bo;
8975
8976		DBG(("%s: trying solid fill [%08lx] blt paths\n",
8977		     __FUNCTION__, gc->fgPixel));
8978
8979		if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU,
8980					      &region.extents, &damage)) &&
8981		    sna_poly_point_blt(drawable, bo, damage,
8982				       gc, mode, n, pt, flags & IS_CLIPPED))
8983			return;
8984	}
8985
8986fallback:
8987	DBG(("%s: fallback\n", __FUNCTION__));
8988	region.data = NULL;
8989	if (!region_maybe_clip(&region, gc->pCompositeClip))
8990		return;
8991
8992	if (!sna_gc_move_to_cpu(gc, drawable, &region))
8993		goto out;
8994	if (!sna_drawable_move_region_to_cpu(drawable, &region,
8995					     MOVE_READ | MOVE_WRITE))
8996		goto out;
8997
8998	if (sigtrap_get() == 0) {
8999		DBG(("%s: fbPolyPoint\n", __FUNCTION__));
9000		fbPolyPoint(drawable, gc, mode, n, pt, flags);
9001		FALLBACK_FLUSH(drawable);
9002		sigtrap_put();
9003	}
9004out:
9005	sna_gc_move_to_gpu(gc);
9006	RegionUninit(&region);
9007}
9008
9009static bool
9010sna_poly_zero_line_blt(DrawablePtr drawable,
9011		       struct kgem_bo *bo,
9012		       struct sna_damage **damage,
9013		       GCPtr gc, int mode, const int _n, const DDXPointRec * const _pt,
9014		       const BoxRec *extents, unsigned clipped)
9015{
9016	static void * const _jump[] = {
9017		&&no_damage,
9018		&&damage,
9019
9020		&&no_damage_offset,
9021		&&damage_offset,
9022	};
9023
9024	PixmapPtr pixmap = get_drawable_pixmap(drawable);
9025	struct sna *sna = to_sna_from_pixmap(pixmap);
9026	int x2, y2, xstart, ystart, oc2;
9027	unsigned int bias = miGetZeroLineBias(drawable->pScreen);
9028	bool degenerate = true;
9029	struct sna_fill_op fill;
9030	RegionRec clip;
9031	BoxRec box[512], *b, * const last_box = box + ARRAY_SIZE(box);
9032	const BoxRec *last_extents;
9033	int16_t dx, dy;
9034	void *jump, *ret;
9035
9036	DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n",
9037	     __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage));
9038	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_SPANS))
9039		return false;
9040
9041	get_drawable_deltas(drawable, pixmap, &dx, &dy);
9042
9043	region_set(&clip, extents);
9044	if (clipped) {
9045		if (!region_maybe_clip(&clip, gc->pCompositeClip))
9046			return true;
9047	}
9048
9049	jump = _jump[(damage != NULL) | !!(dx|dy) << 1];
9050	DBG(("%s: [clipped=%x] extents=(%d, %d), (%d, %d), delta=(%d, %d), damage=%p\n",
9051	     __FUNCTION__, clipped,
9052	     clip.extents.x1, clip.extents.y1,
9053	     clip.extents.x2, clip.extents.y2,
9054	     dx, dy, damage));
9055
9056	extents = region_rects(&clip);
9057	last_extents = extents + region_num_rects(&clip);
9058
9059	b = box;
9060	do {
9061		int n = _n;
9062		const DDXPointRec *pt = _pt;
9063
9064		xstart = pt->x + drawable->x;
9065		ystart = pt->y + drawable->y;
9066
9067		x2 = xstart;
9068		y2 = ystart;
9069		oc2 = 0;
9070		OUTCODES(oc2, x2, y2, extents);
9071
9072		while (--n) {
9073			int16_t sdx, sdy;
9074			int adx, ady, length;
9075			int e, e1, e2, e3;
9076			int x1 = x2, x;
9077			int y1 = y2, y;
9078			int oc1 = oc2;
9079			int octant;
9080
9081			++pt;
9082
9083			x2 = pt->x;
9084			y2 = pt->y;
9085			if (mode == CoordModePrevious) {
9086				x2 += x1;
9087				y2 += y1;
9088			} else {
9089				x2 += drawable->x;
9090				y2 += drawable->y;
9091			}
9092			DBG(("%s: segment (%d, %d) to (%d, %d)\n",
9093			     __FUNCTION__, x1, y1, x2, y2));
9094			if (x2 == x1 && y2 == y1)
9095				continue;
9096
9097			degenerate = false;
9098
9099			oc2 = 0;
9100			OUTCODES(oc2, x2, y2, extents);
9101			if (oc1 & oc2)
9102				continue;
9103
9104			CalcLineDeltas(x1, y1, x2, y2,
9105				       adx, ady, sdx, sdy,
9106				       1, 1, octant);
9107
9108			DBG(("%s: adx=(%d, %d), sdx=(%d, %d), oc1=%x, oc2=%x\n",
9109			     __FUNCTION__, adx, ady, sdx, sdy, oc1, oc2));
9110			if (adx == 0 || ady == 0) {
9111				if (x1 <= x2) {
9112					b->x1 = x1;
9113					b->x2 = x2;
9114				} else {
9115					b->x1 = x2;
9116					b->x2 = x1;
9117				}
9118				if (y1 <= y2) {
9119					b->y1 = y1;
9120					b->y2 = y2;
9121				} else {
9122					b->y1 = y2;
9123					b->y2 = y1;
9124				}
9125				b->x2++;
9126				b->y2++;
9127				if (oc1 | oc2) {
9128					bool intersects;
9129
9130					intersects = box_intersect(b, extents);
9131					assert(intersects);
9132				}
9133				if (++b == last_box) {
9134					ret = &&rectangle_continue;
9135					goto *jump;
9136rectangle_continue:
9137					b = box;
9138				}
9139			} else if (adx >= ady) {
9140				int x2_clipped = x2, y2_clipped = y2;
9141				bool dirty;
9142
9143				/* X-major segment */
9144				e1 = ady << 1;
9145				e2 = e1 - (adx << 1);
9146				e  = e1 - adx;
9147				length = adx;
9148
9149				FIXUP_ERROR(e, octant, bias);
9150
9151				x = x1;
9152				y = y1;
9153
9154				if (oc1 | oc2) {
9155					int pt1_clipped, pt2_clipped;
9156
9157					if (miZeroClipLine(extents->x1, extents->y1,
9158							   extents->x2-1, extents->y2-1,
9159							   &x, &y, &x2_clipped, &y2_clipped,
9160							   adx, ady,
9161							   &pt1_clipped, &pt2_clipped,
9162							   octant, bias, oc1, oc2) == -1)
9163						continue;
9164
9165					length = abs(x2_clipped - x);
9166					if (length == 0)
9167						continue;
9168
9169					if (pt1_clipped) {
9170						int clipdx = abs(x - x1);
9171						int clipdy = abs(y - y1);
9172						e += clipdy * e2 + (clipdx - clipdy) * e1;
9173					}
9174				}
9175
9176				e3 = e2 - e1;
9177				e  = e - e1;
9178
9179				b->x1 = x;
9180				b->y1 = y;
9181				dirty = false;
9182				while (length--) {
9183					e += e1;
9184					dirty = true;
9185					if (e >= 0) {
9186						e += e3;
9187
9188						if (sdx < 0) {
9189							b->x2 = b->x1 + 1;
9190							b->x1 = x;
9191						} else
9192							b->x2 = x + 1;
9193						b->y2 = b->y1 + 1;
9194
9195						if (++b == last_box) {
9196							ret = &&X_continue;
9197							goto *jump;
9198X_continue:
9199							b = box;
9200						}
9201
9202						b->x1 = x + sdx;
9203						b->y1 = y += sdy;
9204						dirty = false;
9205					}
9206					x += sdx;
9207				}
9208				if (dirty) {
9209					x -= sdx;
9210					if (sdx < 0) {
9211						b->x2 = b->x1 + 1;
9212						b->x1 = x;
9213					} else
9214						b->x2 = x + 1;
9215					b->y2 = b->y1 + 1;
9216
9217					if (++b == last_box) {
9218						ret = &&X2_continue;
9219						goto *jump;
9220X2_continue:
9221						b = box;
9222					}
9223				}
9224			} else {
9225				int x2_clipped = x2, y2_clipped = y2;
9226				bool dirty;
9227
9228				/* Y-major segment */
9229				e1 = adx << 1;
9230				e2 = e1 - (ady << 1);
9231				e  = e1 - ady;
9232				length  = ady;
9233
9234				SetYMajorOctant(octant);
9235				FIXUP_ERROR(e, octant, bias);
9236
9237				x = x1;
9238				y = y1;
9239
9240				if (oc1 | oc2) {
9241					int pt1_clipped, pt2_clipped;
9242
9243					if (miZeroClipLine(extents->x1, extents->y1,
9244							   extents->x2-1, extents->y2-1,
9245							   &x, &y, &x2_clipped, &y2_clipped,
9246							   adx, ady,
9247							   &pt1_clipped, &pt2_clipped,
9248							   octant, bias, oc1, oc2) == -1)
9249						continue;
9250
9251					length = abs(y2_clipped - y);
9252					if (length == 0)
9253						continue;
9254
9255					if (pt1_clipped) {
9256						int clipdx = abs(x - x1);
9257						int clipdy = abs(y - y1);
9258						e += clipdx * e2 + (clipdy - clipdx) * e1;
9259					}
9260				}
9261
9262				e3 = e2 - e1;
9263				e  = e - e1;
9264
9265				b->x1 = x;
9266				b->y1 = y;
9267				dirty = false;
9268				while (length--) {
9269					e += e1;
9270					dirty = true;
9271					if (e >= 0) {
9272						e += e3;
9273
9274						if (sdy < 0) {
9275							b->y2 = b->y1 + 1;
9276							b->y1 = y;
9277						} else
9278							b->y2 = y + 1;
9279						b->x2 = x + 1;
9280
9281						if (++b == last_box) {
9282							ret = &&Y_continue;
9283							goto *jump;
9284Y_continue:
9285							b = box;
9286						}
9287
9288						b->x1 = x += sdx;
9289						b->y1 = y + sdy;
9290						dirty = false;
9291					}
9292					y += sdy;
9293				}
9294
9295				if (dirty) {
9296					y -= sdy;
9297					if (sdy < 0) {
9298						b->y2 = b->y1 + 1;
9299						b->y1 = y;
9300					} else
9301						b->y2 = y + 1;
9302					b->x2 = x + 1;
9303
9304					if (++b == last_box) {
9305						ret = &&Y2_continue;
9306						goto *jump;
9307Y2_continue:
9308						b = box;
9309					}
9310				}
9311			}
9312		}
9313
9314#if 0
9315		/* Only do the CapNotLast check on the last segment
9316		 * and only if the endpoint wasn't clipped.  And then, if the last
9317		 * point is the same as the first point, do not draw it, unless the
9318		 * line is degenerate
9319		 */
9320		if (!pt2_clipped &&
9321		    gc->capStyle != CapNotLast &&
9322		    !(xstart == x2 && ystart == y2 && !degenerate))
9323		{
9324			b->x2 = x2;
9325			b->y2 = y2;
9326			if (b->x2 < b->x1) {
9327				int16_t t = b->x1;
9328				b->x1 = b->x2;
9329				b->x2 = t;
9330			}
9331			if (b->y2 < b->y1) {
9332				int16_t t = b->y1;
9333				b->y1 = b->y2;
9334				b->y2 = t;
9335			}
9336			b->x2++;
9337			b->y2++;
9338			b++;
9339		}
9340#endif
9341	} while (++extents != last_extents);
9342
9343	if (b != box) {
9344		ret = &&done;
9345		goto *jump;
9346	}
9347
9348done:
9349	fill.done(sna, &fill);
9350	assert_pixmap_damage(pixmap);
9351	RegionUninit(&clip);
9352	return true;
9353
9354damage:
9355	assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
9356	sna_damage_add_boxes(damage, box, b-box, 0, 0);
9357no_damage:
9358	fill.boxes(sna, &fill, box, b-box);
9359	goto *ret;
9360
9361no_damage_offset:
9362	{
9363		BoxRec *bb = box;
9364		do {
9365			bb->x1 += dx;
9366			bb->x2 += dx;
9367			bb->y1 += dy;
9368			bb->y2 += dy;
9369		} while (++bb != b);
9370		assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
9371		fill.boxes(sna, &fill, box, b - box);
9372	}
9373	goto *ret;
9374
9375damage_offset:
9376	{
9377		BoxRec *bb = box;
9378		do {
9379			bb->x1 += dx;
9380			bb->x2 += dx;
9381			bb->y1 += dy;
9382			bb->y2 += dy;
9383		} while (++bb != b);
9384		assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
9385		fill.boxes(sna, &fill, box, b - box);
9386		sna_damage_add_boxes(damage, box, b - box, 0, 0);
9387	}
9388	goto *ret;
9389}
9390
9391static bool
9392sna_poly_line_blt(DrawablePtr drawable,
9393		  struct kgem_bo *bo,
9394		  struct sna_damage **damage,
9395		  GCPtr gc, uint32_t pixel,
9396		  int mode, int n, DDXPointPtr pt,
9397		  const BoxRec *extents, bool clipped)
9398{
9399	PixmapPtr pixmap = get_drawable_pixmap(drawable);
9400	struct sna *sna = to_sna_from_pixmap(pixmap);
9401	BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes);
9402	struct sna_fill_op fill;
9403	DDXPointRec last;
9404	int16_t dx, dy;
9405
9406	DBG(("%s: alu=%d, fg=%08x, clipped=%d\n", __FUNCTION__, gc->alu, (unsigned)pixel, clipped));
9407
9408	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_BOXES))
9409		return false;
9410
9411	get_drawable_deltas(drawable, pixmap, &dx, &dy);
9412
9413	if (!clipped) {
9414		dx += drawable->x;
9415		dy += drawable->y;
9416
9417		last.x = pt->x + dx;
9418		last.y = pt->y + dy;
9419		pt++;
9420
9421		while (--n) {
9422			DDXPointRec p;
9423
9424			p = *pt++;
9425			if (mode == CoordModePrevious) {
9426				p.x += last.x;
9427				p.y += last.y;
9428			} else {
9429				p.x += dx;
9430				p.y += dy;
9431			}
9432			DBG(("%s: line (%d, %d) -> (%d, %d)\n", __FUNCTION__, last.x, last.y, p.x, p.y));
9433
9434			if (last.x == p.x) {
9435				b->x1 = last.x;
9436				b->x2 = last.x + 1;
9437			} else if (last.x < p.x) {
9438				b->x1 = last.x;
9439				b->x2 = p.x;
9440			} else {
9441				b->x1 = p.x;
9442				b->x2 = last.x;
9443			}
9444
9445			if (last.y == p.y) {
9446				b->y1 = last.y;
9447				b->y2 = last.y + 1;
9448			} else if (last.y < p.y) {
9449				b->y1 = last.y;
9450				b->y2 = p.y;
9451			} else {
9452				b->y1 = p.y;
9453				b->y2 = last.y;
9454			}
9455			b->y2 += last.x == p.x && last.y != p.y;
9456			b->x2 += last.y == p.y && last.x != p.x;
9457			DBG(("%s: blt (%d, %d), (%d, %d)\n",
9458			     __FUNCTION__,
9459			     b->x1, b->y1, b->x2, b->y2));
9460
9461			if (++b == last_box) {
9462				assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0);
9463				fill.boxes(sna, &fill, boxes, last_box - boxes);
9464				if (damage)
9465					sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0);
9466				b = boxes;
9467			}
9468
9469			last = p;
9470		}
9471	} else {
9472		RegionRec clip;
9473
9474		region_set(&clip, extents);
9475		if (!region_maybe_clip(&clip, gc->pCompositeClip))
9476			return true;
9477
9478		last.x = pt->x + drawable->x;
9479		last.y = pt->y + drawable->y;
9480		pt++;
9481
9482		if (clip.data == NULL) {
9483			while (--n) {
9484				DDXPointRec p;
9485
9486				p = *pt++;
9487				if (mode == CoordModePrevious) {
9488					p.x += last.x;
9489					p.y += last.y;
9490				} else {
9491					p.x += drawable->x;
9492					p.y += drawable->y;
9493				}
9494				if (last.x == p.x) {
9495					b->x1 = last.x;
9496					b->x2 = last.x + 1;
9497				} else if (last.x < p.x) {
9498					b->x1 = last.x;
9499					b->x2 = p.x;
9500				} else {
9501					b->x1 = p.x;
9502					b->x2 = last.x;
9503				}
9504				if (last.y == p.y) {
9505					b->y1 = last.y;
9506					b->y2 = last.y + 1;
9507				} else if (last.y < p.y) {
9508					b->y1 = last.y;
9509					b->y2 = p.y;
9510				} else {
9511					b->y1 = p.y;
9512					b->y2 = last.y;
9513				}
9514				b->y2 += last.x == p.x && last.y != p.y;
9515				b->x2 += last.y == p.y && last.x != p.x;
9516				DBG(("%s: blt (%d, %d), (%d, %d)\n",
9517				     __FUNCTION__,
9518				     b->x1, b->y1, b->x2, b->y2));
9519				if (box_intersect(b, &clip.extents)) {
9520					b->x1 += dx;
9521					b->x2 += dx;
9522					b->y1 += dy;
9523					b->y2 += dy;
9524					if (++b == last_box) {
9525						assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0);
9526						fill.boxes(sna, &fill, boxes, last_box - boxes);
9527						if (damage)
9528							sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0);
9529						b = boxes;
9530					}
9531				}
9532
9533				last = p;
9534			}
9535		} else {
9536			const BoxRec * const clip_start = RegionBoxptr(&clip);
9537			const BoxRec * const clip_end = clip_start + clip.data->numRects;
9538			const BoxRec *c;
9539
9540			while (--n) {
9541				DDXPointRec p;
9542				BoxRec box;
9543
9544				p = *pt++;
9545				if (mode == CoordModePrevious) {
9546					p.x += last.x;
9547					p.y += last.y;
9548				} else {
9549					p.x += drawable->x;
9550					p.y += drawable->y;
9551				}
9552				if (last.x == p.x) {
9553					box.x1 = last.x;
9554					box.x2 = last.x + 1;
9555				} else if (last.x < p.x) {
9556					box.x1 = last.x;
9557					box.x2 = p.x;
9558				} else {
9559					box.x1 = p.x;
9560					box.x2 = last.x;
9561				}
9562				if (last.y == p.y) {
9563					box.y1 = last.y;
9564					box.y2 = last.y + 1;
9565				} else if (last.y < p.y) {
9566					box.y1 = last.y;
9567					box.y2 = p.y;
9568				} else {
9569					box.y1 = p.y;
9570					box.y2 = last.y;
9571				}
9572				b->y2 += last.x == p.x && last.y != p.y;
9573				b->x2 += last.y == p.y && last.x != p.x;
9574				DBG(("%s: blt (%d, %d), (%d, %d)\n",
9575				     __FUNCTION__,
9576				     box.x1, box.y1, box.x2, box.y2));
9577
9578				c = find_clip_box_for_y(clip_start,
9579							clip_end,
9580							box.y1);
9581				while (c != clip_end) {
9582					if (box.y2 <= c->y1)
9583						break;
9584
9585					*b = box;
9586					if (box_intersect(b, c++)) {
9587						b->x1 += dx;
9588						b->x2 += dx;
9589						b->y1 += dy;
9590						b->y2 += dy;
9591						if (++b == last_box) {
9592							assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0);
9593							fill.boxes(sna, &fill, boxes, last_box-boxes);
9594							if (damage)
9595								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
9596							b = boxes;
9597						}
9598					}
9599				}
9600
9601				last = p;
9602			}
9603		}
9604		RegionUninit(&clip);
9605	}
9606	if (b != boxes) {
9607		assert_pixmap_contains_boxes(pixmap, boxes, b-boxes, 0, 0);
9608		fill.boxes(sna, &fill, boxes, b - boxes);
9609		if (damage)
9610			sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0);
9611	}
9612	fill.done(sna, &fill);
9613	assert_pixmap_damage(pixmap);
9614	return true;
9615}
9616
9617static unsigned
9618sna_poly_line_extents(DrawablePtr drawable, GCPtr gc,
9619		      int mode, int n, DDXPointPtr pt,
9620		      BoxPtr out)
9621{
9622	BoxRec box;
9623	bool clip, blt = true;
9624
9625	if (n == 0)
9626		return 0;
9627
9628	box.x2 = box.x1 = pt->x;
9629	box.y2 = box.y1 = pt->y;
9630	if (mode == CoordModePrevious) {
9631		int x = box.x1;
9632		int y = box.y1;
9633		while (--n) {
9634			pt++;
9635			x += pt->x;
9636			y += pt->y;
9637			if (blt)
9638				blt &= pt->x == 0 || pt->y == 0;
9639			box_add_pt(&box, x, y);
9640		}
9641	} else {
9642		int x = box.x1;
9643		int y = box.y1;
9644		while (--n) {
9645			pt++;
9646			if (blt) {
9647				blt &= pt->x == x || pt->y == y;
9648				x = pt->x;
9649				y = pt->y;
9650			}
9651			box_add_pt(&box, pt->x, pt->y);
9652		}
9653	}
9654	box.x2++;
9655	box.y2++;
9656
9657	if (gc->lineWidth) {
9658		int extra = gc->lineWidth >> 1;
9659		if (n > 1) {
9660			if (gc->joinStyle == JoinMiter)
9661				extra = 6 * gc->lineWidth;
9662			else if (gc->capStyle == CapProjecting)
9663				extra = gc->lineWidth;
9664		}
9665		if (extra) {
9666			box.x1 -= extra;
9667			box.x2 += extra;
9668			box.y1 -= extra;
9669			box.y2 += extra;
9670		}
9671	}
9672
9673	clip = trim_and_translate_box(&box, drawable, gc);
9674	if (box_empty(&box))
9675		return 0;
9676
9677	*out = box;
9678	return 1 | blt << 2 | clip << 1;
9679}
9680
9681inline static int
9682_use_line_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags)
9683{
9684	uint32_t ignored;
9685
9686	if (USE_SPANS)
9687		return USE_SPANS > 0;
9688
9689	if (flags & RECTILINEAR)
9690		return PREFER_GPU;
9691
9692	if (gc->lineStyle != LineSolid && gc->lineWidth == 0)
9693		return 0;
9694
9695	if (gc_is_solid(gc, &ignored))
9696		return PREFER_GPU;
9697
9698	return !drawable_gc_inplace_hint(drawable, gc);
9699}
9700
9701inline static int
9702use_line_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags)
9703{
9704	int ret = _use_line_spans(drawable, gc, extents, flags);
9705	DBG(("%s? %d\n", __FUNCTION__, ret));
9706	return ret;
9707}
9708
9709static void
9710sna_poly_line(DrawablePtr drawable, GCPtr gc,
9711	      int mode, int n, DDXPointPtr pt)
9712{
9713	struct sna_pixmap *priv;
9714	struct sna_fill_spans data;
9715	uint32_t color;
9716
9717	DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d), lineWidth=%d\n",
9718	     __FUNCTION__, mode, n, pt[0].x, pt[0].y, gc->lineWidth));
9719
9720	data.flags = sna_poly_line_extents(drawable, gc, mode, n, pt,
9721					   &data.region.extents);
9722	if (data.flags == 0)
9723		return;
9724
9725	DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
9726	     data.region.extents.x1, data.region.extents.y1,
9727	     data.region.extents.x2, data.region.extents.y2,
9728	     data.flags));
9729
9730	data.region.data = NULL;
9731
9732	if (FORCE_FALLBACK)
9733		goto fallback;
9734
9735	if (!ACCEL_POLY_LINE)
9736		goto fallback;
9737
9738	data.pixmap = get_drawable_pixmap(drawable);
9739	data.sna = to_sna_from_pixmap(data.pixmap);
9740	if (wedged(data.sna)) {
9741		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
9742		goto fallback;
9743	}
9744
9745	DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lx [%d], rectlinear=%d\n",
9746	     __FUNCTION__,
9747	     gc->fillStyle, gc->fillStyle == FillSolid,
9748	     gc->lineStyle, gc->lineStyle == LineSolid,
9749	     gc->lineWidth,
9750	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask),
9751	     data.flags & RECTILINEAR));
9752
9753	if (!PM_IS_SOLID(drawable, gc->planemask))
9754		goto fallback;
9755
9756	priv = sna_pixmap(data.pixmap);
9757	if (!priv) {
9758		DBG(("%s: not attached to pixmap %ld\n",
9759		     __FUNCTION__, data.pixmap->drawable.serialNumber));
9760		goto fallback;
9761	}
9762
9763	if (gc->lineStyle != LineSolid) {
9764		DBG(("%s: lineStyle, %d, is not solid\n",
9765		     __FUNCTION__, gc->lineStyle));
9766		goto spans_fallback;
9767	}
9768	if (!(gc->lineWidth == 0 ||
9769	      (gc->lineWidth == 1 && (n == 1 || gc->alu == GXcopy)))) {
9770		DBG(("%s: non-zero lineWidth %d\n",
9771		     __FUNCTION__, gc->lineWidth));
9772		goto spans_fallback;
9773	}
9774
9775	data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
9776				      &data.region.extents,
9777				      &data.damage);
9778	if (data.bo == NULL)
9779		goto fallback;
9780
9781	if (gc_is_solid(gc, &color)) {
9782		DBG(("%s: trying solid fill [%08x]\n",
9783		     __FUNCTION__, (unsigned)color));
9784		if (data.flags & RECTILINEAR) {
9785			if (sna_poly_line_blt(drawable,
9786					      data.bo, data.damage,
9787					      gc, color, mode, n, pt,
9788					      &data.region.extents,
9789					      data.flags & IS_CLIPPED))
9790				return;
9791		} else { /* !rectilinear */
9792			if (sna_poly_zero_line_blt(drawable,
9793						   data.bo, data.damage,
9794						   gc, mode, n, pt,
9795						   &data.region.extents,
9796						   data.flags & IS_CLIPPED))
9797				return;
9798
9799		}
9800	} else if (data.flags & RECTILINEAR) {
9801		/* Try converting these to a set of rectangles instead */
9802		DDXPointRec p1, p2;
9803		xRectangle *rect;
9804		int i;
9805
9806		DBG(("%s: converting to rectagnles\n", __FUNCTION__));
9807
9808		rect = malloc (n * sizeof (xRectangle));
9809		if (rect == NULL)
9810			return;
9811
9812		p1 = pt[0];
9813		for (i = 1; i < n; i++) {
9814			if (mode == CoordModePrevious) {
9815				p2.x = p1.x + pt[i].x;
9816				p2.y = p1.y + pt[i].y;
9817			} else
9818				p2 = pt[i];
9819			if (p1.x < p2.x) {
9820				rect[i].x = p1.x;
9821				rect[i].width = p2.x - p1.x + 1;
9822			} else if (p1.x > p2.x) {
9823				rect[i].x = p2.x;
9824				rect[i].width = p1.x - p2.x + 1;
9825			} else {
9826				rect[i].x = p1.x;
9827				rect[i].width = 1;
9828			}
9829			if (p1.y < p2.y) {
9830				rect[i].y = p1.y;
9831				rect[i].height = p2.y - p1.y + 1;
9832			} else if (p1.y > p2.y) {
9833				rect[i].y = p2.y;
9834				rect[i].height = p1.y - p2.y + 1;
9835			} else {
9836				rect[i].y = p1.y;
9837				rect[i].height = 1;
9838			}
9839
9840			/* don't paint last pixel */
9841			if (gc->capStyle == CapNotLast) {
9842				if (p1.x == p2.x)
9843					rect[i].height--;
9844				else
9845					rect[i].width--;
9846			}
9847			p1 = p2;
9848		}
9849
9850		if (gc->fillStyle == FillTiled) {
9851			i = sna_poly_fill_rect_tiled_blt(drawable,
9852							 data.bo, data.damage,
9853							 gc, n - 1, rect + 1,
9854							 &data.region.extents,
9855							 data.flags & IS_CLIPPED);
9856		} else {
9857			i = sna_poly_fill_rect_stippled_blt(drawable,
9858							    data.bo, data.damage,
9859							    gc, n - 1, rect + 1,
9860							    &data.region.extents,
9861							    data.flags & IS_CLIPPED);
9862		}
9863		free (rect);
9864
9865		if (i)
9866			return;
9867	}
9868
9869spans_fallback:
9870	if ((data.bo = sna_drawable_use_bo(drawable,
9871					   use_line_spans(drawable, gc, &data.region.extents, data.flags),
9872					   &data.region.extents, &data.damage))) {
9873		DBG(("%s: converting line into spans\n", __FUNCTION__));
9874		get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy);
9875		sna_gc(gc)->priv = &data;
9876
9877		if (gc->lineWidth == 0 && gc_is_solid(gc, &color)) {
9878			struct sna_fill_op fill;
9879
9880			if (gc->lineStyle == LineSolid) {
9881				if (!sna_fill_init_blt(&fill,
9882						       data.sna, data.pixmap,
9883						       data.bo, gc->alu, color,
9884						       FILL_POINTS | FILL_SPANS))
9885					goto fallback;
9886
9887				data.op = &fill;
9888
9889				if ((data.flags & IS_CLIPPED) == 0) {
9890					if (data.dx | data.dy)
9891						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
9892					else
9893						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
9894					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill;
9895				} else {
9896					if (!region_maybe_clip(&data.region,
9897							       gc->pCompositeClip))
9898						return;
9899
9900					if (region_is_singular(&data.region)) {
9901						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
9902						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents;
9903					} else {
9904						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
9905						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes;
9906					}
9907				}
9908				assert(gc->miTranslate);
9909
9910				gc->ops = &sna_gc_ops__tmp;
9911				DBG(("%s: miZeroLine (solid fill)\n", __FUNCTION__));
9912				miZeroLine(drawable, gc, mode, n, pt);
9913				fill.done(data.sna, &fill);
9914			} else {
9915				data.op = &fill;
9916
9917				if ((data.flags & IS_CLIPPED) == 0) {
9918					if (data.dx | data.dy)
9919						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_offset;
9920					else
9921						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash;
9922					sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash;
9923				} else {
9924					if (!region_maybe_clip(&data.region,
9925							       gc->pCompositeClip))
9926						return;
9927
9928					if (region_is_singular(&data.region)) {
9929						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_extents;
9930						sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_extents;
9931					} else {
9932						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_boxes;
9933						sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_boxes;
9934					}
9935				}
9936				assert(gc->miTranslate);
9937
9938				DBG(("%s: miZeroLine (solid dash, clipped? %d (complex? %d)), fg pass [%08x]\n",
9939				     __FUNCTION__,
9940				     !!(data.flags & IS_CLIPPED), data.flags & IS_CLIPPED && !region_is_singular(&data.region),
9941				     gc->fgPixel));
9942
9943				if (!sna_fill_init_blt(&fill,
9944						       data.sna, data.pixmap,
9945						       data.bo, gc->alu, color,
9946						       FILL_POINTS | FILL_SPANS))
9947					goto fallback;
9948
9949				gc->ops = &sna_gc_ops__tmp;
9950				data.phase = gc->fgPixel;
9951				miZeroDashLine(drawable, gc, mode, n, pt);
9952				fill.done(data.sna, &fill);
9953
9954				DBG(("%s: miZeroLine (solid dash, clipped? %d (complex? %d)), bg pass [%08x]\n",
9955				     __FUNCTION__,
9956				     !!(data.flags & IS_CLIPPED), data.flags & IS_CLIPPED && !region_is_singular(&data.region),
9957				     gc->bgPixel));
9958
9959				if (sna_fill_init_blt(&fill,
9960						      data.sna, data.pixmap,
9961						      data.bo, gc->alu,
9962						      gc->bgPixel,
9963						      FILL_POINTS | FILL_SPANS)) {
9964					data.phase = gc->bgPixel;
9965					miZeroDashLine(drawable, gc, mode, n, pt);
9966					fill.done(data.sna, &fill);
9967				}
9968			}
9969		} else {
9970			/* Note that the WideDash functions alternate
9971			 * between filling using fgPixel and bgPixel
9972			 * so we need to reset state between FillSpans and
9973			 * cannot use the fill fast paths.
9974			 */
9975			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
9976			sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu;
9977			sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu;
9978			gc->ops = &sna_gc_ops__tmp;
9979
9980			switch (gc->lineStyle) {
9981			default:
9982				assert(0);
9983			case LineSolid:
9984				if (gc->lineWidth == 0) {
9985					DBG(("%s: miZeroLine\n", __FUNCTION__));
9986					miZeroLine(drawable, gc, mode, n, pt);
9987				} else {
9988					DBG(("%s: miWideLine\n", __FUNCTION__));
9989					miWideLine(drawable, gc, mode, n, pt);
9990				}
9991				break;
9992			case LineOnOffDash:
9993			case LineDoubleDash:
9994				if (gc->lineWidth == 0) {
9995					DBG(("%s: miZeroDashLine\n", __FUNCTION__));
9996					miZeroDashLine(drawable, gc, mode, n, pt);
9997				} else {
9998					DBG(("%s: miWideDash\n", __FUNCTION__));
9999					miWideDash(drawable, gc, mode, n, pt);
10000				}
10001				break;
10002			}
10003		}
10004
10005		gc->ops = (GCOps *)&sna_gc_ops;
10006		if (data.damage) {
10007			if (data.dx | data.dy)
10008				pixman_region_translate(&data.region, data.dx, data.dy);
10009			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
10010			sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap);
10011			assert_pixmap_damage(data.pixmap);
10012		}
10013		RegionUninit(&data.region);
10014		return;
10015	}
10016
10017fallback:
10018	DBG(("%s: fallback\n", __FUNCTION__));
10019	if (!region_maybe_clip(&data.region, gc->pCompositeClip))
10020		return;
10021
10022	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
10023		goto out;
10024	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
10025					     drawable_gc_flags(drawable, gc,
10026							       !(data.flags & RECTILINEAR && n == 2))))
10027		goto out;
10028
10029	if (sigtrap_get() == 0) {
10030		DBG(("%s: fbPolyLine\n", __FUNCTION__));
10031		fbPolyLine(drawable, gc, mode, n, pt);
10032		FALLBACK_FLUSH(drawable);
10033		sigtrap_put();
10034	}
10035out:
10036	sna_gc_move_to_gpu(gc);
10037	RegionUninit(&data.region);
10038}
10039
10040static inline void box_from_seg(BoxPtr b, const xSegment *seg, GCPtr gc)
10041{
10042	if (seg->x1 == seg->x2) {
10043		if (seg->y1 > seg->y2) {
10044			b->y2 = seg->y1 + 1;
10045			b->y1 = seg->y2 + 1;
10046			if (gc->capStyle != CapNotLast)
10047				b->y1--;
10048		} else {
10049			b->y1 = seg->y1;
10050			b->y2 = seg->y2;
10051			if (gc->capStyle != CapNotLast)
10052				b->y2++;
10053		}
10054		b->x1 = seg->x1;
10055		b->x2 = seg->x1 + 1;
10056	} else {
10057		if (seg->x1 > seg->x2) {
10058			b->x2 = seg->x1 + 1;
10059			b->x1 = seg->x2 + 1;
10060			if (gc->capStyle != CapNotLast)
10061				b->x1--;
10062		} else {
10063			b->x1 = seg->x1;
10064			b->x2 = seg->x2;
10065			if (gc->capStyle != CapNotLast)
10066				b->x2++;
10067		}
10068		b->y1 = seg->y1;
10069		b->y2 = seg->y1 + 1;
10070	}
10071
10072	DBG(("%s: seg=(%d,%d),(%d,%d); box=(%d,%d),(%d,%d)\n",
10073	     __FUNCTION__,
10074	     seg->x1, seg->y1, seg->x2, seg->y2,
10075	     b->x1, b->y1, b->x2, b->y2));
10076}
10077
10078static bool
10079sna_poly_segment_blt(DrawablePtr drawable,
10080		     struct kgem_bo *bo,
10081		     struct sna_damage **damage,
10082		     GCPtr gc, uint32_t pixel,
10083		     int n, xSegment *seg,
10084		     const BoxRec *extents, unsigned clipped)
10085{
10086	PixmapPtr pixmap = get_drawable_pixmap(drawable);
10087	struct sna *sna = to_sna_from_pixmap(pixmap);
10088	BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes);
10089	struct sna_fill_op fill;
10090	int16_t dx, dy;
10091
10092	DBG(("%s: n=%d, alu=%d, fg=%08lx, clipped=%d\n",
10093	     __FUNCTION__, n, gc->alu, gc->fgPixel, clipped));
10094
10095	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_SPANS))
10096		return false;
10097
10098	get_drawable_deltas(drawable, pixmap, &dx, &dy);
10099
10100	if (!clipped) {
10101		dx += drawable->x;
10102		dy += drawable->y;
10103		if (dx|dy) {
10104			do {
10105				unsigned nbox = n;
10106				if (nbox > ARRAY_SIZE(boxes))
10107					nbox = ARRAY_SIZE(boxes);
10108				n -= nbox;
10109				do {
10110					box_from_seg(b, seg++, gc);
10111					if (b->y2 > b->y1 && b->x2 > b->x1) {
10112						b->x1 += dx;
10113						b->x2 += dx;
10114						b->y1 += dy;
10115						b->y2 += dy;
10116						b++;
10117					}
10118				} while (--nbox);
10119
10120				if (b != boxes) {
10121					fill.boxes(sna, &fill, boxes, b-boxes);
10122					if (damage)
10123						sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
10124					b = boxes;
10125				}
10126			} while (n);
10127		} else {
10128			do {
10129				unsigned nbox = n;
10130				if (nbox > ARRAY_SIZE(boxes))
10131					nbox = ARRAY_SIZE(boxes);
10132				n -= nbox;
10133				do {
10134					box_from_seg(b++, seg++, gc);
10135				} while (--nbox);
10136
10137				if (b != boxes) {
10138					fill.boxes(sna, &fill, boxes, b-boxes);
10139					if (damage)
10140						sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
10141					b = boxes;
10142				}
10143			} while (n);
10144		}
10145	} else {
10146		RegionRec clip;
10147
10148		region_set(&clip, extents);
10149		if (!region_maybe_clip(&clip, gc->pCompositeClip))
10150			goto done;
10151
10152		if (clip.data) {
10153			const BoxRec * const clip_start = RegionBoxptr(&clip);
10154			const BoxRec * const clip_end = clip_start + clip.data->numRects;
10155			const BoxRec *c;
10156			do {
10157				BoxRec box;
10158
10159				box_from_seg(&box, seg++, gc);
10160				box.x1 += drawable->x;
10161				box.x2 += drawable->x;
10162				box.y1 += drawable->y;
10163				box.y2 += drawable->y;
10164				c = find_clip_box_for_y(clip_start,
10165							clip_end,
10166							box.y1);
10167				while (c != clip_end) {
10168					if (box.y2 <= c->y1)
10169						break;
10170
10171					*b = box;
10172					if (box_intersect(b, c++)) {
10173						b->x1 += dx;
10174						b->x2 += dx;
10175						b->y1 += dy;
10176						b->y2 += dy;
10177						if (++b == last_box) {
10178							fill.boxes(sna, &fill, boxes, last_box-boxes);
10179							if (damage)
10180								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
10181							b = boxes;
10182						}
10183					}
10184				}
10185			} while (--n);
10186		} else {
10187			do {
10188				box_from_seg(b, seg++, gc);
10189				b->x1 += drawable->x;
10190				b->x2 += drawable->x;
10191				b->y1 += drawable->y;
10192				b->y2 += drawable->y;
10193				if (box_intersect(b, &clip.extents)) {
10194					b->x1 += dx;
10195					b->x2 += dx;
10196					b->y1 += dy;
10197					b->y2 += dy;
10198					if (++b == last_box) {
10199						fill.boxes(sna, &fill, boxes, last_box-boxes);
10200						if (damage)
10201							sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
10202						b = boxes;
10203					}
10204				}
10205			} while (--n);
10206		}
10207		RegionUninit(&clip);
10208	}
10209	if (b != boxes) {
10210		fill.boxes(sna, &fill, boxes, b - boxes);
10211		if (damage)
10212			sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0);
10213	}
10214done:
10215	fill.done(sna, &fill);
10216	assert_pixmap_damage(pixmap);
10217	return true;
10218}
10219
10220static bool
10221sna_poly_zero_segment_blt(DrawablePtr drawable,
10222			  struct kgem_bo *bo,
10223			  struct sna_damage **damage,
10224			  GCPtr gc, const int _n, const xSegment *_s,
10225			  const BoxRec *extents, unsigned clipped)
10226{
10227	static void * const _jump[] = {
10228		&&no_damage,
10229		&&damage,
10230
10231		&&no_damage_offset,
10232		&&damage_offset,
10233	};
10234
10235	PixmapPtr pixmap = get_drawable_pixmap(drawable);
10236	struct sna *sna = to_sna_from_pixmap(pixmap);
10237	unsigned int bias = miGetZeroLineBias(drawable->pScreen);
10238	struct sna_fill_op fill;
10239	RegionRec clip;
10240	const BoxRec *last_extents;
10241	BoxRec box[512], *b;
10242	BoxRec *const last_box = box + ARRAY_SIZE(box);
10243	int16_t dx, dy;
10244	void *jump, *ret;
10245
10246	DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n",
10247	     __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage));
10248	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_BOXES))
10249		return false;
10250
10251	get_drawable_deltas(drawable, pixmap, &dx, &dy);
10252
10253	region_set(&clip, extents);
10254	if (clipped) {
10255		if (!region_maybe_clip(&clip, gc->pCompositeClip))
10256			return true;
10257	}
10258	DBG(("%s: [clipped] extents=(%d, %d), (%d, %d), delta=(%d, %d)\n",
10259	     __FUNCTION__,
10260	     clip.extents.x1, clip.extents.y1,
10261	     clip.extents.x2, clip.extents.y2,
10262	     dx, dy));
10263
10264	jump = _jump[(damage != NULL) | !!(dx|dy) << 1];
10265
10266	b = box;
10267	extents = region_rects(&clip);
10268	last_extents = extents + region_num_rects(&clip);
10269	do {
10270		int n = _n;
10271		const xSegment *s = _s;
10272		do {
10273			int16_t sdx, sdy;
10274			int adx, ady, length;
10275			int e, e1, e2, e3;
10276			int x1, x2;
10277			int y1, y2;
10278			int oc1, oc2;
10279			int octant;
10280
10281			x1 = s->x1 + drawable->x;
10282			y1 = s->y1 + drawable->y;
10283			x2 = s->x2 + drawable->x;
10284			y2 = s->y2 + drawable->y;
10285			s++;
10286
10287			DBG(("%s: segment (%d, %d) to (%d, %d)\n",
10288			     __FUNCTION__, x1, y1, x2, y2));
10289			if (x2 == x1 && y2 == y1)
10290				continue;
10291
10292			oc1 = 0;
10293			OUTCODES(oc1, x1, y1, extents);
10294			oc2 = 0;
10295			OUTCODES(oc2, x2, y2, extents);
10296			if (oc1 & oc2)
10297				continue;
10298
10299			CalcLineDeltas(x1, y1, x2, y2,
10300				       adx, ady, sdx, sdy,
10301				       1, 1, octant);
10302
10303			DBG(("%s: adx=(%d, %d), sdx=(%d, %d)\n",
10304			     __FUNCTION__, adx, ady, sdx, sdy));
10305			if (adx == 0 || ady == 0) {
10306				if (x1 <= x2) {
10307					b->x1 = x1;
10308					b->x2 = x2;
10309				} else {
10310					b->x1 = x2;
10311					b->x2 = x1;
10312				}
10313				if (y1 <= y2) {
10314					b->y1 = y1;
10315					b->y2 = y2;
10316				} else {
10317					b->y1 = y2;
10318					b->y2 = y1;
10319				}
10320				b->x2++;
10321				b->y2++;
10322				if (oc1 | oc2)
10323					box_intersect(b, extents);
10324				if (++b == last_box) {
10325					ret = &&rectangle_continue;
10326					goto *jump;
10327rectangle_continue:
10328					b = box;
10329				}
10330			} else if (adx >= ady) {
10331				bool dirty;
10332
10333				/* X-major segment */
10334				e1 = ady << 1;
10335				e2 = e1 - (adx << 1);
10336				e  = e1 - adx;
10337				length = adx;	/* don't draw endpoint in main loop */
10338
10339				FIXUP_ERROR(e, octant, bias);
10340
10341				if (oc1 | oc2) {
10342					int pt1_clipped, pt2_clipped;
10343					int x = x1, y = y1;
10344
10345					if (miZeroClipLine(extents->x1, extents->y1,
10346							   extents->x2-1, extents->y2-1,
10347							   &x1, &y1, &x2, &y2,
10348							   adx, ady,
10349							   &pt1_clipped, &pt2_clipped,
10350							   octant, bias, oc1, oc2) == -1)
10351						continue;
10352
10353					length = abs(x2 - x1);
10354					if (length == 0)
10355						continue;
10356
10357					if (pt1_clipped) {
10358						int clipdx = abs(x1 - x);
10359						int clipdy = abs(y1 - y);
10360						e += clipdy * e2 + (clipdx - clipdy) * e1;
10361					}
10362				}
10363				e3 = e2 - e1;
10364				e  = e - e1;
10365
10366				b->x1 = x1;
10367				b->y1 = y1;
10368				dirty = false;
10369				while (length--) {
10370					dirty = true;
10371					e += e1;
10372					if (e >= 0) {
10373						e += e3;
10374
10375						if (sdx < 0) {
10376							b->x2 = b->x1 + 1;
10377							b->x1 = x1;
10378						} else
10379							b->x2 = x1 + 1;
10380						b->y2 = b->y1 + 1;
10381
10382						DBG(("%s: horizontal step: (%d, %d), box: (%d, %d), (%d, %d)\n",
10383						     __FUNCTION__, x1, y1,
10384						     b->x1, b->y1, b->x2, b->y2));
10385
10386						if (++b == last_box) {
10387							ret = &&X_continue;
10388							goto *jump;
10389X_continue:
10390							b = box;
10391						}
10392
10393						b->x1 = x1 + sdx;
10394						b->y1 = y1 += sdy;
10395						dirty = false;
10396					}
10397					x1 += sdx;
10398				}
10399				if (dirty) {
10400					x1 -= sdx;
10401					DBG(("%s: horizontal tail: (%d, %d)\n",
10402					     __FUNCTION__, x1, y1));
10403					if (sdx < 0) {
10404						b->x2 = b->x1 + 1;
10405						b->x1 = x1;
10406					} else
10407						b->x2 = x1 + 1;
10408					b->y2 = b->y1 + 1;
10409
10410					if (++b == last_box) {
10411						ret = &&X2_continue;
10412						goto *jump;
10413X2_continue:
10414						b = box;
10415					}
10416				}
10417			} else {
10418				bool dirty;
10419
10420				/* Y-major segment */
10421				e1 = adx << 1;
10422				e2 = e1 - (ady << 1);
10423				e  = e1 - ady;
10424				length  = ady;	/* don't draw endpoint in main loop */
10425
10426				SetYMajorOctant(octant);
10427				FIXUP_ERROR(e, octant, bias);
10428
10429				if (oc1 | oc2) {
10430					int pt1_clipped, pt2_clipped;
10431					int x = x1, y = y1;
10432
10433					if (miZeroClipLine(extents->x1, extents->y1,
10434							   extents->x2-1, extents->y2-1,
10435							   &x1, &y1, &x2, &y2,
10436							   adx, ady,
10437							   &pt1_clipped, &pt2_clipped,
10438							   octant, bias, oc1, oc2) == -1)
10439						continue;
10440
10441					length = abs(y2 - y1);
10442					if (length == 0)
10443						continue;
10444
10445					if (pt1_clipped) {
10446						int clipdx = abs(x1 - x);
10447						int clipdy = abs(y1 - y);
10448						e += clipdx * e2 + (clipdy - clipdx) * e1;
10449					}
10450				}
10451
10452				e3 = e2 - e1;
10453				e  = e - e1;
10454
10455				b->x1 = x1;
10456				b->y1 = y1;
10457				dirty = false;
10458				while (length--) {
10459					e += e1;
10460					dirty = true;
10461					if (e >= 0) {
10462						e += e3;
10463
10464						if (sdy < 0) {
10465							b->y2 = b->y1 + 1;
10466							b->y1 = y1;
10467						} else
10468							b->y2 = y1 + 1;
10469						b->x2 = x1 + 1;
10470
10471						if (++b == last_box) {
10472							ret = &&Y_continue;
10473							goto *jump;
10474Y_continue:
10475							b = box;
10476						}
10477
10478						b->x1 = x1 += sdx;
10479						b->y1 = y1 + sdy;
10480						dirty = false;
10481					}
10482					y1 += sdy;
10483				}
10484
10485				if (dirty) {
10486					y1 -= sdy;
10487					if (sdy < 0) {
10488						b->y2 = b->y1 + 1;
10489						b->y1 = y1;
10490					} else
10491						b->y2 = y1 + 1;
10492					b->x2 = x1 + 1;
10493
10494					if (++b == last_box) {
10495						ret = &&Y2_continue;
10496						goto *jump;
10497Y2_continue:
10498						b = box;
10499					}
10500				}
10501			}
10502		} while (--n);
10503	} while (++extents != last_extents);
10504
10505	if (b != box) {
10506		ret = &&done;
10507		goto *jump;
10508	}
10509
10510done:
10511	fill.done(sna, &fill);
10512	assert_pixmap_damage(pixmap);
10513	RegionUninit(&clip);
10514	return true;
10515
10516damage:
10517	sna_damage_add_boxes(damage, box, b-box, 0, 0);
10518no_damage:
10519	fill.boxes(sna, &fill, box, b-box);
10520	goto *ret;
10521
10522no_damage_offset:
10523	{
10524		BoxRec *bb = box;
10525		do {
10526			bb->x1 += dx;
10527			bb->x2 += dx;
10528			bb->y1 += dy;
10529			bb->y2 += dy;
10530		} while (++bb != b);
10531		fill.boxes(sna, &fill, box, b - box);
10532	}
10533	goto *ret;
10534
10535damage_offset:
10536	{
10537		BoxRec *bb = box;
10538		do {
10539			bb->x1 += dx;
10540			bb->x2 += dx;
10541			bb->y1 += dy;
10542			bb->y2 += dy;
10543		} while (++bb != b);
10544		fill.boxes(sna, &fill, box, b - box);
10545		sna_damage_add_boxes(damage, box, b - box, 0, 0);
10546	}
10547	goto *ret;
10548}
10549
10550static unsigned
10551sna_poly_segment_extents(DrawablePtr drawable, GCPtr gc,
10552			 int n, xSegment *seg,
10553			 BoxPtr out)
10554{
10555	BoxRec box;
10556	bool clipped, can_blit;
10557
10558	if (n == 0)
10559		return 0;
10560
10561	if (seg->x2 >= seg->x1) {
10562		box.x1 = seg->x1;
10563		box.x2 = seg->x2;
10564	} else {
10565		box.x2 = seg->x1;
10566		box.x1 = seg->x2;
10567	}
10568
10569	if (seg->y2 >= seg->y1) {
10570		box.y1 = seg->y1;
10571		box.y2 = seg->y2;
10572	} else {
10573		box.y2 = seg->y1;
10574		box.y1 = seg->y2;
10575	}
10576
10577	can_blit = seg->x1 == seg->x2 || seg->y1 == seg->y2;
10578	while (--n) {
10579		seg++;
10580		if (seg->x2 > seg->x1) {
10581			if (seg->x1 < box.x1) box.x1 = seg->x1;
10582			if (seg->x2 > box.x2) box.x2 = seg->x2;
10583		} else {
10584			if (seg->x2 < box.x1) box.x1 = seg->x2;
10585			if (seg->x1 > box.x2) box.x2 = seg->x1;
10586		}
10587
10588		if (seg->y2 > seg->y1) {
10589			if (seg->y1 < box.y1) box.y1 = seg->y1;
10590			if (seg->y2 > box.y2) box.y2 = seg->y2;
10591		} else {
10592			if (seg->y2 < box.y1) box.y1 = seg->y2;
10593			if (seg->y1 > box.y2) box.y2 = seg->y1;
10594		}
10595
10596		if (can_blit && !(seg->x1 == seg->x2 || seg->y1 == seg->y2))
10597			can_blit = false;
10598	}
10599
10600	box.x2++;
10601	box.y2++;
10602
10603	if (gc->lineWidth) {
10604		int extra = gc->lineWidth;
10605		if (gc->capStyle != CapProjecting)
10606			extra >>= 1;
10607		if (extra) {
10608			box.x1 -= extra;
10609			box.x2 += extra;
10610			box.y1 -= extra;
10611			box.y2 += extra;
10612		}
10613	}
10614
10615	DBG(("%s: unclipped, untranslated extents (%d, %d), (%d, %d)\n",
10616	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
10617
10618	clipped = trim_and_translate_box(&box, drawable, gc);
10619	if (box_empty(&box))
10620		return 0;
10621
10622	*out = box;
10623	return 1 | clipped << 1 | can_blit << 2;
10624}
10625
10626static void
10627sna_poly_segment(DrawablePtr drawable, GCPtr gc, int n, xSegment *seg)
10628{
10629	struct sna_pixmap *priv;
10630	struct sna_fill_spans data;
10631	uint32_t color;
10632
10633	DBG(("%s(n=%d, first=((%d, %d), (%d, %d)), lineWidth=%d\n",
10634	     __FUNCTION__,
10635	     n, seg->x1, seg->y1, seg->x2, seg->y2,
10636	     gc->lineWidth));
10637
10638	data.flags = sna_poly_segment_extents(drawable, gc, n, seg,
10639					      &data.region.extents);
10640	if (data.flags == 0)
10641		return;
10642
10643	DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__,
10644	     data.region.extents.x1, data.region.extents.y1,
10645	     data.region.extents.x2, data.region.extents.y2));
10646
10647	data.region.data = NULL;
10648
10649	if (FORCE_FALLBACK)
10650		goto fallback;
10651
10652	if (!ACCEL_POLY_SEGMENT)
10653		goto fallback;
10654
10655	data.pixmap = get_drawable_pixmap(drawable);
10656	data.sna = to_sna_from_pixmap(data.pixmap);
10657	priv = sna_pixmap(data.pixmap);
10658	if (priv == NULL) {
10659		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
10660		goto fallback;
10661	}
10662
10663	if (wedged(data.sna)) {
10664		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
10665		goto fallback;
10666	}
10667
10668	DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lu [%d], rectlinear=%d\n",
10669	     __FUNCTION__,
10670	     gc->fillStyle, gc->fillStyle == FillSolid,
10671	     gc->lineStyle, gc->lineStyle == LineSolid,
10672	     gc->lineWidth,
10673	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask),
10674	     data.flags & RECTILINEAR));
10675	if (!PM_IS_SOLID(drawable, gc->planemask))
10676		goto fallback;
10677
10678	if (gc->lineStyle != LineSolid || gc->lineWidth > 1)
10679		goto spans_fallback;
10680
10681	data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
10682				      &data.region.extents,
10683				      &data.damage);
10684	if (data.bo == NULL)
10685		goto fallback;
10686
10687	if (gc_is_solid(gc, &color)) {
10688		DBG(("%s: trying blt solid fill [%08x, flags=%x] paths\n",
10689		     __FUNCTION__, (unsigned)color, data.flags));
10690
10691		if (data.flags & RECTILINEAR) {
10692			if (sna_poly_segment_blt(drawable,
10693						 data.bo, data.damage,
10694						 gc, color, n, seg,
10695						 &data.region.extents,
10696						 data.flags & IS_CLIPPED))
10697				return;
10698		} else {
10699			if (sna_poly_zero_segment_blt(drawable,
10700						      data.bo, data.damage,
10701						      gc, n, seg,
10702						      &data.region.extents,
10703						      data.flags & IS_CLIPPED))
10704				return;
10705		}
10706	} else if (data.flags & RECTILINEAR) {
10707		/* Try converting these to a set of rectangles instead */
10708		xRectangle *rect;
10709		int i;
10710
10711		DBG(("%s: converting to rectangles\n", __FUNCTION__));
10712
10713		rect = malloc (n * sizeof (xRectangle));
10714		if (rect == NULL)
10715			return;
10716
10717		for (i = 0; i < n; i++) {
10718			if (seg[i].x1 < seg[i].x2) {
10719				rect[i].x = seg[i].x1;
10720				rect[i].width = seg[i].x2 - seg[i].x1 + 1;
10721			} else if (seg[i].x1 > seg[i].x2) {
10722				rect[i].x = seg[i].x2;
10723				rect[i].width = seg[i].x1 - seg[i].x2 + 1;
10724			} else {
10725				rect[i].x = seg[i].x1;
10726				rect[i].width = 1;
10727			}
10728			if (seg[i].y1 < seg[i].y2) {
10729				rect[i].y = seg[i].y1;
10730				rect[i].height = seg[i].y2 - seg[i].y1 + 1;
10731			} else if (seg[i].y1 > seg[i].y2) {
10732				rect[i].y = seg[i].y2;
10733				rect[i].height = seg[i].y1 - seg[i].y2 + 1;
10734			} else {
10735				rect[i].y = seg[i].y1;
10736				rect[i].height = 1;
10737			}
10738
10739			/* don't paint last pixel */
10740			if (gc->capStyle == CapNotLast) {
10741				if (seg[i].x1 == seg[i].x2)
10742					rect[i].height--;
10743				else
10744					rect[i].width--;
10745			}
10746		}
10747
10748		if (gc->fillStyle == FillTiled) {
10749			i = sna_poly_fill_rect_tiled_blt(drawable,
10750							 data.bo, data.damage,
10751							 gc, n, rect,
10752							 &data.region.extents,
10753							 data.flags);
10754		} else {
10755			i = sna_poly_fill_rect_stippled_blt(drawable,
10756							    data.bo, data.damage,
10757							    gc, n, rect,
10758							    &data.region.extents,
10759							    data.flags);
10760		}
10761		free (rect);
10762
10763		if (i)
10764			return;
10765	}
10766
10767spans_fallback:
10768	if ((data.bo = sna_drawable_use_bo(drawable,
10769					   use_line_spans(drawable, gc, &data.region.extents, data.flags),
10770					   &data.region.extents,
10771					   &data.damage))) {
10772		void (*line)(DrawablePtr, GCPtr, int, int, DDXPointPtr);
10773		int i;
10774
10775		DBG(("%s: converting segments into spans\n", __FUNCTION__));
10776
10777		switch (gc->lineStyle) {
10778		default:
10779		case LineSolid:
10780			if (gc->lineWidth == 0)
10781				line = miZeroLine;
10782			else
10783				line = miWideLine;
10784			break;
10785		case LineOnOffDash:
10786		case LineDoubleDash:
10787			if (gc->lineWidth == 0)
10788				line = miZeroDashLine;
10789			else
10790				line = miWideDash;
10791			break;
10792		}
10793
10794		get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy);
10795		sna_gc(gc)->priv = &data;
10796
10797		if (gc->lineWidth == 0 &&
10798		    gc->lineStyle == LineSolid &&
10799		    gc_is_solid(gc, &color)) {
10800			struct sna_fill_op fill;
10801
10802			if (!sna_fill_init_blt(&fill,
10803					       data.sna, data.pixmap,
10804					       data.bo, gc->alu, color,
10805					       FILL_POINTS | FILL_SPANS))
10806				goto fallback;
10807
10808			data.op = &fill;
10809
10810			if ((data.flags & IS_CLIPPED) == 0) {
10811				if (data.dx | data.dy)
10812					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
10813				else
10814					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
10815				sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill;
10816			} else {
10817				if (!region_maybe_clip(&data.region,
10818						       gc->pCompositeClip))
10819					return;
10820
10821				if (region_is_singular(&data.region)) {
10822					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
10823					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents;
10824				} else {
10825					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
10826					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes;
10827				}
10828			}
10829			assert(gc->miTranslate);
10830			gc->ops = &sna_gc_ops__tmp;
10831			for (i = 0; i < n; i++)
10832				line(drawable, gc, CoordModeOrigin, 2,
10833				     (DDXPointPtr)&seg[i]);
10834
10835			fill.done(data.sna, &fill);
10836		} else {
10837			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
10838			sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu;
10839			sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu;
10840			gc->ops = &sna_gc_ops__tmp;
10841
10842			for (i = 0; i < n; i++)
10843				line(drawable, gc, CoordModeOrigin, 2,
10844				     (DDXPointPtr)&seg[i]);
10845		}
10846
10847		gc->ops = (GCOps *)&sna_gc_ops;
10848		if (data.damage) {
10849			if (data.dx | data.dy)
10850				pixman_region_translate(&data.region, data.dx, data.dy);
10851			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
10852			sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap);
10853		}
10854		assert_pixmap_damage(data.pixmap);
10855		RegionUninit(&data.region);
10856		return;
10857	}
10858
10859fallback:
10860	DBG(("%s: fallback\n", __FUNCTION__));
10861	if (!region_maybe_clip(&data.region, gc->pCompositeClip))
10862		return;
10863
10864	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
10865		goto out;
10866	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
10867					     drawable_gc_flags(drawable, gc,
10868							       !(data.flags & RECTILINEAR && n == 1))))
10869		goto out;
10870
10871	if (sigtrap_get() == 0) {
10872		DBG(("%s: fbPolySegment\n", __FUNCTION__));
10873		fbPolySegment(drawable, gc, n, seg);
10874		FALLBACK_FLUSH(drawable);
10875		sigtrap_put();
10876	}
10877out:
10878	sna_gc_move_to_gpu(gc);
10879	RegionUninit(&data.region);
10880}
10881
10882static unsigned
10883sna_poly_rectangle_extents(DrawablePtr drawable, GCPtr gc,
10884			   int n, xRectangle *r,
10885			   BoxPtr out)
10886{
10887	Box32Rec box;
10888	int extra = gc->lineWidth >> 1;
10889	bool clipped;
10890	bool zero = false;
10891
10892	if (n == 0)
10893		return 0;
10894
10895	box.x1 = r->x;
10896	box.y1 = r->y;
10897	box.x2 = box.x1 + r->width;
10898	box.y2 = box.y1 + r->height;
10899	zero |= (r->width | r->height) == 0;
10900
10901	while (--n) {
10902		r++;
10903		zero |= (r->width | r->height) == 0;
10904		box32_add_rect(&box, r);
10905	}
10906
10907	box.x2++;
10908	box.y2++;
10909
10910	if (extra) {
10911		box.x1 -= extra;
10912		box.x2 += extra;
10913		box.y1 -= extra;
10914		box.y2 += extra;
10915		zero = !zero;
10916	} else
10917		zero = true;
10918
10919	DBG(("%s: unclipped original extents: (%d, %d), (%d, %d)\n",
10920	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
10921	clipped = box32_trim_and_translate(&box, drawable, gc);
10922	if (!box32_to_box16(&box, out))
10923		return 0;
10924
10925	DBG(("%s: extents: (%d, %d), (%d, %d), clipped? %d\n",
10926	     __FUNCTION__, out->x1, out->y1, out->x2, out->y2, clipped));
10927	return 1 | clipped << 1 | zero << 2;
10928}
10929
10930static bool
10931sna_poly_rectangle_blt(DrawablePtr drawable,
10932		       struct kgem_bo *bo,
10933		       struct sna_damage **damage,
10934		       GCPtr gc, int n, xRectangle *r,
10935		       const BoxRec *extents, unsigned clipped)
10936{
10937	PixmapPtr pixmap = get_drawable_pixmap(drawable);
10938	struct sna *sna = to_sna_from_pixmap(pixmap);
10939	struct sna_fill_op fill;
10940	BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes);
10941	int16_t dx, dy;
10942	static void * const jump[] = {
10943		&&wide,
10944		&&zero,
10945		&&wide_clipped,
10946		&&zero_clipped,
10947	};
10948
10949	DBG(("%s: n=%d, alu=%d, width=%d, fg=%08lx, damge=%p, clipped?=%d\n",
10950	     __FUNCTION__, n, gc->alu, gc->lineWidth, gc->fgPixel, damage, clipped));
10951	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_BOXES))
10952		return false;
10953
10954	get_drawable_deltas(drawable, pixmap, &dx, &dy);
10955
10956	goto *jump[(gc->lineWidth <= 1) | clipped];
10957
10958zero:
10959	dx += drawable->x;
10960	dy += drawable->y;
10961
10962	do {
10963		xRectangle rr = *r++;
10964
10965		if ((rr.width | rr.height) == 0)
10966			continue; /* XXX -> PolyLine */
10967
10968		DBG(("%s - zero : r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__,
10969		     n, rr.x, rr.y, rr.width, rr.height));
10970		rr.x += dx;
10971		rr.y += dy;
10972
10973		if (b+4 > last_box) {
10974			fill.boxes(sna, &fill, boxes, b-boxes);
10975			if (damage)
10976				sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
10977			b = boxes;
10978		}
10979
10980		if (rr.width <= 1 || rr.height <= 1) {
10981			b->x1 = rr.x;
10982			b->y1 = rr.y;
10983			b->x2 = rr.x + rr.width + (rr.height != 0);
10984			b->y2 = rr.y + rr.height + (rr.width != 0);
10985			DBG(("%s: blt (%d, %d), (%d, %d)\n",
10986			     __FUNCTION__,
10987			     b->x1, b->y1, b->x2,b->y2));
10988			b++;
10989		} else {
10990			b[0].x1 = rr.x;
10991			b[0].y1 = rr.y;
10992			b[0].x2 = rr.x + rr.width + 1;
10993			b[0].y2 = rr.y + 1;
10994
10995			b[1] = b[0];
10996			b[1].y1 += rr.height;
10997			b[1].y2 += rr.height;
10998
10999			b[2].y1 = rr.y + 1;
11000			b[2].y2 = rr.y + rr.height;
11001			b[2].x1 = rr.x;
11002			b[2].x2 = rr.x + 1;
11003
11004			b[3] = b[2];
11005			b[3].x1 += rr.width;
11006			b[3].x2 += rr.width;
11007
11008			b += 4;
11009		}
11010	} while (--n);
11011	goto done;
11012
11013zero_clipped:
11014	{
11015		RegionRec clip;
11016		BoxRec box[4];
11017		int count;
11018
11019		region_set(&clip, extents);
11020		if (!region_maybe_clip(&clip, gc->pCompositeClip))
11021			goto done;
11022
11023		if (clip.data) {
11024			const BoxRec * const clip_start = RegionBoxptr(&clip);
11025			const BoxRec * const clip_end = clip_start + clip.data->numRects;
11026			const BoxRec *c;
11027			do {
11028				xRectangle rr = *r++;
11029
11030				DBG(("%s - zero, clipped complex: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__,
11031				     n, rr.x, rr.y, rr.width, rr.height));
11032
11033				if ((rr.width | rr.height) == 0)
11034					continue; /* XXX -> PolyLine */
11035
11036				rr.x += drawable->x;
11037				rr.y += drawable->y;
11038
11039				if (rr.width <= 1 || rr.height <= 1) {
11040					box[0].x1 = rr.x;
11041					box[0].y1 = rr.y;
11042					box[0].x2 = rr.x + rr.width + (rr.height != 0);
11043					box[0].y2 = rr.y + rr.height + (rr.width != 0);
11044					count = 1;
11045				} else {
11046					box[0].x1 = rr.x;
11047					box[0].y1 = rr.y;
11048					box[0].x2 = rr.x + rr.width + 1;
11049					box[0].y2 = rr.y + 1;
11050
11051					box[1] = box[0];
11052					box[1].y1 += rr.height;
11053					box[1].y2 += rr.height;
11054
11055					box[2].y1 = rr.y + 1;
11056					box[2].y2 = rr.y + rr.height;
11057					box[2].x1 = rr.x;
11058					box[2].x2 = rr.x + 1;
11059
11060					box[3] = box[2];
11061					box[3].x1 += rr.width;
11062					box[3].x2 += rr.width;
11063					count = 4;
11064				}
11065
11066				while (count--) {
11067					c = find_clip_box_for_y(clip_start,
11068								clip_end,
11069								box[count].y1);
11070					while (c != clip_end) {
11071						if (box[count].y2 <= c->y1)
11072							break;
11073
11074						*b = box[count];
11075						if (box_intersect(b, c++)) {
11076							b->x1 += dx;
11077							b->x2 += dx;
11078							b->y1 += dy;
11079							b->y2 += dy;
11080							if (++b == last_box) {
11081								fill.boxes(sna, &fill, boxes, last_box-boxes);
11082								if (damage)
11083									sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11084								b = boxes;
11085							}
11086						}
11087
11088					}
11089				}
11090			} while (--n);
11091		} else {
11092			do {
11093				xRectangle rr = *r++;
11094				DBG(("%s - zero, clip: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__,
11095				     n, rr.x, rr.y, rr.width, rr.height));
11096
11097				if ((rr.width | rr.height) == 0)
11098					continue; /* XXX -> PolyLine */
11099
11100				rr.x += drawable->x;
11101				rr.y += drawable->y;
11102
11103				if (rr.width <= 1 || rr.height <= 1) {
11104					box[0].x1 = rr.x;
11105					box[0].y1 = rr.y;
11106					box[0].x2 = rr.x + rr.width + (rr.height != 0);
11107					box[0].y2 = rr.y + rr.height + (rr.width != 0);
11108					count = 1;
11109				} else {
11110					box[0].x1 = rr.x;
11111					box[0].y1 = rr.y;
11112					box[0].x2 = rr.x + rr.width + 1;
11113					box[0].y2 = rr.y + 1;
11114
11115					box[1] = box[0];
11116					box[1].y1 += rr.height;
11117					box[1].y2 += rr.height;
11118
11119					box[2].y1 = rr.y + 1;
11120					box[2].y2 = rr.y + rr.height;
11121					box[2].x1 = rr.x;
11122					box[2].x2 = rr.x + 1;
11123
11124					box[3] = box[2];
11125					box[3].x1 += rr.width;
11126					box[3].x2 += rr.width;
11127					count = 4;
11128				}
11129
11130				while (count--) {
11131					*b = box[count];
11132					if (box_intersect(b, &clip.extents)) {
11133						b->x1 += dx;
11134						b->x2 += dx;
11135						b->y1 += dy;
11136						b->y2 += dy;
11137						if (++b == last_box) {
11138							fill.boxes(sna, &fill, boxes, last_box-boxes);
11139							if (damage)
11140								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11141							b = boxes;
11142						}
11143					}
11144
11145				}
11146			} while (--n);
11147		}
11148		RegionUninit(&clip);
11149	}
11150	goto done;
11151
11152wide_clipped:
11153	{
11154		RegionRec clip;
11155		BoxRec box[4];
11156		int16_t offset2 = gc->lineWidth;
11157		int16_t offset1 = offset2 >> 1;
11158		int16_t offset3 = offset2 - offset1;
11159
11160		region_set(&clip, extents);
11161		if (!region_maybe_clip(&clip, gc->pCompositeClip))
11162			goto done;
11163
11164		DBG(("%s: wide clipped: extents=((%d, %d), (%d, %d))\n",
11165		     __FUNCTION__,
11166		     clip.extents.x1, clip.extents.y1,
11167		     clip.extents.x2, clip.extents.y2));
11168
11169		if (clip.data) {
11170			const BoxRec * const clip_start = RegionBoxptr(&clip);
11171			const BoxRec * const clip_end = clip_start + clip.data->numRects;
11172			const BoxRec *c;
11173			do {
11174				xRectangle rr = *r++;
11175				int count;
11176
11177				if ((rr.width | rr.height) == 0)
11178					continue; /* XXX -> PolyLine */
11179
11180				rr.x += drawable->x;
11181				rr.y += drawable->y;
11182
11183				if (rr.height <= offset2 || rr.width <= offset2) {
11184					if (rr.height == 0) {
11185						box[0].x1 = rr.x;
11186						box[0].x2 = rr.x + rr.width;
11187					} else {
11188						box[0].x1 = rr.x - offset1;
11189						box[0].x2 = rr.x + rr.width + offset3;
11190					}
11191					if (rr.width == 0) {
11192						box[0].y1 = rr.y;
11193						box[0].y2 = rr.y + rr.height;
11194					} else {
11195						box[0].y1 = rr.y - offset1;
11196						box[0].y2 = rr.y + rr.height + offset3;
11197					}
11198					count = 1;
11199				} else {
11200					box[0].x1 = rr.x - offset1;
11201					box[0].x2 = box[0].x1 + rr.width + offset2;
11202					box[0].y1 = rr.y - offset1;
11203					box[0].y2 = box[0].y1 + offset2;
11204
11205					box[1].x1 = rr.x - offset1;
11206					box[1].x2 = box[1].x1 + offset2;
11207					box[1].y1 = rr.y + offset3;
11208					box[1].y2 = rr.y + rr.height - offset1;
11209
11210					box[2] = box[1];
11211					box[2].x1 += rr.width;
11212					box[2].x2 += rr.width;
11213
11214					box[3] = box[0];
11215					box[3].y1 += rr.height;
11216					box[3].y2 += rr.height;
11217					count = 4;
11218				}
11219
11220				while (count--) {
11221					c = find_clip_box_for_y(clip_start,
11222								clip_end,
11223								box[count].y1);
11224					while (c != clip_end) {
11225						if (box[count].y2 <= c->y1)
11226							break;
11227
11228						*b = box[count];
11229						if (box_intersect(b, c++)) {
11230							b->x1 += dx;
11231							b->x2 += dx;
11232							b->y1 += dy;
11233							b->y2 += dy;
11234							if (++b == last_box) {
11235								fill.boxes(sna, &fill, boxes, last_box-boxes);
11236								if (damage)
11237									sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11238								b = boxes;
11239							}
11240						}
11241					}
11242				}
11243			} while (--n);
11244		} else {
11245			DBG(("%s: singular clip offset1=%d, offset2=%d, offset3=%d\n",
11246			     __FUNCTION__, offset1, offset2, offset3));
11247			do {
11248				xRectangle rr = *r++;
11249				int count;
11250				rr.x += drawable->x;
11251				rr.y += drawable->y;
11252
11253				DBG(("%s: r=(%d, %d)x(%d, %d)\n",
11254				     __FUNCTION__, rr.x, rr.y, rr.width, rr.height));
11255				if (rr.height <= offset2 || rr.width <= offset2) {
11256					if (rr.height == 0) {
11257						box[0].x1 = rr.x;
11258						box[0].x2 = rr.x + rr.width;
11259					} else {
11260						box[0].x1 = rr.x - offset1;
11261						box[0].x2 = box[0].x1 + rr.width + offset2;
11262					}
11263					if (rr.width == 0) {
11264						box[0].y1 = rr.y;
11265						box[0].y2 = rr.y + rr.height;
11266					} else {
11267						box[0].y1 = rr.y - offset1;
11268						box[0].y2 = box[0].y1 + rr.height + offset2;
11269					}
11270					count = 1;
11271				} else {
11272					box[0].x1 = rr.x - offset1;
11273					box[0].x2 = box[0].x1 + rr.width + offset2;
11274					box[0].y1 = rr.y - offset1;
11275					box[0].y2 = box[0].y1 + offset2;
11276					DBG(("%s: box[0]=(%d, %d), (%d, %d)\n",
11277					     __FUNCTION__,
11278					     box[0].x1, box[0].y1,
11279					     box[0].x2, box[0].y2));
11280
11281					box[1].x1 = rr.x - offset1;
11282					box[1].x2 = box[1].x1 + offset2;
11283					box[1].y1 = rr.y + offset3;
11284					box[1].y2 = rr.y + rr.height - offset1;
11285					DBG(("%s: box[1]=(%d, %d), (%d, %d)\n",
11286					     __FUNCTION__,
11287					     box[1].x1, box[1].y1,
11288					     box[1].x2, box[1].y2));
11289
11290					box[2] = box[1];
11291					box[2].x1 += rr.width;
11292					box[2].x2 += rr.width;
11293					DBG(("%s: box[2]=(%d, %d), (%d, %d)\n",
11294					     __FUNCTION__,
11295					     box[2].x1, box[2].y1,
11296					     box[2].x2, box[2].y2));
11297
11298					box[3] = box[0];
11299					box[3].y1 += rr.height;
11300					box[3].y2 += rr.height;
11301					DBG(("%s: box[3]=(%d, %d), (%d, %d)\n",
11302					     __FUNCTION__,
11303					     box[3].x1, box[3].y1,
11304					     box[3].x2, box[3].y2));
11305
11306					count = 4;
11307				}
11308
11309				while (count--) {
11310					*b = box[count];
11311					if (box_intersect(b, &clip.extents)) {
11312						b->x1 += dx;
11313						b->x2 += dx;
11314						b->y1 += dy;
11315						b->y2 += dy;
11316						if (++b == last_box) {
11317							fill.boxes(sna, &fill, boxes, last_box-boxes);
11318							if (damage)
11319								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11320							b = boxes;
11321						}
11322					}
11323				}
11324			} while (--n);
11325		}
11326		RegionUninit(&clip);
11327	}
11328	goto done;
11329
11330wide:
11331	{
11332		int offset2 = gc->lineWidth;
11333		int offset1 = offset2 >> 1;
11334		int offset3 = offset2 - offset1;
11335
11336		dx += drawable->x;
11337		dy += drawable->y;
11338
11339		do {
11340			xRectangle rr = *r++;
11341
11342			if ((rr.width | rr.height) == 0)
11343				continue; /* XXX -> PolyLine */
11344
11345			rr.x += dx;
11346			rr.y += dy;
11347
11348			if (b+4 > last_box) {
11349				fill.boxes(sna, &fill, boxes, last_box-boxes);
11350				if (damage)
11351					sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11352				b = boxes;
11353			}
11354
11355			if (rr.height <= offset2 || rr.width <= offset2) {
11356				if (rr.height == 0) {
11357					b->x1 = rr.x;
11358					b->x2 = rr.x + rr.width;
11359				} else {
11360					b->x1 = rr.x - offset1;
11361					b->x2 = rr.x + rr.width + offset3;
11362				}
11363				if (rr.width == 0) {
11364					b->y1 = rr.y;
11365					b->y2 = rr.y + rr.height;
11366				} else {
11367					b->y1 = rr.y - offset1;
11368					b->y2 = rr.y + rr.height + offset3;
11369				}
11370				b++;
11371			} else {
11372				b[0].x1 = rr.x - offset1;
11373				b[0].x2 = b[0].x1 + rr.width + offset2;
11374				b[0].y1 = rr.y - offset1;
11375				b[0].y2 = b[0].y1 + offset2;
11376
11377				b[1].x1 = rr.x - offset1;
11378				b[1].x2 = b[1].x1 + offset2;
11379				b[1].y1 = rr.y + offset3;
11380				b[1].y2 = rr.y + rr.height - offset1;
11381
11382				b[2] = b[1];
11383				b[2].x1 += rr.width;
11384				b[2].x2 += rr.width;
11385
11386				b[3] = b[0];
11387				b[3].y1 += rr.height;
11388				b[3].y2 += rr.height;
11389				b += 4;
11390			}
11391		} while (--n);
11392	}
11393	goto done;
11394
11395done:
11396	if (b != boxes) {
11397		fill.boxes(sna, &fill, boxes, b-boxes);
11398		if (damage)
11399			sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
11400	}
11401	fill.done(sna, &fill);
11402	assert_pixmap_damage(pixmap);
11403	return true;
11404}
11405
11406static void
11407sna_poly_rectangle(DrawablePtr drawable, GCPtr gc, int n, xRectangle *r)
11408{
11409	PixmapPtr pixmap = get_drawable_pixmap(drawable);
11410	struct sna *sna = to_sna_from_pixmap(pixmap);
11411	struct sna_damage **damage;
11412	struct kgem_bo *bo;
11413	RegionRec region;
11414	unsigned flags;
11415
11416	DBG(("%s(n=%d, first=((%d, %d)x(%d, %d)), lineWidth=%d\n",
11417	     __FUNCTION__,
11418	     n, r->x, r->y, r->width, r->height,
11419	     gc->lineWidth));
11420
11421	flags = sna_poly_rectangle_extents(drawable, gc, n, r, &region.extents);
11422	if (flags == 0)
11423		return;
11424
11425	DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
11426	     region.extents.x1, region.extents.y1,
11427	     region.extents.x2, region.extents.y2,
11428	     flags));
11429
11430	if (FORCE_FALLBACK)
11431		goto fallback;
11432
11433	if (!ACCEL_POLY_RECTANGLE)
11434		goto fallback;
11435
11436	if (wedged(sna)) {
11437		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
11438		goto fallback;
11439	}
11440
11441	DBG(("%s: fill=%d [%d], line=%d [%d], join=%d [%d], mask=%lu [%d]\n",
11442	     __FUNCTION__,
11443	     gc->fillStyle, gc->fillStyle == FillSolid,
11444	     gc->lineStyle, gc->lineStyle == LineSolid,
11445	     gc->joinStyle, gc->joinStyle == JoinMiter,
11446	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask)));
11447
11448	if (!PM_IS_SOLID(drawable, gc->planemask))
11449		goto fallback;
11450
11451	if (flags & RECTILINEAR && gc->fillStyle == FillSolid && gc->lineStyle == LineSolid && gc->joinStyle == JoinMiter) {
11452		DBG(("%s: trying blt solid fill [%08lx] paths\n",
11453		     __FUNCTION__, gc->fgPixel));
11454		if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU,
11455					      &region.extents, &damage)) &&
11456		    sna_poly_rectangle_blt(drawable, bo, damage,
11457					   gc, n, r, &region.extents, flags&2))
11458			return;
11459	} else {
11460		/* Not a trivial outline, but we still maybe able to break it
11461		 * down into simpler operations that we can accelerate.
11462		 */
11463		if (sna_drawable_use_bo(drawable, PREFER_GPU,
11464					&region.extents, &damage)) {
11465			miPolyRectangle(drawable, gc, n, r);
11466			return;
11467		}
11468	}
11469
11470fallback:
11471	DBG(("%s: fallback, clip=%dx[(%d, %d), (%d, %d)]\n", __FUNCTION__,
11472	     region_num_rects(gc->pCompositeClip),
11473	     gc->pCompositeClip->extents.x1, gc->pCompositeClip->extents.y1,
11474	     gc->pCompositeClip->extents.x2, gc->pCompositeClip->extents.y2));
11475
11476	region.data = NULL;
11477	if (!region_maybe_clip(&region, gc->pCompositeClip))
11478		return;
11479
11480	DBG(("%s: CPU region=%dx[(%d, %d), (%d, %d)]\n", __FUNCTION__,
11481	     region_num_rects(&region),
11482	     region.extents.x1, region.extents.y1,
11483	     region.extents.x2, region.extents.y2));
11484	if (!sna_gc_move_to_cpu(gc, drawable, &region))
11485		goto out;
11486	if (!sna_drawable_move_region_to_cpu(drawable, &region,
11487					     drawable_gc_flags(drawable, gc, true)))
11488		goto out;
11489
11490	if (sigtrap_get() == 0) {
11491		DBG(("%s: miPolyRectangle\n", __FUNCTION__));
11492		miPolyRectangle(drawable, gc, n, r);
11493		FALLBACK_FLUSH(drawable);
11494		sigtrap_put();
11495	}
11496out:
11497	sna_gc_move_to_gpu(gc);
11498	RegionUninit(&region);
11499}
11500
11501static unsigned
11502sna_poly_arc_extents(DrawablePtr drawable, GCPtr gc,
11503		     int n, xArc *arc,
11504		     BoxPtr out)
11505{
11506	BoxRec box;
11507	bool clipped;
11508	int v;
11509
11510	if (n == 0)
11511		return 0;
11512
11513	box.x1 = arc->x;
11514	box.x2 = bound(box.x1, arc->width);
11515	box.y1 = arc->y;
11516	box.y2 = bound(box.y1, arc->height);
11517
11518	while (--n) {
11519		arc++;
11520		if (box.x1 > arc->x)
11521			box.x1 = arc->x;
11522		v = bound(arc->x, arc->width);
11523		if (box.x2 < v)
11524			box.x2 = v;
11525		if (box.y1 > arc->y)
11526			box.y1 = arc->y;
11527		v = bound(arc->y, arc->height);
11528		if (box.y2 < v)
11529			box.y2 = v;
11530	}
11531
11532	v = gc->lineWidth >> 1;
11533	if (v) {
11534		box.x1 -= v;
11535		box.x2 += v;
11536		box.y1 -= v;
11537		box.y2 += v;
11538	}
11539
11540	box.x2++;
11541	box.y2++;
11542
11543	clipped = trim_and_translate_box(&box, drawable, gc);
11544	if (box_empty(&box))
11545		return 0;
11546
11547	*out = box;
11548	return 1 | clipped << 1;
11549}
11550
11551static void
11552sna_poly_arc(DrawablePtr drawable, GCPtr gc, int n, xArc *arc)
11553{
11554	struct sna_fill_spans data;
11555	struct sna_pixmap *priv;
11556
11557	DBG(("%s(n=%d, lineWidth=%d\n", __FUNCTION__, n, gc->lineWidth));
11558
11559	data.flags = sna_poly_arc_extents(drawable, gc, n, arc,
11560					  &data.region.extents);
11561	if (data.flags == 0)
11562		return;
11563
11564	DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
11565	     data.region.extents.x1, data.region.extents.y1,
11566	     data.region.extents.x2, data.region.extents.y2,
11567	     data.flags));
11568
11569	data.region.data = NULL;
11570
11571	if (FORCE_FALLBACK)
11572		goto fallback;
11573
11574	if (!ACCEL_POLY_ARC)
11575		goto fallback;
11576
11577	data.pixmap = get_drawable_pixmap(drawable);
11578	data.sna = to_sna_from_pixmap(data.pixmap);
11579	priv = sna_pixmap(data.pixmap);
11580	if (priv == NULL) {
11581		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
11582		goto fallback;
11583	}
11584
11585	if (wedged(data.sna)) {
11586		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
11587		goto fallback;
11588	}
11589
11590	if (!PM_IS_SOLID(drawable, gc->planemask))
11591		goto fallback;
11592
11593	if ((data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
11594					   &data.region.extents, &data.damage))) {
11595		uint32_t color;
11596
11597		DBG(("%s: converting arcs into spans\n", __FUNCTION__));
11598		get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy);
11599
11600		if (gc_is_solid(gc, &color)) {
11601			sna_gc(gc)->priv = &data;
11602
11603			assert(gc->miTranslate);
11604			if (gc->lineStyle == LineSolid) {
11605				struct sna_fill_op fill;
11606
11607				if (!sna_fill_init_blt(&fill,
11608						       data.sna, data.pixmap,
11609						       data.bo, gc->alu, color,
11610						       FILL_POINTS | FILL_SPANS))
11611					goto fallback;
11612
11613				if ((data.flags & IS_CLIPPED) == 0) {
11614					if (data.dx | data.dy)
11615						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
11616					else
11617						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
11618					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill;
11619				} else {
11620					if (!region_maybe_clip(&data.region,
11621							       gc->pCompositeClip))
11622						return;
11623
11624					if (region_is_singular(&data.region)) {
11625						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
11626						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents;
11627					} else {
11628						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
11629						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes;
11630					}
11631				}
11632
11633				data.op = &fill;
11634				gc->ops = &sna_gc_ops__tmp;
11635				if (gc->lineWidth == 0)
11636					miZeroPolyArc(drawable, gc, n, arc);
11637				else
11638					miPolyArc(drawable, gc, n, arc);
11639				gc->ops = (GCOps *)&sna_gc_ops;
11640
11641				fill.done(data.sna, &fill);
11642			} else {
11643				if (!region_maybe_clip(&data.region,
11644						       gc->pCompositeClip))
11645					return;
11646
11647				sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
11648				sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu;
11649
11650				gc->ops = &sna_gc_ops__tmp;
11651				if (gc->lineWidth == 0)
11652					miZeroPolyArc(drawable, gc, n, arc);
11653				else
11654					miPolyArc(drawable, gc, n, arc);
11655				gc->ops = (GCOps *)&sna_gc_ops;
11656			}
11657
11658			if (data.damage) {
11659				if (data.dx | data.dy)
11660					pixman_region_translate(&data.region, data.dx, data.dy);
11661				assert_pixmap_contains_box(data.pixmap, &data.region.extents);
11662				sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap);
11663			}
11664			assert_pixmap_damage(data.pixmap);
11665			RegionUninit(&data.region);
11666			return;
11667		}
11668
11669		/* XXX still around 10x slower for x11perf -ellipse */
11670		if (gc->lineWidth == 0)
11671			miZeroPolyArc(drawable, gc, n, arc);
11672		else
11673			miPolyArc(drawable, gc, n, arc);
11674		return;
11675	}
11676
11677fallback:
11678	DBG(("%s -- fallback\n", __FUNCTION__));
11679	if (!region_maybe_clip(&data.region, gc->pCompositeClip))
11680		return;
11681
11682	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
11683		goto out;
11684	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
11685					     drawable_gc_flags(drawable, gc, true)))
11686		goto out;
11687
11688	if (sigtrap_get() == 0) {
11689		DBG(("%s -- fbPolyArc\n", __FUNCTION__));
11690		fbPolyArc(drawable, gc, n, arc);
11691		FALLBACK_FLUSH(drawable);
11692		sigtrap_put();
11693	}
11694out:
11695	sna_gc_move_to_gpu(gc);
11696	RegionUninit(&data.region);
11697}
11698
11699static bool
11700sna_poly_fill_rect_blt(DrawablePtr drawable,
11701		       struct kgem_bo *bo,
11702		       struct sna_damage **damage,
11703		       GCPtr gc, uint32_t pixel,
11704		       int n, const xRectangle *rect,
11705		       const BoxRec *extents,
11706		       unsigned flags)
11707{
11708	PixmapPtr pixmap = get_drawable_pixmap(drawable);
11709	struct sna *sna = to_sna_from_pixmap(pixmap);
11710	struct sna_fill_op fill;
11711	BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes);
11712	int16_t dx, dy;
11713
11714	DBG(("%s pixmap=%ld x %d [(%d, %d)x(%d, %d)...]+(%d,%d), clipped?=%d\n",
11715	     __FUNCTION__, pixmap->drawable.serialNumber, n,
11716	     rect->x, rect->y, rect->width, rect->height,
11717	     drawable->x, drawable->y,
11718	     flags&2));
11719
11720	if (n == 1 && region_is_singular(gc->pCompositeClip)) {
11721		BoxRec r;
11722		bool success = true;
11723
11724		r.x1 = rect->x + drawable->x;
11725		r.y1 = rect->y + drawable->y;
11726		r.x2 = bound(r.x1, rect->width);
11727		r.y2 = bound(r.y1, rect->height);
11728		if (box_intersect(&r, &gc->pCompositeClip->extents)) {
11729			if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
11730				r.x1 += dx; r.y1 += dy;
11731				r.x2 += dx; r.y2 += dy;
11732			}
11733			DBG(("%s: using fill_one() fast path: (%d, %d), (%d, %d). alu=%d, pixel=%08x, damage?=%d\n",
11734			     __FUNCTION__, r.x1, r.y1, r.x2, r.y2, gc->alu, pixel, damage != NULL));
11735
11736			assert_pixmap_contains_box(pixmap, &r);
11737			if (sna->render.fill_one(sna, pixmap, bo, pixel,
11738						 r.x1, r.y1, r.x2, r.y2,
11739						 gc->alu)) {
11740				if (r.x2 - r.x1 == pixmap->drawable.width &&
11741				    r.y2 - r.y1 == pixmap->drawable.height) {
11742					if (damage) {
11743						sna_damage_all(damage, pixmap);
11744						damage = NULL;
11745					}
11746					if (flags & OVERWRITES) {
11747						struct sna_pixmap *priv = sna_pixmap(pixmap);
11748						if (bo == priv->gpu_bo) {
11749							assert(damage == NULL || damage == &priv->gpu_damage);
11750							assert(priv->gpu_bo->proxy == NULL);
11751							sna_damage_destroy(&priv->cpu_damage);
11752							list_del(&priv->flush_list);
11753							priv->clear = true;
11754							priv->clear_color = gc->alu == GXcopyInverted ? ~pixel & ((1 << gc->depth) - 1) : pixel;
11755
11756							DBG(("%s: pixmap=%ld, marking clear [%08x]\n",
11757							     __FUNCTION__, pixmap->drawable.serialNumber, priv->clear_color));
11758						}
11759					}
11760				}
11761				if (damage)
11762					sna_damage_add_box(damage, &r);
11763				assert_pixmap_damage(pixmap);
11764			} else
11765				success = false;
11766		}
11767
11768		return success;
11769	}
11770
11771	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_BOXES)) {
11772		DBG(("%s: unsupported blt\n", __FUNCTION__));
11773		return false;
11774	}
11775
11776	get_drawable_deltas(drawable, pixmap, &dx, &dy);
11777	if ((flags & IS_CLIPPED) == 0) {
11778		dx += drawable->x;
11779		dy += drawable->y;
11780
11781		sna_damage_add_rectangles(damage, rect, n, dx, dy);
11782		if (dx|dy) {
11783			do {
11784				unsigned nbox = n;
11785				if (nbox > ARRAY_SIZE(boxes))
11786					nbox = ARRAY_SIZE(boxes);
11787				n -= nbox;
11788				do {
11789					b->x1 = rect->x + dx;
11790					b->y1 = rect->y + dy;
11791					b->x2 = b->x1 + rect->width;
11792					b->y2 = b->y1 + rect->height;
11793					b++;
11794					rect++;
11795				} while (--nbox);
11796				fill.boxes(sna, &fill, boxes, b-boxes);
11797				b = boxes;
11798			} while (n);
11799		} else {
11800			do {
11801				unsigned nbox = n;
11802				if (nbox > ARRAY_SIZE(boxes))
11803					nbox = ARRAY_SIZE(boxes);
11804				n -= nbox;
11805				do {
11806					b->x1 = rect->x;
11807					b->y1 = rect->y;
11808					b->x2 = b->x1 + rect->width;
11809					b->y2 = b->y1 + rect->height;
11810					b++;
11811					rect++;
11812				} while (--nbox);
11813				fill.boxes(sna, &fill, boxes, b-boxes);
11814				b = boxes;
11815			} while (n);
11816		}
11817	} else {
11818		RegionRec clip;
11819
11820		region_set(&clip, extents);
11821		if (!region_maybe_clip(&clip, gc->pCompositeClip))
11822			goto done;
11823
11824		if (clip.data == NULL) {
11825			do {
11826				b->x1 = rect->x + drawable->x;
11827				b->y1 = rect->y + drawable->y;
11828				b->x2 = bound(b->x1, rect->width);
11829				b->y2 = bound(b->y1, rect->height);
11830				rect++;
11831
11832				if (box_intersect(b, &clip.extents)) {
11833					b->x1 += dx;
11834					b->x2 += dx;
11835					b->y1 += dy;
11836					b->y2 += dy;
11837					if (++b == last_box) {
11838						fill.boxes(sna, &fill, boxes, last_box-boxes);
11839						if (damage)
11840							sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11841						b = boxes;
11842					}
11843				}
11844			} while (--n);
11845		} else {
11846			const BoxRec * const clip_start = RegionBoxptr(&clip);
11847			const BoxRec * const clip_end = clip_start + clip.data->numRects;
11848			const BoxRec *c;
11849
11850			do {
11851				BoxRec box;
11852
11853				box.x1 = rect->x + drawable->x;
11854				box.y1 = rect->y + drawable->y;
11855				box.x2 = bound(box.x1, rect->width);
11856				box.y2 = bound(box.y1, rect->height);
11857				rect++;
11858
11859				c = find_clip_box_for_y(clip_start,
11860							clip_end,
11861							box.y1);
11862				while (c != clip_end) {
11863					if (box.y2 <= c->y1)
11864						break;
11865
11866					*b = box;
11867					if (box_intersect(b, c++)) {
11868						b->x1 += dx;
11869						b->x2 += dx;
11870						b->y1 += dy;
11871						b->y2 += dy;
11872						if (++b == last_box) {
11873							fill.boxes(sna, &fill, boxes, last_box-boxes);
11874							if (damage)
11875								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11876							b = boxes;
11877						}
11878					}
11879
11880				}
11881			} while (--n);
11882		}
11883
11884		RegionUninit(&clip);
11885		if (b != boxes) {
11886			fill.boxes(sna, &fill, boxes, b-boxes);
11887			if (damage)
11888				sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
11889		}
11890	}
11891done:
11892	fill.done(sna, &fill);
11893	assert_pixmap_damage(pixmap);
11894	return true;
11895}
11896
11897static uint32_t
11898get_pixel(PixmapPtr pixmap)
11899{
11900	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber));
11901	if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
11902		return 0;
11903
11904	switch (pixmap->drawable.bitsPerPixel) {
11905	case 32: return *(uint32_t *)pixmap->devPrivate.ptr;
11906	case 16: return *(uint16_t *)pixmap->devPrivate.ptr;
11907	default: return *(uint8_t *)pixmap->devPrivate.ptr;
11908	}
11909}
11910
11911inline static int
11912_use_fill_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags)
11913{
11914	if (USE_SPANS)
11915		return USE_SPANS > 0;
11916
11917	if (gc->fillStyle == FillTiled && !gc->tileIsPixel &&
11918	    sna_pixmap_is_gpu(gc->tile.pixmap)) {
11919		DBG(("%s: source is already on the gpu\n", __FUNCTION__));
11920		return PREFER_GPU | FORCE_GPU;
11921	}
11922
11923	return PREFER_GPU;
11924}
11925
11926static int
11927use_fill_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags)
11928{
11929	int ret = _use_fill_spans(drawable, gc, extents, flags);
11930	DBG(("%s? %d\n", __FUNCTION__, ret));
11931	return ret;
11932}
11933
11934static void
11935sna_poly_fill_polygon(DrawablePtr draw, GCPtr gc,
11936		      int shape, int mode,
11937		      int n, DDXPointPtr pt)
11938{
11939	struct sna_fill_spans data;
11940	struct sna_pixmap *priv;
11941
11942	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
11943	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
11944	     (gc->fillStyle == FillSolid ||
11945	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
11946	     gc->fillStyle, gc->tileIsPixel,
11947	     gc->alu));
11948	DBG(("%s: draw=%ld, offset=(%d, %d), size=%dx%d\n",
11949	     __FUNCTION__, draw->serialNumber,
11950	     draw->x, draw->y, draw->width, draw->height));
11951
11952	data.flags = sna_poly_point_extents(draw, gc, mode, n, pt,
11953					    &data.region.extents);
11954	if (data.flags == 0) {
11955		DBG(("%s, nothing to do\n", __FUNCTION__));
11956		return;
11957	}
11958
11959	DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
11960	     data.region.extents.x1, data.region.extents.y1,
11961	     data.region.extents.x2, data.region.extents.y2,
11962	     data.flags));
11963
11964	data.region.data = NULL;
11965
11966	if (FORCE_FALLBACK)
11967		goto fallback;
11968
11969	if (!ACCEL_POLY_FILL_POLYGON)
11970		goto fallback;
11971
11972	data.pixmap = get_drawable_pixmap(draw);
11973	data.sna = to_sna_from_pixmap(data.pixmap);
11974	priv = sna_pixmap(data.pixmap);
11975	if (priv == NULL) {
11976		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
11977		goto fallback;
11978	}
11979
11980	if (wedged(data.sna)) {
11981		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
11982		goto fallback;
11983	}
11984
11985	if (!PM_IS_SOLID(draw, gc->planemask))
11986		goto fallback;
11987
11988	if ((data.bo = sna_drawable_use_bo(draw,
11989					   use_fill_spans(draw, gc, &data.region.extents, data.flags),
11990					   &data.region.extents,
11991					   &data.damage))) {
11992		uint32_t color;
11993
11994		sna_gc(gc)->priv = &data;
11995		get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy);
11996
11997		if (gc_is_solid(gc, &color)) {
11998			struct sna_fill_op fill;
11999
12000			if (!sna_fill_init_blt(&fill,
12001					       data.sna, data.pixmap,
12002					       data.bo, gc->alu, color,
12003					       FILL_SPANS))
12004				goto fallback;
12005
12006			data.op = &fill;
12007
12008			if ((data.flags & IS_CLIPPED) == 0) {
12009				if (data.dx | data.dy)
12010					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
12011				else
12012					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
12013			} else {
12014				if (!region_maybe_clip(&data.region,
12015						       gc->pCompositeClip))
12016					return;
12017
12018				if (region_is_singular(&data.region))
12019					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
12020				else
12021					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
12022			}
12023			assert(gc->miTranslate);
12024			gc->ops = &sna_gc_ops__tmp;
12025
12026			miFillPolygon(draw, gc, shape, mode, n, pt);
12027			fill.done(data.sna, &fill);
12028		} else {
12029			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
12030			gc->ops = &sna_gc_ops__tmp;
12031
12032			miFillPolygon(draw, gc, shape, mode, n, pt);
12033		}
12034
12035		gc->ops = (GCOps *)&sna_gc_ops;
12036		if (data.damage) {
12037			if (data.dx | data.dy)
12038				pixman_region_translate(&data.region, data.dx, data.dy);
12039			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
12040			sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap);
12041		}
12042		assert_pixmap_damage(data.pixmap);
12043		RegionUninit(&data.region);
12044		return;
12045	}
12046
12047fallback:
12048	DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__,
12049	     data.region.extents.x1, data.region.extents.y1,
12050	     data.region.extents.x2, data.region.extents.y2));
12051	if (!region_maybe_clip(&data.region, gc->pCompositeClip)) {
12052		DBG(("%s: nothing to do, all clipped\n", __FUNCTION__));
12053		return;
12054	}
12055
12056	if (!sna_gc_move_to_cpu(gc, draw, &data.region))
12057		goto out;
12058	if (!sna_drawable_move_region_to_cpu(draw, &data.region,
12059					     drawable_gc_flags(draw, gc, true)))
12060		goto out;
12061
12062	if (sigtrap_get() == 0) {
12063		DBG(("%s: fallback -- miFillPolygon -> sna_fill_spans__cpu\n",
12064		     __FUNCTION__));
12065		miFillPolygon(draw, gc, shape, mode, n, pt);
12066		sigtrap_put();
12067	}
12068out:
12069	sna_gc_move_to_gpu(gc);
12070	RegionUninit(&data.region);
12071}
12072
12073static struct kgem_bo *
12074sna_pixmap_get_source_bo(PixmapPtr pixmap)
12075{
12076	struct sna_pixmap *priv = sna_pixmap(pixmap);
12077	unsigned flags;
12078	BoxRec box;
12079
12080	box.x1 = box.y1 = 0;
12081	box.x2 = pixmap->drawable.width;
12082	box.y2 = pixmap->drawable.height;
12083
12084	DBG(("%s(pixmap=%ld, size=%dx%d)\n", __FUNCTION__,
12085	     pixmap->drawable.serialNumber, pixmap->drawable.width, pixmap->drawable.height));
12086
12087	if (priv == NULL) {
12088		DBG(("%s: unattached, uploading data into temporary\n", __FUNCTION__));
12089		return kgem_upload_source_image(&to_sna_from_pixmap(pixmap)->kgem,
12090						pixmap->devPrivate.ptr, &box,
12091						pixmap->devKind,
12092						pixmap->drawable.bitsPerPixel);
12093	}
12094
12095	if (priv->gpu_damage) {
12096		if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT))
12097			return kgem_bo_reference(priv->gpu_bo);
12098	} else if (priv->cpu_damage) {
12099		if (priv->cpu_bo)
12100			return kgem_bo_reference(priv->cpu_bo);
12101	} else {
12102		if (priv->gpu_bo)
12103			return kgem_bo_reference(priv->gpu_bo);
12104		if (priv->cpu_bo)
12105			return kgem_bo_reference(priv->cpu_bo);
12106	}
12107
12108	flags = MOVE_READ | MOVE_ASYNC_HINT;
12109	if (priv->gpu_bo && priv->gpu_bo->proxy) {
12110		struct kgem_bo *bo = priv->gpu_bo;
12111		if (bo->rq == NULL && (bo->snoop || bo->pitch >= 4096))
12112			flags |= __MOVE_FORCE;
12113	}
12114	if (priv->gpu_bo == NULL) {
12115		if (++priv->source_count > SOURCE_BIAS)
12116			flags |= __MOVE_FORCE;
12117	}
12118
12119	if (!sna_pixmap_move_to_gpu(pixmap, flags)) {
12120		struct kgem_bo *upload;
12121
12122		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
12123			return NULL;
12124
12125		upload = kgem_upload_source_image(&to_sna_from_pixmap(pixmap)->kgem,
12126						  pixmap->devPrivate.ptr, &box,
12127						  pixmap->devKind,
12128						  pixmap->drawable.bitsPerPixel);
12129		if (upload == NULL)
12130			return NULL;
12131
12132		if (priv->gpu_bo == NULL) {
12133			DBG(("%s: adding upload cache to pixmap=%ld\n",
12134			     __FUNCTION__, pixmap->drawable.serialNumber));
12135			assert(upload->proxy != NULL);
12136			kgem_proxy_bo_attach(upload, &priv->gpu_bo);
12137		}
12138
12139		return upload;
12140	}
12141
12142	return kgem_bo_reference(priv->gpu_bo);
12143}
12144
12145/*
12146static bool
12147tile(DrawablePtr drawable,
12148	struct kgem_bo *bo, struct sna_damage **damage,
12149	PixmapPtr tile, const DDXPointRec * const origin, int alu,
12150	int n, xRectangle *rect,
12151	const BoxRec *extents, unsigned clipped)
12152	*/
12153
12154static bool
12155sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
12156				 struct kgem_bo *bo, struct sna_damage **damage,
12157				 struct kgem_bo *tile_bo, GCPtr gc,
12158				 int n, const xRectangle *r,
12159				 const BoxRec *extents, unsigned clipped)
12160{
12161	PixmapPtr pixmap = get_drawable_pixmap(drawable);
12162	struct sna *sna = to_sna_from_pixmap(pixmap);
12163	const DDXPointRec * const origin = &gc->patOrg;
12164	uint32_t br00, br13;
12165	int tx, ty;
12166	int16_t dx, dy;
12167	uint32_t *b;
12168
12169	if (NO_TILE_8x8)
12170		return false;
12171
12172	DBG(("%s x %d [(%d, %d)x(%d, %d)...], clipped=%x, origin=(%d, %d)\n",
12173	     __FUNCTION__, n, r->x, r->y, r->width, r->height, clipped, origin->x, origin->y));
12174
12175	DBG(("%s: tile_bo tiling=%d, pitch=%d\n", __FUNCTION__, tile_bo->tiling, tile_bo->pitch));
12176	if (tile_bo->tiling)
12177		return false;
12178
12179	if (!kgem_bo_can_blt(&sna->kgem, bo) ||
12180	    !kgem_bo_can_blt(&sna->kgem, tile_bo))
12181		return false;
12182
12183	assert(tile_bo->pitch == 8 * drawable->bitsPerPixel >> 3);
12184
12185	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
12186	assert(kgem_bo_can_blt(&sna->kgem, bo));
12187	if (!kgem_check_batch(&sna->kgem, 10+2*3) ||
12188	    !kgem_check_reloc(&sna->kgem, 2) ||
12189	    !kgem_check_many_bo_fenced(&sna->kgem, bo, tile_bo, NULL)) {
12190		kgem_submit(&sna->kgem);
12191		if (!kgem_check_many_bo_fenced(&sna->kgem, bo, tile_bo, NULL))
12192			return false;
12193		_kgem_set_mode(&sna->kgem, KGEM_BLT);
12194	}
12195
12196	get_drawable_deltas(drawable, pixmap, &dx, &dy);
12197	assert(extents->x1 + dx >= 0);
12198	assert(extents->y1 + dy >= 0);
12199	assert(extents->x2 + dx <= pixmap->drawable.width);
12200	assert(extents->y2 + dy <= pixmap->drawable.height);
12201
12202	br00 = XY_SCANLINE_BLT;
12203	tx = (-drawable->x - dx - origin->x) % 8;
12204	if (tx < 0)
12205		tx += 8;
12206	ty = (-drawable->y - dy - origin->y) % 8;
12207	if (ty < 0)
12208		ty += 8;
12209	br00 |= tx << 12 | ty << 8;
12210
12211	br13 = bo->pitch;
12212	if (sna->kgem.gen >= 040 && bo->tiling) {
12213		br00 |= BLT_DST_TILED;
12214		br13 >>= 2;
12215	}
12216	br13 |= blt_depth(drawable->depth) << 24;
12217	br13 |= fill_ROP[gc->alu] << 16;
12218
12219	if (!clipped) {
12220		dx += drawable->x;
12221		dy += drawable->y;
12222
12223		sna_damage_add_rectangles(damage, r, n, dx, dy);
12224		if (n == 1) {
12225			DBG(("%s: rect=(%d, %d)x(%d, %d) + (%d, %d), tile=(%d, %d)\n",
12226			     __FUNCTION__, r->x, r->y, r->width, r->height, dx, dy, tx, ty));
12227
12228			assert(r->x + dx >= 0);
12229			assert(r->y + dy >= 0);
12230			assert(r->x + dx + r->width  <= pixmap->drawable.width);
12231			assert(r->y + dy + r->height <= pixmap->drawable.height);
12232
12233			assert(sna->kgem.mode == KGEM_BLT);
12234			b = sna->kgem.batch + sna->kgem.nbatch;
12235			if (sna->kgem.gen >= 0100) {
12236				b[0] = XY_PAT_BLT | 3 << 20 | (br00 & 0x7f00) | 6;
12237				b[1] = br13;
12238				b[2] = (r->y + dy) << 16 | (r->x + dx);
12239				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
12240				*(uint64_t *)(b+4) =
12241					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12242							 I915_GEM_DOMAIN_RENDER << 16 |
12243							 I915_GEM_DOMAIN_RENDER |
12244							 KGEM_RELOC_FENCED,
12245							 0);
12246				*(uint64_t *)(b+6) =
12247					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, tile_bo,
12248							 I915_GEM_DOMAIN_RENDER << 16 |
12249							 KGEM_RELOC_FENCED,
12250							 0);
12251				sna->kgem.nbatch += 8;
12252			} else {
12253				b[0] = XY_PAT_BLT | 3 << 20 | (br00 & 0x7f00) | 4;
12254				b[1] = br13;
12255				b[2] = (r->y + dy) << 16 | (r->x + dx);
12256				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
12257				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12258						      I915_GEM_DOMAIN_RENDER << 16 |
12259						      I915_GEM_DOMAIN_RENDER |
12260						      KGEM_RELOC_FENCED,
12261						      0);
12262				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, tile_bo,
12263						      I915_GEM_DOMAIN_RENDER << 16 |
12264						      KGEM_RELOC_FENCED,
12265						      0);
12266				sna->kgem.nbatch += 6;
12267			}
12268		} else do {
12269			int n_this_time, rem;
12270
12271			assert(sna->kgem.mode == KGEM_BLT);
12272			b = sna->kgem.batch + sna->kgem.nbatch;
12273			if (sna->kgem.gen >= 0100) {
12274				b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
12275				b[1] = br13;
12276				b[2] = 0;
12277				b[3] = 0;
12278				*(uint64_t *)(b+4) =
12279					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12280							 I915_GEM_DOMAIN_RENDER << 16 |
12281							 I915_GEM_DOMAIN_RENDER |
12282							 KGEM_RELOC_FENCED,
12283							 0);
12284				b[6] = gc->bgPixel;
12285				b[7] = gc->fgPixel;
12286				*(uint64_t *)(b+8) =
12287					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo,
12288							 I915_GEM_DOMAIN_RENDER << 16 |
12289							 KGEM_RELOC_FENCED,
12290							 0);
12291				sna->kgem.nbatch += 10;
12292			} else {
12293				b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6;
12294				b[1] = br13;
12295				b[2] = 0;
12296				b[3] = 0;
12297				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12298						      I915_GEM_DOMAIN_RENDER << 16 |
12299						      I915_GEM_DOMAIN_RENDER |
12300						      KGEM_RELOC_FENCED,
12301						      0);
12302				b[5] = gc->bgPixel;
12303				b[6] = gc->fgPixel;
12304				b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
12305						      I915_GEM_DOMAIN_RENDER << 16 |
12306						      KGEM_RELOC_FENCED,
12307						      0);
12308				sna->kgem.nbatch += 8;
12309			}
12310
12311			n_this_time = n;
12312			rem = kgem_batch_space(&sna->kgem);
12313			if (3*n_this_time > rem)
12314				n_this_time = rem / 3;
12315			assert(n_this_time);
12316			n -= n_this_time;
12317
12318			assert(sna->kgem.mode == KGEM_BLT);
12319			b = sna->kgem.batch + sna->kgem.nbatch;
12320			sna->kgem.nbatch += 3*n_this_time;
12321			do {
12322				assert(r->x + dx >= 0);
12323				assert(r->y + dy >= 0);
12324				assert(r->x + dx + r->width  <= pixmap->drawable.width);
12325				assert(r->y + dy + r->height <= pixmap->drawable.height);
12326
12327				b[0] = br00;
12328				b[1] = (r->y + dy) << 16 | (r->x + dx);
12329				b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
12330				b += 3; r++;
12331			} while (--n_this_time);
12332
12333			if (!n)
12334				break;
12335
12336			_kgem_submit(&sna->kgem);
12337			_kgem_set_mode(&sna->kgem, KGEM_BLT);
12338		} while (1);
12339	} else {
12340		RegionRec clip;
12341		uint16_t unwind_batch, unwind_reloc;
12342
12343		region_set(&clip, extents);
12344		if (!region_maybe_clip(&clip, gc->pCompositeClip))
12345			goto done;
12346
12347		unwind_batch = sna->kgem.nbatch;
12348		unwind_reloc = sna->kgem.nreloc;
12349
12350		assert(sna->kgem.mode == KGEM_BLT);
12351		b = sna->kgem.batch + sna->kgem.nbatch;
12352		if (sna->kgem.gen >= 0100) {
12353			b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
12354			b[1] = br13;
12355			b[2] = 0;
12356			b[3] = 0;
12357			*(uint64_t *)(b+4) =
12358				kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12359						 I915_GEM_DOMAIN_RENDER << 16 |
12360						 I915_GEM_DOMAIN_RENDER |
12361						 KGEM_RELOC_FENCED,
12362						 0);
12363			b[6] = gc->bgPixel;
12364			b[7] = gc->fgPixel;
12365			*(uint64_t *)(b+8) =
12366				kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo,
12367						 I915_GEM_DOMAIN_RENDER << 16 |
12368						 KGEM_RELOC_FENCED,
12369						 0);
12370			sna->kgem.nbatch += 10;
12371		} else {
12372			b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6;
12373			b[1] = br13;
12374			b[2] = 0;
12375			b[3] = 0;
12376			b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12377					      I915_GEM_DOMAIN_RENDER << 16 |
12378					      I915_GEM_DOMAIN_RENDER |
12379					      KGEM_RELOC_FENCED,
12380					      0);
12381			b[5] = gc->bgPixel;
12382			b[6] = gc->fgPixel;
12383			b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
12384					      I915_GEM_DOMAIN_RENDER << 16 |
12385					      KGEM_RELOC_FENCED,
12386					      0);
12387			sna->kgem.nbatch += 8;
12388		}
12389
12390		if (clip.data == NULL) {
12391			const BoxRec *c = &clip.extents;
12392			DBG(("%s: simple clip, %d boxes\n", __FUNCTION__, n));
12393			while (n--) {
12394				BoxRec box;
12395
12396				box.x1 = r->x + drawable->x;
12397				box.y1 = r->y + drawable->y;
12398				box.x2 = bound(box.x1, r->width);
12399				box.y2 = bound(box.y1, r->height);
12400				r++;
12401
12402				if (box_intersect(&box, c)) {
12403					if (!kgem_check_batch(&sna->kgem, 3)) {
12404						_kgem_submit(&sna->kgem);
12405						_kgem_set_mode(&sna->kgem, KGEM_BLT);
12406
12407						unwind_batch = sna->kgem.nbatch;
12408						unwind_reloc = sna->kgem.nreloc;
12409
12410						assert(sna->kgem.mode == KGEM_BLT);
12411						b = sna->kgem.batch + sna->kgem.nbatch;
12412						if (sna->kgem.gen >= 0100) {
12413							b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
12414							b[1] = br13;
12415							b[2] = 0;
12416							b[3] = 0;
12417							*(uint64_t *)(b+4) =
12418								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12419										 I915_GEM_DOMAIN_RENDER << 16 |
12420										 I915_GEM_DOMAIN_RENDER |
12421										 KGEM_RELOC_FENCED,
12422										 0);
12423							b[6] = gc->bgPixel;
12424							b[7] = gc->fgPixel;
12425							*(uint64_t *)(b+8) =
12426								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo,
12427										 I915_GEM_DOMAIN_RENDER << 16 |
12428										 KGEM_RELOC_FENCED,
12429										 0);
12430							sna->kgem.nbatch += 10;
12431						} else {
12432							b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6;
12433							b[1] = br13;
12434							b[2] = 0;
12435							b[3] = 0;
12436							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12437									      I915_GEM_DOMAIN_RENDER << 16 |
12438									      I915_GEM_DOMAIN_RENDER |
12439									      KGEM_RELOC_FENCED,
12440									      0);
12441							b[5] = gc->bgPixel;
12442							b[6] = gc->fgPixel;
12443							b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
12444									      I915_GEM_DOMAIN_RENDER << 16 |
12445									      KGEM_RELOC_FENCED,
12446									      0);
12447							sna->kgem.nbatch += 8;
12448						}
12449					}
12450
12451					assert(box.x1 + dx >= 0);
12452					assert(box.y1 + dy >= 0);
12453					assert(box.x2 + dx <= pixmap->drawable.width);
12454					assert(box.y2 + dy <= pixmap->drawable.height);
12455
12456					DBG(("%s: box=(%d, %d),(%d, %d) + (%d, %d), tile=(%d, %d)\n",
12457					     __FUNCTION__, box.x1, box.y1, box.x2, box.y2, dx, dy, tx, ty));
12458
12459					assert(sna->kgem.mode == KGEM_BLT);
12460					b = sna->kgem.batch + sna->kgem.nbatch;
12461					b[0] = br00;
12462					b[1] = (box.y1 + dy) << 16 | (box.x1 + dx);
12463					b[2] = (box.y2 + dy) << 16 | (box.x2 + dx);
12464					sna->kgem.nbatch += 3;
12465				}
12466			}
12467		} else {
12468			const BoxRec * const clip_start = RegionBoxptr(&clip);
12469			const BoxRec * const clip_end = clip_start + clip.data->numRects;
12470			const BoxRec *c;
12471
12472			DBG(("%s: complex clip (%ld cliprects), %d boxes\n", __FUNCTION__, (long)clip.data->numRects, n));
12473			do {
12474				BoxRec box;
12475
12476				box.x1 = r->x + drawable->x;
12477				box.y1 = r->y + drawable->y;
12478				box.x2 = bound(box.x1, r->width);
12479				box.y2 = bound(box.y1, r->height);
12480				DBG(("%s: rect=(%d, %d), (%d, %d), box=(%d, %d), (%d, %d)\n", __FUNCTION__,
12481				     r->x, r->y, r->width, r->height,
12482				     box.x1, box.y1, box.x2, box.y2));
12483				r++;
12484
12485				c = find_clip_box_for_y(clip_start,
12486							clip_end,
12487							box.y1);
12488				while (c != clip_end) {
12489					BoxRec bb;
12490
12491					DBG(("%s: clip=(%d, %d), (%d, %d)\n", __FUNCTION__, c->x1, c->y1, c->x2, c->y2));
12492
12493					if (box.y2 <= c->y1)
12494						break;
12495
12496					bb = box;
12497					if (box_intersect(&bb, c++)) {
12498						if (!kgem_check_batch(&sna->kgem, 3)) {
12499							DBG(("%s: emitting split batch\n", __FUNCTION__));
12500							_kgem_submit(&sna->kgem);
12501							_kgem_set_mode(&sna->kgem, KGEM_BLT);
12502
12503							unwind_batch = sna->kgem.nbatch;
12504							unwind_reloc = sna->kgem.nreloc;
12505
12506							assert(sna->kgem.mode == KGEM_BLT);
12507							b = sna->kgem.batch + sna->kgem.nbatch;
12508							if (sna->kgem.gen >= 0100) {
12509								b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
12510								b[1] = br13;
12511								b[2] = 0;
12512								b[3] = 0;
12513								*(uint64_t *)(b+4) =
12514									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12515											 I915_GEM_DOMAIN_RENDER << 16 |
12516											 I915_GEM_DOMAIN_RENDER |
12517											 KGEM_RELOC_FENCED,
12518											 0);
12519								b[6] = gc->bgPixel;
12520								b[7] = gc->fgPixel;
12521								*(uint64_t *)(b+8) =
12522									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo,
12523											 I915_GEM_DOMAIN_RENDER << 16 |
12524											 KGEM_RELOC_FENCED,
12525											 0);
12526								sna->kgem.nbatch += 10;
12527							} else {
12528								b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6;
12529								b[1] = br13;
12530								b[2] = 0;
12531								b[3] = 0;
12532								b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12533										      I915_GEM_DOMAIN_RENDER << 16 |
12534										      I915_GEM_DOMAIN_RENDER |
12535										      KGEM_RELOC_FENCED,
12536										      0);
12537								b[5] = gc->bgPixel;
12538								b[6] = gc->fgPixel;
12539								b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
12540										      I915_GEM_DOMAIN_RENDER << 16 |
12541										      KGEM_RELOC_FENCED,
12542										      0);
12543								sna->kgem.nbatch += 8;
12544							}
12545						}
12546
12547						assert(bb.x1 + dx >= 0);
12548						assert(bb.y1 + dy >= 0);
12549						assert(bb.x2 + dx <= pixmap->drawable.width);
12550						assert(bb.y2 + dy <= pixmap->drawable.height);
12551
12552						DBG(("%s: emit box=(%d, %d),(%d, %d) + (%d, %d), tile=(%d, %d) [relative to drawable: (%d, %d)]\n",
12553						     __FUNCTION__, bb.x1, bb.y1, bb.x2, bb.y2, dx, dy, tx, ty, bb.x1 - drawable->x, bb.y1 - drawable->y));
12554
12555						assert(sna->kgem.mode == KGEM_BLT);
12556						b = sna->kgem.batch + sna->kgem.nbatch;
12557						b[0] = br00;
12558						b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx);
12559						b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx);
12560						sna->kgem.nbatch += 3;
12561					}
12562				}
12563			} while (--n);
12564		}
12565
12566		if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) {
12567			sna->kgem.nbatch = unwind_batch;
12568			sna->kgem.nreloc = unwind_reloc;
12569			if (sna->kgem.nbatch == 0)
12570				kgem_bo_pair_undo(&sna->kgem, bo, tile_bo);
12571		}
12572	}
12573done:
12574	assert_pixmap_damage(pixmap);
12575	sna->blt_state.fill_bo = 0;
12576	return true;
12577}
12578
12579static bool tile8(int x)
12580{
12581	switch(x) {
12582	case 1:
12583	case 2:
12584	case 4:
12585	case 8:
12586		return true;
12587	default:
12588		return false;
12589	}
12590}
12591
12592static int next8(int x, int max)
12593{
12594	if (x > 2 && x <= 4)
12595		x = 4;
12596	else if (x < 8)
12597		x = 8;
12598	return MIN(x, max);
12599}
12600
12601static bool
12602sna_poly_fill_rect_tiled_nxm_blt(DrawablePtr drawable,
12603				 struct kgem_bo *bo,
12604				 struct sna_damage **damage,
12605				 GCPtr gc, int n, const xRectangle *rect,
12606				 const BoxRec *extents, unsigned clipped)
12607{
12608	PixmapPtr pixmap = get_drawable_pixmap(drawable);
12609	struct sna *sna = to_sna_from_pixmap(pixmap);
12610	PixmapPtr tile = gc->tile.pixmap;
12611	int w, h, tx, ty, tw, th, bpp = tile->drawable.bitsPerPixel;
12612	const DDXPointRec origin = gc->patOrg;
12613	struct kgem_bo *upload;
12614	bool ret = false;
12615	uint8_t *src;
12616	void *ptr;
12617
12618	tx = 0, tw = tile->drawable.width;
12619	if (!tile8(tw) && tw > extents->x2 - extents->x1) {
12620		tx = (extents->x1 - gc->patOrg.x - drawable->x) % tw;
12621		if (tx < 0)
12622			tx += tw;
12623		tw = next8(extents->x2 - extents->x1, tw);
12624		gc->patOrg.x = extents->x1 - drawable->x;
12625	}
12626
12627	ty = 0, th = tile->drawable.height;
12628	if (!tile8(th) && th > extents->y2 - extents->y1) {
12629		ty = (extents->y1 - gc->patOrg.y - drawable->y) % th;
12630		if (ty < 0)
12631			ty += th;
12632		th = next8(extents->y2 - extents->y1, th);
12633		gc->patOrg.y = extents->y1 - drawable->y;
12634	}
12635
12636	DBG(("%s: %dx%d+%d+%d (full tile size %dx%d)\n", __FUNCTION__,
12637	     tw, th, tx, ty, tile->drawable.width, tile->drawable.height));
12638	assert(tx < tile->drawable.width && tx >= 0);
12639	assert(ty < tile->drawable.height && ty >= 0);
12640	assert(tw && tw <= 8 && tw <= tile->drawable.width);
12641	assert(is_power_of_two(tw));
12642	assert(th && th <= 8 && th <= tile->drawable.height);
12643	assert(is_power_of_two(th));
12644
12645	if (!sna_pixmap_move_to_cpu(tile, MOVE_READ))
12646		goto out_gc;
12647
12648	assert(tile->devKind);
12649	assert(has_coherent_ptr(sna, sna_pixmap(tile), MOVE_READ));
12650
12651	src = tile->devPrivate.ptr;
12652	src += tile->devKind * ty;
12653	src += tx * bpp/8;
12654
12655	if ((tw | th) == 1) {
12656		uint32_t pixel;
12657		switch (bpp) {
12658			case 32: pixel = *(uint32_t *)src; break;
12659			case 16: pixel = *(uint16_t *)src; break;
12660			default: pixel = *(uint8_t *)src; break;
12661		}
12662		return sna_poly_fill_rect_blt(drawable, bo, damage,
12663					      gc, pixel, n, rect,
12664					      extents, clipped);
12665	}
12666
12667	upload = kgem_create_buffer(&sna->kgem, 8*bpp, KGEM_BUFFER_WRITE, &ptr);
12668	if (upload == NULL)
12669		goto out_gc;
12670
12671	upload->pitch = bpp; /* for sanity checks */
12672
12673	if (sigtrap_get() == 0) {
12674		uint8_t *dst = ptr;
12675		if (tx + tw > tile->drawable.width ||
12676		    ty + th > tile->drawable.height) {
12677			int sy = ty;
12678			src = tile->devPrivate.ptr;
12679			for (h = 0; h < th; h++) {
12680				int sx = tx;
12681				for (w = 0; w < tw; w++) {
12682					memcpy(dst + w*bpp/8, src + sy * tile->devKind + sx*bpp/8, bpp/8);
12683					if (++sx == tile->drawable.width)
12684						sx = 0;
12685				}
12686				w *= bpp/8;
12687				while (w < bpp) {
12688					memcpy(dst+w, dst, w);
12689					w *= 2;
12690				}
12691				if (++sy == tile->drawable.height)
12692					sy = 0;
12693				dst += bpp;
12694			}
12695			while (h < 8) {
12696				memcpy(dst, ptr, bpp*h);
12697				dst += bpp * h;
12698				h *= 2;
12699			}
12700		} else {
12701			for (h = 0; h < th; h++) {
12702				w = tw*bpp/8;
12703				memcpy(dst, src, w);
12704				while (w < bpp) {
12705					memcpy(dst+w, dst, w);
12706					w *= 2;
12707				}
12708				assert(w == bpp);
12709
12710				src += tile->devKind;
12711				dst += bpp;
12712			}
12713			while (h < 8) {
12714				memcpy(dst, ptr, bpp*h);
12715				dst += bpp * h;
12716				h *= 2;
12717			}
12718			assert(h == 8);
12719		}
12720
12721		ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage,
12722						       upload, gc, n, rect,
12723						       extents, clipped);
12724		sigtrap_put();
12725	}
12726
12727	kgem_bo_destroy(&sna->kgem, upload);
12728out_gc:
12729	gc->patOrg = origin;
12730	return ret;
12731}
12732
12733inline static bool tile_is_solid(GCPtr gc, uint32_t *pixel)
12734{
12735	PixmapPtr tile = gc->tile.pixmap;
12736	struct sna_pixmap *priv;
12737
12738	if ((tile->drawable.width | tile->drawable.height) == 1) {
12739		DBG(("%s: single pixel tile pixmap, converting to solid fill\n", __FUNCTION__));
12740		*pixel = get_pixel(tile);
12741		return true;
12742	}
12743
12744	priv = sna_pixmap(tile);
12745	if (priv == NULL || !priv->clear)
12746		return false;
12747
12748	DBG(("%s: tile is clear, converting to solid fill\n", __FUNCTION__));
12749	*pixel = priv->clear_color;
12750	return true;
12751}
12752
12753static bool
12754sna_poly_fill_rect_tiled_blt(DrawablePtr drawable,
12755			     struct kgem_bo *bo,
12756			     struct sna_damage **damage,
12757			     GCPtr gc, int n, xRectangle *rect,
12758			     const BoxRec *extents, unsigned clipped)
12759{
12760	PixmapPtr pixmap = get_drawable_pixmap(drawable);
12761	struct sna *sna = to_sna_from_pixmap(pixmap);
12762	PixmapPtr tile = gc->tile.pixmap;
12763	struct kgem_bo *tile_bo;
12764	const DDXPointRec * const origin = &gc->patOrg;
12765	struct sna_copy_op copy;
12766	CARD32 alu = gc->alu;
12767	int tile_width, tile_height;
12768	int16_t dx, dy;
12769	uint32_t pixel;
12770
12771	DBG(("%s pixmap=%ld, x %d [(%d, %d)x(%d, %d)...], clipped? %d\n",
12772	     __FUNCTION__, pixmap->drawable.serialNumber,
12773	     n, rect->x, rect->y, rect->width, rect->height,
12774	     clipped));
12775
12776	assert(tile->drawable.depth == drawable->depth);
12777	assert(bo);
12778
12779	if (tile_is_solid(gc, &pixel))
12780		return sna_poly_fill_rect_blt(drawable, bo, damage,
12781					      gc, pixel,
12782					      n, rect,
12783					      extents, clipped);
12784
12785	/* XXX [248]x[238] tiling can be reduced to a pattern fill.
12786	 * Also we can do the lg2 reduction for BLT and use repeat modes for
12787	 * RENDER.
12788	 */
12789
12790	tile_width = tile->drawable.width;
12791	tile_height = tile->drawable.height;
12792	if ((tile_width | tile_height) == 8) {
12793		bool ret;
12794
12795		DBG(("%s: have 8x8 tile, using BLT fast path\n", __FUNCTION__));
12796
12797		tile_bo = sna_pixmap_get_source_bo(tile);
12798		if (tile_bo == NULL) {
12799			DBG(("%s: unable to move tile go GPU, fallback\n",
12800			     __FUNCTION__));
12801			return false;
12802		}
12803
12804		ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage,
12805						       tile_bo, gc, n, rect,
12806						       extents, clipped);
12807		if (ret) {
12808			kgem_bo_destroy(&sna->kgem, tile_bo);
12809			return true;
12810		}
12811	} else {
12812		int w = tile_width, h = tile_height;
12813		struct sna_pixmap *priv = sna_pixmap(tile);
12814
12815		if (priv == NULL || priv->gpu_damage == NULL) {
12816			w = next8(extents->x2 - extents->x1, w);
12817			h = next8(extents->y2 - extents->y1, h);
12818		}
12819
12820		DBG(("%s: not 8x8, triming size for tile: %dx%d from %dx%d (area %dx%d)\n",
12821		     __FUNCTION__, w, h, tile_width, tile_height, extents->x2-extents->x1, extents->y2-extents->y1));
12822
12823		if ((w|h) < 0x10 && is_power_of_two(w) && is_power_of_two(h) &&
12824		    sna_poly_fill_rect_tiled_nxm_blt(drawable, bo, damage,
12825						     gc, n, rect,
12826						     extents, clipped))
12827			return true;
12828
12829		tile_bo = sna_pixmap_get_source_bo(tile);
12830		if (tile_bo == NULL) {
12831			DBG(("%s: unable to move tile go GPU, fallback\n",
12832						__FUNCTION__));
12833			return false;
12834		}
12835	}
12836
12837	if (!sna_copy_init_blt(&copy, sna, tile, tile_bo, pixmap, bo, alu)) {
12838		DBG(("%s: unsupported blt\n", __FUNCTION__));
12839		kgem_bo_destroy(&sna->kgem, tile_bo);
12840		return false;
12841	}
12842
12843	get_drawable_deltas(drawable, pixmap, &dx, &dy);
12844	DBG(("%s: drawable offset into pixmap(%ld) = (%d, %d)\n",
12845	     __FUNCTION__, pixmap->drawable.serialNumber, dx, dy));
12846	if (!clipped) {
12847		dx += drawable->x;
12848		dy += drawable->y;
12849
12850		sna_damage_add_rectangles(damage, rect, n, dx, dy);
12851		do {
12852			xRectangle r = *rect++;
12853			int16_t tile_y = (r.y - origin->y) % tile_height;
12854			if (tile_y < 0)
12855				tile_y += tile_height;
12856
12857			assert(r.x + dx >= 0);
12858			assert(r.y + dy >= 0);
12859			assert(r.x + dx + r.width  <= pixmap->drawable.width);
12860			assert(r.y + dy + r.height <= pixmap->drawable.height);
12861
12862			r.y += dy;
12863			do {
12864				int16_t width = r.width;
12865				int16_t x = r.x + dx, tile_x;
12866				int16_t h = tile_height - tile_y;
12867				if (h > r.height)
12868					h = r.height;
12869				r.height -= h;
12870
12871				tile_x = (r.x - origin->x) % tile_width;
12872				if (tile_x < 0)
12873					tile_x += tile_width;
12874
12875				do {
12876					int16_t w = tile_width - tile_x;
12877					if (w > width)
12878						w = width;
12879					width -= w;
12880
12881					copy.blt(sna, &copy,
12882						 tile_x, tile_y,
12883						 w, h,
12884						 x, r.y);
12885
12886					x += w;
12887					tile_x = 0;
12888				} while (width);
12889				r.y += h;
12890				tile_y = 0;
12891			} while (r.height);
12892		} while (--n);
12893	} else {
12894		RegionRec clip;
12895
12896		region_set(&clip, extents);
12897		if (!region_maybe_clip(&clip, gc->pCompositeClip))
12898			goto done;
12899
12900		if (clip.data == NULL) {
12901			const BoxRec *box = &clip.extents;
12902			DBG(("%s: single clip box [(%d, %d), (%d, %d)]\n",
12903			     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
12904			while (n--) {
12905				BoxRec r;
12906
12907				r.x1 = rect->x + drawable->x;
12908				r.y1 = rect->y + drawable->y;
12909				r.x2 = bound(r.x1, rect->width);
12910				r.y2 = bound(r.y1, rect->height);
12911				rect++;
12912
12913				DBG(("%s: rectangle [(%d, %d), (%d, %d)]\n",
12914				     __FUNCTION__, r.x1, r.y1, r.x2, r.y2));
12915
12916				if (box_intersect(&r, box)) {
12917					int height = r.y2 - r.y1;
12918					int dst_y = r.y1;
12919					int tile_y = (r.y1 - drawable->y - origin->y) % tile_height;
12920					if (tile_y < 0)
12921						tile_y += tile_height;
12922
12923					assert(r.x1 + dx >= 0);
12924					assert(r.y1 + dy >= 0);
12925					assert(r.x2 + dx <= pixmap->drawable.width);
12926					assert(r.y2 + dy <= pixmap->drawable.height);
12927
12928					while (height) {
12929						int width = r.x2 - r.x1;
12930						int dst_x = r.x1, tile_x;
12931						int h = tile_height - tile_y;
12932						if (h > height)
12933							h = height;
12934						height -= h;
12935
12936						tile_x = (r.x1 - drawable->x - origin->x) % tile_width;
12937						if (tile_x < 0)
12938							tile_x += tile_width;
12939
12940						while (width > 0) {
12941							int w = tile_width - tile_x;
12942							if (w > width)
12943								w = width;
12944							width -= w;
12945
12946							copy.blt(sna, &copy,
12947								 tile_x, tile_y,
12948								 w, h,
12949								 dst_x + dx, dst_y + dy);
12950							if (damage) {
12951								BoxRec b;
12952
12953								b.x1 = dst_x + dx;
12954								b.y1 = dst_y + dy;
12955								b.x2 = b.x1 + w;
12956								b.y2 = b.y1 + h;
12957
12958								assert_pixmap_contains_box(pixmap, &b);
12959								sna_damage_add_box(damage, &b);
12960							}
12961
12962							dst_x += w;
12963							tile_x = 0;
12964						}
12965						dst_y += h;
12966						tile_y = 0;
12967					}
12968				}
12969			}
12970		} else {
12971			while (n--) {
12972				RegionRec region;
12973				const BoxRec *box;
12974				int nbox;
12975
12976				region.extents.x1 = rect->x + drawable->x;
12977				region.extents.y1 = rect->y + drawable->y;
12978				region.extents.x2 = bound(region.extents.x1, rect->width);
12979				region.extents.y2 = bound(region.extents.y1, rect->height);
12980				rect++;
12981
12982				DBG(("%s: rectangle [(%d, %d), (%d, %d)]\n",
12983				     __FUNCTION__,
12984				     region.extents.x1,
12985				     region.extents.y1,
12986				     region.extents.x2,
12987				     region.extents.y2));
12988
12989				region.data = NULL;
12990				RegionIntersect(&region, &region, &clip);
12991
12992				assert(region.extents.x1 + dx >= 0);
12993				assert(region.extents.y1 + dy >= 0);
12994				assert(region.extents.x2 + dx <= pixmap->drawable.width);
12995				assert(region.extents.y2 + dy <= pixmap->drawable.height);
12996
12997				nbox = region_num_rects(&region);
12998				box = region_rects(&region);
12999				DBG(("%s: split into %d boxes after clipping\n", __FUNCTION__, nbox));
13000				while (nbox--) {
13001					int height = box->y2 - box->y1;
13002					int dst_y = box->y1;
13003					int tile_y = (box->y1 - drawable->y - origin->y) % tile_height;
13004					if (tile_y < 0)
13005						tile_y += tile_height;
13006
13007					while (height) {
13008						int width = box->x2 - box->x1;
13009						int dst_x = box->x1, tile_x;
13010						int h = tile_height - tile_y;
13011						if (h > height)
13012							h = height;
13013						height -= h;
13014
13015						tile_x = (box->x1 - drawable->x - origin->x) % tile_width;
13016						if (tile_x < 0)
13017							tile_x += tile_width;
13018
13019						while (width > 0) {
13020							int w = tile_width - tile_x;
13021							if (w > width)
13022								w = width;
13023							width -= w;
13024
13025							copy.blt(sna, &copy,
13026								 tile_x, tile_y,
13027								 w, h,
13028								 dst_x + dx, dst_y + dy);
13029							if (damage) {
13030								BoxRec b;
13031
13032								b.x1 = dst_x + dx;
13033								b.y1 = dst_y + dy;
13034								b.x2 = b.x1 + w;
13035								b.y2 = b.y1 + h;
13036
13037								assert_pixmap_contains_box(pixmap, &b);
13038								sna_damage_add_box(damage, &b);
13039							}
13040
13041							dst_x += w;
13042							tile_x = 0;
13043						}
13044						dst_y += h;
13045						tile_y = 0;
13046					}
13047					box++;
13048				}
13049
13050				RegionUninit(&region);
13051			}
13052		}
13053
13054		RegionUninit(&clip);
13055	}
13056done:
13057	copy.done(sna, &copy);
13058	assert_pixmap_damage(pixmap);
13059	kgem_bo_destroy(&sna->kgem, tile_bo);
13060	return true;
13061}
13062
13063static bool
13064sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
13065				    struct kgem_bo *bo,
13066				    struct sna_damage **damage,
13067				    GCPtr gc, int n, xRectangle *r,
13068				    const BoxRec *extents, unsigned clipped)
13069{
13070	PixmapPtr pixmap = get_drawable_pixmap(drawable);
13071	struct sna *sna = to_sna_from_pixmap(pixmap);
13072	uint32_t pat[2] = {0, 0}, br00, br13;
13073	int16_t dx, dy;
13074	uint32_t *b;
13075
13076	if (NO_STIPPLE_8x8)
13077		return false;
13078
13079	DBG(("%s: alu=%d, upload (%d, %d), (%d, %d), origin (%d, %d)\n",
13080	     __FUNCTION__, gc->alu,
13081	     extents->x1, extents->y1,
13082	     extents->x2, extents->y2,
13083	     gc->patOrg.x, gc->patOrg.y));
13084
13085	get_drawable_deltas(drawable, pixmap, &dx, &dy);
13086	{
13087		int px, py;
13088
13089		px = (0 - gc->patOrg.x - drawable->x - dx) % 8;
13090		if (px < 0)
13091			px += 8;
13092
13093		py = (0 - gc->patOrg.y - drawable->y - dy) % 8;
13094		if (py < 0)
13095			py += 8;
13096		DBG(("%s: pat offset (%d, %d)\n", __FUNCTION__ ,px, py));
13097
13098		br00 = XY_SCANLINE_BLT | px << 12 | py << 8 | 3 << 20;
13099		br13 = bo->pitch;
13100		if (sna->kgem.gen >= 040 && bo->tiling) {
13101			br00 |= BLT_DST_TILED;
13102			br13 >>= 2;
13103		}
13104		br13 |= (gc->fillStyle == FillStippled) << 28;
13105		br13 |= blt_depth(drawable->depth) << 24;
13106		br13 |= fill_ROP[gc->alu] << 16;
13107	}
13108
13109	assert(gc->stipple->devKind);
13110	{
13111		uint8_t *dst = (uint8_t *)pat;
13112		const uint8_t *src = gc->stipple->devPrivate.ptr;
13113		int stride = gc->stipple->devKind;
13114		int j = gc->stipple->drawable.height;
13115		do {
13116			*dst++ = byte_reverse(*src);
13117			src += stride;
13118		} while (--j);
13119	}
13120
13121	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
13122	assert(kgem_bo_can_blt(&sna->kgem, bo));
13123	if (!kgem_check_batch(&sna->kgem, 10 + 2*3) ||
13124	    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13125	    !kgem_check_reloc(&sna->kgem, 1)) {
13126		kgem_submit(&sna->kgem);
13127		if (!kgem_check_bo_fenced(&sna->kgem, bo))
13128			return false;
13129		_kgem_set_mode(&sna->kgem, KGEM_BLT);
13130	}
13131
13132	if (!clipped) {
13133		dx += drawable->x;
13134		dy += drawable->y;
13135
13136		sna_damage_add_rectangles(damage, r, n, dx, dy);
13137		if (n == 1) {
13138			DBG(("%s: single unclipped rect (%d, %d)x(%d, %d)\n",
13139			     __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height));
13140
13141			assert(sna->kgem.mode == KGEM_BLT);
13142			b = sna->kgem.batch + sna->kgem.nbatch;
13143			if (sna->kgem.gen >= 0100) {
13144				b[0] = XY_MONO_PAT | (br00 & 0x7f00) | 3<<20 | 8;
13145				b[1] = br13;
13146				b[2] = (r->y + dy) << 16 | (r->x + dx);
13147				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13148				*(uint64_t *)(b+4) =
13149					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13150							 I915_GEM_DOMAIN_RENDER << 16 |
13151							 I915_GEM_DOMAIN_RENDER |
13152							 KGEM_RELOC_FENCED,
13153							 0);
13154				b[6] = gc->bgPixel;
13155				b[7] = gc->fgPixel;
13156				b[8] = pat[0];
13157				b[9] = pat[1];
13158				sna->kgem.nbatch += 10;
13159			} else {
13160				b[0] = XY_MONO_PAT | (br00 & 0x7f00) | 3<<20 | 7;
13161				b[1] = br13;
13162				b[2] = (r->y + dy) << 16 | (r->x + dx);
13163				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13164				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13165						      I915_GEM_DOMAIN_RENDER << 16 |
13166						      I915_GEM_DOMAIN_RENDER |
13167						      KGEM_RELOC_FENCED,
13168						      0);
13169				b[5] = gc->bgPixel;
13170				b[6] = gc->fgPixel;
13171				b[7] = pat[0];
13172				b[8] = pat[1];
13173				sna->kgem.nbatch += 9;
13174			}
13175		} else do {
13176			int n_this_time, rem;
13177
13178			assert(sna->kgem.mode == KGEM_BLT);
13179			b = sna->kgem.batch + sna->kgem.nbatch;
13180			if (sna->kgem.gen >= 0100) {
13181				b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
13182				b[1] = br13;
13183				b[2] = 0;
13184				b[3] = 0;
13185				*(uint64_t *)(b+4) =
13186					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13187							 I915_GEM_DOMAIN_RENDER << 16 |
13188							 I915_GEM_DOMAIN_RENDER |
13189							 KGEM_RELOC_FENCED,
13190							 0);
13191				b[6] = gc->bgPixel;
13192				b[7] = gc->fgPixel;
13193				b[8] = pat[0];
13194				b[9] = pat[1];
13195				sna->kgem.nbatch += 10;
13196			} else {
13197				b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7;
13198				b[1] = br13;
13199				b[2] = 0;
13200				b[3] = 0;
13201				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13202						      I915_GEM_DOMAIN_RENDER << 16 |
13203						      I915_GEM_DOMAIN_RENDER |
13204						      KGEM_RELOC_FENCED,
13205						      0);
13206				b[5] = gc->bgPixel;
13207				b[6] = gc->fgPixel;
13208				b[7] = pat[0];
13209				b[8] = pat[1];
13210				sna->kgem.nbatch += 9;
13211			}
13212
13213			n_this_time = n;
13214			rem = kgem_batch_space(&sna->kgem);
13215			if (3*n_this_time > rem)
13216				n_this_time = rem / 3;
13217			assert(n_this_time);
13218			n -= n_this_time;
13219
13220			assert(sna->kgem.mode == KGEM_BLT);
13221			b = sna->kgem.batch + sna->kgem.nbatch;
13222			sna->kgem.nbatch += 3 * n_this_time;
13223			do {
13224				DBG(("%s: rect (%d, %d)x(%d, %d)\n",
13225				     __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height));
13226				assert(r->x + dx >= 0);
13227				assert(r->y + dy >= 0);
13228				assert(r->x + dx + r->width  <= pixmap->drawable.width);
13229				assert(r->y + dy + r->height <= pixmap->drawable.height);
13230
13231				b[0] = br00;
13232				b[1] = (r->y + dy) << 16 | (r->x + dx);
13233				b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13234
13235				b += 3; r++;
13236			} while(--n_this_time);
13237
13238			if (!n)
13239				break;
13240
13241			_kgem_submit(&sna->kgem);
13242			_kgem_set_mode(&sna->kgem, KGEM_BLT);
13243		} while (1);
13244	} else {
13245		RegionRec clip;
13246
13247		region_set(&clip, extents);
13248		if (!region_maybe_clip(&clip, gc->pCompositeClip))
13249			return true;
13250
13251		assert(sna->kgem.mode == KGEM_BLT);
13252		b = sna->kgem.batch + sna->kgem.nbatch;
13253		if (sna->kgem.gen >= 0100) {
13254			b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
13255			b[1] = br13;
13256			b[2] = 0;
13257			b[3] = 0;
13258			*(uint64_t *)(b+4) =
13259				kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13260						 I915_GEM_DOMAIN_RENDER << 16 |
13261						 I915_GEM_DOMAIN_RENDER |
13262						 KGEM_RELOC_FENCED,
13263						 0);
13264			b[6] = gc->bgPixel;
13265			b[7] = gc->fgPixel;
13266			b[8] = pat[0];
13267			b[9] = pat[1];
13268			sna->kgem.nbatch += 10;
13269		} else {
13270			b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7;
13271			b[1] = br13;
13272			b[2] = 0;
13273			b[3] = 0;
13274			b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13275					      I915_GEM_DOMAIN_RENDER << 16 |
13276					      I915_GEM_DOMAIN_RENDER |
13277					      KGEM_RELOC_FENCED,
13278					      0);
13279			b[5] = gc->bgPixel;
13280			b[6] = gc->fgPixel;
13281			b[7] = pat[0];
13282			b[8] = pat[1];
13283			sna->kgem.nbatch += 9;
13284		}
13285
13286		if (clip.data == NULL) {
13287			do {
13288				BoxRec box;
13289
13290				box.x1 = r->x + drawable->x;
13291				box.y1 = r->y + drawable->y;
13292				box.x2 = bound(box.x1, r->width);
13293				box.y2 = bound(box.y1, r->height);
13294				r++;
13295
13296				if (box_intersect(&box, &clip.extents)) {
13297					if (!kgem_check_batch(&sna->kgem, 3)) {
13298						_kgem_submit(&sna->kgem);
13299						_kgem_set_mode(&sna->kgem, KGEM_BLT);
13300
13301						assert(sna->kgem.mode == KGEM_BLT);
13302						b = sna->kgem.batch + sna->kgem.nbatch;
13303						if (sna->kgem.gen >= 0100) {
13304							b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
13305							b[1] = br13;
13306							b[2] = 0;
13307							b[3] = 0;
13308							*(uint64_t *)(b+4) =
13309								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13310										 I915_GEM_DOMAIN_RENDER << 16 |
13311										 I915_GEM_DOMAIN_RENDER |
13312										 KGEM_RELOC_FENCED,
13313										 0);
13314							b[6] = gc->bgPixel;
13315							b[7] = gc->fgPixel;
13316							b[8] = pat[0];
13317							b[9] = pat[1];
13318							sna->kgem.nbatch += 10;
13319						} else {
13320							b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7;
13321							b[1] = br13;
13322							b[2] = 0;
13323							b[3] = 0;
13324							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13325									      I915_GEM_DOMAIN_RENDER << 16 |
13326									      I915_GEM_DOMAIN_RENDER |
13327									      KGEM_RELOC_FENCED,
13328									      0);
13329							b[5] = gc->bgPixel;
13330							b[6] = gc->fgPixel;
13331							b[7] = pat[0];
13332							b[8] = pat[1];
13333							sna->kgem.nbatch += 9;
13334						}
13335					}
13336
13337					assert(sna->kgem.mode == KGEM_BLT);
13338					b = sna->kgem.batch + sna->kgem.nbatch;
13339					sna->kgem.nbatch += 3;
13340					b[0] = br00;
13341					b[1] = (box.y1 + dy) << 16 | (box.x1 + dx);
13342					b[2] = (box.y2 + dy) << 16 | (box.x2 + dx);
13343				}
13344			} while (--n);
13345		} else {
13346			const BoxRec * const clip_start = RegionBoxptr(&clip);
13347			const BoxRec * const clip_end = clip_start + clip.data->numRects;
13348			const BoxRec *c;
13349
13350			do {
13351				BoxRec box;
13352
13353				box.x1 = r->x + drawable->x;
13354				box.y1 = r->y + drawable->y;
13355				box.x2 = bound(box.x1, r->width);
13356				box.y2 = bound(box.y1, r->height);
13357				r++;
13358
13359				c = find_clip_box_for_y(clip_start,
13360							clip_end,
13361							box.y1);
13362				while (c != clip_end) {
13363					BoxRec bb;
13364					if (box.y2 <= c->y1)
13365						break;
13366
13367					bb = box;
13368					if (box_intersect(&bb, c++)) {
13369						if (!kgem_check_batch(&sna->kgem, 3)) {
13370							_kgem_submit(&sna->kgem);
13371							_kgem_set_mode(&sna->kgem, KGEM_BLT);
13372
13373							assert(sna->kgem.mode == KGEM_BLT);
13374							b = sna->kgem.batch + sna->kgem.nbatch;
13375							if (sna->kgem.gen >= 0100) {
13376								b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
13377								b[1] = br13;
13378								b[2] = 0;
13379								b[3] = 0;
13380								*(uint64_t *)(b+4) =
13381									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13382											 I915_GEM_DOMAIN_RENDER << 16 |
13383											 I915_GEM_DOMAIN_RENDER |
13384											 KGEM_RELOC_FENCED,
13385											 0);
13386								b[6] = gc->bgPixel;
13387								b[7] = gc->fgPixel;
13388								b[8] = pat[0];
13389								b[9] = pat[1];
13390								sna->kgem.nbatch += 10;
13391							} else {
13392								b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7;
13393								b[1] = br13;
13394								b[2] = 0;
13395								b[3] = 0;
13396								b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13397										      I915_GEM_DOMAIN_RENDER << 16 |
13398										      I915_GEM_DOMAIN_RENDER |
13399										      KGEM_RELOC_FENCED,
13400										      0);
13401								b[5] = gc->bgPixel;
13402								b[6] = gc->fgPixel;
13403								b[7] = pat[0];
13404								b[8] = pat[1];
13405								sna->kgem.nbatch += 9;
13406							}
13407						}
13408
13409						assert(sna->kgem.mode == KGEM_BLT);
13410						b = sna->kgem.batch + sna->kgem.nbatch;
13411						sna->kgem.nbatch += 3;
13412						b[0] = br00;
13413						b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx);
13414						b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx);
13415					}
13416				}
13417			} while (--n);
13418		}
13419	}
13420
13421	assert_pixmap_damage(pixmap);
13422	sna->blt_state.fill_bo = 0;
13423	return true;
13424}
13425
13426static bool
13427sna_poly_fill_rect_stippled_nxm_blt(DrawablePtr drawable,
13428				    struct kgem_bo *bo,
13429				    struct sna_damage **damage,
13430				    GCPtr gc, int n, xRectangle *r,
13431				    const BoxRec *extents, unsigned clipped)
13432{
13433	PixmapPtr scratch, stipple;
13434	uint8_t bytes[8], *dst = bytes;
13435	const uint8_t *src, *end;
13436	int j, stride;
13437	bool ret;
13438
13439	DBG(("%s: expanding %dx%d stipple to 8x8\n",
13440	     __FUNCTION__,
13441	     gc->stipple->drawable.width,
13442	     gc->stipple->drawable.height));
13443
13444	scratch = GetScratchPixmapHeader(drawable->pScreen,
13445					 8, 8, 1, 1, 1, bytes);
13446	if (scratch == NullPixmap)
13447		return false;
13448
13449	stipple = gc->stipple;
13450	gc->stipple = scratch;
13451
13452	assert(stipple->devKind);
13453	stride = stipple->devKind;
13454	src = stipple->devPrivate.ptr;
13455	end = src + stride * stipple->drawable.height;
13456	for(j = 0; j < 8; j++) {
13457		switch (stipple->drawable.width) {
13458		case 1: *dst = (*src & 1) * 0xff; break;
13459		case 2: *dst = (*src & 3) * 0x55; break;
13460		case 4: *dst = (*src & 15) * 0x11; break;
13461		case 8: *dst = *src; break;
13462		default: assert(0); break;
13463		}
13464		dst++;
13465		src += stride;
13466		if (src == end)
13467			src = stipple->devPrivate.ptr;
13468	}
13469
13470	ret = sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage,
13471						  gc, n, r, extents, clipped);
13472
13473	gc->stipple = stipple;
13474	FreeScratchPixmapHeader(scratch);
13475
13476	return ret;
13477}
13478
13479static bool
13480sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
13481				  struct kgem_bo *bo,
13482				  struct sna_damage **damage,
13483				  GCPtr gc, int n, xRectangle *r,
13484				  const BoxRec *extents, unsigned clipped)
13485{
13486	PixmapPtr pixmap = get_drawable_pixmap(drawable);
13487	struct sna *sna = to_sna_from_pixmap(pixmap);
13488	PixmapPtr stipple = gc->stipple;
13489	const DDXPointRec *origin = &gc->patOrg;
13490	int16_t dx, dy;
13491	uint32_t br00, br13;
13492
13493	DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%x\n", __FUNCTION__,
13494	     extents->x1, extents->y1,
13495	     extents->x2, extents->y2,
13496	     origin->x, origin->y,
13497	     clipped));
13498
13499	get_drawable_deltas(drawable, pixmap, &dx, &dy);
13500	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
13501	assert(kgem_bo_can_blt(&sna->kgem, bo));
13502
13503	br00 = 3 << 20;
13504	br13 = bo->pitch;
13505	if (sna->kgem.gen >= 040 && bo->tiling) {
13506		br00 |= BLT_DST_TILED;
13507		br13 >>= 2;
13508	}
13509	br13 |= (gc->fillStyle == FillStippled) << 29;
13510	br13 |= blt_depth(drawable->depth) << 24;
13511	br13 |= copy_ROP[gc->alu] << 16;
13512
13513	if (!clipped) {
13514		dx += drawable->x;
13515		dy += drawable->y;
13516
13517		sna_damage_add_rectangles(damage, r, n, dx, dy);
13518		do {
13519			int bx1 = (r->x - origin->x) & ~7;
13520			int bx2 = (r->x + r->width - origin->x + 7) & ~7;
13521			int bw = (bx2 - bx1)/8;
13522			int bh = r->height;
13523			int bstride = ALIGN(bw, 2);
13524			int src_stride;
13525			uint8_t *dst, *src;
13526			uint32_t *b;
13527
13528			DBG(("%s: rect (%d, %d)x(%d, %d) stipple [%d,%d]\n",
13529			     __FUNCTION__,
13530			     r->x, r->y, r->width, r->height,
13531			     bx1, bx2));
13532
13533			src_stride = bstride*bh;
13534			assert(src_stride > 0);
13535			if (src_stride <= 128) {
13536				src_stride = ALIGN(src_stride, 8) / 4;
13537				assert(src_stride <= 32);
13538				if (!kgem_check_batch(&sna->kgem, 8+src_stride) ||
13539				    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13540				    !kgem_check_reloc(&sna->kgem, 1)) {
13541					kgem_submit(&sna->kgem);
13542					if (!kgem_check_bo_fenced(&sna->kgem, bo))
13543						return false;
13544					_kgem_set_mode(&sna->kgem, KGEM_BLT);
13545				}
13546
13547				assert(sna->kgem.mode == KGEM_BLT);
13548				b = sna->kgem.batch + sna->kgem.nbatch;
13549				if (sna->kgem.gen >= 0100) {
13550					b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00;
13551					b[0] |= ((r->x - origin->x) & 7) << 17;
13552					b[1] = br13;
13553					b[2] = (r->y + dy) << 16 | (r->x + dx);
13554					b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13555					*(uint64_t *)(b+4) =
13556						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13557								 I915_GEM_DOMAIN_RENDER << 16 |
13558								 I915_GEM_DOMAIN_RENDER |
13559								 KGEM_RELOC_FENCED,
13560								 0);
13561					b[6] = gc->bgPixel;
13562					b[7] = gc->fgPixel;
13563
13564					dst = (uint8_t *)&b[8];
13565					sna->kgem.nbatch += 8 + src_stride;
13566				} else {
13567					b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
13568					b[0] |= ((r->x - origin->x) & 7) << 17;
13569					b[1] = br13;
13570					b[2] = (r->y + dy) << 16 | (r->x + dx);
13571					b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13572					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13573							      I915_GEM_DOMAIN_RENDER << 16 |
13574							      I915_GEM_DOMAIN_RENDER |
13575							      KGEM_RELOC_FENCED,
13576							      0);
13577					b[5] = gc->bgPixel;
13578					b[6] = gc->fgPixel;
13579
13580					dst = (uint8_t *)&b[7];
13581					sna->kgem.nbatch += 7 + src_stride;
13582				}
13583				assert(stipple->devKind);
13584				src_stride = stipple->devKind;
13585				src = stipple->devPrivate.ptr;
13586				src += (r->y - origin->y) * src_stride + bx1/8;
13587				src_stride -= bstride;
13588				do {
13589					int i = bstride;
13590					do {
13591						*dst++ = byte_reverse(*src++);
13592						*dst++ = byte_reverse(*src++);
13593						i -= 2;
13594					} while (i);
13595					src += src_stride;
13596				} while (--bh);
13597			} else {
13598				struct kgem_bo *upload;
13599				void *ptr;
13600
13601				if (!kgem_check_batch(&sna->kgem, 10) ||
13602				    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13603				    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
13604					kgem_submit(&sna->kgem);
13605					if (!kgem_check_bo_fenced(&sna->kgem, bo))
13606						return false;
13607					_kgem_set_mode(&sna->kgem, KGEM_BLT);
13608				}
13609
13610				upload = kgem_create_buffer(&sna->kgem,
13611							    bstride*bh,
13612							    KGEM_BUFFER_WRITE_INPLACE,
13613							    &ptr);
13614				if (!upload)
13615					break;
13616
13617				if (sigtrap_get() == 0) {
13618					dst = ptr;
13619					assert(stipple->devKind);
13620					src_stride = stipple->devKind;
13621					src = stipple->devPrivate.ptr;
13622					src += (r->y - origin->y) * src_stride + bx1/8;
13623					src_stride -= bstride;
13624					do {
13625						int i = bstride;
13626						do {
13627							*dst++ = byte_reverse(*src++);
13628							*dst++ = byte_reverse(*src++);
13629							i -= 2;
13630						} while (i);
13631						src += src_stride;
13632					} while (--bh);
13633
13634					assert(sna->kgem.mode == KGEM_BLT);
13635					b = sna->kgem.batch + sna->kgem.nbatch;
13636					if (sna->kgem.gen >= 0100) {
13637						b[0] = XY_MONO_SRC_COPY | br00 | 8;
13638						b[0] |= ((r->x - origin->x) & 7) << 17;
13639						b[1] = br13;
13640						b[2] = (r->y + dy) << 16 | (r->x + dx);
13641						b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13642						*(uint64_t *)(b+4) =
13643							kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13644									I915_GEM_DOMAIN_RENDER << 16 |
13645									I915_GEM_DOMAIN_RENDER |
13646									KGEM_RELOC_FENCED,
13647									0);
13648						*(uint64_t *)(b+6) =
13649							kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
13650									I915_GEM_DOMAIN_RENDER << 16 |
13651									KGEM_RELOC_FENCED,
13652									0);
13653						b[8] = gc->bgPixel;
13654						b[9] = gc->fgPixel;
13655						sna->kgem.nbatch += 10;
13656					} else {
13657						b[0] = XY_MONO_SRC_COPY | br00 | 6;
13658						b[0] |= ((r->x - origin->x) & 7) << 17;
13659						b[1] = br13;
13660						b[2] = (r->y + dy) << 16 | (r->x + dx);
13661						b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13662						b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13663								I915_GEM_DOMAIN_RENDER << 16 |
13664								I915_GEM_DOMAIN_RENDER |
13665								KGEM_RELOC_FENCED,
13666								0);
13667						b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
13668								I915_GEM_DOMAIN_RENDER << 16 |
13669								KGEM_RELOC_FENCED,
13670								0);
13671						b[6] = gc->bgPixel;
13672						b[7] = gc->fgPixel;
13673
13674						sna->kgem.nbatch += 8;
13675					}
13676					sigtrap_put();
13677				}
13678
13679				kgem_bo_destroy(&sna->kgem, upload);
13680			}
13681
13682			r++;
13683		} while (--n);
13684	} else {
13685		RegionRec clip;
13686		DDXPointRec pat;
13687
13688		region_set(&clip, extents);
13689		if (!region_maybe_clip(&clip, gc->pCompositeClip))
13690			return true;
13691
13692		pat.x = origin->x + drawable->x;
13693		pat.y = origin->y + drawable->y;
13694
13695		if (clip.data == NULL) {
13696			do {
13697				BoxRec box;
13698				int bx1, bx2, bw, bh, bstride;
13699				int src_stride;
13700				uint8_t *dst, *src;
13701				uint32_t *b;
13702				struct kgem_bo *upload;
13703				void *ptr;
13704
13705				box.x1 = r->x + drawable->x;
13706				box.x2 = bound(box.x1, r->width);
13707				box.y1 = r->y + drawable->y;
13708				box.y2 = bound(box.y1, r->height);
13709				r++;
13710
13711				if (!box_intersect(&box, &clip.extents))
13712					continue;
13713
13714				bx1 = (box.x1 - pat.x) & ~7;
13715				bx2 = (box.x2 - pat.x + 7) & ~7;
13716				bw = (bx2 - bx1)/8;
13717				bh = box.y2 - box.y1;
13718				bstride = ALIGN(bw, 2);
13719
13720				DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d], pitch=%d, stride=%d\n",
13721				     __FUNCTION__,
13722				     r->x, r->y, r->width, r->height,
13723				     box.x1, box.y1, box.x2, box.y2,
13724				     bx1, bx2, bw, bstride));
13725
13726				src_stride = bstride*bh;
13727				assert(src_stride > 0);
13728				if (src_stride <= 128) {
13729					src_stride = ALIGN(src_stride, 8) / 4;
13730					assert(src_stride <= 32);
13731					if (!kgem_check_batch(&sna->kgem, 8+src_stride) ||
13732					    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13733					    !kgem_check_reloc(&sna->kgem, 1)) {
13734						kgem_submit(&sna->kgem);
13735						if (!kgem_check_bo_fenced(&sna->kgem, bo))
13736							return false;
13737						_kgem_set_mode(&sna->kgem, KGEM_BLT);
13738					}
13739
13740					assert(sna->kgem.mode == KGEM_BLT);
13741					b = sna->kgem.batch + sna->kgem.nbatch;
13742					if (sna->kgem.gen >= 0100) {
13743						b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00;
13744						b[0] |= ((box.x1 - pat.x) & 7) << 17;
13745						b[1] = br13;
13746						b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13747						b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13748						*(uint64_t *)(b+4) =
13749							kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13750									 I915_GEM_DOMAIN_RENDER << 16 |
13751									 I915_GEM_DOMAIN_RENDER |
13752									 KGEM_RELOC_FENCED,
13753									 0);
13754						b[6] = gc->bgPixel;
13755						b[7] = gc->fgPixel;
13756
13757						dst = (uint8_t *)&b[8];
13758						sna->kgem.nbatch += 8 + src_stride;
13759					} else {
13760						b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
13761						b[0] |= ((box.x1 - pat.x) & 7) << 17;
13762						b[1] = br13;
13763						b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13764						b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13765						b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13766								      I915_GEM_DOMAIN_RENDER << 16 |
13767								      I915_GEM_DOMAIN_RENDER |
13768								      KGEM_RELOC_FENCED,
13769								      0);
13770						b[5] = gc->bgPixel;
13771						b[6] = gc->fgPixel;
13772
13773						dst = (uint8_t *)&b[7];
13774						sna->kgem.nbatch += 7 + src_stride;
13775					}
13776
13777					assert(stipple->devKind);
13778					src_stride = stipple->devKind;
13779					src = stipple->devPrivate.ptr;
13780					src += (box.y1 - pat.y) * src_stride + bx1/8;
13781					src_stride -= bstride;
13782					do {
13783						int i = bstride;
13784						do {
13785							*dst++ = byte_reverse(*src++);
13786							*dst++ = byte_reverse(*src++);
13787							i -= 2;
13788						} while (i);
13789						src += src_stride;
13790					} while (--bh);
13791				} else {
13792					if (!kgem_check_batch(&sna->kgem, 10) ||
13793					    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13794					    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
13795						kgem_submit(&sna->kgem);
13796						if (!kgem_check_bo_fenced(&sna->kgem, bo))
13797							return false;
13798						_kgem_set_mode(&sna->kgem, KGEM_BLT);
13799					}
13800
13801					upload = kgem_create_buffer(&sna->kgem,
13802								    bstride*bh,
13803								    KGEM_BUFFER_WRITE_INPLACE,
13804								    &ptr);
13805					if (!upload)
13806						break;
13807
13808					if (sigtrap_get() == 0) {
13809						dst = ptr;
13810						assert(stipple->devKind);
13811						src_stride = stipple->devKind;
13812						src = stipple->devPrivate.ptr;
13813						src += (box.y1 - pat.y) * src_stride + bx1/8;
13814						src_stride -= bstride;
13815						do {
13816							int i = bstride;
13817							do {
13818								*dst++ = byte_reverse(*src++);
13819								*dst++ = byte_reverse(*src++);
13820								i -= 2;
13821							} while (i);
13822							src += src_stride;
13823						} while (--bh);
13824
13825						assert(sna->kgem.mode == KGEM_BLT);
13826						b = sna->kgem.batch + sna->kgem.nbatch;
13827						if (sna->kgem.gen >= 0100) {
13828							b[0] = XY_MONO_SRC_COPY | br00 | 8;
13829							b[0] |= ((box.x1 - pat.x) & 7) << 17;
13830							b[1] = br13;
13831							b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13832							b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13833							*(uint64_t *)(b+4) =
13834								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13835										I915_GEM_DOMAIN_RENDER << 16 |
13836										I915_GEM_DOMAIN_RENDER |
13837										KGEM_RELOC_FENCED,
13838										0);
13839							*(uint64_t *)(b+5) =
13840								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
13841										I915_GEM_DOMAIN_RENDER << 16 |
13842										KGEM_RELOC_FENCED,
13843										0);
13844							b[8] = gc->bgPixel;
13845							b[9] = gc->fgPixel;
13846							sna->kgem.nbatch += 10;
13847						} else {
13848							b[0] = XY_MONO_SRC_COPY | br00 | 6;
13849							b[0] |= ((box.x1 - pat.x) & 7) << 17;
13850							b[1] = br13;
13851							b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13852							b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13853							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13854									I915_GEM_DOMAIN_RENDER << 16 |
13855									I915_GEM_DOMAIN_RENDER |
13856									KGEM_RELOC_FENCED,
13857									0);
13858							b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
13859									I915_GEM_DOMAIN_RENDER << 16 |
13860									KGEM_RELOC_FENCED,
13861									0);
13862							b[6] = gc->bgPixel;
13863							b[7] = gc->fgPixel;
13864
13865							sna->kgem.nbatch += 8;
13866						}
13867						sigtrap_put();
13868					}
13869					kgem_bo_destroy(&sna->kgem, upload);
13870				}
13871			} while (--n);
13872		} else {
13873			const BoxRec * const clip_start = RegionBoxptr(&clip);
13874			const BoxRec * const clip_end = clip_start + clip.data->numRects;
13875			const BoxRec *c;
13876
13877			do {
13878				BoxRec unclipped;
13879				int bx1, bx2, bw, bh, bstride;
13880				int src_stride;
13881				uint8_t *dst, *src;
13882				uint32_t *b;
13883				struct kgem_bo *upload;
13884				void *ptr;
13885
13886				unclipped.x1 = r->x + drawable->x;
13887				unclipped.x2 = bound(unclipped.x1, r->width);
13888				unclipped.y1 = r->y + drawable->y;
13889				unclipped.y2 = bound(unclipped.y1, r->height);
13890				r++;
13891
13892				c = find_clip_box_for_y(clip_start,
13893							clip_end,
13894							unclipped.y1);
13895				while (c != clip_end) {
13896					BoxRec box;
13897
13898					if (unclipped.y2 <= c->y1)
13899						break;
13900
13901					box = unclipped;
13902					if (!box_intersect(&box, c++))
13903						continue;
13904
13905					bx1 = (box.x1 - pat.x) & ~7;
13906					bx2 = (box.x2 - pat.x + 7) & ~7;
13907					bw = (bx2 - bx1)/8;
13908					bh = box.y2 - box.y1;
13909					bstride = ALIGN(bw, 2);
13910
13911					DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d]\n",
13912					     __FUNCTION__,
13913					     r->x, r->y, r->width, r->height,
13914					     box.x1, box.y1, box.x2, box.y2,
13915					     bx1, bx2));
13916
13917					src_stride = bstride*bh;
13918					assert(src_stride > 0);
13919					if (src_stride <= 128) {
13920						src_stride = ALIGN(src_stride, 8) / 4;
13921						assert(src_stride <= 32);
13922						if (!kgem_check_batch(&sna->kgem, 8+src_stride) ||
13923						    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13924						    !kgem_check_reloc(&sna->kgem, 1)) {
13925							kgem_submit(&sna->kgem);
13926							if (!kgem_check_bo_fenced(&sna->kgem, bo))
13927								return false;
13928							_kgem_set_mode(&sna->kgem, KGEM_BLT);
13929						}
13930
13931						assert(sna->kgem.mode == KGEM_BLT);
13932						b = sna->kgem.batch + sna->kgem.nbatch;
13933						if (sna->kgem.gen >= 0100) {
13934							b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00;
13935							b[0] |= ((box.x1 - pat.x) & 7) << 17;
13936							b[1] = br13;
13937							b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13938							b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13939							*(uint64_t *)(b+4) =
13940								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13941										 I915_GEM_DOMAIN_RENDER << 16 |
13942										 I915_GEM_DOMAIN_RENDER |
13943										 KGEM_RELOC_FENCED,
13944										 0);
13945							b[6] = gc->bgPixel;
13946							b[7] = gc->fgPixel;
13947
13948							dst = (uint8_t *)&b[8];
13949							sna->kgem.nbatch += 8 + src_stride;
13950						} else {
13951							b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
13952							b[0] |= ((box.x1 - pat.x) & 7) << 17;
13953							b[1] = br13;
13954							b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13955							b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13956							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13957									      I915_GEM_DOMAIN_RENDER << 16 |
13958									      I915_GEM_DOMAIN_RENDER |
13959									      KGEM_RELOC_FENCED,
13960									      0);
13961							b[5] = gc->bgPixel;
13962							b[6] = gc->fgPixel;
13963
13964							dst = (uint8_t *)&b[7];
13965							sna->kgem.nbatch += 7 + src_stride;
13966						}
13967						assert(stipple->devKind);
13968						src_stride = stipple->devKind;
13969						src = stipple->devPrivate.ptr;
13970						src += (box.y1 - pat.y) * src_stride + bx1/8;
13971						src_stride -= bstride;
13972						do {
13973							int i = bstride;
13974							do {
13975								*dst++ = byte_reverse(*src++);
13976								*dst++ = byte_reverse(*src++);
13977								i -= 2;
13978							} while (i);
13979							src += src_stride;
13980						} while (--bh);
13981					} else {
13982						if (!kgem_check_batch(&sna->kgem, 10) ||
13983						    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13984						    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
13985							kgem_submit(&sna->kgem);
13986							if (!kgem_check_bo_fenced(&sna->kgem, bo))
13987								return false;
13988							_kgem_set_mode(&sna->kgem, KGEM_BLT);
13989						}
13990
13991						upload = kgem_create_buffer(&sna->kgem,
13992									    bstride*bh,
13993									    KGEM_BUFFER_WRITE_INPLACE,
13994									    &ptr);
13995						if (!upload)
13996							break;
13997
13998						if (sigtrap_get() == 0) {
13999							dst = ptr;
14000							assert(stipple->devKind);
14001							src_stride = stipple->devKind;
14002							src = stipple->devPrivate.ptr;
14003							src += (box.y1 - pat.y) * src_stride + bx1/8;
14004							src_stride -= bstride;
14005							do {
14006								int i = bstride;
14007								do {
14008									*dst++ = byte_reverse(*src++);
14009									*dst++ = byte_reverse(*src++);
14010									i -= 2;
14011								} while (i);
14012								src += src_stride;
14013							} while (--bh);
14014
14015							assert(sna->kgem.mode == KGEM_BLT);
14016							b = sna->kgem.batch + sna->kgem.nbatch;
14017							if (sna->kgem.gen >= 0100) {
14018								b[0] = XY_MONO_SRC_COPY | br00 | 8;
14019								b[0] |= ((box.x1 - pat.x) & 7) << 17;
14020								b[1] = br13;
14021								b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
14022								b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
14023								*(uint64_t *)(b+4) =
14024									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14025											I915_GEM_DOMAIN_RENDER << 16 |
14026											I915_GEM_DOMAIN_RENDER |
14027											KGEM_RELOC_FENCED,
14028											0);
14029								*(uint64_t *)(b+6) =
14030									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
14031											I915_GEM_DOMAIN_RENDER << 16 |
14032											KGEM_RELOC_FENCED,
14033											0);
14034								b[8] = gc->bgPixel;
14035								b[9] = gc->fgPixel;
14036								sna->kgem.nbatch += 10;
14037							} else {
14038								b[0] = XY_MONO_SRC_COPY | br00 | 6;
14039								b[0] |= ((box.x1 - pat.x) & 7) << 17;
14040								b[1] = br13;
14041								b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
14042								b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
14043								b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14044										I915_GEM_DOMAIN_RENDER << 16 |
14045										I915_GEM_DOMAIN_RENDER |
14046										KGEM_RELOC_FENCED,
14047										0);
14048								b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
14049										I915_GEM_DOMAIN_RENDER << 16 |
14050										KGEM_RELOC_FENCED,
14051										0);
14052								b[6] = gc->bgPixel;
14053								b[7] = gc->fgPixel;
14054
14055								sna->kgem.nbatch += 8;
14056							}
14057							sigtrap_put();
14058						}
14059						kgem_bo_destroy(&sna->kgem, upload);
14060					}
14061				}
14062			} while (--n);
14063
14064		}
14065	}
14066
14067	sna->blt_state.fill_bo = 0;
14068	return true;
14069}
14070
14071static void
14072sna_poly_fill_rect_stippled_n_box__imm(struct sna *sna,
14073				       struct kgem_bo *bo,
14074				       uint32_t br00, uint32_t br13,
14075				       const GC *gc,
14076				       const BoxRec *box,
14077				       const DDXPointRec *origin)
14078{
14079	int x1, x2, y1, y2;
14080	uint32_t *b;
14081
14082	for (y1 = box->y1; y1 < box->y2; y1 = y2) {
14083		int oy = (y1 - origin->y) % gc->stipple->drawable.height;
14084		if (oy < 0)
14085			oy += gc->stipple->drawable.height;
14086
14087		y2 = box->y2;
14088		if (y2 - y1 > gc->stipple->drawable.height - oy)
14089			y2 = y1 + gc->stipple->drawable.height - oy;
14090
14091		for (x1 = box->x1; x1 < box->x2; x1 = x2) {
14092			int bx1, bx2, bw, bh, len, ox;
14093			uint8_t *dst, *src;
14094
14095			x2 = box->x2;
14096			ox = (x1 - origin->x) % gc->stipple->drawable.width;
14097			if (ox < 0)
14098				ox += gc->stipple->drawable.width;
14099			bx1 = ox & ~7;
14100			bx2 = ox + (x2 - x1);
14101			if (bx2 > gc->stipple->drawable.width) {
14102				bx2 = gc->stipple->drawable.width;
14103				x2 = x1 + bx2-ox;
14104			}
14105			bw = (bx2 - bx1 + 7)/8;
14106			bw = ALIGN(bw, 2);
14107			bh = y2 - y1;
14108
14109			DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d\n",
14110			     __FUNCTION__,
14111			     x1, y1, x2-x1, y2-y1,
14112			     origin->x, origin->y,
14113			     ox, oy, bx1, bx2,
14114			     gc->stipple->drawable.width,
14115			     gc->stipple->drawable.height));
14116
14117			len = bw*bh;
14118			len = ALIGN(len, 8) / 4;
14119			assert(len > 0);
14120			assert(len <= 32);
14121			if (!kgem_check_batch(&sna->kgem, 8+len) ||
14122			    !kgem_check_bo_fenced(&sna->kgem, bo) ||
14123			    !kgem_check_reloc(&sna->kgem, 1)) {
14124				kgem_submit(&sna->kgem);
14125				if (!kgem_check_bo_fenced(&sna->kgem, bo))
14126					return; /* XXX fallback? */
14127				_kgem_set_mode(&sna->kgem, KGEM_BLT);
14128			}
14129
14130			assert(sna->kgem.mode == KGEM_BLT);
14131			b = sna->kgem.batch + sna->kgem.nbatch;
14132			if (sna->kgem.gen >= 0100) {
14133				b[0] = br00 | (6 + len) | (ox & 7) << 17;
14134				b[1] = br13;
14135				b[2] = y1 << 16 | x1;
14136				b[3] = y2 << 16 | x2;
14137				*(uint64_t *)(b+4) =
14138					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14139							 I915_GEM_DOMAIN_RENDER << 16 |
14140							 I915_GEM_DOMAIN_RENDER |
14141							 KGEM_RELOC_FENCED,
14142							 0);
14143				b[6] = gc->bgPixel;
14144				b[7] = gc->fgPixel;
14145				dst = (uint8_t *)&b[8];
14146				sna->kgem.nbatch += 8 + len;
14147			} else {
14148				b[0] = br00 | (5 + len) | (ox & 7) << 17;
14149				b[1] = br13;
14150				b[2] = y1 << 16 | x1;
14151				b[3] = y2 << 16 | x2;
14152				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14153						      I915_GEM_DOMAIN_RENDER << 16 |
14154						      I915_GEM_DOMAIN_RENDER |
14155						      KGEM_RELOC_FENCED,
14156						      0);
14157				b[5] = gc->bgPixel;
14158				b[6] = gc->fgPixel;
14159				dst = (uint8_t *)&b[7];
14160				sna->kgem.nbatch += 7 + len;
14161			}
14162
14163			assert(gc->stipple->devKind);
14164			len = gc->stipple->devKind;
14165			src = gc->stipple->devPrivate.ptr;
14166			src += oy*len + ox/8;
14167			len -= bw;
14168			do {
14169				int i = bw;
14170				do {
14171					*dst++ = byte_reverse(*src++);
14172					*dst++ = byte_reverse(*src++);
14173					i -= 2;
14174				} while (i);
14175				src += len;
14176			} while (--bh);
14177		}
14178	}
14179}
14180
14181static void
14182sna_poly_fill_rect_stippled_n_box(struct sna *sna,
14183				  struct kgem_bo *bo,
14184				  struct kgem_bo **tile,
14185				  uint32_t br00, uint32_t br13,
14186				  const GC *gc,
14187				  const BoxRec *box,
14188				  const DDXPointRec *origin)
14189{
14190	int x1, x2, y1, y2;
14191	int w = gc->stipple->drawable.width;
14192	int h = gc->stipple->drawable.height;
14193	int stride = gc->stipple->devKind;
14194	uint32_t *b;
14195
14196	assert(stride);
14197	if ((((box->y2-box->y1) | (box->x2-box->x1)) & ~31) == 0) {
14198		br00 = XY_MONO_SRC_COPY_IMM |(br00 & (BLT_DST_TILED | 3 << 20));
14199		sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
14200						       br00, br13, gc,
14201						       box, origin);
14202		return;
14203	}
14204
14205	for (y1 = box->y1; y1 < box->y2; y1 = y2) {
14206		int row, oy = (y1 - origin->y) % gc->stipple->drawable.height;
14207		if (oy < 0)
14208			oy += h;
14209
14210		y2 = box->y2;
14211		if (y2 - y1 > h - oy)
14212			y2 = y1 + h - oy;
14213
14214		row = oy * stride;
14215		for (x1 = box->x1; x1 < box->x2; x1 = x2) {
14216			int bx1, bx2, bw, bh, len, ox;
14217			bool use_tile;
14218
14219			x2 = box->x2;
14220			ox = (x1 - origin->x) % w;
14221			if (ox < 0)
14222				ox += w;
14223			bx1 = ox & ~7;
14224			bx2 = ox + (x2 - x1);
14225			if (bx2 > w) {
14226				bx2 = w;
14227				x2 = x1 + bx2-ox;
14228			}
14229
14230			use_tile = y2-y1 == h && x2-x1 == w;
14231
14232			DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d, full tile?=%d\n",
14233			     __FUNCTION__,
14234			     x1, y1, x2-x1, y2-y1,
14235			     origin->x, origin->y,
14236			     ox, oy, bx1, bx2, w, h,
14237			     use_tile));
14238
14239			bw = (bx2 - bx1 + 7)/8;
14240			bw = ALIGN(bw, 2);
14241			bh = y2 - y1;
14242
14243			len = bw*bh;
14244			len = ALIGN(len, 8) / 4;
14245			assert(len > 0);
14246			if (!kgem_check_batch(&sna->kgem, 8+len) ||
14247			    !kgem_check_bo_fenced(&sna->kgem, bo) ||
14248			    !kgem_check_reloc(&sna->kgem, 2)) {
14249				kgem_submit(&sna->kgem);
14250				if (!kgem_check_bo_fenced(&sna->kgem, bo))
14251					return; /* XXX fallback? */
14252				_kgem_set_mode(&sna->kgem, KGEM_BLT);
14253			}
14254
14255			assert(sna->kgem.mode == KGEM_BLT);
14256			b = sna->kgem.batch + sna->kgem.nbatch;
14257
14258			if (!use_tile && len <= 32) {
14259				uint8_t *dst, *src;
14260
14261				if (sna->kgem.gen >= 0100) {
14262					b[0] = XY_MONO_SRC_COPY_IMM;
14263					b[0] |= (br00 & (BLT_DST_TILED | 3 << 20));
14264					b[0] |= (ox & 7) << 17;
14265					b[0] |= (6 + len);
14266					b[1] = br13;
14267					b[2] = y1 << 16 | x1;
14268					b[3] = y2 << 16 | x2;
14269					*(uint64_t *)(b+4) =
14270						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14271								 I915_GEM_DOMAIN_RENDER << 16 |
14272								 I915_GEM_DOMAIN_RENDER |
14273								 KGEM_RELOC_FENCED,
14274								 0);
14275					b[6] = gc->bgPixel;
14276					b[7] = gc->fgPixel;
14277
14278					dst = (uint8_t *)&b[8];
14279					sna->kgem.nbatch += 8 + len;
14280				} else {
14281					b[0] = XY_MONO_SRC_COPY_IMM;
14282					b[0] |= (br00 & (BLT_DST_TILED | 3 << 20));
14283					b[0] |= (ox & 7) << 17;
14284					b[0] |= (5 + len);
14285					b[1] = br13;
14286					b[2] = y1 << 16 | x1;
14287					b[3] = y2 << 16 | x2;
14288					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14289							      I915_GEM_DOMAIN_RENDER << 16 |
14290							      I915_GEM_DOMAIN_RENDER |
14291							      KGEM_RELOC_FENCED,
14292							      0);
14293					b[5] = gc->bgPixel;
14294					b[6] = gc->fgPixel;
14295
14296					dst = (uint8_t *)&b[7];
14297					sna->kgem.nbatch += 7 + len;
14298				}
14299
14300				assert(gc->stipple->devKind);
14301				len = gc->stipple->devKind;
14302				src = gc->stipple->devPrivate.ptr;
14303				src += oy*len + ox/8;
14304				len -= bw;
14305				do {
14306					int i = bw;
14307					do {
14308						*dst++ = byte_reverse(*src++);
14309						*dst++ = byte_reverse(*src++);
14310						i -= 2;
14311					} while (i);
14312					src += len;
14313				} while (--bh);
14314			} else {
14315				bool has_tile = use_tile && *tile;
14316				struct kgem_bo *upload;
14317				uint8_t *dst, *src;
14318				void *ptr;
14319
14320				if (has_tile) {
14321					upload = kgem_bo_reference(*tile);
14322				} else {
14323					upload = kgem_create_buffer(&sna->kgem, bw*bh,
14324								    KGEM_BUFFER_WRITE_INPLACE,
14325								    &ptr);
14326					if (!upload)
14327						return;
14328				}
14329
14330				assert(sna->kgem.mode == KGEM_BLT);
14331				b = sna->kgem.batch + sna->kgem.nbatch;
14332				if (sna->kgem.gen >= 0100) {
14333					b[0] = br00 | (ox & 7) << 17 | 8;
14334					b[1] = br13;
14335					b[2] = y1 << 16 | x1;
14336					b[3] = y2 << 16 | x2;
14337					*(uint64_t *)(b+4) =
14338						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14339								 I915_GEM_DOMAIN_RENDER << 16 |
14340								 I915_GEM_DOMAIN_RENDER |
14341								 KGEM_RELOC_FENCED,
14342								 0);
14343					*(uint64_t *)(b+6) =
14344						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
14345							       I915_GEM_DOMAIN_RENDER << 16 |
14346							       KGEM_RELOC_FENCED,
14347							       0);
14348					b[8] = gc->bgPixel;
14349					b[9] = gc->fgPixel;
14350					sna->kgem.nbatch += 10;
14351				} else {
14352					b[0] = br00 | (ox & 7) << 17 | 6;
14353					b[1] = br13;
14354					b[2] = y1 << 16 | x1;
14355					b[3] = y2 << 16 | x2;
14356					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14357							      I915_GEM_DOMAIN_RENDER << 16 |
14358							      I915_GEM_DOMAIN_RENDER |
14359							      KGEM_RELOC_FENCED,
14360							      0);
14361					b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
14362							      I915_GEM_DOMAIN_RENDER << 16 |
14363							      KGEM_RELOC_FENCED,
14364							      0);
14365					b[6] = gc->bgPixel;
14366					b[7] = gc->fgPixel;
14367					sna->kgem.nbatch += 8;
14368				}
14369
14370				if (!has_tile) {
14371					dst = ptr;
14372					len = stride;
14373					src = gc->stipple->devPrivate.ptr;
14374					src += row + (ox >> 3);
14375					len -= bw;
14376					do {
14377						int i = bw;
14378						do {
14379							*dst++ = byte_reverse(*src++);
14380							*dst++ = byte_reverse(*src++);
14381							i -= 2;
14382						} while (i);
14383						src += len;
14384					} while (--bh);
14385					if (use_tile)
14386						*tile = kgem_bo_reference(upload);
14387				}
14388
14389				kgem_bo_destroy(&sna->kgem, upload);
14390			}
14391		}
14392	}
14393}
14394
14395static bool
14396sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable,
14397				       struct kgem_bo *bo,
14398				       struct sna_damage **damage,
14399				       GCPtr gc, int n, xRectangle *r,
14400				       const BoxRec *extents, unsigned clipped)
14401{
14402	PixmapPtr pixmap = get_drawable_pixmap(drawable);
14403	struct sna *sna = to_sna_from_pixmap(pixmap);
14404	DDXPointRec origin = gc->patOrg;
14405	int16_t dx, dy;
14406	uint32_t br00, br13;
14407
14408	DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__,
14409	     extents->x1, extents->y1,
14410	     extents->x2, extents->y2,
14411	     origin.x, origin.y,
14412	     clipped, gc->alu, gc->fillStyle == FillOpaqueStippled));
14413
14414	get_drawable_deltas(drawable, pixmap, &dx, &dy);
14415	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
14416	assert(kgem_bo_can_blt(&sna->kgem, bo));
14417
14418	br00 = XY_MONO_SRC_COPY_IMM | 3 << 20;
14419	br13 = bo->pitch;
14420	if (sna->kgem.gen >= 040 && bo->tiling) {
14421		br00 |= BLT_DST_TILED;
14422		br13 >>= 2;
14423	}
14424	br13 |= (gc->fillStyle == FillStippled) << 29;
14425	br13 |= blt_depth(drawable->depth) << 24;
14426	br13 |= copy_ROP[gc->alu] << 16;
14427
14428	origin.x += dx + drawable->x;
14429	origin.y += dy + drawable->y;
14430
14431	if (!clipped) {
14432		dx += drawable->x;
14433		dy += drawable->y;
14434
14435		sna_damage_add_rectangles(damage, r, n, dx, dy);
14436		do {
14437			BoxRec box;
14438
14439			box.x1 = r->x + dx;
14440			box.y1 = r->y + dy;
14441			box.x2 = box.x1 + r->width;
14442			box.y2 = box.y1 + r->height;
14443
14444			sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
14445							       br00, br13, gc,
14446							       &box, &origin);
14447			r++;
14448		} while (--n);
14449	} else {
14450		RegionRec clip;
14451
14452		region_set(&clip, extents);
14453		if (!region_maybe_clip(&clip, gc->pCompositeClip)) {
14454			DBG(("%s: all clipped\n", __FUNCTION__));
14455			return true;
14456		}
14457
14458		if (clip.data == NULL) {
14459			DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n",
14460			     __FUNCTION__,
14461			     clip.extents.x1, clip.extents.y1,
14462			     clip.extents.x2, clip.extents.y2));
14463			do {
14464				BoxRec box;
14465
14466				box.x1 = r->x + drawable->x;
14467				box.x2 = bound(box.x1, r->width);
14468				box.y1 = r->y + drawable->y;
14469				box.y2 = bound(box.y1, r->height);
14470				r++;
14471
14472				DBG(("%s: box (%d, %d), (%d, %d)\n",
14473				     __FUNCTION__,
14474				     box.x1, box.y1, box.x2, box.y2));
14475				if (!box_intersect(&box, &clip.extents))
14476					continue;
14477
14478				box.x1 += dx; box.x2 += dx;
14479				box.y1 += dy; box.y2 += dy;
14480
14481				sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
14482								       br00, br13, gc,
14483								       &box, &origin);
14484			} while (--n);
14485		} else {
14486			const BoxRec * const clip_start = RegionBoxptr(&clip);
14487			const BoxRec * const clip_end = clip_start + clip.data->numRects;
14488			const BoxRec *c;
14489
14490			DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__,
14491			     clip_start->x1, clip_start->y1,
14492			     clip_start->x2, clip_start->y2,
14493			     clip_end->x1, clip_end->y1,
14494			     clip_end->x2, clip_end->y2));
14495			do {
14496				BoxRec unclipped;
14497
14498				unclipped.x1 = r->x + drawable->x;
14499				unclipped.x2 = bound(unclipped.x1, r->width);
14500				unclipped.y1 = r->y + drawable->y;
14501				unclipped.y2 = bound(unclipped.y1, r->height);
14502				r++;
14503
14504				c = find_clip_box_for_y(clip_start,
14505							clip_end,
14506							unclipped.y1);
14507				while (c != clip_end) {
14508					BoxRec box;
14509
14510					if (unclipped.y2 <= c->y1)
14511						break;
14512
14513					box = unclipped;
14514					if (!box_intersect(&box, c++))
14515						continue;
14516
14517					box.x1 += dx; box.x2 += dx;
14518					box.y1 += dy; box.y2 += dy;
14519
14520					sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
14521									       br00, br13, gc,
14522									       &box, &origin);
14523				}
14524			} while (--n);
14525		}
14526	}
14527
14528	assert_pixmap_damage(pixmap);
14529	sna->blt_state.fill_bo = 0;
14530	return true;
14531}
14532
14533static bool
14534sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable,
14535				  struct kgem_bo *bo,
14536				  struct sna_damage **damage,
14537				  GCPtr gc, int n, xRectangle *r,
14538				  const BoxRec *extents, unsigned clipped)
14539{
14540	PixmapPtr pixmap = get_drawable_pixmap(drawable);
14541	struct sna *sna = to_sna_from_pixmap(pixmap);
14542	DDXPointRec origin = gc->patOrg;
14543	struct kgem_bo *tile = NULL;
14544	int16_t dx, dy;
14545	uint32_t br00, br13;
14546
14547	DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__,
14548	     extents->x1, extents->y1,
14549	     extents->x2, extents->y2,
14550	     origin.x, origin.y,
14551	     clipped, gc->alu, gc->fillStyle == FillOpaqueStippled));
14552
14553	if (((gc->stipple->drawable.width | gc->stipple->drawable.height) & ~31) == 0)
14554		return sna_poly_fill_rect_stippled_n_blt__imm(drawable,
14555							      bo, damage,
14556							      gc, n, r,
14557							      extents, clipped);
14558
14559	get_drawable_deltas(drawable, pixmap, &dx, &dy);
14560	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
14561	assert(kgem_bo_can_blt(&sna->kgem, bo));
14562
14563	br00 = XY_MONO_SRC_COPY | 3 << 20;
14564	br13 = bo->pitch;
14565	if (sna->kgem.gen >= 040 && bo->tiling) {
14566		br00 |= BLT_DST_TILED;
14567		br13 >>= 2;
14568	}
14569	br13 |= (gc->fillStyle == FillStippled) << 29;
14570	br13 |= blt_depth(drawable->depth) << 24;
14571	br13 |= copy_ROP[gc->alu] << 16;
14572
14573	origin.x += dx + drawable->x;
14574	origin.y += dy + drawable->y;
14575
14576	if (!clipped) {
14577		dx += drawable->x;
14578		dy += drawable->y;
14579
14580		sna_damage_add_rectangles(damage, r, n, dx, dy);
14581		do {
14582			BoxRec box;
14583
14584			box.x1 = r->x + dx;
14585			box.y1 = r->y + dy;
14586			box.x2 = box.x1 + r->width;
14587			box.y2 = box.y1 + r->height;
14588
14589			sna_poly_fill_rect_stippled_n_box(sna, bo, &tile,
14590							  br00, br13, gc,
14591							  &box, &origin);
14592			r++;
14593		} while (--n);
14594	} else {
14595		RegionRec clip;
14596
14597		region_set(&clip, extents);
14598		if (!region_maybe_clip(&clip, gc->pCompositeClip)) {
14599			DBG(("%s: all clipped\n", __FUNCTION__));
14600			return true;
14601		}
14602
14603		if (clip.data == NULL) {
14604			DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n",
14605			     __FUNCTION__,
14606			     clip.extents.x1, clip.extents.y1,
14607			     clip.extents.x2, clip.extents.y2));
14608			do {
14609				BoxRec box;
14610
14611				box.x1 = r->x + drawable->x;
14612				box.x2 = bound(box.x1, r->width);
14613				box.y1 = r->y + drawable->y;
14614				box.y2 = bound(box.y1, r->height);
14615				r++;
14616
14617				DBG(("%s: box (%d, %d), (%d, %d)\n",
14618				     __FUNCTION__,
14619				     box.x1, box.y1, box.x2, box.y2));
14620				if (!box_intersect(&box, &clip.extents))
14621					continue;
14622
14623				box.x1 += dx; box.x2 += dx;
14624				box.y1 += dy; box.y2 += dy;
14625
14626				sna_poly_fill_rect_stippled_n_box(sna, bo, &tile,
14627								  br00, br13, gc,
14628								  &box, &origin);
14629			} while (--n);
14630		} else {
14631			const BoxRec * const clip_start = RegionBoxptr(&clip);
14632			const BoxRec * const clip_end = clip_start + clip.data->numRects;
14633			const BoxRec *c;
14634
14635			DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__,
14636			     clip_start->x1, clip_start->y1,
14637			     clip_start->x2, clip_start->y2,
14638			     clip_end->x1, clip_end->y1,
14639			     clip_end->x2, clip_end->y2));
14640			do {
14641				BoxRec unclipped;
14642
14643				unclipped.x1 = r->x + drawable->x;
14644				unclipped.x2 = bound(unclipped.x1, r->width);
14645				unclipped.y1 = r->y + drawable->y;
14646				unclipped.y2 = bound(unclipped.y1, r->height);
14647				r++;
14648
14649				c = find_clip_box_for_y(clip_start,
14650							clip_end,
14651							unclipped.y1);
14652				while (c != clip_end) {
14653					BoxRec box;
14654
14655					if (unclipped.y2 <= c->y1)
14656						break;
14657
14658					box = unclipped;
14659					if (!box_intersect(&box, c++))
14660						continue;
14661
14662					box.x1 += dx; box.x2 += dx;
14663					box.y1 += dy; box.y2 += dy;
14664
14665					sna_poly_fill_rect_stippled_n_box(sna, bo, &tile,
14666									  br00, br13, gc,
14667									  &box, &origin);
14668				}
14669			} while (--n);
14670		}
14671	}
14672
14673	assert_pixmap_damage(pixmap);
14674	if (tile)
14675		kgem_bo_destroy(&sna->kgem, tile);
14676	sna->blt_state.fill_bo = 0;
14677	return true;
14678}
14679
14680static bool
14681sna_poly_fill_rect_stippled_blt(DrawablePtr drawable,
14682				struct kgem_bo *bo,
14683				struct sna_damage **damage,
14684				GCPtr gc, int n, xRectangle *rect,
14685				const BoxRec *extents, unsigned clipped)
14686{
14687
14688	PixmapPtr stipple = gc->stipple;
14689	PixmapPtr pixmap = get_drawable_pixmap(drawable);
14690
14691	if (bo->tiling == I915_TILING_Y) {
14692		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
14693		/* This is cheating, but only the gpu_bo can be tiled */
14694		assert(bo == __sna_pixmap_get_bo(pixmap));
14695		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
14696		if (bo == NULL) {
14697			DBG(("%s: fallback -- unable to change tiling\n",
14698			     __FUNCTION__));
14699			return false;
14700		}
14701	}
14702
14703	if (!kgem_bo_can_blt(&to_sna_from_pixmap(pixmap)->kgem, bo))
14704		return false;
14705
14706	if (!sna_drawable_move_to_cpu(&stipple->drawable, MOVE_READ))
14707		return false;
14708
14709	DBG(("%s: origin (%d, %d), extents (stipple): (%d, %d), stipple size %dx%d\n",
14710	     __FUNCTION__, gc->patOrg.x, gc->patOrg.y,
14711	     extents->x2 - gc->patOrg.x - drawable->x,
14712	     extents->y2 - gc->patOrg.y - drawable->y,
14713	     stipple->drawable.width, stipple->drawable.height));
14714
14715	if ((stipple->drawable.width | stipple->drawable.height) == 8)
14716		return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage,
14717							   gc, n, rect,
14718							   extents, clipped);
14719
14720	if ((stipple->drawable.width | stipple->drawable.height) <= 0xc &&
14721	    is_power_of_two(stipple->drawable.width) &&
14722	    is_power_of_two(stipple->drawable.height))
14723		return sna_poly_fill_rect_stippled_nxm_blt(drawable, bo, damage,
14724							   gc, n, rect,
14725							   extents, clipped);
14726
14727	if (extents->x1 - gc->patOrg.x - drawable->x >= 0 &&
14728	    extents->x2 - gc->patOrg.x - drawable->x <= stipple->drawable.width &&
14729	    extents->y1 - gc->patOrg.y - drawable->y >= 0 &&
14730	    extents->y2 - gc->patOrg.y - drawable->y <= stipple->drawable.height) {
14731		if (stipple->drawable.width <= 8 && stipple->drawable.height <= 8)
14732			return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage,
14733								   gc, n, rect,
14734								   extents, clipped);
14735		else
14736			return sna_poly_fill_rect_stippled_1_blt(drawable, bo, damage,
14737								 gc, n, rect,
14738								 extents, clipped);
14739	} else {
14740		return sna_poly_fill_rect_stippled_n_blt(drawable, bo, damage,
14741							 gc, n, rect,
14742							 extents, clipped);
14743	}
14744}
14745
14746static unsigned
14747sna_poly_fill_rect_extents(DrawablePtr drawable, GCPtr gc,
14748			   int *_n, xRectangle **_r,
14749			   BoxPtr out)
14750{
14751	int n;
14752	xRectangle *r;
14753	Box32Rec box;
14754	bool clipped;
14755
14756	if (*_n == 0)
14757		return 0;
14758
14759	DBG(("%s: [0] = (%d, %d)x(%d, %d)\n",
14760	     __FUNCTION__, (*_r)->x, (*_r)->y, (*_r)->width, (*_r)->height));
14761
14762	/* Remove any zero-size rectangles from the array */
14763	while (*_n && ((*_r)->width == 0 || (*_r)->height == 0))
14764		--*_n, ++*_r;
14765
14766	if (*_n == 0)
14767		return 0;
14768
14769	n = *_n;
14770	r = *_r;
14771
14772	box.x1 = r->x;
14773	box.x2 = box.x1 + r->width;
14774	box.y1 = r->y;
14775	box.y2 = box.y1 + r->height;
14776	r++;
14777
14778	while (--n) {
14779		if (r->width == 0 || r->height == 0)
14780			goto slow;
14781
14782		box32_add_rect(&box, r++);
14783	}
14784	goto done;
14785slow:
14786	{
14787		xRectangle *rr = r;
14788		do {
14789			do {
14790				--*_n, r++;
14791			} while (--n && (r->width == 0 || r->height == 0));
14792			while (n && r->width && r->height) {
14793				box32_add_rect(&box, r);
14794				*rr++ = *r++;
14795				n--;
14796			}
14797		} while (n);
14798	}
14799done:
14800
14801	clipped = box32_trim_and_translate(&box, drawable, gc);
14802	if (!box32_to_box16(&box, out))
14803		return 0;
14804
14805	return 1 | clipped << 1;
14806}
14807
14808static void
14809sna_poly_fill_rect(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect)
14810{
14811	PixmapPtr pixmap = get_drawable_pixmap(draw);
14812	struct sna *sna = to_sna_from_pixmap(pixmap);
14813	struct sna_pixmap *priv = sna_pixmap(pixmap);
14814	struct sna_damage **damage;
14815	struct kgem_bo *bo;
14816	RegionRec region;
14817	unsigned flags, hint;
14818	uint32_t color;
14819
14820	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
14821	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
14822	     (gc->fillStyle == FillSolid ||
14823	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
14824	     gc->fillStyle, gc->tileIsPixel,
14825	     gc->alu));
14826
14827	flags = sna_poly_fill_rect_extents(draw, gc, &n, &rect, &region.extents);
14828	if (flags == 0) {
14829		DBG(("%s, nothing to do\n", __FUNCTION__));
14830		return;
14831	}
14832
14833	DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
14834	     region.extents.x1, region.extents.y1,
14835	     region.extents.x2, region.extents.y2,
14836	     flags));
14837
14838	if (FORCE_FALLBACK || !ACCEL_POLY_FILL_RECT) {
14839		DBG(("%s: fallback forced\n", __FUNCTION__));
14840		goto fallback;
14841	}
14842
14843	if (priv == NULL) {
14844		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
14845		goto fallback;
14846	}
14847
14848	if (wedged(sna)) {
14849		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
14850		goto fallback;
14851	}
14852
14853	if (!PM_IS_SOLID(draw, gc->planemask)) {
14854		DBG(("%s: fallback -- planemask=0x%lx (not-solid)\n",
14855		     __FUNCTION__, gc->planemask));
14856		goto fallback;
14857	}
14858
14859	if (alu_overwrites(gc->alu))
14860		flags |= OVERWRITES;
14861
14862	/* Clear the cpu damage so that we refresh the GPU status of the
14863	 * pixmap upon a redraw after a period of inactivity.
14864	 */
14865	hint = PREFER_GPU;
14866	if (n == 1 && gc->fillStyle != FillStippled && flags & OVERWRITES) {
14867		int16_t dx, dy;
14868
14869		region.data = NULL;
14870
14871		if (get_drawable_deltas(draw, pixmap, &dx, &dy)) {
14872			DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy));
14873			RegionTranslate(&region, dx, dy);
14874		}
14875
14876		if ((flags & IS_CLIPPED) == 0) {
14877			hint |= IGNORE_DAMAGE;
14878			if (region_subsumes_drawable(&region, &pixmap->drawable)) {
14879				discard_cpu_damage(sna, priv);
14880				hint |= REPLACES;
14881			} else {
14882				if (priv->cpu_damage &&
14883				    region_subsumes_damage(&region, priv->cpu_damage))
14884					discard_cpu_damage(sna, priv);
14885			}
14886		}
14887		if (priv->cpu_damage == NULL) {
14888			if (priv->gpu_bo &&
14889			    (hint & REPLACES ||
14890			     box_covers_pixmap(pixmap, &region.extents) ||
14891			     box_inplace(pixmap, &region.extents))) {
14892				DBG(("%s: promoting to full GPU\n",
14893				     __FUNCTION__));
14894				assert(priv->gpu_bo->proxy == NULL);
14895				sna_damage_all(&priv->gpu_damage, pixmap);
14896			}
14897			DBG(("%s: dropping last-cpu hint\n", __FUNCTION__));
14898			priv->cpu = false;
14899		}
14900
14901		if (dx | dy)
14902			RegionTranslate(&region, -dx, -dy);
14903	}
14904
14905	/* If the source is already on the GPU, keep the operation on the GPU */
14906	if (gc->fillStyle == FillTiled && !gc->tileIsPixel &&
14907	    sna_pixmap_is_gpu(gc->tile.pixmap)) {
14908		DBG(("%s: source is already on the gpu\n", __FUNCTION__));
14909		hint |= FORCE_GPU;
14910	}
14911
14912	bo = sna_drawable_use_bo(draw, hint, &region.extents, &damage);
14913	if (bo == NULL) {
14914		DBG(("%s: not using GPU, hint=%x\n", __FUNCTION__, hint));
14915		goto fallback;
14916	}
14917	if (hint & REPLACES && UNDO)
14918		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
14919
14920	if (gc_is_solid(gc, &color)) {
14921		DBG(("%s: solid fill [%08x], testing for blt\n",
14922		     __FUNCTION__, color));
14923
14924		if (sna_poly_fill_rect_blt(draw,
14925					   bo, damage,
14926					   gc, color, n, rect,
14927					   &region.extents, flags))
14928			return;
14929	} else if (gc->fillStyle == FillTiled) {
14930		DBG(("%s: tiled fill, testing for blt\n", __FUNCTION__));
14931
14932		if (sna_poly_fill_rect_tiled_blt(draw, bo, damage,
14933						 gc, n, rect,
14934						 &region.extents, flags))
14935			return;
14936	} else {
14937		DBG(("%s: stippled fill, testing for blt\n", __FUNCTION__));
14938
14939		if (sna_poly_fill_rect_stippled_blt(draw, bo, damage,
14940						    gc, n, rect,
14941						    &region.extents, flags))
14942			return;
14943	}
14944
14945fallback:
14946	DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__,
14947	     region.extents.x1, region.extents.y1,
14948	     region.extents.x2, region.extents.y2));
14949	region.data = NULL;
14950	if (!region_maybe_clip(&region, gc->pCompositeClip)) {
14951		DBG(("%s: nothing to do, all clipped\n", __FUNCTION__));
14952		return;
14953	}
14954
14955	if (!sna_gc_move_to_cpu(gc, draw, &region))
14956		goto out;
14957	if (!sna_drawable_move_region_to_cpu(draw, &region,
14958					     drawable_gc_flags(draw, gc, n > 1)))
14959		goto out;
14960
14961	if (sigtrap_get() == 0) {
14962		DBG(("%s: fallback - fbPolyFillRect\n", __FUNCTION__));
14963		fbPolyFillRect(draw, gc, n, rect);
14964		FALLBACK_FLUSH(draw);
14965		sigtrap_put();
14966	}
14967out:
14968	sna_gc_move_to_gpu(gc);
14969	RegionUninit(&region);
14970}
14971
14972static void
14973sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *r)
14974{
14975	struct sna_fill_spans *data = sna_gc(gc)->priv;
14976	uint32_t color;
14977
14978	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
14979	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
14980	     (gc->fillStyle == FillSolid ||
14981	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
14982	     gc->fillStyle, gc->tileIsPixel,
14983	     gc->alu));
14984
14985	assert(PM_IS_SOLID(draw, gc->planemask));
14986	if (n == 0)
14987		return;
14988
14989	/* The mi routines do not attempt to keep the spans it generates
14990	 * within the clip, so we must run them through the clipper.
14991	 */
14992
14993	if (gc_is_solid(gc, &color)) {
14994		(void)sna_poly_fill_rect_blt(draw,
14995					     data->bo, NULL,
14996					     gc, color, n, r,
14997					     &data->region.extents,
14998					     IS_CLIPPED);
14999	} else if (gc->fillStyle == FillTiled) {
15000		(void)sna_poly_fill_rect_tiled_blt(draw,
15001						   data->bo, NULL,
15002						   gc, n, r,
15003						   &data->region.extents,
15004						   IS_CLIPPED);
15005	} else {
15006		(void)sna_poly_fill_rect_stippled_blt(draw,
15007						    data->bo, NULL,
15008						    gc, n, r,
15009						    &data->region.extents,
15010						    IS_CLIPPED);
15011	}
15012}
15013
15014static void
15015sna_poly_fill_arc(DrawablePtr draw, GCPtr gc, int n, xArc *arc)
15016{
15017	struct sna_fill_spans data;
15018	struct sna_pixmap *priv;
15019
15020	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
15021	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
15022	     (gc->fillStyle == FillSolid ||
15023	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
15024	     gc->fillStyle, gc->tileIsPixel,
15025	     gc->alu));
15026
15027	data.flags = sna_poly_arc_extents(draw, gc, n, arc,
15028					  &data.region.extents);
15029	if (data.flags == 0)
15030		return;
15031
15032	DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
15033	     data.region.extents.x1, data.region.extents.y1,
15034	     data.region.extents.x2, data.region.extents.y2,
15035	     data.flags));
15036
15037	data.region.data = NULL;
15038
15039	if (FORCE_FALLBACK)
15040		goto fallback;
15041
15042	if (!ACCEL_POLY_FILL_ARC)
15043		goto fallback;
15044
15045	data.pixmap = get_drawable_pixmap(draw);
15046	data.sna = to_sna_from_pixmap(data.pixmap);
15047	priv = sna_pixmap(data.pixmap);
15048	if (priv == NULL) {
15049		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
15050		goto fallback;
15051	}
15052
15053	if (wedged(data.sna)) {
15054		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
15055		goto fallback;
15056	}
15057
15058	if (!PM_IS_SOLID(draw, gc->planemask))
15059		goto fallback;
15060
15061	if ((data.bo = sna_drawable_use_bo(draw,
15062					   use_fill_spans(draw, gc, &data.region.extents, data.flags),
15063					   &data.region.extents,
15064					   &data.damage))) {
15065		uint32_t color;
15066
15067		get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy);
15068		sna_gc(gc)->priv = &data;
15069
15070		if (gc_is_solid(gc, &color)) {
15071			struct sna_fill_op fill;
15072
15073			if (!sna_fill_init_blt(&fill,
15074					       data.sna, data.pixmap,
15075					       data.bo, gc->alu, color,
15076					       FILL_SPANS))
15077				goto fallback;
15078
15079			data.op = &fill;
15080
15081			if ((data.flags & IS_CLIPPED) == 0) {
15082				if (data.dx | data.dy)
15083					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
15084				else
15085					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
15086			} else {
15087				if (!region_maybe_clip(&data.region,
15088						       gc->pCompositeClip))
15089					return;
15090
15091				if (region_is_singular(&data.region))
15092					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
15093				else
15094					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
15095			}
15096			assert(gc->miTranslate);
15097			gc->ops = &sna_gc_ops__tmp;
15098
15099			miPolyFillArc(draw, gc, n, arc);
15100			fill.done(data.sna, &fill);
15101		} else {
15102			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
15103			gc->ops = &sna_gc_ops__tmp;
15104
15105			miPolyFillArc(draw, gc, n, arc);
15106		}
15107
15108		gc->ops = (GCOps *)&sna_gc_ops;
15109		if (data.damage) {
15110			if (data.dx | data.dy)
15111				pixman_region_translate(&data.region, data.dx, data.dy);
15112			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
15113			sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap);
15114		}
15115		assert_pixmap_damage(data.pixmap);
15116		RegionUninit(&data.region);
15117		return;
15118	}
15119
15120fallback:
15121	DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__,
15122	     data.region.extents.x1, data.region.extents.y1,
15123	     data.region.extents.x2, data.region.extents.y2));
15124	if (!region_maybe_clip(&data.region, gc->pCompositeClip)) {
15125		DBG(("%s: nothing to do, all clipped\n", __FUNCTION__));
15126		return;
15127	}
15128
15129	if (!sna_gc_move_to_cpu(gc, draw, &data.region))
15130		goto out;
15131	if (!sna_drawable_move_region_to_cpu(draw, &data.region,
15132					     drawable_gc_flags(draw, gc, true)))
15133		goto out;
15134
15135	if (sigtrap_get() == 0) {
15136		DBG(("%s: fallback -- miPolyFillArc -> sna_fill_spans__cpu\n",
15137		     __FUNCTION__));
15138		miPolyFillArc(draw, gc, n, arc);
15139		sigtrap_put();
15140	}
15141out:
15142	sna_gc_move_to_gpu(gc);
15143	RegionUninit(&data.region);
15144}
15145
15146struct sna_font {
15147	CharInfoRec glyphs8[256];
15148	CharInfoRec *glyphs16[256];
15149};
15150#define GLYPH_INVALID (void *)1
15151#define GLYPH_EMPTY (void *)2
15152
15153static Bool
15154sna_realize_font(ScreenPtr screen, FontPtr font)
15155{
15156	struct sna_font *priv;
15157
15158	DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key));
15159
15160	priv = calloc(1, sizeof(struct sna_font));
15161	if (priv == NULL)
15162		return FALSE;
15163
15164	if (!FontSetPrivate(font, sna_font_key, priv)) {
15165		free(priv);
15166		return FALSE;
15167	}
15168
15169	return TRUE;
15170}
15171
15172static Bool
15173sna_unrealize_font(ScreenPtr screen, FontPtr font)
15174{
15175	struct sna_font *priv = FontGetPrivate(font, sna_font_key);
15176	int i, j;
15177
15178	DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key));
15179
15180	if (priv == NULL)
15181		return TRUE;
15182
15183	for (i = 0; i < 256; i++) {
15184		if ((uintptr_t)priv->glyphs8[i].bits & ~3)
15185			free(priv->glyphs8[i].bits);
15186	}
15187	for (j = 0; j < 256; j++) {
15188		if (priv->glyphs16[j] == NULL)
15189			continue;
15190
15191		for (i = 0; i < 256; i++) {
15192			if ((uintptr_t)priv->glyphs16[j][i].bits & ~3)
15193				free(priv->glyphs16[j][i].bits);
15194		}
15195		free(priv->glyphs16[j]);
15196	}
15197	free(priv);
15198
15199	FontSetPrivate(font, sna_font_key, NULL);
15200	return TRUE;
15201}
15202
15203static bool
15204sna_glyph_blt(DrawablePtr drawable, GCPtr gc,
15205	      int _x, int _y, unsigned int _n,
15206	      CharInfoPtr *_info,
15207	      RegionRec *clip,
15208	      uint32_t fg, uint32_t bg,
15209	      bool transparent)
15210{
15211	PixmapPtr pixmap = get_drawable_pixmap(drawable);
15212	struct sna *sna = to_sna_from_pixmap(pixmap);
15213	struct kgem_bo *bo;
15214	struct sna_damage **damage;
15215	const BoxRec *extents, *last_extents;
15216	uint32_t *b;
15217	int16_t dx, dy;
15218	uint32_t br00;
15219	uint16_t unwind_batch, unwind_reloc;
15220	unsigned hint;
15221
15222	uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S;
15223
15224	DBG(("%s (%d, %d) x %d, fg=%08x, bg=%08x alu=%02x\n",
15225	     __FUNCTION__, _x, _y, _n, fg, bg, rop));
15226
15227	if (wedged(sna)) {
15228		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
15229		return false;
15230	}
15231
15232	if (!transparent && clip->data == NULL)
15233		hint = PREFER_GPU | IGNORE_DAMAGE;
15234	else
15235		hint = PREFER_GPU;
15236
15237	bo = sna_drawable_use_bo(drawable, hint, &clip->extents, &damage);
15238	if (bo == NULL)
15239		return false;
15240
15241	if (bo->tiling == I915_TILING_Y) {
15242		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
15243		assert(bo == __sna_pixmap_get_bo(pixmap));
15244		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
15245		if (bo == NULL) {
15246			DBG(("%s: fallback -- unable to change tiling\n",
15247			     __FUNCTION__));
15248			return false;
15249		}
15250	}
15251
15252	if (!kgem_bo_can_blt(&sna->kgem, bo))
15253		return false;
15254
15255	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
15256		RegionTranslate(clip, dx, dy);
15257	_x += drawable->x + dx;
15258	_y += drawable->y + dy;
15259
15260	extents = region_rects(clip);
15261	last_extents = extents + region_num_rects(clip);
15262
15263	if (!transparent) { /* emulate miImageGlyphBlt */
15264		if (!sna_blt_fill_boxes(sna, GXcopy,
15265					bo, drawable->bitsPerPixel,
15266					bg, extents, last_extents - extents)) {
15267			RegionTranslate(clip, -dx, -dy);
15268			return false;
15269		}
15270	}
15271
15272	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
15273	assert(kgem_bo_can_blt(&sna->kgem, bo));
15274	if (!kgem_check_batch(&sna->kgem, 20) ||
15275	    !kgem_check_bo_fenced(&sna->kgem, bo) ||
15276	    !kgem_check_reloc(&sna->kgem, 1)) {
15277		kgem_submit(&sna->kgem);
15278		if (!kgem_check_bo_fenced(&sna->kgem, bo)) {
15279			RegionTranslate(clip, -dx, -dy);
15280			return false;
15281		}
15282		_kgem_set_mode(&sna->kgem, KGEM_BLT);
15283	}
15284
15285	DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
15286	     __FUNCTION__,
15287	     extents->x1, extents->y1,
15288	     extents->x2, extents->y2));
15289
15290	unwind_batch = sna->kgem.nbatch;
15291	unwind_reloc = sna->kgem.nreloc;
15292
15293	assert(sna->kgem.mode == KGEM_BLT);
15294	b = sna->kgem.batch + sna->kgem.nbatch;
15295	if (sna->kgem.gen >= 0100) {
15296		b[0] = XY_SETUP_BLT | 3 << 20 | 8;
15297		b[1] = bo->pitch;
15298		if (sna->kgem.gen >= 040 && bo->tiling) {
15299			b[0] |= BLT_DST_TILED;
15300			b[1] >>= 2;
15301		}
15302		b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15303		b[2] = extents->y1 << 16 | extents->x1;
15304		b[3] = extents->y2 << 16 | extents->x2;
15305		*(uint64_t *)(b+4) =
15306			kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
15307					 I915_GEM_DOMAIN_RENDER << 16 |
15308					 I915_GEM_DOMAIN_RENDER |
15309					 KGEM_RELOC_FENCED,
15310					 0);
15311		b[6] = bg;
15312		b[7] = fg;
15313		b[8] = 0;
15314		b[9] = 0;
15315		sna->kgem.nbatch += 10;
15316	} else {
15317		b[0] = XY_SETUP_BLT | 3 << 20 | 6;
15318		b[1] = bo->pitch;
15319		if (sna->kgem.gen >= 040 && bo->tiling) {
15320			b[0] |= BLT_DST_TILED;
15321			b[1] >>= 2;
15322		}
15323		b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15324		b[2] = extents->y1 << 16 | extents->x1;
15325		b[3] = extents->y2 << 16 | extents->x2;
15326		b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
15327				      I915_GEM_DOMAIN_RENDER << 16 |
15328				      I915_GEM_DOMAIN_RENDER |
15329				      KGEM_RELOC_FENCED,
15330				      0);
15331		b[5] = bg;
15332		b[6] = fg;
15333		b[7] = 0;
15334		sna->kgem.nbatch += 8;
15335	}
15336
15337	br00 = XY_TEXT_IMMEDIATE_BLT;
15338	if (bo->tiling && sna->kgem.gen >= 040)
15339		br00 |= BLT_DST_TILED;
15340
15341	do {
15342		CharInfoPtr *info = _info;
15343		int x = _x, y = _y, n = _n;
15344
15345		do {
15346			CharInfoPtr c = *info++;
15347			int w = GLYPHWIDTHPIXELS(c);
15348			int h = GLYPHHEIGHTPIXELS(c);
15349			int w8 = (w + 7) >> 3;
15350			int x1, y1, len;
15351
15352			if (c->bits == GLYPH_EMPTY)
15353				goto skip;
15354
15355			len = (w8 * h + 7) >> 3 << 1;
15356			x1 = x + c->metrics.leftSideBearing;
15357			y1 = y - c->metrics.ascent;
15358
15359			DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__,
15360			     x,y, x1, y1, w, w8, h, len));
15361
15362			if (x1 >= extents->x2 || y1 >= extents->y2)
15363				goto skip;
15364			if (x1 + w <= extents->x1 || y1 + h <= extents->y1)
15365				goto skip;
15366
15367			assert(len > 0);
15368			if (!kgem_check_batch(&sna->kgem, 3+len)) {
15369				_kgem_submit(&sna->kgem);
15370				_kgem_set_mode(&sna->kgem, KGEM_BLT);
15371
15372				DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n",
15373				     __FUNCTION__,
15374				     extents->x1, extents->y1,
15375				     extents->x2, extents->y2));
15376
15377				unwind_batch = sna->kgem.nbatch;
15378				unwind_reloc = sna->kgem.nreloc;
15379
15380				assert(sna->kgem.mode == KGEM_BLT);
15381				b = sna->kgem.batch + sna->kgem.nbatch;
15382				if (sna->kgem.gen >= 0100) {
15383					b[0] = XY_SETUP_BLT | 3 << 20 | 8;
15384					b[1] = bo->pitch;
15385					if (bo->tiling) {
15386						b[0] |= BLT_DST_TILED;
15387						b[1] >>= 2;
15388					}
15389					b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15390					b[2] = extents->y1 << 16 | extents->x1;
15391					b[3] = extents->y2 << 16 | extents->x2;
15392					*(uint64_t *)(b+4) =
15393						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
15394								 I915_GEM_DOMAIN_RENDER << 16 |
15395								 I915_GEM_DOMAIN_RENDER |
15396								 KGEM_RELOC_FENCED,
15397								 0);
15398					b[6] = bg;
15399					b[7] = fg;
15400					b[8] = 0;
15401					b[9] = 0;
15402					sna->kgem.nbatch += 10;
15403				} else {
15404					b[0] = XY_SETUP_BLT | 3 << 20 | 6;
15405					b[1] = bo->pitch;
15406					if (sna->kgem.gen >= 040 && bo->tiling) {
15407						b[0] |= BLT_DST_TILED;
15408						b[1] >>= 2;
15409					}
15410					b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15411					b[2] = extents->y1 << 16 | extents->x1;
15412					b[3] = extents->y2 << 16 | extents->x2;
15413					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
15414							      I915_GEM_DOMAIN_RENDER << 16 |
15415							      I915_GEM_DOMAIN_RENDER |
15416							      KGEM_RELOC_FENCED,
15417							      0);
15418					b[5] = bg;
15419					b[6] = fg;
15420					b[7] = 0;
15421					sna->kgem.nbatch += 8;
15422				}
15423			}
15424
15425			assert(sna->kgem.mode == KGEM_BLT);
15426			b = sna->kgem.batch + sna->kgem.nbatch;
15427			sna->kgem.nbatch += 3 + len;
15428
15429			b[0] = br00 | (1 + len);
15430			b[1] = (uint16_t)y1 << 16 | (uint16_t)x1;
15431			b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w);
15432			{
15433				uint64_t *src = (uint64_t *)c->bits;
15434				uint64_t *dst = (uint64_t *)(b + 3);
15435				do  {
15436					*dst++ = *src++;
15437					len -= 2;
15438				} while (len);
15439			}
15440
15441			if (damage) {
15442				BoxRec r;
15443
15444				r.x1 = x1;
15445				r.y1 = y1;
15446				r.x2 = x1 + w;
15447				r.y2 = y1 + h;
15448				if (box_intersect(&r, extents))
15449					sna_damage_add_box(damage, &r);
15450			}
15451skip:
15452			x += c->metrics.characterWidth;
15453		} while (--n);
15454
15455		if (++extents == last_extents)
15456			break;
15457
15458		if (kgem_check_batch(&sna->kgem, 3)) {
15459			assert(sna->kgem.mode == KGEM_BLT);
15460			b = sna->kgem.batch + sna->kgem.nbatch;
15461			sna->kgem.nbatch += 3;
15462
15463			DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
15464			     __FUNCTION__,
15465			     extents->x1, extents->y1,
15466			     extents->x2, extents->y2));
15467
15468			b[0] = XY_SETUP_CLIP;
15469			b[1] = extents->y1 << 16 | extents->x1;
15470			b[2] = extents->y2 << 16 | extents->x2;
15471		}
15472	} while (1);
15473
15474	if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) {
15475		sna->kgem.nbatch = unwind_batch;
15476		sna->kgem.nreloc = unwind_reloc;
15477		if (sna->kgem.nbatch == 0)
15478			kgem_bo_undo(&sna->kgem, bo);
15479	}
15480
15481	assert_pixmap_damage(pixmap);
15482	sna->blt_state.fill_bo = 0;
15483	return true;
15484}
15485
15486static void
15487sna_glyph_extents(FontPtr font,
15488		  CharInfoPtr *info,
15489		  unsigned long count,
15490		  ExtentInfoRec *extents)
15491{
15492	extents->drawDirection = font->info.drawDirection;
15493	extents->fontAscent = font->info.fontAscent;
15494	extents->fontDescent = font->info.fontDescent;
15495
15496	extents->overallAscent = info[0]->metrics.ascent;
15497	extents->overallDescent = info[0]->metrics.descent;
15498	extents->overallLeft = info[0]->metrics.leftSideBearing;
15499	extents->overallRight = info[0]->metrics.rightSideBearing;
15500	extents->overallWidth = info[0]->metrics.characterWidth;
15501
15502	while (--count) {
15503		CharInfoPtr p =*++info;
15504		int v;
15505
15506		if (p->metrics.ascent > extents->overallAscent)
15507			extents->overallAscent = p->metrics.ascent;
15508		if (p->metrics.descent > extents->overallDescent)
15509			extents->overallDescent = p->metrics.descent;
15510
15511		v = extents->overallWidth + p->metrics.leftSideBearing;
15512		if (v < extents->overallLeft)
15513			extents->overallLeft = v;
15514
15515		v = extents->overallWidth + p->metrics.rightSideBearing;
15516		if (v > extents->overallRight)
15517			extents->overallRight = v;
15518
15519		extents->overallWidth += p->metrics.characterWidth;
15520	}
15521}
15522
15523static bool sna_set_glyph(CharInfoPtr in, CharInfoPtr out)
15524{
15525	int w = GLYPHWIDTHPIXELS(in);
15526	int h = GLYPHHEIGHTPIXELS(in);
15527	int stride = GLYPHWIDTHBYTESPADDED(in);
15528	uint8_t *dst, *src;
15529	int clear = 1;
15530
15531	out->metrics = in->metrics;
15532
15533	/* Skip empty glyphs */
15534	if (w == 0 || h == 0 || ((w|h) == 1 && (in->bits[0] & 1) == 0)) {
15535		out->bits = GLYPH_EMPTY;
15536		return true;
15537	}
15538
15539	w = (w + 7) >> 3;
15540
15541	out->bits = malloc((w*h + 7) & ~7);
15542	if (out->bits == NULL)
15543		return false;
15544
15545	VG(memset(out->bits, 0, (w*h + 7) & ~7));
15546	src = (uint8_t *)in->bits;
15547	dst = (uint8_t *)out->bits;
15548	stride -= w;
15549	do {
15550		int i = w;
15551		do {
15552			clear &= *src == 0;
15553			*dst++ = byte_reverse(*src++);
15554		} while (--i);
15555		src += stride;
15556	} while (--h);
15557
15558	if (clear) {
15559		free(out->bits);
15560		out->bits = GLYPH_EMPTY;
15561	}
15562
15563	return true;
15564}
15565
15566inline static bool sna_get_glyph8(FontPtr font, struct sna_font *priv,
15567				  uint8_t g, CharInfoPtr *out)
15568{
15569	unsigned long n;
15570	CharInfoPtr p, ret;
15571
15572	p = &priv->glyphs8[g];
15573	if (p->bits) {
15574		*out = p;
15575		return p->bits != GLYPH_INVALID;
15576	}
15577
15578	font->get_glyphs(font, 1, &g, Linear8Bit, &n, &ret);
15579	if (n == 0) {
15580		p->bits = GLYPH_INVALID;
15581		return false;
15582	}
15583
15584	return sna_set_glyph(ret, *out = p);
15585}
15586
15587inline static bool sna_get_glyph16(FontPtr font, struct sna_font *priv,
15588				   uint16_t g, CharInfoPtr *out)
15589{
15590	unsigned long n;
15591	CharInfoPtr page, p, ret;
15592
15593	page = priv->glyphs16[g>>8];
15594	if (page == NULL)
15595		page = priv->glyphs16[g>>8] = calloc(256, sizeof(CharInfoRec));
15596
15597	p = &page[g&0xff];
15598	if (p->bits) {
15599		*out = p;
15600		return p->bits != GLYPH_INVALID;
15601	}
15602
15603	font->get_glyphs(font, 1, (unsigned char *)&g,
15604			 FONTLASTROW(font) ? TwoD16Bit : Linear16Bit,
15605			 &n, &ret);
15606	if (n == 0) {
15607		p->bits = GLYPH_INVALID;
15608		return false;
15609	}
15610
15611	return sna_set_glyph(ret, *out = p);
15612}
15613
15614static inline bool sna_font_too_large(FontPtr font)
15615{
15616	int top = max(FONTMAXBOUNDS(font, ascent), FONTASCENT(font));
15617	int bot = max(FONTMAXBOUNDS(font, descent), FONTDESCENT(font));
15618	int width = max(FONTMAXBOUNDS(font, characterWidth), -FONTMINBOUNDS(font, characterWidth));
15619	DBG(("%s? (%d + %d) x %d: %d > 124\n", __FUNCTION__,
15620	     top, bot, width, (top + bot) * (width + 7)/8));
15621	return (top + bot) * (width + 7)/8 > 124;
15622}
15623
15624static int
15625sna_poly_text8(DrawablePtr drawable, GCPtr gc,
15626	       int x, int y,
15627	       int count, char *chars)
15628{
15629	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
15630	CharInfoPtr info[255];
15631	ExtentInfoRec extents;
15632	RegionRec region;
15633	long unsigned i, n;
15634	uint32_t fg;
15635
15636	for (i = n = 0; i < count; i++) {
15637		if (sna_get_glyph8(gc->font, priv, chars[i], &info[n]))
15638			n++;
15639	}
15640	if (n == 0)
15641		return x;
15642
15643	sna_glyph_extents(gc->font, info, n, &extents);
15644	region.extents.x1 = x + extents.overallLeft;
15645	region.extents.y1 = y - extents.overallAscent;
15646	region.extents.x2 = x + extents.overallRight;
15647	region.extents.y2 = y + extents.overallDescent;
15648
15649	translate_box(&region.extents, drawable);
15650	clip_box(&region.extents, gc);
15651	if (box_empty(&region.extents))
15652		return x + extents.overallRight;
15653
15654	region.data = NULL;
15655	if (!region_maybe_clip(&region, gc->pCompositeClip))
15656		return x + extents.overallRight;
15657
15658	if (FORCE_FALLBACK)
15659		goto fallback;
15660
15661	if (!ACCEL_POLY_TEXT8)
15662		goto fallback;
15663
15664	if (sna_font_too_large(gc->font))
15665		goto fallback;
15666
15667	if (!PM_IS_SOLID(drawable, gc->planemask))
15668		goto fallback;
15669
15670	if (!gc_is_solid(gc, &fg))
15671		goto fallback;
15672
15673	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region, fg, -1, true)) {
15674fallback:
15675		DBG(("%s: fallback\n", __FUNCTION__));
15676		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
15677				     Linear8Bit, &n, info);
15678
15679		if (!sna_gc_move_to_cpu(gc, drawable, &region))
15680			goto out;
15681		if (!sna_drawable_move_region_to_cpu(drawable, &region,
15682						     MOVE_READ | MOVE_WRITE))
15683			goto out;
15684
15685		if (sigtrap_get() == 0) {
15686			DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
15687			fbPolyGlyphBlt(drawable, gc, x, y, n,
15688				       info, FONTGLYPHS(gc->font));
15689			FALLBACK_FLUSH(drawable);
15690			sigtrap_put();
15691		}
15692out:
15693		sna_gc_move_to_gpu(gc);
15694	}
15695	RegionUninit(&region);
15696	return x + extents.overallRight;
15697}
15698
15699static int
15700sna_poly_text16(DrawablePtr drawable, GCPtr gc,
15701		int x, int y,
15702		int count, unsigned short *chars)
15703{
15704	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
15705	CharInfoPtr info[255];
15706	ExtentInfoRec extents;
15707	RegionRec region;
15708	long unsigned i, n;
15709	uint32_t fg;
15710
15711	for (i = n = 0; i < count; i++) {
15712		if (sna_get_glyph16(gc->font, priv, chars[i], &info[n]))
15713			n++;
15714	}
15715	if (n == 0)
15716		return x;
15717
15718	sna_glyph_extents(gc->font, info, n, &extents);
15719	region.extents.x1 = x + extents.overallLeft;
15720	region.extents.y1 = y - extents.overallAscent;
15721	region.extents.x2 = x + extents.overallRight;
15722	region.extents.y2 = y + extents.overallDescent;
15723
15724	translate_box(&region.extents, drawable);
15725	clip_box(&region.extents, gc);
15726	if (box_empty(&region.extents))
15727		return x + extents.overallRight;
15728
15729	region.data = NULL;
15730	if (!region_maybe_clip(&region, gc->pCompositeClip))
15731		return x + extents.overallRight;
15732
15733	if (FORCE_FALLBACK)
15734		goto fallback;
15735
15736	if (!ACCEL_POLY_TEXT16)
15737		goto fallback;
15738
15739	if (sna_font_too_large(gc->font))
15740		goto fallback;
15741
15742	if (!PM_IS_SOLID(drawable, gc->planemask))
15743		goto fallback;
15744
15745	if (!gc_is_solid(gc, &fg))
15746		goto fallback;
15747
15748	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region, fg, -1, true)) {
15749fallback:
15750		DBG(("%s: fallback\n", __FUNCTION__));
15751		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
15752				     FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit,
15753				     &n, info);
15754
15755		if (!sna_gc_move_to_cpu(gc, drawable, &region))
15756			goto out;
15757		if (!sna_drawable_move_region_to_cpu(drawable, &region,
15758						     MOVE_READ | MOVE_WRITE))
15759			goto out;
15760
15761		if (sigtrap_get() == 0) {
15762			DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
15763			fbPolyGlyphBlt(drawable, gc, x, y, n,
15764				       info, FONTGLYPHS(gc->font));
15765			FALLBACK_FLUSH(drawable);
15766			sigtrap_put();
15767		}
15768out:
15769		sna_gc_move_to_gpu(gc);
15770	}
15771	RegionUninit(&region);
15772	return x + extents.overallRight;
15773}
15774
15775static void
15776sna_image_text8(DrawablePtr drawable, GCPtr gc,
15777		int x, int y,
15778		int count, char *chars)
15779{
15780	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
15781	CharInfoPtr info[255];
15782	ExtentInfoRec extents;
15783	RegionRec region;
15784	long unsigned i, n;
15785
15786	for (i = n = 0; i < count; i++) {
15787		if (sna_get_glyph8(gc->font, priv, chars[i], &info[n]))
15788			n++;
15789	}
15790	if (n == 0)
15791		return;
15792
15793	sna_glyph_extents(gc->font, info, n, &extents);
15794	region.extents.x1 = x + MIN(0, extents.overallLeft);
15795	region.extents.y1 = y - extents.fontAscent;
15796	region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight);
15797	region.extents.y2 = y + extents.fontDescent;
15798
15799	DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n",
15800	     __FUNCTION__, n, count,
15801	     extents.overallLeft, extents.overallRight, extents.overallWidth,
15802	     extents.fontAscent, extents.fontDescent,
15803	     region.extents.x1, region.extents.y1,
15804	     region.extents.x2, region.extents.y2));
15805
15806	translate_box(&region.extents, drawable);
15807	clip_box(&region.extents, gc);
15808	if (box_empty(&region.extents))
15809		return;
15810
15811	region.data = NULL;
15812	if (!region_maybe_clip(&region, gc->pCompositeClip))
15813		return;
15814
15815	DBG(("%s: clipped extents (%d, %d), (%d, %d)\n",
15816	     __FUNCTION__,
15817	     region.extents.x1, region.extents.y1,
15818	     region.extents.x2, region.extents.y2));
15819
15820	if (FORCE_FALLBACK)
15821		goto fallback;
15822
15823	if (!ACCEL_IMAGE_TEXT8)
15824		goto fallback;
15825
15826	if (sna_font_too_large(gc->font))
15827		goto fallback;
15828
15829	if (!PM_IS_SOLID(drawable, gc->planemask))
15830		goto fallback;
15831
15832	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region,
15833			   gc->fgPixel, gc->bgPixel, false)) {
15834fallback:
15835		DBG(("%s: fallback\n", __FUNCTION__));
15836		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
15837				     Linear8Bit, &n, info);
15838
15839		if (!sna_gc_move_to_cpu(gc, drawable, &region))
15840			goto out;
15841		if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_WRITE))
15842			goto out;
15843
15844		if (sigtrap_get() == 0) {
15845			DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
15846			fbImageGlyphBlt(drawable, gc, x, y, n,
15847					info, FONTGLYPHS(gc->font));
15848			FALLBACK_FLUSH(drawable);
15849			sigtrap_put();
15850		}
15851out:
15852		sna_gc_move_to_gpu(gc);
15853	}
15854	RegionUninit(&region);
15855}
15856
15857static void
15858sna_image_text16(DrawablePtr drawable, GCPtr gc,
15859		int x, int y,
15860		int count, unsigned short *chars)
15861{
15862	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
15863	CharInfoPtr info[255];
15864	ExtentInfoRec extents;
15865	RegionRec region;
15866	long unsigned i, n;
15867
15868	for (i = n = 0; i < count; i++) {
15869		if (sna_get_glyph16(gc->font, priv, chars[i], &info[n]))
15870			n++;
15871	}
15872	if (n == 0)
15873		return;
15874
15875	sna_glyph_extents(gc->font, info, n, &extents);
15876	region.extents.x1 = x + MIN(0, extents.overallLeft);
15877	region.extents.y1 = y - extents.fontAscent;
15878	region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight);
15879	region.extents.y2 = y + extents.fontDescent;
15880
15881	DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n",
15882	     __FUNCTION__, n, count,
15883	     extents.overallLeft, extents.overallRight, extents.overallWidth,
15884	     extents.fontAscent, extents.fontDescent,
15885	     region.extents.x1, region.extents.y1,
15886	     region.extents.x2, region.extents.y2));
15887
15888	translate_box(&region.extents, drawable);
15889	clip_box(&region.extents, gc);
15890	if (box_empty(&region.extents))
15891		return;
15892
15893	region.data = NULL;
15894	if (!region_maybe_clip(&region, gc->pCompositeClip))
15895		return;
15896
15897	DBG(("%s: clipped extents (%d, %d), (%d, %d)\n",
15898	     __FUNCTION__,
15899	     region.extents.x1, region.extents.y1,
15900	     region.extents.x2, region.extents.y2));
15901
15902	if (FORCE_FALLBACK)
15903		goto fallback;
15904
15905	if (!ACCEL_IMAGE_TEXT16)
15906		goto fallback;
15907
15908	if (sna_font_too_large(gc->font))
15909		goto fallback;
15910
15911	if (!PM_IS_SOLID(drawable, gc->planemask))
15912		goto fallback;
15913
15914	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region,
15915			   gc->fgPixel, gc->bgPixel, false)) {
15916fallback:
15917		DBG(("%s: fallback\n", __FUNCTION__));
15918		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
15919				     FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit,
15920				     &n, info);
15921
15922		if (!sna_gc_move_to_cpu(gc, drawable, &region))
15923			goto out;
15924		if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_WRITE))
15925			goto out;
15926
15927		if (sigtrap_get() == 0) {
15928			DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
15929			fbImageGlyphBlt(drawable, gc, x, y, n,
15930					info, FONTGLYPHS(gc->font));
15931			FALLBACK_FLUSH(drawable);
15932			sigtrap_put();
15933		}
15934out:
15935		sna_gc_move_to_gpu(gc);
15936	}
15937	RegionUninit(&region);
15938}
15939
15940/* XXX Damage bypasses the Text interface and so we lose our custom gluphs */
15941static bool
15942sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc,
15943		       int _x, int _y, unsigned int _n,
15944		       CharInfoPtr *_info, pointer _base,
15945		       struct kgem_bo *bo,
15946		       struct sna_damage **damage,
15947		       RegionPtr clip,
15948		       uint32_t fg, uint32_t bg,
15949		       bool transparent)
15950{
15951	PixmapPtr pixmap = get_drawable_pixmap(drawable);
15952	struct sna *sna = to_sna_from_pixmap(pixmap);
15953	const BoxRec *extents, *last_extents;
15954	uint32_t *b;
15955	int16_t dx, dy;
15956	uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S;
15957	uint16_t unwind_batch, unwind_reloc;
15958
15959	DBG(("%s: pixmap=%ld, bo=%d, damage=%p, fg=%08x, bg=%08x\n",
15960	     __FUNCTION__, pixmap->drawable.serialNumber, bo->handle, damage, fg, bg));
15961
15962	if (bo->tiling == I915_TILING_Y) {
15963		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
15964		assert(bo == __sna_pixmap_get_bo(pixmap));
15965		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
15966		if (bo == NULL) {
15967			DBG(("%s: fallback -- unable to change tiling\n",
15968			     __FUNCTION__));
15969			return false;
15970		}
15971	}
15972
15973	if (!kgem_bo_can_blt(&sna->kgem, bo))
15974		return false;
15975
15976	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
15977		RegionTranslate(clip, dx, dy);
15978	_x += drawable->x + dx;
15979	_y += drawable->y + dy;
15980
15981	extents = region_rects(clip);
15982	last_extents = extents + region_num_rects(clip);
15983
15984	if (!transparent) { /* emulate miImageGlyphBlt */
15985		if (!sna_blt_fill_boxes(sna, GXcopy,
15986					bo, drawable->bitsPerPixel,
15987					bg, extents, last_extents - extents)) {
15988			RegionTranslate(clip, -dx, -dy);
15989			return false;
15990		}
15991	}
15992
15993	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
15994	assert(kgem_bo_can_blt(&sna->kgem, bo));
15995	if (!kgem_check_batch(&sna->kgem, 20) ||
15996	    !kgem_check_bo_fenced(&sna->kgem, bo) ||
15997	    !kgem_check_reloc(&sna->kgem, 1)) {
15998		kgem_submit(&sna->kgem);
15999		if (!kgem_check_bo_fenced(&sna->kgem, bo)) {
16000			RegionTranslate(clip, -dx, -dy);
16001			return false;
16002		}
16003		_kgem_set_mode(&sna->kgem, KGEM_BLT);
16004	}
16005
16006	unwind_batch = sna->kgem.nbatch;
16007	unwind_reloc = sna->kgem.nreloc;
16008
16009	DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
16010	     __FUNCTION__,
16011	     extents->x1, extents->y1,
16012	     extents->x2, extents->y2));
16013
16014	assert(sna->kgem.mode == KGEM_BLT);
16015	b = sna->kgem.batch + sna->kgem.nbatch;
16016	if (sna->kgem.gen >= 0100) {
16017		b[0] = XY_SETUP_BLT | 1 << 20 | 8;
16018		b[1] = bo->pitch;
16019		if (sna->kgem.gen >= 040 && bo->tiling) {
16020			b[0] |= BLT_DST_TILED;
16021			b[1] >>= 2;
16022		}
16023		b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
16024		b[2] = extents->y1 << 16 | extents->x1;
16025		b[3] = extents->y2 << 16 | extents->x2;
16026		*(uint64_t *)(b+4) =
16027			kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
16028					 I915_GEM_DOMAIN_RENDER << 16 |
16029					 I915_GEM_DOMAIN_RENDER |
16030					 KGEM_RELOC_FENCED,
16031					 0);
16032		b[6] = bg;
16033		b[7] = fg;
16034		b[8] = 0;
16035		b[9] = 0;
16036		sna->kgem.nbatch += 10;
16037	} else {
16038		b[0] = XY_SETUP_BLT | 1 << 20 | 6;
16039		b[1] = bo->pitch;
16040		if (sna->kgem.gen >= 040 && bo->tiling) {
16041			b[0] |= BLT_DST_TILED;
16042			b[1] >>= 2;
16043		}
16044		b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
16045		b[2] = extents->y1 << 16 | extents->x1;
16046		b[3] = extents->y2 << 16 | extents->x2;
16047		b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
16048				      I915_GEM_DOMAIN_RENDER << 16 |
16049				      I915_GEM_DOMAIN_RENDER |
16050				      KGEM_RELOC_FENCED,
16051				      0);
16052		b[5] = bg;
16053		b[6] = fg;
16054		b[7] = 0;
16055		sna->kgem.nbatch += 8;
16056	}
16057
16058	do {
16059		CharInfoPtr *info = _info;
16060		int x = _x, y = _y, n = _n;
16061
16062		do {
16063			CharInfoPtr c = *info++;
16064			uint8_t *glyph = FONTGLYPHBITS(base, c);
16065			int w = GLYPHWIDTHPIXELS(c);
16066			int h = GLYPHHEIGHTPIXELS(c);
16067			int stride = GLYPHWIDTHBYTESPADDED(c);
16068			int w8 = (w + 7) >> 3;
16069			int x1, y1, len, i;
16070			uint8_t *byte;
16071
16072			if (w == 0 || h == 0)
16073				goto skip;
16074
16075			len = (w8 * h + 7) >> 3 << 1;
16076			x1 = x + c->metrics.leftSideBearing;
16077			y1 = y - c->metrics.ascent;
16078
16079			DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__,
16080			     x,y, x1, y1, w, w8, h, len));
16081
16082			if (x1 >= extents->x2 || y1 >= extents->y2 ||
16083			    x1 + w <= extents->x1 || y1 + h <= extents->y1) {
16084				DBG(("%s: glyph is clipped (%d, %d)x(%d,%d) against extents (%d, %d), (%d, %d)\n",
16085				     __FUNCTION__,
16086				     x1, y1, w, h,
16087				     extents->x1, extents->y1,
16088				     extents->x2, extents->y2));
16089				goto skip;
16090			}
16091
16092			{
16093				int clear = 1, j = h;
16094				uint8_t *g = glyph;
16095
16096				do {
16097					i = w8;
16098					do {
16099						clear = *g++ == 0;
16100					} while (clear && --i);
16101					g += stride - w8;
16102				} while (clear && --j);
16103				if (clear) {
16104					DBG(("%s: skipping clear glyph for ImageGlyph\n",
16105					     __FUNCTION__));
16106					goto skip;
16107				}
16108			}
16109
16110			assert(len > 0);
16111			if (!kgem_check_batch(&sna->kgem, 3+len)) {
16112				_kgem_submit(&sna->kgem);
16113				_kgem_set_mode(&sna->kgem, KGEM_BLT);
16114
16115				unwind_batch = sna->kgem.nbatch;
16116				unwind_reloc = sna->kgem.nreloc;
16117
16118				DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n",
16119				     __FUNCTION__,
16120				     extents->x1, extents->y1,
16121				     extents->x2, extents->y2));
16122
16123				assert(sna->kgem.mode == KGEM_BLT);
16124				b = sna->kgem.batch + sna->kgem.nbatch;
16125				if (sna->kgem.gen >= 0100) {
16126					b[0] = XY_SETUP_BLT | 1 << 20 | 8;
16127					b[1] = bo->pitch;
16128					if (bo->tiling) {
16129						b[0] |= BLT_DST_TILED;
16130						b[1] >>= 2;
16131					}
16132					b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
16133					b[2] = extents->y1 << 16 | extents->x1;
16134					b[3] = extents->y2 << 16 | extents->x2;
16135					*(uint64_t *)(b+4) =
16136						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
16137								 I915_GEM_DOMAIN_RENDER << 16 |
16138								 I915_GEM_DOMAIN_RENDER |
16139								 KGEM_RELOC_FENCED,
16140								 0);
16141					b[6] = bg;
16142					b[7] = fg;
16143					b[8] = 0;
16144					b[9] = 0;
16145					sna->kgem.nbatch += 10;
16146				} else {
16147					b[0] = XY_SETUP_BLT | 1 << 20 | 6;
16148					b[1] = bo->pitch;
16149					if (sna->kgem.gen >= 040 && bo->tiling) {
16150						b[0] |= BLT_DST_TILED;
16151						b[1] >>= 2;
16152					}
16153					b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
16154					b[2] = extents->y1 << 16 | extents->x1;
16155					b[3] = extents->y2 << 16 | extents->x2;
16156					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
16157							      I915_GEM_DOMAIN_RENDER << 16 |
16158							      I915_GEM_DOMAIN_RENDER |
16159							      KGEM_RELOC_FENCED,
16160							      0);
16161					b[5] = bg;
16162					b[6] = fg;
16163					b[7] = 0;
16164					sna->kgem.nbatch += 8;
16165				}
16166			}
16167
16168			assert(sna->kgem.mode == KGEM_BLT);
16169			b = sna->kgem.batch + sna->kgem.nbatch;
16170			sna->kgem.nbatch += 3 + len;
16171
16172			b[0] = XY_TEXT_IMMEDIATE_BLT | (1 + len);
16173			if (bo->tiling && sna->kgem.gen >= 040)
16174				b[0] |= BLT_DST_TILED;
16175			b[1] = (uint16_t)y1 << 16 | (uint16_t)x1;
16176			b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w);
16177
16178			byte = (uint8_t *)&b[3];
16179			stride -= w8;
16180			do {
16181				i = w8;
16182				do {
16183					*byte++ = byte_reverse(*glyph++);
16184				} while (--i);
16185				glyph += stride;
16186			} while (--h);
16187			while ((byte - (uint8_t *)&b[3]) & 7)
16188				*byte++ = 0;
16189			assert((uint32_t *)byte == sna->kgem.batch + sna->kgem.nbatch);
16190
16191			if (damage) {
16192				BoxRec r;
16193
16194				r.x1 = x1;
16195				r.y1 = y1;
16196				r.x2 = x1 + w;
16197				r.y2 = y1 + h;
16198				if (box_intersect(&r, extents))
16199					sna_damage_add_box(damage, &r);
16200			}
16201skip:
16202			x += c->metrics.characterWidth;
16203		} while (--n);
16204
16205		if (++extents == last_extents)
16206			break;
16207
16208		if (kgem_check_batch(&sna->kgem, 3 + 5)) {
16209			assert(sna->kgem.mode == KGEM_BLT);
16210			b = sna->kgem.batch + sna->kgem.nbatch;
16211			sna->kgem.nbatch += 3;
16212
16213			DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
16214			     __FUNCTION__,
16215			     extents->x1, extents->y1,
16216			     extents->x2, extents->y2));
16217
16218			b[0] = XY_SETUP_CLIP;
16219			b[1] = extents->y1 << 16 | extents->x1;
16220			b[2] = extents->y2 << 16 | extents->x2;
16221		}
16222	} while (1);
16223
16224	if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) {
16225		sna->kgem.nbatch = unwind_batch;
16226		sna->kgem.nreloc = unwind_reloc;
16227		if (sna->kgem.nbatch == 0)
16228			kgem_bo_undo(&sna->kgem, bo);
16229	}
16230
16231	assert_pixmap_damage(pixmap);
16232	sna->blt_state.fill_bo = 0;
16233	return true;
16234}
16235
16236static void
16237sna_image_glyph(DrawablePtr drawable, GCPtr gc,
16238		int x, int y, unsigned int n,
16239		CharInfoPtr *info, pointer base)
16240{
16241	PixmapPtr pixmap = get_drawable_pixmap(drawable);
16242	struct sna *sna = to_sna_from_pixmap(pixmap);
16243	ExtentInfoRec extents;
16244	RegionRec region;
16245	struct sna_damage **damage;
16246	struct kgem_bo *bo;
16247	unsigned hint;
16248
16249	if (n == 0)
16250		return;
16251
16252	sna_glyph_extents(gc->font, info, n, &extents);
16253	region.extents.x1 = x + MIN(0, extents.overallLeft);
16254	region.extents.y1 = y - extents.fontAscent;
16255	region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight);
16256	region.extents.y2 = y + extents.fontDescent;
16257
16258	DBG(("%s: count=%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n",
16259	     __FUNCTION__, n,
16260	     extents.overallLeft, extents.overallRight, extents.overallWidth,
16261	     extents.fontAscent, extents.fontDescent,
16262	     region.extents.x1, region.extents.y1,
16263	     region.extents.x2, region.extents.y2));
16264
16265	translate_box(&region.extents, drawable);
16266	clip_box(&region.extents, gc);
16267	if (box_empty(&region.extents))
16268		return;
16269
16270	DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__,
16271	     region.extents.x1, region.extents.y1,
16272	     region.extents.x2, region.extents.y2));
16273
16274	region.data = NULL;
16275	if (!region_maybe_clip(&region, gc->pCompositeClip))
16276		return;
16277
16278	if (FORCE_FALLBACK)
16279		goto fallback;
16280
16281	if (!ACCEL_IMAGE_GLYPH)
16282		goto fallback;
16283
16284	if (wedged(sna)) {
16285		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
16286		goto fallback;
16287	}
16288
16289	if (!PM_IS_SOLID(drawable, gc->planemask))
16290		goto fallback;
16291
16292	if (sna_font_too_large(gc->font))
16293		goto fallback;
16294
16295	if (region.data == NULL)
16296		hint = IGNORE_DAMAGE | PREFER_GPU;
16297	else
16298		hint = PREFER_GPU;
16299	if ((bo = sna_drawable_use_bo(drawable, hint,
16300				      &region.extents, &damage)) &&
16301	    sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base,
16302				   bo, damage, &region,
16303				   gc->fgPixel, gc->bgPixel, false))
16304		goto out;
16305
16306fallback:
16307	DBG(("%s: fallback\n", __FUNCTION__));
16308	if (!sna_gc_move_to_cpu(gc, drawable, &region))
16309		goto out_gc;
16310	if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_WRITE))
16311		goto out_gc;
16312
16313	if (sigtrap_get() == 0) {
16314		DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
16315		fbImageGlyphBlt(drawable, gc, x, y, n, info, base);
16316		FALLBACK_FLUSH(drawable);
16317		sigtrap_put();
16318	}
16319out_gc:
16320	sna_gc_move_to_gpu(gc);
16321out:
16322	RegionUninit(&region);
16323}
16324
16325static void
16326sna_poly_glyph(DrawablePtr drawable, GCPtr gc,
16327	       int x, int y, unsigned int n,
16328	       CharInfoPtr *info, pointer base)
16329{
16330	PixmapPtr pixmap = get_drawable_pixmap(drawable);
16331	struct sna *sna = to_sna_from_pixmap(pixmap);
16332	ExtentInfoRec extents;
16333	RegionRec region;
16334	struct sna_damage **damage;
16335	struct kgem_bo *bo;
16336	uint32_t fg;
16337
16338	if (n == 0)
16339		return;
16340
16341	sna_glyph_extents(gc->font, info, n, &extents);
16342	region.extents.x1 = x + extents.overallLeft;
16343	region.extents.y1 = y - extents.overallAscent;
16344	region.extents.x2 = x + extents.overallRight;
16345	region.extents.y2 = y + extents.overallDescent;
16346
16347	translate_box(&region.extents, drawable);
16348	clip_box(&region.extents, gc);
16349	if (box_empty(&region.extents))
16350		return;
16351
16352	DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__,
16353	     region.extents.x1, region.extents.y1,
16354	     region.extents.x2, region.extents.y2));
16355
16356	region.data = NULL;
16357	if (!region_maybe_clip(&region, gc->pCompositeClip))
16358		return;
16359
16360	if (FORCE_FALLBACK)
16361		goto fallback;
16362
16363	if (!ACCEL_POLY_GLYPH)
16364		goto fallback;
16365
16366	if (wedged(sna)) {
16367		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
16368		goto fallback;
16369	}
16370
16371	if (!PM_IS_SOLID(drawable, gc->planemask))
16372		goto fallback;
16373
16374	if (!gc_is_solid(gc, &fg))
16375		goto fallback;
16376
16377	if (sna_font_too_large(gc->font))
16378		goto fallback;
16379
16380	if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU,
16381				      &region.extents, &damage)) &&
16382	    sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base,
16383				   bo, damage, &region, fg, -1, true))
16384		goto out;
16385
16386fallback:
16387	DBG(("%s: fallback\n", __FUNCTION__));
16388	if (!sna_gc_move_to_cpu(gc, drawable, &region))
16389		goto out_gc;
16390	if (!sna_drawable_move_region_to_cpu(drawable, &region,
16391					     MOVE_READ | MOVE_WRITE))
16392		goto out_gc;
16393
16394	if (sigtrap_get() == 0) {
16395		DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
16396		fbPolyGlyphBlt(drawable, gc, x, y, n, info, base);
16397		FALLBACK_FLUSH(drawable);
16398		sigtrap_put();
16399	}
16400out_gc:
16401	sna_gc_move_to_gpu(gc);
16402out:
16403	RegionUninit(&region);
16404}
16405
16406static bool
16407sna_push_pixels_solid_blt(GCPtr gc,
16408			  PixmapPtr bitmap,
16409			  DrawablePtr drawable,
16410			  RegionPtr region)
16411{
16412	PixmapPtr pixmap = get_drawable_pixmap(drawable);
16413	struct sna *sna = to_sna_from_pixmap(pixmap);
16414	struct sna_damage **damage;
16415	struct kgem_bo *bo;
16416	const BoxRec *box;
16417	int16_t dx, dy;
16418	int n;
16419	uint8_t rop = copy_ROP[gc->alu];
16420
16421	bo = sna_drawable_use_bo(drawable, PREFER_GPU, &region->extents, &damage);
16422	if (bo == NULL)
16423		return false;
16424
16425	if (bo->tiling == I915_TILING_Y) {
16426		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
16427		assert(bo == __sna_pixmap_get_bo(pixmap));
16428		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
16429		if (bo == NULL) {
16430			DBG(("%s: fallback -- unable to change tiling\n",
16431			     __FUNCTION__));
16432			return false;
16433		}
16434	}
16435
16436	if (!kgem_bo_can_blt(&sna->kgem, bo))
16437		return false;
16438
16439	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
16440		RegionTranslate(region, dx, dy);
16441
16442	assert_pixmap_contains_box(pixmap, RegionExtents(region));
16443	if (damage)
16444		sna_damage_add_to_pixmap(damage, region, pixmap);
16445	assert_pixmap_damage(pixmap);
16446
16447	DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__,
16448	     region->extents.x1, region->extents.y1,
16449	     region->extents.x2, region->extents.y2));
16450
16451	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
16452	assert(kgem_bo_can_blt(&sna->kgem, bo));
16453
16454	/* Region is pre-clipped and translated into pixmap space */
16455	box = region_rects(region);
16456	n = region_num_rects(region);
16457	do {
16458		int bx1 = (box->x1 - region->extents.x1) & ~7;
16459		int bx2 = (box->x2 - region->extents.x1 + 7) & ~7;
16460		int bw = (bx2 - bx1)/8;
16461		int bh = box->y2 - box->y1;
16462		int bstride = ALIGN(bw, 2);
16463		struct kgem_bo *upload;
16464		void *ptr;
16465
16466		if (!kgem_check_batch(&sna->kgem, 10) ||
16467		    !kgem_check_bo_fenced(&sna->kgem, bo) ||
16468		    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
16469			kgem_submit(&sna->kgem);
16470			if (!kgem_check_bo_fenced(&sna->kgem, bo))
16471				return false;
16472			_kgem_set_mode(&sna->kgem, KGEM_BLT);
16473		}
16474
16475		upload = kgem_create_buffer(&sna->kgem,
16476					    bstride*bh,
16477					    KGEM_BUFFER_WRITE_INPLACE,
16478					    &ptr);
16479		if (!upload)
16480			break;
16481
16482		if (sigtrap_get() == 0) {
16483			uint8_t *dst = ptr;
16484
16485			int src_stride = bitmap->devKind;
16486			uint8_t *src;
16487			uint32_t *b;
16488
16489			assert(src_stride);
16490			src = (uint8_t*)bitmap->devPrivate.ptr;
16491			src += (box->y1 - region->extents.y1) * src_stride + bx1/8;
16492			src_stride -= bstride;
16493			do {
16494				int i = bstride;
16495				do {
16496					*dst++ = byte_reverse(*src++);
16497					*dst++ = byte_reverse(*src++);
16498					i -= 2;
16499				} while (i);
16500				src += src_stride;
16501			} while (--bh);
16502
16503			assert(sna->kgem.mode == KGEM_BLT);
16504			b = sna->kgem.batch + sna->kgem.nbatch;
16505			if (sna->kgem.gen >= 0100) {
16506				b[0] = XY_MONO_SRC_COPY | 3 << 20 | 8;
16507				b[0] |= ((box->x1 - region->extents.x1) & 7) << 17;
16508				b[1] = bo->pitch;
16509				if (sna->kgem.gen >= 040 && bo->tiling) {
16510					b[0] |= BLT_DST_TILED;
16511					b[1] >>= 2;
16512				}
16513				b[1] |= 1 << 29;
16514				b[1] |= blt_depth(drawable->depth) << 24;
16515				b[1] |= rop << 16;
16516				b[2] = box->y1 << 16 | box->x1;
16517				b[3] = box->y2 << 16 | box->x2;
16518				*(uint64_t *)(b+4) =
16519					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
16520							I915_GEM_DOMAIN_RENDER << 16 |
16521							I915_GEM_DOMAIN_RENDER |
16522							KGEM_RELOC_FENCED,
16523							0);
16524				*(uint64_t *)(b+6) =
16525					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
16526							I915_GEM_DOMAIN_RENDER << 16 |
16527							KGEM_RELOC_FENCED,
16528							0);
16529				b[8] = gc->bgPixel;
16530				b[9] = gc->fgPixel;
16531				sna->kgem.nbatch += 10;
16532			} else {
16533				b[0] = XY_MONO_SRC_COPY | 3 << 20 | 6;
16534				b[0] |= ((box->x1 - region->extents.x1) & 7) << 17;
16535				b[1] = bo->pitch;
16536				if (sna->kgem.gen >= 040 && bo->tiling) {
16537					b[0] |= BLT_DST_TILED;
16538					b[1] >>= 2;
16539				}
16540				b[1] |= 1 << 29;
16541				b[1] |= blt_depth(drawable->depth) << 24;
16542				b[1] |= rop << 16;
16543				b[2] = box->y1 << 16 | box->x1;
16544				b[3] = box->y2 << 16 | box->x2;
16545				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
16546						I915_GEM_DOMAIN_RENDER << 16 |
16547						I915_GEM_DOMAIN_RENDER |
16548						KGEM_RELOC_FENCED,
16549						0);
16550				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
16551						I915_GEM_DOMAIN_RENDER << 16 |
16552						KGEM_RELOC_FENCED,
16553						0);
16554				b[6] = gc->bgPixel;
16555				b[7] = gc->fgPixel;
16556
16557				sna->kgem.nbatch += 8;
16558			}
16559			sigtrap_put();
16560		}
16561
16562		kgem_bo_destroy(&sna->kgem, upload);
16563
16564		box++;
16565	} while (--n);
16566
16567	sna->blt_state.fill_bo = 0;
16568	return true;
16569}
16570
16571static void
16572sna_push_pixels(GCPtr gc, PixmapPtr bitmap, DrawablePtr drawable,
16573		int w, int h,
16574		int x, int y)
16575{
16576	RegionRec region;
16577
16578	if (w == 0 || h == 0)
16579		return;
16580
16581	DBG(("%s (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
16582
16583	region.extents.x1 = x;
16584	region.extents.y1 = y;
16585	region.extents.x2 = region.extents.x1 + w;
16586	region.extents.y2 = region.extents.y1 + h;
16587
16588	clip_box(&region.extents, gc);
16589	if (box_empty(&region.extents))
16590		return;
16591
16592	DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__,
16593	     region.extents.x1, region.extents.y1,
16594	     region.extents.x2, region.extents.y2));
16595
16596	region.data = NULL;
16597	if (!region_maybe_clip(&region, gc->pCompositeClip))
16598		return;
16599
16600	switch (gc->fillStyle) {
16601	case FillSolid:
16602		if (sna_push_pixels_solid_blt(gc, bitmap, drawable, &region))
16603			return;
16604		break;
16605	default:
16606		break;
16607	}
16608
16609	DBG(("%s: fallback\n", __FUNCTION__));
16610	if (!sna_gc_move_to_cpu(gc, drawable, &region))
16611		goto out;
16612	if (!sna_pixmap_move_to_cpu(bitmap, MOVE_READ))
16613		goto out;
16614	if (!sna_drawable_move_region_to_cpu(drawable, &region,
16615					     drawable_gc_flags(drawable, gc, false)))
16616		goto out;
16617
16618	if (sigtrap_get() == 0) {
16619		DBG(("%s: fallback, fbPushPixels(%d, %d, %d %d)\n",
16620		     __FUNCTION__, w, h, x, y));
16621		fbPushPixels(gc, bitmap, drawable, w, h, x, y);
16622		FALLBACK_FLUSH(drawable);
16623		sigtrap_put();
16624	}
16625out:
16626	sna_gc_move_to_gpu(gc);
16627	RegionUninit(&region);
16628}
16629
16630static const GCOps sna_gc_ops = {
16631	sna_fill_spans,
16632	sna_set_spans,
16633	sna_put_image,
16634	sna_copy_area,
16635	sna_copy_plane,
16636	sna_poly_point,
16637	sna_poly_line,
16638	sna_poly_segment,
16639	sna_poly_rectangle,
16640	sna_poly_arc,
16641	sna_poly_fill_polygon,
16642	sna_poly_fill_rect,
16643	sna_poly_fill_arc,
16644	sna_poly_text8,
16645	sna_poly_text16,
16646	sna_image_text8,
16647	sna_image_text16,
16648	sna_image_glyph,
16649	sna_poly_glyph,
16650	sna_push_pixels,
16651};
16652
16653static const GCOps sna_gc_ops__cpu = {
16654	fbFillSpans,
16655	fbSetSpans,
16656	fbPutImage,
16657	fbCopyArea,
16658	fbCopyPlane,
16659	sna_poly_point__cpu,
16660	fbPolyLine,
16661	fbPolySegment,
16662	miPolyRectangle,
16663	fbPolyArc,
16664	miFillPolygon,
16665	fbPolyFillRect,
16666	miPolyFillArc,
16667	miPolyText8,
16668	miPolyText16,
16669	miImageText8,
16670	miImageText16,
16671	fbImageGlyphBlt,
16672	fbPolyGlyphBlt,
16673	fbPushPixels
16674};
16675
16676static GCOps sna_gc_ops__tmp = {
16677	sna_fill_spans,
16678	sna_set_spans,
16679	sna_put_image,
16680	sna_copy_area,
16681	sna_copy_plane,
16682	sna_poly_point,
16683	sna_poly_line,
16684	sna_poly_segment,
16685	sna_poly_rectangle,
16686	sna_poly_arc,
16687	sna_poly_fill_polygon,
16688	sna_poly_fill_rect,
16689	sna_poly_fill_arc,
16690	sna_poly_text8,
16691	sna_poly_text16,
16692	sna_image_text8,
16693	sna_image_text16,
16694	sna_image_glyph,
16695	sna_poly_glyph,
16696	sna_push_pixels,
16697};
16698
16699static void
16700sna_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable)
16701{
16702	DBG(("%s(%p) changes=%lx, previous serial=%lx, drawable=%lx\n", __FUNCTION__, gc,
16703	     changes, gc->serialNumber, drawable->serialNumber));
16704
16705	if (changes & (GCClipMask|GCSubwindowMode) ||
16706	    drawable->serialNumber != (gc->serialNumber & DRAWABLE_SERIAL_BITS) ||
16707	    (has_clip(gc) && (changes & (GCClipXOrigin | GCClipYOrigin)))) {
16708		DBG(("%s: recomputing clip\n", __FUNCTION__));
16709		miComputeCompositeClip(gc, drawable);
16710		DBG(("%s: composite clip=%dx[(%d, %d), (%d, %d)] [%p]\n",
16711		     __FUNCTION__,
16712		     region_num_rects(gc->pCompositeClip),
16713		     gc->pCompositeClip->extents.x1,
16714		     gc->pCompositeClip->extents.y1,
16715		     gc->pCompositeClip->extents.x2,
16716		     gc->pCompositeClip->extents.y2,
16717		     gc->pCompositeClip));
16718	}
16719
16720	assert(gc->pCompositeClip);
16721	assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.x1 >= drawable->x);
16722	assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.y1 >= drawable->y);
16723	assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.x2 - drawable->x <= drawable->width);
16724	assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.y2 - drawable->y <= drawable->height);
16725
16726	sna_gc(gc)->changes |= changes;
16727	sna_gc(gc)->serial = gc->serialNumber;
16728}
16729
16730static const GCFuncs sna_gc_funcs = {
16731	sna_validate_gc,
16732	miChangeGC,
16733	miCopyGC,
16734	miDestroyGC,
16735	miChangeClip,
16736	miDestroyClip,
16737	miCopyClip
16738};
16739
16740static const GCFuncs sna_gc_funcs__cpu = {
16741	fbValidateGC,
16742	miChangeGC,
16743	miCopyGC,
16744	miDestroyGC,
16745	miChangeClip,
16746	miDestroyClip,
16747	miCopyClip
16748};
16749
16750static int sna_create_gc(GCPtr gc)
16751{
16752	gc->miTranslate = 1;
16753	gc->fExpose = 1;
16754
16755	gc->freeCompClip = 0;
16756	gc->pCompositeClip = 0;
16757
16758	fb_gc(gc)->bpp = bits_per_pixel(gc->depth);
16759
16760	gc->funcs = (GCFuncs *)&sna_gc_funcs;
16761	gc->ops = (GCOps *)&sna_gc_ops;
16762	return true;
16763}
16764
16765static bool
16766sna_get_image__inplace(PixmapPtr pixmap,
16767		       RegionPtr region,
16768		       char *dst,
16769		       unsigned flags,
16770		       bool idle)
16771{
16772	struct sna_pixmap *priv = sna_pixmap(pixmap);
16773	struct sna *sna = to_sna_from_pixmap(pixmap);
16774	char *src;
16775
16776	if (!USE_INPLACE)
16777		return false;
16778
16779	assert(priv && priv->gpu_bo);
16780
16781	switch (priv->gpu_bo->tiling) {
16782	case I915_TILING_Y:
16783		return false;
16784	case I915_TILING_X:
16785		if (!sna->kgem.memcpy_from_tiled_x)
16786			return false;
16787	default:
16788		break;
16789	}
16790
16791	if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC))
16792		return false;
16793
16794	if (idle && __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
16795		return false;
16796
16797	if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ))
16798		return false;
16799
16800	assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
16801	assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
16802
16803	src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
16804	if (src == NULL)
16805		return false;
16806
16807	kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC);
16808
16809	if (sigtrap_get())
16810		return false;
16811
16812	if (priv->gpu_bo->tiling) {
16813		DBG(("%s: download through a tiled CPU map\n", __FUNCTION__));
16814		memcpy_from_tiled_x(&sna->kgem, src, dst,
16815				    pixmap->drawable.bitsPerPixel,
16816				    priv->gpu_bo->pitch,
16817				    PixmapBytePad(region->extents.x2 - region->extents.x1,
16818						  pixmap->drawable.depth),
16819				    region->extents.x1, region->extents.y1,
16820				    0, 0,
16821				    region->extents.x2 - region->extents.x1,
16822				    region->extents.y2 - region->extents.y1);
16823	} else {
16824		DBG(("%s: download through a linear CPU map\n", __FUNCTION__));
16825		memcpy_blt(src, dst,
16826			   pixmap->drawable.bitsPerPixel,
16827			   priv->gpu_bo->pitch,
16828			   PixmapBytePad(region->extents.x2 - region->extents.x1,
16829					 pixmap->drawable.depth),
16830			   region->extents.x1, region->extents.y1,
16831			   0, 0,
16832			   region->extents.x2 - region->extents.x1,
16833			   region->extents.y2 - region->extents.y1);
16834		if (!priv->shm) {
16835			assert(src == MAP(priv->gpu_bo->map__cpu));
16836			pixmap->devPrivate.ptr = src;
16837			pixmap->devKind = priv->gpu_bo->pitch;
16838			priv->mapped = MAPPED_CPU;
16839			assert_pixmap_map(pixmap, priv);
16840			priv->cpu = true;
16841		}
16842	}
16843
16844	sigtrap_put();
16845	return true;
16846}
16847
16848static bool
16849sna_get_image__blt(PixmapPtr pixmap,
16850		   RegionPtr region,
16851		   char *dst,
16852		   unsigned flags)
16853{
16854	struct sna_pixmap *priv = sna_pixmap(pixmap);
16855	struct sna *sna = to_sna_from_pixmap(pixmap);
16856	struct kgem_bo *dst_bo;
16857	bool ok = false;
16858	int pitch;
16859
16860	assert(priv && priv->gpu_bo);
16861
16862	if (!sna->kgem.has_userptr || !USE_USERPTR_DOWNLOADS)
16863		return false;
16864
16865	if (!sna->kgem.can_blt_cpu)
16866		return false;
16867
16868	if ((priv->create & (KGEM_CAN_CREATE_GTT | KGEM_CAN_CREATE_LARGE)) == KGEM_CAN_CREATE_GTT &&
16869	    kgem_bo_can_map(&sna->kgem, priv->gpu_bo)) {
16870		if (flags & (MOVE_WHOLE_HINT | MOVE_INPLACE_HINT))
16871			return false;
16872
16873		if (priv->gpu_damage == NULL)
16874			return false;
16875
16876		assert(priv->gpu_bo);
16877		if (!__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
16878			return false;
16879	} else {
16880		if (priv->gpu_damage == NULL)
16881			return false;
16882
16883		assert(priv->gpu_bo);
16884	}
16885
16886	if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ))
16887		return false;
16888
16889	DBG(("%s: download through a temporary map\n", __FUNCTION__));
16890
16891	assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
16892	assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
16893
16894	pitch = PixmapBytePad(region->extents.x2 - region->extents.x1,
16895			      pixmap->drawable.depth);
16896	dst_bo = kgem_create_map(&sna->kgem, dst,
16897				 pitch * (region->extents.y2 - region->extents.y1),
16898				 false);
16899	if (dst_bo) {
16900		dst_bo->pitch = pitch;
16901		kgem_bo_mark_unreusable(dst_bo);
16902
16903		ok = sna->render.copy_boxes(sna, GXcopy,
16904					    &pixmap->drawable, priv->gpu_bo, 0, 0,
16905					    &pixmap->drawable, dst_bo,
16906					    -region->extents.x1,
16907					    -region->extents.y1,
16908					    &region->extents, 1,
16909					    COPY_LAST);
16910
16911		kgem_bo_sync__cpu(&sna->kgem, dst_bo);
16912		assert(dst_bo->rq == NULL);
16913		kgem_bo_destroy(&sna->kgem, dst_bo);
16914	}
16915
16916	return ok;
16917}
16918
16919static bool
16920sna_get_image__fast(PixmapPtr pixmap,
16921		   RegionPtr region,
16922		   char *dst,
16923		   unsigned flags)
16924{
16925	struct sna_pixmap *priv = sna_pixmap(pixmap);
16926
16927	DBG(("%s: attached?=%d, has gpu damage?=%d\n",
16928	     __FUNCTION__, priv != NULL,  priv && priv->gpu_damage));
16929	if (priv == NULL || priv->gpu_damage == NULL)
16930		return false;
16931
16932	if (priv->clear) {
16933		int w = region->extents.x2 - region->extents.x1;
16934		int h = region->extents.y2 - region->extents.y1;
16935		int pitch = PixmapBytePad(w, pixmap->drawable.depth);
16936
16937		DBG(("%s: applying clear [%08x]\n",
16938		     __FUNCTION__, priv->clear_color));
16939		assert(DAMAGE_IS_ALL(priv->gpu_damage));
16940		assert(priv->cpu_damage == NULL);
16941
16942		if (priv->clear_color == 0 ||
16943		    pixmap->drawable.bitsPerPixel == 8 ||
16944		    priv->clear_color == (1U << pixmap->drawable.depth) - 1) {
16945			DBG(("%s: memset clear [%02x]\n",
16946			     __FUNCTION__, priv->clear_color & 0xff));
16947			memset(dst, priv->clear_color, pitch * h);
16948		} else {
16949			pixman_fill((uint32_t *)dst,
16950				    pitch/sizeof(uint32_t),
16951				    pixmap->drawable.bitsPerPixel,
16952				    0, 0,
16953				    w, h,
16954				    priv->clear_color);
16955		}
16956
16957		return true;
16958	}
16959
16960	if (!DAMAGE_IS_ALL(priv->gpu_damage) &&
16961	    !sna_damage_contains_box__no_reduce(priv->gpu_damage,
16962						&region->extents))
16963		return false;
16964
16965	if (sna_get_image__inplace(pixmap, region, dst, flags, true))
16966		return true;
16967
16968	if (sna_get_image__blt(pixmap, region, dst, flags))
16969		return true;
16970
16971	if (sna_get_image__inplace(pixmap, region, dst, flags, false))
16972		return true;
16973
16974	return false;
16975}
16976
16977static void
16978sna_get_image(DrawablePtr drawable,
16979	      int x, int y, int w, int h,
16980	      unsigned int format, unsigned long mask,
16981	      char *dst)
16982{
16983	RegionRec region;
16984	unsigned int flags;
16985
16986	if (!fbDrawableEnabled(drawable))
16987		return;
16988
16989	DBG(("%s: pixmap=%ld (%d, %d)x(%d, %d), format=%d, mask=%lx, depth=%d\n",
16990	     __FUNCTION__,
16991	     (long)get_drawable_pixmap(drawable)->drawable.serialNumber,
16992	     x, y, w, h, format, mask, drawable->depth));
16993
16994	flags = MOVE_READ;
16995	if ((w | h) == 1)
16996		flags |= MOVE_INPLACE_HINT;
16997	if (w == drawable->width)
16998		flags |= MOVE_WHOLE_HINT;
16999
17000	if (ACCEL_GET_IMAGE &&
17001	    !FORCE_FALLBACK &&
17002	    format == ZPixmap &&
17003	    drawable->bitsPerPixel >= 8 &&
17004	    PM_IS_SOLID(drawable, mask)) {
17005		PixmapPtr pixmap = get_drawable_pixmap(drawable);
17006		int16_t dx, dy;
17007
17008		get_drawable_deltas(drawable, pixmap, &dx, &dy);
17009		region.extents.x1 = x + drawable->x + dx;
17010		region.extents.y1 = y + drawable->y + dy;
17011		region.extents.x2 = region.extents.x1 + w;
17012		region.extents.y2 = region.extents.y1 + h;
17013		region.data = NULL;
17014
17015		if (sna_get_image__fast(pixmap, &region, dst, flags))
17016			return;
17017
17018		if (!sna_drawable_move_region_to_cpu(&pixmap->drawable,
17019						     &region, flags))
17020			return;
17021
17022		DBG(("%s: copy box (%d, %d), (%d, %d)\n",
17023		     __FUNCTION__,
17024		     region.extents.x1, region.extents.y1,
17025		     region.extents.x2, region.extents.y2));
17026		assert(has_coherent_ptr(to_sna_from_pixmap(pixmap), sna_pixmap(pixmap), MOVE_READ));
17027		if (sigtrap_get() == 0) {
17028			assert(pixmap->devKind);
17029			memcpy_blt(pixmap->devPrivate.ptr, dst, drawable->bitsPerPixel,
17030				   pixmap->devKind, PixmapBytePad(w, drawable->depth),
17031				   region.extents.x1, region.extents.y1, 0, 0, w, h);
17032			sigtrap_put();
17033		}
17034	} else {
17035		region.extents.x1 = x + drawable->x;
17036		region.extents.y1 = y + drawable->y;
17037		region.extents.x2 = region.extents.x1 + w;
17038		region.extents.y2 = region.extents.y1 + h;
17039		region.data = NULL;
17040
17041		if (sna_drawable_move_region_to_cpu(drawable, &region, flags))
17042			fbGetImage(drawable, x, y, w, h, format, mask, dst);
17043	}
17044}
17045
17046static void
17047sna_get_spans(DrawablePtr drawable, int wMax,
17048	      DDXPointPtr pt, int *width, int n, char *start)
17049{
17050	RegionRec region;
17051
17052	if (!fbDrawableEnabled(drawable))
17053		return;
17054
17055	if (sna_spans_extents(drawable, NULL, n, pt, width, &region.extents) == 0)
17056		return;
17057
17058	region.data = NULL;
17059	if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_READ))
17060		return;
17061
17062	fbGetSpans(drawable, wMax, pt, width, n, start);
17063}
17064
17065static void
17066sna_copy_window(WindowPtr win, DDXPointRec origin, RegionPtr src)
17067{
17068	PixmapPtr pixmap = get_window_pixmap(win);
17069	struct sna *sna = to_sna_from_pixmap(pixmap);
17070	RegionRec dst;
17071	int dx, dy;
17072
17073	DBG(("%s origin=(%d, %d)\n", __FUNCTION__, origin.x, origin.y));
17074	if (!fbWindowEnabled(win))
17075		return;
17076
17077	dx = origin.x - win->drawable.x;
17078	dy = origin.y - win->drawable.y;
17079	RegionTranslate(src, -dx, -dy);
17080
17081	RegionNull(&dst);
17082	RegionIntersect(&dst, &win->borderClip, src);
17083	if (box_empty(&dst.extents))
17084		return;
17085
17086#ifdef COMPOSITE
17087	if (pixmap->screen_x | pixmap->screen_y)
17088		RegionTranslate(&dst, -pixmap->screen_x, -pixmap->screen_y);
17089#endif
17090
17091	if (wedged(sna) || FORCE_FALLBACK || !ACCEL_COPY_WINDOW) {
17092		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
17093		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE))
17094			return;
17095
17096		if (sigtrap_get() == 0) {
17097			miCopyRegion(&pixmap->drawable, &pixmap->drawable,
17098				     0, &dst, dx, dy, fbCopyNtoN, 0, NULL);
17099			sigtrap_put();
17100		}
17101	} else {
17102		sna_self_copy_boxes(&pixmap->drawable, &pixmap->drawable, NULL,
17103				    &dst, dx, dy, 0, NULL);
17104	}
17105
17106	RegionUninit(&dst);
17107}
17108
17109static Bool sna_change_window_attributes(WindowPtr win, unsigned long mask)
17110{
17111	bool ret = true;
17112
17113	DBG(("%s\n", __FUNCTION__));
17114
17115	/* Check if the fb layer wishes to modify the attached pixmaps,
17116	 * to fix up mismatches between the window and pixmap depths.
17117	 */
17118	if (mask & CWBackPixmap && win->backgroundState == BackgroundPixmap) {
17119		DBG(("%s: flushing background pixmap\n", __FUNCTION__));
17120		ret &= sna_validate_pixmap(&win->drawable, win->background.pixmap);
17121	}
17122
17123	if (mask & CWBorderPixmap && win->borderIsPixel == false) {
17124		DBG(("%s: flushing border pixmap\n", __FUNCTION__));
17125		ret &= sna_validate_pixmap(&win->drawable, win->border.pixmap);
17126	}
17127
17128	return ret;
17129}
17130
17131void sna_accel_flush(struct sna *sna)
17132{
17133	struct sna_pixmap *priv;
17134
17135	/* XXX we should be able to reduce the frequency of flushes further
17136	 * by checking for outgoing damage events or sync replies. Tricky,
17137	 * and doesn't appear to mitigate the performance loss.
17138	 */
17139	DBG(("%s: flush?=%d, dirty?=%d\n", __FUNCTION__,
17140	     sna->kgem.flush, !list_is_empty(&sna->flush_pixmaps)));
17141
17142	/* flush any pending damage from shadow copies to tfp clients */
17143	while (!list_is_empty(&sna->flush_pixmaps)) {
17144		bool ret;
17145
17146		priv = list_first_entry(&sna->flush_pixmaps,
17147					struct sna_pixmap, flush_list);
17148
17149		list_del(&priv->flush_list);
17150		if (priv->shm) {
17151			DBG(("%s: syncing SHM pixmap=%ld (refcnt=%d)\n",
17152			     __FUNCTION__,
17153			     priv->pixmap->drawable.serialNumber,
17154			     priv->pixmap->refcnt));
17155			assert(!priv->flush);
17156			ret = sna_pixmap_move_to_cpu(priv->pixmap,
17157						     MOVE_READ | MOVE_WRITE);
17158			assert(!ret || priv->gpu_bo == NULL);
17159			if (priv->pixmap->refcnt == 0) {
17160				sna_damage_destroy(&priv->cpu_damage);
17161				__sna_free_pixmap(sna, priv->pixmap, priv);
17162			}
17163		} else {
17164			DBG(("%s: flushing DRI pixmap=%ld\n", __FUNCTION__,
17165			     priv->pixmap->drawable.serialNumber));
17166			assert(priv->flush);
17167			if (sna_pixmap_move_to_gpu(priv->pixmap,
17168						   MOVE_READ | __MOVE_FORCE)) {
17169				if (priv->flush & IS_CLIPPED) {
17170					kgem_bo_unclean(&sna->kgem, priv->gpu_bo);
17171					sna_damage_all(&priv->gpu_damage, priv->pixmap);
17172					assert(priv->cpu_damage == NULL);
17173					priv->clear = false;
17174					priv->cpu = false;
17175				}
17176			}
17177		}
17178		(void)ret;
17179	}
17180
17181	if (sna->kgem.flush)
17182		kgem_submit(&sna->kgem);
17183}
17184
17185static void
17186sna_accel_flush_callback(CallbackListPtr *list,
17187			 pointer user_data, pointer call_data)
17188{
17189	sna_accel_flush(user_data);
17190}
17191
17192static struct sna_pixmap *sna_accel_scanout(struct sna *sna)
17193{
17194	struct sna_pixmap *priv;
17195
17196	if (sna->mode.front_active == 0)
17197		return NULL;
17198
17199	assert(sna->vblank_interval);
17200	assert(sna->front);
17201
17202	priv = sna_pixmap(sna->front);
17203	if (priv->gpu_bo == NULL)
17204		return NULL;
17205
17206	return priv;
17207}
17208
17209#define TIME currentTime.milliseconds
17210static void sna_accel_disarm_timer(struct sna *sna, int id)
17211{
17212	DBG(("%s[%d] (time=%ld)\n", __FUNCTION__, id, (long)TIME));
17213	sna->timer_active &= ~(1<<id);
17214}
17215
17216static bool has_offload_slaves(struct sna *sna)
17217{
17218#if HAS_PIXMAP_SHARING
17219	ScreenPtr screen = sna->scrn->pScreen;
17220	PixmapDirtyUpdatePtr dirty;
17221
17222	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
17223		assert(dirty->src == sna->front);
17224		if (RegionNotEmpty(DamageRegion(dirty->damage)))
17225			return true;
17226	}
17227#endif
17228	return false;
17229}
17230
17231static bool has_shadow(struct sna *sna)
17232{
17233	DamagePtr damage = sna->mode.shadow_damage;
17234
17235	if (damage == NULL)
17236		return false;
17237
17238	DBG(("%s: has pending damage? %d, outstanding flips: %d\n",
17239	     __FUNCTION__,
17240	     RegionNotEmpty(DamageRegion(damage)),
17241	     sna->mode.flip_active));
17242
17243	return RegionNotEmpty(DamageRegion(damage));
17244}
17245
17246static bool start_flush(struct sna *sna)
17247{
17248	struct sna_pixmap *scanout;
17249
17250	if (has_offload_slaves(sna)) {
17251		DBG(("%s: has offload slaves\n", __FUNCTION__));
17252		return true;
17253	}
17254
17255	if (has_shadow(sna)) {
17256		DBG(("%s: has dirty shadow\n", __FUNCTION__));
17257		return true;
17258	}
17259
17260	scanout = sna_accel_scanout(sna);
17261	if (!scanout)
17262		return false;
17263
17264	if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) {
17265		scanout->gpu_bo->needs_flush = true;
17266		return true;
17267	}
17268
17269	if (scanout->cpu_damage || scanout->gpu_bo->needs_flush)
17270		return true;
17271
17272	kgem_scanout_flush(&sna->kgem, scanout->gpu_bo);
17273	return false;
17274}
17275
17276static bool stop_flush(struct sna *sna, struct sna_pixmap *scanout)
17277{
17278	DBG(("%s: scanout=%d shadow?=%d, slaves?=%d, (cpu?=%d || gpu?=%d))\n",
17279	     __FUNCTION__,
17280	     scanout && scanout->gpu_bo ? scanout->gpu_bo->handle : 0,
17281	     has_shadow(sna), has_offload_slaves(sna),
17282	     scanout && scanout->cpu_damage != NULL,
17283	     scanout && scanout->gpu_bo && scanout->gpu_bo->rq != NULL));
17284
17285	if (has_offload_slaves(sna))
17286		return true;
17287
17288	if (has_shadow(sna))
17289		return true;
17290
17291	if (!scanout)
17292		return false;
17293
17294	if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) {
17295		scanout->gpu_bo->needs_flush = true;
17296		return true;
17297	}
17298
17299	return scanout->cpu_damage || scanout->gpu_bo->needs_flush;
17300}
17301
17302static void timer_enable(struct sna *sna, int whom, int interval)
17303{
17304	if (!sna->timer_active)
17305		UpdateCurrentTimeIf();
17306	sna->timer_active |= 1 << whom;
17307	sna->timer_expire[whom] = TIME + interval;
17308	DBG(("%s (time=%ld), starting timer %d\n", __FUNCTION__, (long)TIME, whom));
17309}
17310
17311static bool sna_scanout_do_flush(struct sna *sna)
17312{
17313	int interval = sna->vblank_interval ?: 50;
17314	if (sna->timer_active & (1<<(FLUSH_TIMER))) {
17315		int32_t delta = sna->timer_expire[FLUSH_TIMER] - TIME;
17316		DBG(("%s: flush timer active: delta=%d\n",
17317		     __FUNCTION__, delta));
17318		if (delta <= 3) {
17319			DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME));
17320			sna->timer_expire[FLUSH_TIMER] = TIME + interval;
17321			return true;
17322		}
17323	} else {
17324		if (start_flush(sna))
17325			timer_enable(sna, FLUSH_TIMER, interval/2);
17326	}
17327
17328	return false;
17329}
17330
17331static bool sna_accel_do_throttle(struct sna *sna)
17332{
17333	if (sna->timer_active & (1<<(THROTTLE_TIMER))) {
17334		int32_t delta = sna->timer_expire[THROTTLE_TIMER] - TIME;
17335		if (delta <= 3) {
17336			DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME));
17337			sna->timer_expire[THROTTLE_TIMER] = TIME + 20;
17338			return true;
17339		}
17340	} else if (!sna->kgem.need_retire) {
17341		DBG(("%s -- no pending activity\n", __FUNCTION__));
17342	} else
17343		timer_enable(sna, THROTTLE_TIMER, 20);
17344
17345	return false;
17346}
17347
17348static bool sna_accel_do_expire(struct sna *sna)
17349{
17350	if (sna->timer_active & (1<<(EXPIRE_TIMER))) {
17351		int32_t delta = sna->timer_expire[EXPIRE_TIMER] - TIME;
17352		if (delta <= 3) {
17353			DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME));
17354			sna->timer_expire[EXPIRE_TIMER] =
17355				TIME + MAX_INACTIVE_TIME * 1000;
17356			return true;
17357		}
17358	} else if (sna->kgem.need_expire)
17359		timer_enable(sna, EXPIRE_TIMER, MAX_INACTIVE_TIME * 1000);
17360
17361	return false;
17362}
17363
17364static void sna_accel_post_damage(struct sna *sna)
17365{
17366#if HAS_PIXMAP_SHARING
17367	ScreenPtr screen = sna->scrn->pScreen;
17368	PixmapDirtyUpdatePtr dirty;
17369	bool flush = false;
17370
17371	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
17372		RegionRec region, *damage;
17373		PixmapPtr src, dst;
17374		const BoxRec *box;
17375		int16_t dx, dy;
17376		int n;
17377
17378		assert(dirty->src == sna->front);
17379
17380		damage = DamageRegion(dirty->damage);
17381		if (RegionNil(damage))
17382			continue;
17383
17384		src = (PixmapPtr)dirty->src;
17385		dst = dirty->slave_dst->master_pixmap;
17386
17387		region.extents.x1 = dirty->x;
17388		region.extents.x2 = dirty->x + dst->drawable.width;
17389		region.extents.y1 = dirty->y;
17390		region.extents.y2 = dirty->y + dst->drawable.height;
17391		region.data = NULL;
17392
17393		DBG(("%s: pushing damage ((%d, %d), (%d, %d))x%d to slave pixmap=%d, ((%d, %d), (%d, %d))\n", __FUNCTION__,
17394		     damage->extents.x1, damage->extents.y1,
17395		     damage->extents.x2, damage->extents.y2,
17396		     region_num_rects(damage),
17397		     dst->drawable.serialNumber,
17398		     region.extents.x1, region.extents.y1,
17399		     region.extents.x2, region.extents.y2));
17400
17401		RegionIntersect(&region, &region, damage);
17402		if (RegionNil(&region))
17403			goto skip;
17404
17405		dx = -dirty->x;
17406		dy = -dirty->y;
17407#if HAS_DIRTYTRACKING2
17408		dx += dirty->dst_x;
17409		dy += dirty->dst_y;
17410#endif
17411		RegionTranslate(&region, dx, dy);
17412		DamageRegionAppend(&dirty->slave_dst->drawable, &region);
17413
17414		DBG(("%s: slave:  ((%d, %d), (%d, %d))x%d\n", __FUNCTION__,
17415		     region.extents.x1, region.extents.y1,
17416		     region.extents.x2, region.extents.y2,
17417		     region_num_rects(&region)));
17418
17419		box = region_rects(&region);
17420		n = region_num_rects(&region);
17421		if (wedged(sna)) {
17422fallback:
17423			if (!sna_pixmap_move_to_cpu(src, MOVE_READ))
17424				goto skip;
17425
17426			if (!sna_pixmap_move_to_cpu(dst, MOVE_READ | MOVE_WRITE | MOVE_INPLACE_HINT))
17427				goto skip;
17428
17429			if (sigtrap_get() == 0) {
17430				assert(src->drawable.bitsPerPixel == dst->drawable.bitsPerPixel);
17431				do {
17432					DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n",
17433					     __FUNCTION__,
17434					     box->x1 - dx, box->y1 - dy,
17435					     box->x1, box->y1,
17436					     box->x2 - box->x1, box->y2 - box->y1));
17437
17438					assert(box->x2 > box->x1);
17439					assert(box->y2 > box->y1);
17440
17441					assert(box->x1 - dx >= 0);
17442					assert(box->y1 - dy >= 0);
17443					assert(box->x2 - dx <= src->drawable.width);
17444					assert(box->y2 - dy <= src->drawable.height);
17445
17446					assert(box->x1 >= 0);
17447					assert(box->y1 >= 0);
17448					assert(box->x2 <= src->drawable.width);
17449					assert(box->y2 <= src->drawable.height);
17450
17451					assert(has_coherent_ptr(sna, sna_pixmap(src), MOVE_READ));
17452					assert(has_coherent_ptr(sna, sna_pixmap(dst), MOVE_WRITE));
17453					assert(src->devKind);
17454					assert(dst->devKind);
17455					memcpy_blt(src->devPrivate.ptr,
17456						   dst->devPrivate.ptr,
17457						   src->drawable.bitsPerPixel,
17458						   src->devKind, dst->devKind,
17459						   box->x1 - dx,      box->y1 - dy,
17460						   box->x1,           box->y1,
17461						   box->x2 - box->x1, box->y2 - box->y1);
17462					box++;
17463				} while (--n);
17464				sigtrap_put();
17465			}
17466		} else {
17467			if (!sna_pixmap_move_to_gpu(src, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE))
17468				goto fallback;
17469
17470			if (!sna_pixmap_move_to_gpu(dst, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE))
17471				goto fallback;
17472
17473			if (!sna->render.copy_boxes(sna, GXcopy,
17474						    &src->drawable, __sna_pixmap_get_bo(src), -dx, -dy,
17475						    &dst->drawable, __sna_pixmap_get_bo(dst),   0,   0,
17476						    box, n, COPY_LAST))
17477				goto fallback;
17478
17479			flush = true;
17480		}
17481
17482		DamageRegionProcessPending(&dirty->slave_dst->drawable);
17483skip:
17484		RegionUninit(&region);
17485		DamageEmpty(dirty->damage);
17486	}
17487	if (flush)
17488		kgem_submit(&sna->kgem);
17489#endif
17490}
17491
17492static void sna_scanout_flush(struct sna *sna)
17493{
17494	struct sna_pixmap *priv = sna_accel_scanout(sna);
17495	bool busy;
17496
17497	DBG(("%s (time=%ld), cpu damage? %d, exec? %d nbatch=%d, busy? %d\n",
17498	     __FUNCTION__, (long)TIME,
17499	     priv && priv->cpu_damage,
17500	     priv && priv->gpu_bo->exec != NULL,
17501	     sna->kgem.nbatch,
17502	     sna->kgem.busy));
17503
17504	busy = stop_flush(sna, priv);
17505	if (!sna->kgem.busy && !busy)
17506		sna_accel_disarm_timer(sna, FLUSH_TIMER);
17507	sna->kgem.busy = busy;
17508
17509	if (priv &&
17510	    sna->mode.shadow_damage == NULL &&
17511	    sna_pixmap_force_to_gpu(priv->pixmap,
17512				    MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT))
17513		kgem_scanout_flush(&sna->kgem, priv->gpu_bo);
17514
17515	sna_mode_redisplay(sna);
17516	sna_accel_post_damage(sna);
17517}
17518
17519static void sna_accel_throttle(struct sna *sna)
17520{
17521	DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME));
17522
17523	if (sna->kgem.need_throttle) {
17524		kgem_submit(&sna->kgem);
17525		kgem_throttle(&sna->kgem);
17526	}
17527
17528	if (!sna->kgem.need_retire)
17529		sna_accel_disarm_timer(sna, THROTTLE_TIMER);
17530}
17531
17532static void sna_pixmap_expire(struct sna *sna)
17533{
17534	while (sna->freed_pixmap) {
17535		PixmapPtr pixmap = __pop_freed_pixmap(sna);
17536		free(sna_pixmap(pixmap));
17537		FreePixmap(pixmap);
17538	}
17539}
17540
17541static void sna_accel_expire(struct sna *sna)
17542{
17543	DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME));
17544
17545	kgem_expire_cache(&sna->kgem);
17546	sna_pixmap_expire(sna);
17547
17548	if (!sna->kgem.need_expire)
17549		sna_accel_disarm_timer(sna, EXPIRE_TIMER);
17550}
17551
17552#ifdef DEBUG_MEMORY
17553static bool sna_accel_do_debug_memory(struct sna *sna)
17554{
17555	int32_t delta = sna->timer_expire[DEBUG_MEMORY_TIMER] - TIME;
17556
17557	if (delta <= 3) {
17558		sna->timer_expire[DEBUG_MEMORY_TIMER] = TIME + 10 * 1000;
17559		return true;
17560	} else
17561		return false;
17562}
17563
17564static void sna_accel_debug_memory(struct sna *sna)
17565{
17566	ErrorF("Allocated pixmaps: %d (cached: %d), bo: %d, %lu bytes (CPU bo: %d, %lu bytes)\n",
17567	       sna->debug_memory.pixmap_allocs,
17568	       sna->debug_memory.pixmap_cached,
17569	       sna->kgem.debug_memory.bo_allocs,
17570	       (unsigned long)sna->kgem.debug_memory.bo_bytes,
17571	       sna->debug_memory.cpu_bo_allocs,
17572	       (unsigned long)sna->debug_memory.cpu_bo_bytes);
17573
17574#ifdef VALGRIND_DO_ADDED_LEAK_CHECK
17575	VG(VALGRIND_DO_ADDED_LEAK_CHECK);
17576#endif
17577}
17578
17579#else
17580#define sna_accel_do_debug_memory(x) 0
17581static void sna_accel_debug_memory(struct sna *sna) { }
17582#endif
17583
17584static ShmFuncs shm_funcs = { sna_pixmap_create_shm, NULL };
17585
17586static PixmapPtr
17587sna_get_window_pixmap(WindowPtr window)
17588{
17589	return get_window_pixmap(window);
17590}
17591
17592static void
17593sna_set_window_pixmap(WindowPtr window, PixmapPtr pixmap)
17594{
17595	DBG(("%s: window=%ld, old pixmap=%ld new pixmap=%ld\n",
17596	     __FUNCTION__, window->drawable.id,
17597	     get_window_pixmap(window) ? get_window_pixmap(window)->drawable.serialNumber : 0,
17598	     pixmap->drawable.serialNumber));
17599
17600	sna_dri2_decouple_window(window);
17601
17602	*(PixmapPtr *)__get_private(window, sna_window_key) = pixmap;
17603}
17604
17605struct sna_visit_set_pixmap_window {
17606	PixmapPtr old, new;
17607};
17608
17609static int
17610sna_visit_set_window_pixmap(WindowPtr window, pointer data)
17611{
17612    struct sna_visit_set_pixmap_window *visit = data;
17613
17614    if (sna_get_window_pixmap(window) == visit->old) {
17615	    window->drawable.pScreen->SetWindowPixmap(window, visit->new);
17616	    return WT_WALKCHILDREN;
17617    }
17618
17619    return WT_DONTWALKCHILDREN;
17620}
17621
17622static void
17623migrate_dirty_tracking(PixmapPtr old_front, PixmapPtr new_front)
17624{
17625#if HAS_PIXMAP_SHARING
17626	ScreenPtr screen = old_front->drawable.pScreen;
17627	PixmapDirtyUpdatePtr dirty, safe;
17628
17629	xorg_list_for_each_entry_safe(dirty, safe, &screen->pixmap_dirty_list, ent) {
17630		assert(dirty->src == old_front);
17631		if ((PixmapPtr)dirty->src != old_front)
17632			continue;
17633
17634		DamageUnregister(&dirty->src->drawable, dirty->damage);
17635		DamageDestroy(dirty->damage);
17636
17637		dirty->damage = DamageCreate(NULL, NULL,
17638					     DamageReportNone,
17639					     TRUE, screen, screen);
17640		if (!dirty->damage) {
17641			xorg_list_del(&dirty->ent);
17642			free(dirty);
17643			continue;
17644		}
17645
17646		DamageRegister(&new_front->drawable, dirty->damage);
17647		dirty->src = (DrawablePtr)new_front;
17648	}
17649#endif
17650}
17651
17652static void
17653sna_set_screen_pixmap(PixmapPtr pixmap)
17654{
17655	ScreenPtr screen = pixmap->drawable.pScreen;
17656	PixmapPtr old_front = screen->devPrivate;
17657	WindowPtr root;
17658
17659	DBG(("%s: changing from pixmap=%ld to pixmap=%ld, (sna->front=%ld)\n",
17660	     __FUNCTION__,
17661	     old_front ? (long)old_front->drawable.serialNumber : 0,
17662	     pixmap ? (long)pixmap->drawable.serialNumber : 0,
17663	     to_sna_from_pixmap(pixmap)->front ? (long)to_sna_from_pixmap(pixmap)->front->drawable.serialNumber : 0));
17664
17665	assert(to_sna_from_pixmap(pixmap) == to_sna_from_screen(screen));
17666	assert(to_sna_from_pixmap(pixmap)->front == old_front);
17667
17668	if (old_front) {
17669		assert(to_sna_from_pixmap(old_front)->front == old_front);
17670		migrate_dirty_tracking(old_front, pixmap);
17671	}
17672
17673	root = get_root_window(screen);
17674	if (root) {
17675		struct sna_visit_set_pixmap_window visit = { old_front, pixmap };
17676		TraverseTree(root, sna_visit_set_window_pixmap, &visit);
17677		assert(fbGetWindowPixmap(root) == pixmap);
17678	}
17679
17680	to_sna_from_pixmap(pixmap)->front = pixmap;
17681	screen->devPrivate = pixmap;
17682	pixmap->refcnt++;
17683
17684	if (old_front)
17685		screen->DestroyPixmap(old_front);
17686}
17687
17688static Bool
17689sna_create_window(WindowPtr win)
17690{
17691	sna_set_window_pixmap(win, win->drawable.pScreen->devPrivate);
17692	return TRUE;
17693}
17694
17695static Bool
17696sna_map_window(WindowPtr win)
17697{
17698	return TRUE;
17699}
17700
17701static Bool
17702sna_position_window(WindowPtr win, int x, int y)
17703{
17704	return TRUE;
17705}
17706
17707static Bool
17708sna_unmap_window(WindowPtr win)
17709{
17710	return TRUE;
17711}
17712
17713static Bool
17714sna_destroy_window(WindowPtr win)
17715{
17716	sna_video_destroy_window(win);
17717	sna_dri2_destroy_window(win);
17718	return TRUE;
17719}
17720
17721static void
17722sna_query_best_size(int class,
17723		    unsigned short *width, unsigned short *height,
17724		    ScreenPtr screen)
17725{
17726	unsigned short w;
17727
17728	switch (class) {
17729	case CursorShape:
17730		if (*width > screen->width)
17731			*width = screen->width;
17732		if (*height > screen->height)
17733			*height = screen->height;
17734		break;
17735
17736	case TileShape:
17737	case StippleShape:
17738		w = *width;
17739		if ((w & (w - 1)) && w < FB_UNIT) {
17740			for (w = 1; w < *width; w <<= 1)
17741				;
17742			*width = w;
17743		}
17744		break;
17745	}
17746}
17747
17748static void sna_store_colors(ColormapPtr cmap, int n, xColorItem *def)
17749{
17750}
17751
17752static bool sna_picture_init(ScreenPtr screen)
17753{
17754	PictureScreenPtr ps;
17755
17756	DBG(("%s\n", __FUNCTION__));
17757
17758	if (!miPictureInit(screen, NULL, 0))
17759		return false;
17760
17761	ps = GetPictureScreen(screen);
17762	assert(ps != NULL);
17763	assert(ps->CreatePicture != NULL);
17764	assert(ps->DestroyPicture != NULL);
17765
17766	ps->Composite = sna_composite;
17767	ps->CompositeRects = sna_composite_rectangles;
17768	ps->Glyphs = sna_glyphs;
17769	if (xf86IsEntityShared(xf86ScreenToScrn(screen)->entityList[0]))
17770		ps->Glyphs = sna_glyphs__shared;
17771	ps->UnrealizeGlyph = sna_glyph_unrealize;
17772	ps->AddTraps = sna_add_traps;
17773	ps->Trapezoids = sna_composite_trapezoids;
17774#if HAS_PIXMAN_TRIANGLES
17775	ps->Triangles = sna_composite_triangles;
17776#if PICTURE_SCREEN_VERSION >= 2
17777	ps->TriStrip = sna_composite_tristrip;
17778	ps->TriFan = sna_composite_trifan;
17779#endif
17780#endif
17781
17782	return true;
17783}
17784
17785static bool sna_option_accel_none(struct sna *sna)
17786{
17787	const char *s;
17788
17789	if (wedged(sna))
17790		return true;
17791
17792	if (xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_DISABLE, FALSE))
17793		return true;
17794
17795	s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD);
17796	if (s == NULL)
17797		return IS_DEFAULT_ACCEL_METHOD(NOACCEL);
17798
17799	return strcasecmp(s, "none") == 0;
17800}
17801
17802static bool sna_option_accel_blt(struct sna *sna)
17803{
17804	const char *s;
17805
17806	s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD);
17807	if (s == NULL)
17808		return false;
17809
17810	return strcasecmp(s, "blt") == 0;
17811}
17812
17813bool sna_accel_init(ScreenPtr screen, struct sna *sna)
17814{
17815	const char *backend;
17816
17817	DBG(("%s\n", __FUNCTION__));
17818
17819	sna_font_key = AllocateFontPrivateIndex();
17820
17821	list_init(&sna->flush_pixmaps);
17822	list_init(&sna->active_pixmaps);
17823
17824#if HAVE_NOTIFY_FD
17825	SetNotifyFd(sna->kgem.fd, NULL, X_NOTIFY_NONE, NULL);
17826#else
17827	AddGeneralSocket(sna->kgem.fd);
17828#endif
17829
17830#ifdef DEBUG_MEMORY
17831	sna->timer_expire[DEBUG_MEMORY_TIMER] = GetTimeInMillis()+ 10 * 1000;
17832#endif
17833
17834	screen->defColormap = FakeClientID(0);
17835	/* let CreateDefColormap do whatever it wants for pixels */
17836	screen->blackPixel = screen->whitePixel = (Pixel) 0;
17837	screen->QueryBestSize = sna_query_best_size;
17838	assert(screen->GetImage == NULL);
17839	screen->GetImage = sna_get_image;
17840	assert(screen->GetSpans == NULL);
17841	screen->GetSpans = sna_get_spans;
17842	assert(screen->CreateWindow == NULL);
17843	screen->CreateWindow = sna_create_window;
17844	assert(screen->DestroyWindow == NULL);
17845	screen->DestroyWindow = sna_destroy_window;
17846	screen->PositionWindow = sna_position_window;
17847	screen->ChangeWindowAttributes = sna_change_window_attributes;
17848	screen->RealizeWindow = sna_map_window;
17849	screen->UnrealizeWindow = sna_unmap_window;
17850	screen->CopyWindow = sna_copy_window;
17851	assert(screen->CreatePixmap == NULL);
17852	screen->CreatePixmap = sna_create_pixmap;
17853	assert(screen->DestroyPixmap == NULL);
17854	screen->DestroyPixmap = sna_destroy_pixmap;
17855#ifdef CREATE_PIXMAP_USAGE_SHARED
17856	screen->SharePixmapBacking = sna_share_pixmap_backing;
17857	screen->SetSharedPixmapBacking = sna_set_shared_pixmap_backing;
17858#endif
17859	screen->RealizeFont = sna_realize_font;
17860	screen->UnrealizeFont = sna_unrealize_font;
17861	assert(screen->CreateGC == NULL);
17862	screen->CreateGC = sna_create_gc;
17863	screen->CreateColormap = miInitializeColormap;
17864	screen->DestroyColormap = (void (*)(ColormapPtr)) NoopDDA;
17865	screen->InstallColormap = miInstallColormap;
17866	screen->UninstallColormap = miUninstallColormap;
17867	screen->ListInstalledColormaps = miListInstalledColormaps;
17868	screen->ResolveColor = miResolveColor;
17869	assert(screen->StoreColors == NULL);
17870	screen->StoreColors = sna_store_colors;
17871	screen->BitmapToRegion = fbBitmapToRegion;
17872
17873#if HAS_PIXMAP_SHARING
17874	screen->StartPixmapTracking = PixmapStartDirtyTracking;
17875	screen->StopPixmapTracking = PixmapStopDirtyTracking;
17876#endif
17877
17878	assert(screen->GetWindowPixmap == NULL);
17879	screen->GetWindowPixmap = sna_get_window_pixmap;
17880	assert(screen->SetWindowPixmap == NULL);
17881	screen->SetWindowPixmap = sna_set_window_pixmap;
17882
17883	screen->SetScreenPixmap = sna_set_screen_pixmap;
17884
17885	if (sna->kgem.has_userptr)
17886		ShmRegisterFuncs(screen, &shm_funcs);
17887	else
17888		ShmRegisterFbFuncs(screen);
17889
17890	if (!sna_picture_init(screen))
17891		return false;
17892
17893	backend = no_render_init(sna);
17894	if (sna_option_accel_none(sna)) {
17895		backend = "disabled";
17896		sna->kgem.wedged = true;
17897		sna_render_mark_wedged(sna);
17898	} else if (sna_option_accel_blt(sna) || sna->info->gen >= 0110)
17899		(void)backend;
17900	else if (sna->info->gen >= 0100)
17901		backend = gen8_render_init(sna, backend);
17902	else if (sna->info->gen >= 070)
17903		backend = gen7_render_init(sna, backend);
17904	else if (sna->info->gen >= 060)
17905		backend = gen6_render_init(sna, backend);
17906	else if (sna->info->gen >= 050)
17907		backend = gen5_render_init(sna, backend);
17908	else if (sna->info->gen >= 040)
17909		backend = gen4_render_init(sna, backend);
17910	else if (sna->info->gen >= 030)
17911		backend = gen3_render_init(sna, backend);
17912	else if (sna->info->gen >= 020)
17913		backend = gen2_render_init(sna, backend);
17914
17915	DBG(("%s(backend=%s, prefer_gpu=%x)\n",
17916	     __FUNCTION__, backend, sna->render.prefer_gpu));
17917
17918	kgem_reset(&sna->kgem);
17919	sigtrap_init();
17920
17921	xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
17922		   "SNA initialized with %s backend\n",
17923		   backend);
17924
17925	return true;
17926}
17927
17928void sna_accel_create(struct sna *sna)
17929{
17930	DBG(("%s\n", __FUNCTION__));
17931
17932	if (!sna_glyphs_create(sna))
17933		goto fail;
17934
17935	if (!sna_gradients_create(sna))
17936		goto fail;
17937
17938	if (!sna_composite_create(sna))
17939		goto fail;
17940
17941	return;
17942
17943fail:
17944	xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
17945		   "Failed to allocate caches, disabling RENDER acceleration\n");
17946	no_render_init(sna);
17947}
17948
17949void sna_accel_watch_flush(struct sna *sna, int enable)
17950{
17951	DBG(("%s: enable=%d\n", __FUNCTION__, enable));
17952	assert(enable);
17953
17954	if (sna->watch_flush == 0) {
17955		DBG(("%s: installing watchers\n", __FUNCTION__));
17956		assert(enable > 0);
17957		if (!AddCallback(&FlushCallback, sna_accel_flush_callback, sna)) {
17958			xf86DrvMsg(sna->scrn->scrnIndex, X_Error,
17959				   "Failed to attach ourselves to the flush callbacks, expect missing synchronisation with DRI clients (e.g a compositor)\n");
17960		}
17961		sna->watch_flush++;
17962	}
17963
17964	sna->watch_flush += enable;
17965}
17966
17967void sna_accel_leave(struct sna *sna)
17968{
17969	DBG(("%s\n", __FUNCTION__));
17970
17971	/* as root we always have permission to render */
17972	if (geteuid() == 0)
17973		return;
17974
17975	/* as a user, we can only render now if we have a rendernode */
17976	if (intel_has_render_node(sna->dev))
17977		return;
17978
17979	/* no longer authorized to use our fd */
17980	DBG(("%s: dropping render privileges\n", __FUNCTION__));
17981
17982	kgem_submit(&sna->kgem);
17983	sna->kgem.wedged |= 2;
17984}
17985
17986void sna_accel_enter(struct sna *sna)
17987{
17988	DBG(("%s\n", __FUNCTION__));
17989	sna->kgem.wedged &= kgem_is_wedged(&sna->kgem);
17990	kgem_throttle(&sna->kgem);
17991}
17992
17993void sna_accel_close(struct sna *sna)
17994{
17995	DBG(("%s\n", __FUNCTION__));
17996
17997	sna_composite_close(sna);
17998	sna_gradients_close(sna);
17999	sna_glyphs_close(sna);
18000
18001	sna_pixmap_expire(sna);
18002
18003	DeleteCallback(&FlushCallback, sna_accel_flush_callback, sna);
18004#if HAVE_NOTIFY_FD
18005	RemoveNotifyFd(sna->kgem.fd);
18006#else
18007	RemoveGeneralSocket(sna->kgem.fd);
18008#endif
18009
18010	kgem_cleanup_cache(&sna->kgem);
18011}
18012
18013/* tv changed from timeval to milliseconds in ABI 23 */
18014#if ABI_VIDEODRV_VERSION < SET_ABI_VERSION(23, 0)
18015void sna_accel_block_handler(struct sna *sna, struct timeval **tv)
18016#else
18017void sna_accel_block_handler(struct sna *sna, int *tv_msec)
18018#endif
18019{
18020	sigtrap_assert_inactive();
18021
18022	if (sna->kgem.need_retire)
18023		kgem_retire(&sna->kgem);
18024	kgem_retire__buffers(&sna->kgem);
18025
18026	if (sna->timer_active)
18027		UpdateCurrentTimeIf();
18028
18029	if (sna->kgem.nbatch &&
18030	    (sna->kgem.scanout_busy ||
18031	     kgem_ring_is_idle(&sna->kgem, sna->kgem.ring))) {
18032		DBG(("%s: GPU idle, flushing\n", __FUNCTION__));
18033		_kgem_submit(&sna->kgem);
18034	}
18035
18036	if (sna->mode.dirty)
18037		sna_crtc_config_notify(xf86ScrnToScreen(sna->scrn));
18038
18039restart:
18040	if (sna_scanout_do_flush(sna))
18041		sna_scanout_flush(sna);
18042	assert(sna_accel_scanout(sna) == NULL ||
18043	       !sna_accel_scanout(sna)->gpu_bo->needs_flush ||
18044	       sna->timer_active & (1<<(FLUSH_TIMER)));
18045
18046	if (sna_accel_do_throttle(sna))
18047		sna_accel_throttle(sna);
18048	assert(!sna->kgem.need_retire ||
18049	       sna->timer_active & (1<<(THROTTLE_TIMER)));
18050
18051	if (sna_accel_do_expire(sna))
18052		sna_accel_expire(sna);
18053	assert(!sna->kgem.need_expire ||
18054	       sna->timer_active & (1<<(EXPIRE_TIMER)));
18055
18056	if (sna_accel_do_debug_memory(sna))
18057		sna_accel_debug_memory(sna);
18058
18059	if (sna->watch_flush == 1) {
18060		DBG(("%s: removing watchers\n", __FUNCTION__));
18061		DeleteCallback(&FlushCallback, sna_accel_flush_callback, sna);
18062		sna->watch_flush = 0;
18063	}
18064
18065	if (sna->timer_active & 1) {
18066		int32_t timeout;
18067
18068		DBG(("%s: evaluating timers, active=%x\n",
18069		     __FUNCTION__, sna->timer_active));
18070
18071		timeout = sna->timer_expire[FLUSH_TIMER] - TIME;
18072		DBG(("%s: flush timer expires in %d [%d]\n",
18073		     __FUNCTION__, timeout, sna->timer_expire[FLUSH_TIMER]));
18074		if (timeout < 3)
18075			goto restart;
18076
18077#if ABI_VIDEODRV_VERSION < SET_ABI_VERSION(23, 0)
18078		if (*tv == NULL) {
18079			*tv = &sna->timer_tv;
18080			goto set_tv;
18081		}
18082		if ((*tv)->tv_sec * 1000 + (*tv)->tv_usec / 1000 > timeout) {
18083set_tv:
18084			(*tv)->tv_sec = timeout / 1000;
18085			(*tv)->tv_usec = timeout % 1000 * 1000;
18086		}
18087#else
18088		if (*tv_msec > timeout)
18089			*tv_msec = timeout;
18090#endif
18091	}
18092
18093	sna->kgem.scanout_busy = false;
18094
18095	if (FAULT_INJECTION && (rand() % FAULT_INJECTION) == 0) {
18096		DBG(("%s hardware acceleration\n",
18097		     sna->kgem.wedged ? "Re-enabling" : "Disabling"));
18098		kgem_submit(&sna->kgem);
18099		sna->kgem.wedged = !sna->kgem.wedged;
18100	}
18101}
18102
18103void sna_accel_wakeup_handler(struct sna *sna)
18104{
18105	DBG(("%s: nbatch=%d, need_retire=%d, need_purge=%d\n", __FUNCTION__,
18106	     sna->kgem.nbatch, sna->kgem.need_retire, sna->kgem.need_purge));
18107
18108	if (!sna->kgem.nbatch)
18109		return;
18110
18111	if (kgem_is_idle(&sna->kgem)) {
18112		DBG(("%s: GPU idle, flushing\n", __FUNCTION__));
18113		_kgem_submit(&sna->kgem);
18114	}
18115
18116	sigtrap_assert_inactive();
18117}
18118
18119void sna_accel_free(struct sna *sna)
18120{
18121	DBG(("%s\n", __FUNCTION__));
18122	sigtrap_assert_inactive();
18123}
18124