sna_accel.c revision 42542f5f
1/*
2 * Copyright (c) 2011 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 *    Chris Wilson <chris@chris-wilson.co.uk>
25 *
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include "sna.h"
33#include "sna_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_WIDE_SPANS 0 /* -1 force CPU, 1 force GPU */
73#define USE_ZERO_SPANS 1 /* -1 force CPU, 1 force GPU */
74#define USE_CPU_BO 1
75#define USE_USERPTR_UPLOADS 1
76#define USE_USERPTR_DOWNLOADS 1
77#define USE_COW 1
78#define UNDO 1
79
80#define MIGRATE_ALL 0
81#define DBG_NO_PARTIAL_MOVE_TO_CPU 0
82#define DBG_NO_CPU_UPLOAD 0
83#define DBG_NO_CPU_DOWNLOAD 0
84
85#define ACCEL_FILL_SPANS 1
86#define ACCEL_SET_SPANS 1
87#define ACCEL_PUT_IMAGE 1
88#define ACCEL_GET_IMAGE 1
89#define ACCEL_COPY_AREA 1
90#define ACCEL_COPY_PLANE 1
91#define ACCEL_COPY_WINDOW 1
92#define ACCEL_POLY_POINT 1
93#define ACCEL_POLY_LINE 1
94#define ACCEL_POLY_SEGMENT 1
95#define ACCEL_POLY_RECTANGLE 1
96#define ACCEL_POLY_ARC 1
97#define ACCEL_POLY_FILL_POLYGON 1
98#define ACCEL_POLY_FILL_RECT 1
99#define ACCEL_POLY_FILL_ARC 1
100#define ACCEL_POLY_TEXT8 1
101#define ACCEL_POLY_TEXT16 1
102#define ACCEL_POLY_GLYPH 1
103#define ACCEL_IMAGE_TEXT8 1
104#define ACCEL_IMAGE_TEXT16 1
105#define ACCEL_IMAGE_GLYPH 1
106#define ACCEL_PUSH_PIXELS 1
107
108#define NO_TILE_8x8 0
109#define NO_STIPPLE_8x8 0
110
111#define IS_COW_OWNER(ptr) ((uintptr_t)(ptr) & 1)
112#define MAKE_COW_OWNER(ptr) ((void*)((uintptr_t)(ptr) | 1))
113#define COW(ptr) (void *)((uintptr_t)(ptr) & ~1)
114
115#if 0
116static void __sna_fallback_flush(DrawablePtr d)
117{
118	PixmapPtr pixmap = get_drawable_pixmap(d);
119	struct sna *sna = to_sna_from_pixmap(pixmap);
120	struct sna_pixmap *priv;
121	BoxRec box;
122	PixmapPtr tmp;
123	int i, j;
124	char *src, *dst;
125
126	DBG(("%s: uploading CPU damage...\n", __FUNCTION__));
127	priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ);
128	if (priv == NULL)
129		return;
130
131	DBG(("%s: downloading GPU damage...\n", __FUNCTION__));
132	if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
133		return;
134
135	box.x1 = box.y1 = 0;
136	box.x2 = pixmap->drawable.width;
137	box.y2 = pixmap->drawable.height;
138
139	tmp = sna_pixmap_create_unattached(pixmap->drawable.pScreen,
140					   pixmap->drawable.width,
141					   pixmap->drawable.height,
142					   pixmap->drawable.depth,
143					   0);
144
145	DBG(("%s: comparing with direct read...\n", __FUNCTION__));
146	sna_read_boxes(sna, tmp, priv->gpu_bo, &box, 1);
147
148	src = pixmap->devPrivate.ptr;
149	dst = tmp->devPrivate.ptr;
150	for (i = 0; i < tmp->drawable.height; i++) {
151		if (memcmp(src, dst, tmp->drawable.width * tmp->drawable.bitsPerPixel >> 3)) {
152			for (j = 0; src[j] == dst[j]; j++)
153				;
154			ERR(("mismatch at (%d, %d)\n",
155			     8*j / tmp->drawable.bitsPerPixel, i));
156			abort();
157		}
158		src += pixmap->devKind;
159		dst += tmp->devKind;
160	}
161	tmp->drawable.pScreen->DestroyPixmap(tmp);
162}
163#define FALLBACK_FLUSH(d) __sna_fallback_flush(d)
164#else
165#define FALLBACK_FLUSH(d)
166#endif
167
168static int sna_font_key;
169
170static const uint8_t copy_ROP[] = {
171	ROP_0,		/* GXclear */
172	ROP_DSa,	/* GXand */
173	ROP_SDna,	/* GXandReverse */
174	ROP_S,		/* GXcopy */
175	ROP_DSna,	/* GXandInverted */
176	ROP_D,		/* GXnoop */
177	ROP_DSx,	/* GXxor */
178	ROP_DSo,	/* GXor */
179	ROP_DSon,	/* GXnor */
180	ROP_DSxn,	/* GXequiv */
181	ROP_Dn,		/* GXinvert */
182	ROP_SDno,	/* GXorReverse */
183	ROP_Sn,		/* GXcopyInverted */
184	ROP_DSno,	/* GXorInverted */
185	ROP_DSan,	/* GXnand */
186	ROP_1		/* GXset */
187};
188static const uint8_t fill_ROP[] = {
189	ROP_0,
190	ROP_DPa,
191	ROP_PDna,
192	ROP_P,
193	ROP_DPna,
194	ROP_D,
195	ROP_DPx,
196	ROP_DPo,
197	ROP_DPon,
198	ROP_PDxn,
199	ROP_Dn,
200	ROP_PDno,
201	ROP_Pn,
202	ROP_DPno,
203	ROP_DPan,
204	ROP_1
205};
206
207static const GCOps sna_gc_ops;
208static const GCOps sna_gc_ops__cpu;
209static GCOps sna_gc_ops__tmp;
210static const GCFuncs sna_gc_funcs;
211static const GCFuncs sna_gc_funcs__cpu;
212
213static void
214sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect);
215
216static inline void region_set(RegionRec *r, const BoxRec *b)
217{
218	r->extents = *b;
219	r->data = NULL;
220}
221
222static inline bool region_maybe_clip(RegionRec *r, RegionRec *clip)
223{
224	if (clip->data && !RegionIntersect(r, r, clip))
225		return false;
226
227	return !box_empty(&r->extents);
228}
229
230static inline bool region_is_singular(const RegionRec *r)
231{
232	return r->data == NULL;
233}
234
235static inline bool region_is_unclipped(const RegionRec *r, int w, int h)
236{
237	return (region_is_singular(r) &&
238		w == r->extents.x2 - r->extents.x1 &&
239		h == r->extents.y2 - r->extents.y1);
240}
241
242typedef struct box32 {
243	int32_t x1, y1, x2, y2;
244} Box32Rec;
245
246#define PM_IS_SOLID(_draw, _pm) \
247	(((_pm) & FbFullMask((_draw)->depth)) == FbFullMask((_draw)->depth))
248
249#ifndef NDEBUG
250static void _assert_pixmap_contains_box(PixmapPtr pixmap, const BoxRec *box, const char *function)
251{
252	if (box->x1 < 0 || box->y1 < 0 ||
253	    box->x2 > pixmap->drawable.width ||
254	    box->y2 > pixmap->drawable.height)
255	{
256		FatalError("%s: damage box [(%d, %d), (%d, %d)] is beyond the pixmap=%ld size=%dx%d\n",
257			   function, box->x1, box->y1, box->x2, box->y2,
258			   pixmap->drawable.serialNumber,
259			   pixmap->drawable.width,
260			   pixmap->drawable.height);
261	}
262}
263
264static void
265_assert_pixmap_contains_damage(PixmapPtr pixmap, struct sna_damage *damage, const char *function)
266{
267	if (damage == NULL)
268		return;
269
270	_assert_pixmap_contains_box(pixmap, &DAMAGE_PTR(damage)->extents, function);
271}
272#define assert_pixmap_contains_damage(p,d) _assert_pixmap_contains_damage(p, d, __FUNCTION__)
273#else
274#define assert_pixmap_contains_damage(p,d)
275#endif
276
277#define __assert_pixmap_damage(p) do { \
278	struct sna_pixmap *priv__ = sna_pixmap(p); \
279	if (priv__) { \
280		assert(priv__->gpu_damage == NULL || priv__->gpu_bo); \
281		assert(priv__->gpu_bo == NULL || priv__->gpu_bo->refcnt); \
282		assert(priv__->cpu_bo == NULL || priv__->cpu_bo->refcnt); \
283		assert_pixmap_contains_damage(p, priv__->gpu_damage); \
284		assert_pixmap_contains_damage(p, priv__->cpu_damage); \
285		assert_pixmap_map(p, priv__); \
286	} \
287} while (0)
288
289#ifdef DEBUG_PIXMAP
290static void _assert_pixmap_contains_box_with_offset(PixmapPtr pixmap, const BoxRec *box, int dx, int dy, const char *function)
291{
292	BoxRec b = *box;
293	b.x1 += dx; b.x2 += dx;
294	b.y1 += dy; b.y2 += dy;
295	_assert_pixmap_contains_box(pixmap, &b, function);
296}
297
298static void _assert_pixmap_contains_boxes(PixmapPtr pixmap, const BoxRec *box, int n, int dx, int dy, const char *function)
299{
300	BoxRec extents;
301
302	extents = *box;
303	while (--n) {
304		++box;
305
306		if (box->x1 < extents.x1)
307			extents.x1 = box->x1;
308		if (box->x2 > extents.x2)
309			extents.x2 = box->x2;
310
311		if (box->y1 < extents.y1)
312			extents.y1 = box->y1;
313		if (box->y2 > extents.y2)
314			extents.y2 = box->y2;
315	}
316	extents.x1 += dx;
317	extents.x2 += dx;
318	extents.y1 += dy;
319	extents.y2 += dy;
320	_assert_pixmap_contains_box(pixmap, &extents, function);
321}
322
323
324static void _assert_pixmap_contains_points(PixmapPtr pixmap, const DDXPointRec *pt, int n, int dx, int dy, const char *function)
325{
326	BoxRec extents;
327
328	extents.x2 = extents.x1 = pt->x;
329	extents.y2 = extents.y1 = pt->y;
330	while (--n) {
331		++pt;
332
333		if (pt->x < extents.x1)
334			extents.x1 = pt->x;
335		else if (pt->x > extents.x2)
336			extents.x2 = pt->x;
337
338		if (pt->y < extents.y1)
339			extents.y1 = pt->y;
340		else if (pt->y > extents.y2)
341			extents.y2 = pt->y;
342	}
343	extents.x1 += dx;
344	extents.x2 += dx + 1;
345	extents.y1 += dy;
346	extents.y2 += dy + 1;
347	_assert_pixmap_contains_box(pixmap, &extents, function);
348}
349
350static void _assert_drawable_contains_box(DrawablePtr drawable, const BoxRec *box, const char *function)
351{
352	if (box->x1 < drawable->x ||
353	    box->y1 < drawable->y ||
354	    box->x2 > drawable->x + drawable->width ||
355	    box->y2 > drawable->y + drawable->height)
356	{
357		FatalError("%s: damage box is beyond the drawable: box=(%d, %d), (%d, %d), drawable=(%d, %d)x(%d, %d)\n",
358			   function,
359			   box->x1, box->y1, box->x2, box->y2,
360			   drawable->x, drawable->y,
361			   drawable->width, drawable->height);
362	}
363}
364
365static void assert_pixmap_damage(PixmapPtr p)
366{
367	struct sna_pixmap *priv;
368	RegionRec reg, cpu, gpu;
369
370	priv = sna_pixmap(p);
371	if (priv == NULL)
372		return;
373
374	__assert_pixmap_damage(p);
375
376	if (priv->clear) {
377		assert(DAMAGE_IS_ALL(priv->gpu_damage));
378		assert(priv->cpu_damage == NULL);
379	}
380
381	if (DAMAGE_IS_ALL(priv->gpu_damage) && DAMAGE_IS_ALL(priv->cpu_damage)) {
382		/* special upload buffer */
383		assert(priv->gpu_bo && priv->gpu_bo->proxy);
384		assert(priv->cpu_bo == NULL);
385		return;
386	}
387
388	assert(!DAMAGE_IS_ALL(priv->gpu_damage) || priv->cpu_damage == NULL);
389	assert(!DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL);
390
391	/* Avoid reducing damage to minimise interferrence */
392	RegionNull(&reg);
393	RegionNull(&gpu);
394	RegionNull(&cpu);
395
396	if (priv->gpu_damage)
397		_sna_damage_debug_get_region(DAMAGE_PTR(priv->gpu_damage), &gpu);
398
399	if (priv->cpu_damage)
400		_sna_damage_debug_get_region(DAMAGE_PTR(priv->cpu_damage), &cpu);
401
402	RegionIntersect(&reg, &cpu, &gpu);
403	assert(RegionNil(&reg));
404
405	RegionUninit(&reg);
406	RegionUninit(&gpu);
407	RegionUninit(&cpu);
408}
409
410#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__)
411#define assert_pixmap_contains_box_with_offset(p, b, dx, dy) _assert_pixmap_contains_box_with_offset(p, b, dx, dy, __FUNCTION__)
412#define assert_drawable_contains_box(d, b) _assert_drawable_contains_box(d, b, __FUNCTION__)
413#define assert_pixmap_contains_boxes(p, b, n, x, y) _assert_pixmap_contains_boxes(p, b, n, x, y, __FUNCTION__)
414#define assert_pixmap_contains_points(p, pt, n, x, y) _assert_pixmap_contains_points(p, pt, n, x, y, __FUNCTION__)
415
416#else
417#define assert_pixmap_contains_box(p, b)
418#define assert_pixmap_contains_box_with_offset(p, b, dx, dy)
419#define assert_pixmap_contains_boxes(p, b, n, x, y)
420#define assert_pixmap_contains_points(p, pt, n, x, y)
421#define assert_drawable_contains_box(d, b)
422#ifndef NDEBUG
423#define assert_pixmap_damage(p) __assert_pixmap_damage(p)
424#else
425#define assert_pixmap_damage(p)
426#endif
427#endif
428
429jmp_buf sigjmp[4];
430volatile sig_atomic_t sigtrap;
431
432static int sigtrap_handler(int sig)
433{
434	/* XXX rate-limited squawk? */
435	DBG(("%s(sig=%d) sigtrap=%d\n", __FUNCTION__, sig, sigtrap));
436	sna_threads_trap(sig);
437
438	if (sigtrap)
439		siglongjmp(sigjmp[--sigtrap], sig);
440
441	return -1;
442}
443
444static void sigtrap_init(void)
445{
446#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0)
447	OsRegisterSigWrapper(sigtrap_handler);
448#endif
449}
450
451inline static bool
452sna_fill_init_blt(struct sna_fill_op *fill,
453		  struct sna *sna,
454		  PixmapPtr pixmap,
455		  struct kgem_bo *bo,
456		  uint8_t alu,
457		  uint32_t pixel,
458		  unsigned flags)
459{
460	return sna->render.fill(sna, alu, pixmap, bo, pixel, flags, fill);
461}
462
463static bool
464sna_copy_init_blt(struct sna_copy_op *copy,
465		  struct sna *sna,
466		  PixmapPtr src, struct kgem_bo *src_bo,
467		  PixmapPtr dst, struct kgem_bo *dst_bo,
468		  uint8_t alu)
469{
470	memset(copy, 0, sizeof(*copy));
471	return sna->render.copy(sna, alu, src, src_bo, dst, dst_bo, copy);
472}
473
474static void sna_pixmap_free_gpu(struct sna *sna, struct sna_pixmap *priv)
475{
476	DBG(("%s: handle=%d (pinned? %d)\n", __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->pinned));
477	assert(priv->gpu_damage == NULL || priv->gpu_bo);
478
479	if (priv->cow)
480		sna_pixmap_undo_cow(sna, priv, MOVE_WRITE);
481	assert(priv->cow == NULL);
482
483	if (priv->move_to_gpu) {
484		sna_pixmap_discard_shadow_damage(priv, NULL);
485		priv->move_to_gpu(sna, priv, MOVE_WRITE);
486	}
487
488	sna_damage_destroy(&priv->gpu_damage);
489	priv->clear = false;
490
491	if (priv->gpu_bo) {
492		if (!priv->pinned) {
493			assert(!priv->flush);
494			assert(!priv->move_to_gpu);
495			sna_pixmap_unmap(priv->pixmap, priv);
496			kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
497			priv->gpu_bo = NULL;
498		} else
499			kgem_bo_undo(&sna->kgem, priv->gpu_bo);
500	}
501
502	/* and reset the upload counter */
503	priv->source_count = SOURCE_BIAS;
504}
505
506static bool must_check
507sna_pixmap_alloc_cpu(struct sna *sna,
508		     PixmapPtr pixmap,
509		     struct sna_pixmap *priv,
510		     unsigned flags)
511{
512	/* Restore after a GTT mapping? */
513	assert(priv->gpu_damage == NULL || priv->gpu_bo);
514	assert(!priv->shm);
515	if (priv->ptr)
516		goto done;
517
518	DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
519	assert(priv->stride);
520
521	if (priv->create & KGEM_CAN_CREATE_CPU) {
522		unsigned hint;
523
524		DBG(("%s: allocating CPU buffer (%dx%d)\n", __FUNCTION__,
525		     pixmap->drawable.width, pixmap->drawable.height));
526
527		hint = 0;
528		if ((flags & MOVE_ASYNC_HINT) == 0 &&
529		    ((flags & MOVE_READ) == 0 || (priv->gpu_damage && !priv->clear && !sna->kgem.has_llc)))
530			hint = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE;
531
532		priv->cpu_bo = kgem_create_cpu_2d(&sna->kgem,
533						  pixmap->drawable.width,
534						  pixmap->drawable.height,
535						  pixmap->drawable.bitsPerPixel,
536						  hint);
537		if (priv->cpu_bo) {
538			priv->ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo);
539			if (priv->ptr) {
540				DBG(("%s: allocated CPU handle=%d (snooped? %d)\n", __FUNCTION__,
541				     priv->cpu_bo->handle, priv->cpu_bo->snoop));
542				priv->stride = priv->cpu_bo->pitch;
543#ifdef DEBUG_MEMORY
544				sna->debug_memory.cpu_bo_allocs++;
545				sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo);
546#endif
547			} else {
548				kgem_bo_destroy(&sna->kgem, priv->cpu_bo);
549				priv->cpu_bo = NULL;
550			}
551		}
552	}
553
554	if (priv->ptr == NULL) {
555		DBG(("%s: allocating ordinary memory for shadow pixels [%d bytes]\n",
556		     __FUNCTION__, priv->stride * pixmap->drawable.height));
557		priv->ptr = malloc(priv->stride * pixmap->drawable.height);
558	}
559
560done:
561	assert(priv->stride);
562	assert(!priv->mapped);
563	pixmap->devPrivate.ptr = PTR(priv->ptr);
564	pixmap->devKind = priv->stride;
565	return priv->ptr != NULL;
566}
567
568static void __sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv)
569{
570	if (priv->cpu_bo) {
571		DBG(("%s: discarding CPU buffer, handle=%d, size=%d\n",
572		     __FUNCTION__, priv->cpu_bo->handle, kgem_bo_size(priv->cpu_bo)));
573#ifdef DEBUG_MEMORY
574		sna->debug_memory.cpu_bo_allocs--;
575		sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
576#endif
577		if (priv->cpu_bo->flush) {
578			assert(!priv->cpu_bo->reusable);
579			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
580			sna_accel_watch_flush(sna, -1);
581		}
582		kgem_bo_destroy(&sna->kgem, priv->cpu_bo);
583	} else if (!IS_STATIC_PTR(priv->ptr))
584		free(priv->ptr);
585}
586
587static bool sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv, bool active)
588{
589	if (active)
590		return false;
591
592	if (IS_STATIC_PTR(priv->ptr))
593		return false;
594
595	if (priv->ptr == NULL)
596		return true;
597
598	__sna_pixmap_free_cpu(sna, priv);
599
600	priv->cpu_bo = NULL;
601	priv->ptr = NULL;
602
603	if (priv->mapped == MAPPED_NONE)
604		priv->pixmap->devPrivate.ptr = NULL;
605
606	return true;
607}
608
609static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap)
610{
611#if DEFAULT_TILING == I915_TILING_NONE
612	return I915_TILING_NONE;
613#elif DEFAULT_TILING == I915_TILING_X
614	return I915_TILING_X;
615#else
616	/* Try to avoid hitting the Y-tiling GTT mapping bug on 855GM */
617	if (sna->kgem.gen == 021)
618		return I915_TILING_X;
619
620	/* Only on later generations was the render pipeline
621	 * more flexible than the BLT. So on gen2/3, prefer to
622	 * keep large objects accessible through the BLT.
623	 */
624	if (sna->kgem.gen < 040 &&
625	    (pixmap->drawable.width  > sna->render.max_3d_size ||
626	     pixmap->drawable.height > sna->render.max_3d_size))
627		return I915_TILING_X;
628
629	if (sna_damage_is_all(&sna_pixmap(pixmap)->cpu_damage,
630			      pixmap->drawable.width,
631			      pixmap->drawable.height)) {
632		DBG(("%s: entire source is damaged, using Y-tiling\n",
633		     __FUNCTION__));
634		sna_damage_destroy(&sna_pixmap(priv)->gpu_damage);
635		return I915_TILING_Y;
636	}
637
638	return I915_TILING_Y;
639#endif
640}
641
642pure static uint32_t sna_pixmap_default_tiling(struct sna *sna, PixmapPtr pixmap)
643{
644	/* Also adjust tiling if it is not supported or likely to
645	 * slow us down,
646	 */
647	return kgem_choose_tiling(&sna->kgem,
648				  default_tiling(sna, pixmap),
649				  pixmap->drawable.width,
650				  pixmap->drawable.height,
651				  pixmap->drawable.bitsPerPixel);
652}
653
654struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling)
655{
656	struct sna_pixmap *priv = sna_pixmap(pixmap);
657	struct sna *sna = to_sna_from_pixmap(pixmap);
658	struct kgem_bo *bo;
659	BoxRec box;
660
661	DBG(("%s: changing tiling %d -> %d for %dx%d pixmap\n",
662	     __FUNCTION__, priv->gpu_bo->tiling, tiling,
663	     pixmap->drawable.width, pixmap->drawable.height));
664	assert(priv->gpu_damage == NULL || priv->gpu_bo);
665
666	if (priv->pinned) {
667		DBG(("%s: can't convert pinned bo\n", __FUNCTION__));
668		return NULL;
669	}
670
671	if (wedged(sna)) {
672		DBG(("%s: can't convert bo, wedged\n", __FUNCTION__));
673		return NULL;
674	}
675
676	assert_pixmap_damage(pixmap);
677	assert(!priv->move_to_gpu);
678
679	bo = kgem_create_2d(&sna->kgem,
680			    pixmap->drawable.width,
681			    pixmap->drawable.height,
682			    pixmap->drawable.bitsPerPixel,
683			    tiling, 0);
684	if (bo == NULL) {
685		DBG(("%s: allocation failed\n", __FUNCTION__));
686		return NULL;
687	}
688
689	box.x1 = box.y1 = 0;
690	box.x2 = pixmap->drawable.width;
691	box.y2 = pixmap->drawable.height;
692
693	if (!sna->render.copy_boxes(sna, GXcopy,
694				    &pixmap->drawable, priv->gpu_bo, 0, 0,
695				    &pixmap->drawable, bo, 0, 0,
696				    &box, 1, 0)) {
697		DBG(("%s: copy failed\n", __FUNCTION__));
698		kgem_bo_destroy(&sna->kgem, bo);
699		return NULL;
700	}
701
702	sna_pixmap_unmap(pixmap, priv);
703	kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
704
705	return priv->gpu_bo = bo;
706}
707
708static inline void sna_set_pixmap(PixmapPtr pixmap, struct sna_pixmap *sna)
709{
710	((void **)__get_private(pixmap, sna_pixmap_key))[1] = sna;
711	assert(sna_pixmap(pixmap) == sna);
712}
713
714static struct sna_pixmap *
715_sna_pixmap_init(struct sna_pixmap *priv, PixmapPtr pixmap)
716{
717	list_init(&priv->flush_list);
718	list_init(&priv->cow_list);
719	priv->source_count = SOURCE_BIAS;
720	priv->pixmap = pixmap;
721
722	return priv;
723}
724
725static struct sna_pixmap *
726_sna_pixmap_reset(PixmapPtr pixmap)
727{
728	struct sna_pixmap *priv;
729
730	assert(pixmap->drawable.type == DRAWABLE_PIXMAP);
731	assert(pixmap->drawable.class == 0);
732	assert(pixmap->drawable.x == 0);
733	assert(pixmap->drawable.y == 0);
734
735	priv = sna_pixmap(pixmap);
736	assert(priv != NULL);
737
738	memset(priv, 0, sizeof(*priv));
739	return _sna_pixmap_init(priv, pixmap);
740}
741
742static struct sna_pixmap *sna_pixmap_attach(PixmapPtr pixmap)
743{
744	struct sna_pixmap *priv;
745
746	priv = calloc(1, sizeof(*priv));
747	if (!priv)
748		return NULL;
749
750	sna_set_pixmap(pixmap, priv);
751	return _sna_pixmap_init(priv, pixmap);
752}
753
754struct sna_pixmap *sna_pixmap_attach_to_bo(PixmapPtr pixmap, struct kgem_bo *bo)
755{
756	struct sna_pixmap *priv;
757
758	assert(bo);
759	assert(bo->proxy == NULL);
760	assert(bo->unique_id);
761
762	priv = sna_pixmap_attach(pixmap);
763	if (!priv)
764		return NULL;
765
766	DBG(("%s: attaching %s handle=%d to pixmap=%ld\n",
767	     __FUNCTION__, bo->snoop ? "CPU" : "GPU", bo->handle, pixmap->drawable.serialNumber));
768
769	assert(!priv->mapped);
770	assert(!priv->move_to_gpu);
771
772	if (bo->snoop) {
773		priv->cpu_bo = bo;
774		sna_damage_all(&priv->cpu_damage, pixmap);
775	} else {
776		priv->gpu_bo = bo;
777		sna_damage_all(&priv->gpu_damage, pixmap);
778	}
779
780	return priv;
781}
782
783static int bits_per_pixel(int depth)
784{
785	switch (depth) {
786	case 1: return 1;
787	case 4:
788	case 8: return 8;
789	case 15:
790	case 16: return 16;
791	case 24:
792	case 30:
793	case 32: return 32;
794	default: return 0;
795	}
796}
797static PixmapPtr
798create_pixmap(struct sna *sna, ScreenPtr screen,
799	      int width, int height, int depth,
800	      unsigned usage_hint)
801{
802	PixmapPtr pixmap;
803	size_t datasize;
804	size_t stride;
805	int base, bpp;
806
807	bpp = bits_per_pixel(depth);
808	if (bpp == 0)
809		return NullPixmap;
810
811	stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
812	if (stride / 4 > 32767 || height > 32767)
813		return NullPixmap;
814
815	datasize = height * stride;
816	base = screen->totalPixmapSize;
817	if (datasize && base & 15) {
818		int adjust = 16 - (base & 15);
819		base += adjust;
820		datasize += adjust;
821	}
822
823	DBG(("%s: allocating pixmap %dx%d, depth=%d, size=%ld\n",
824	     __FUNCTION__, width, height, depth, (long)datasize));
825	pixmap = AllocatePixmap(screen, datasize);
826	if (!pixmap)
827		return NullPixmap;
828
829	((void **)__get_private(pixmap, sna_pixmap_key))[0] = sna;
830	assert(to_sna_from_pixmap(pixmap) == sna);
831
832	pixmap->drawable.type = DRAWABLE_PIXMAP;
833	pixmap->drawable.class = 0;
834	pixmap->drawable.pScreen = screen;
835	pixmap->drawable.depth = depth;
836	pixmap->drawable.bitsPerPixel = bpp;
837	pixmap->drawable.id = 0;
838	pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
839	pixmap->drawable.x = 0;
840	pixmap->drawable.y = 0;
841	pixmap->drawable.width = width;
842	pixmap->drawable.height = height;
843	pixmap->devKind = stride;
844	pixmap->refcnt = 1;
845	pixmap->devPrivate.ptr = datasize ? (char *)pixmap + base : NULL;
846
847#ifdef COMPOSITE
848	pixmap->screen_x = 0;
849	pixmap->screen_y = 0;
850#endif
851
852	pixmap->usage_hint = usage_hint;
853#if DEBUG_MEMORY
854	sna->debug_memory.pixmap_allocs++;
855#endif
856
857	DBG(("%s: serial=%ld, usage=%d, %dx%d\n",
858	     __FUNCTION__,
859	     pixmap->drawable.serialNumber,
860	     pixmap->usage_hint,
861	     pixmap->drawable.width,
862	     pixmap->drawable.height));
863
864	return pixmap;
865}
866
867static PixmapPtr
868__pop_freed_pixmap(struct sna *sna)
869{
870	PixmapPtr pixmap;
871
872	assert(sna->freed_pixmap);
873
874	pixmap = sna->freed_pixmap;
875	sna->freed_pixmap = pixmap->devPrivate.ptr;
876
877	assert(pixmap->refcnt == 0);
878	assert(sna_pixmap(pixmap));
879	assert(sna_pixmap(pixmap)->header);
880
881#if DEBUG_MEMORY
882	sna->debug_memory.pixmap_cached--;
883#endif
884
885	return pixmap;
886}
887
888inline static PixmapPtr
889create_pixmap_hdr(struct sna *sna, ScreenPtr screen,
890		  int width, int height, int depth, int usage,
891		  struct sna_pixmap **priv)
892{
893	PixmapPtr pixmap;
894
895	if (sna->freed_pixmap == NULL) {
896		pixmap = create_pixmap(sna, screen, 0, 0, depth, usage);
897		if (pixmap == NullPixmap)
898			return NullPixmap;
899
900		*priv = sna_pixmap_attach(pixmap);
901		if (!*priv) {
902			FreePixmap(pixmap);
903			return NullPixmap;
904		}
905	} else {
906		pixmap = __pop_freed_pixmap(sna);
907		*priv = _sna_pixmap_reset(pixmap);
908
909		assert(pixmap->drawable.type == DRAWABLE_PIXMAP);
910		assert(pixmap->drawable.class == 0);
911		assert(pixmap->drawable.pScreen == screen);
912		assert(pixmap->drawable.x == 0);
913		assert(pixmap->drawable.y == 0);
914
915		pixmap->drawable.id = 0;
916
917		pixmap->drawable.depth = depth;
918		pixmap->drawable.bitsPerPixel = bits_per_pixel(depth);
919		pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
920
921		pixmap->devKind = 0;
922		pixmap->devPrivate.ptr = NULL;
923
924#ifdef COMPOSITE
925		pixmap->screen_x = 0;
926		pixmap->screen_y = 0;
927#endif
928
929#if DEBUG_MEMORY
930		sna->debug_memory.pixmap_allocs++;
931#endif
932
933		pixmap->refcnt = 1;
934	}
935
936	pixmap->drawable.width = width;
937	pixmap->drawable.height = height;
938	pixmap->usage_hint = usage;
939
940	(*priv)->header = true;
941	return pixmap;
942}
943
944static PixmapPtr
945sna_pixmap_create_shm(ScreenPtr screen,
946		      int width, int height, int depth,
947		      char *addr)
948{
949	struct sna *sna = to_sna_from_screen(screen);
950	int bpp = bits_per_pixel(depth);
951	int pitch = PixmapBytePad(width, depth);
952	struct sna_pixmap *priv;
953	PixmapPtr pixmap;
954
955	DBG(("%s(%dx%d, depth=%d, bpp=%d, pitch=%d)\n",
956	     __FUNCTION__, width, height, depth, bpp, pitch));
957
958	if (wedged(sna) || bpp == 0 || pitch*height < 4096) {
959fallback:
960		pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth);
961		if (pixmap == NULL)
962			return NULL;
963
964		if (!screen->ModifyPixmapHeader(pixmap, width, height, depth,
965						bpp, pitch, addr)) {
966			screen->DestroyPixmap(pixmap);
967			return NULL;
968		}
969
970		return pixmap;
971	}
972
973	pixmap = create_pixmap_hdr(sna, screen, width, height, depth, 0, &priv);
974	if (pixmap == NullPixmap) {
975		DBG(("%s: allocation failed\n", __FUNCTION__));
976		goto fallback;
977	}
978
979	priv->cpu_bo = kgem_create_map(&sna->kgem, addr, pitch*height, false);
980	if (priv->cpu_bo == NULL) {
981		DBG(("%s: mapping SHM segment failed\n", __FUNCTION__));
982		sna_pixmap_destroy(pixmap);
983		goto fallback;
984	}
985	priv->cpu_bo->pitch = pitch;
986	kgem_bo_mark_unreusable(priv->cpu_bo);
987	sna_accel_watch_flush(sna, 1);
988#ifdef DEBUG_MEMORY
989	sna->debug_memory.cpu_bo_allocs++;
990	sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo);
991#endif
992
993	/* Be wary as we cannot cache SHM Pixmap in our freed cache */
994	priv->header = false;
995	priv->cpu = true;
996	priv->shm = true;
997	priv->stride = pitch;
998	priv->ptr = MAKE_STATIC_PTR(addr);
999	sna_damage_all(&priv->cpu_damage, pixmap);
1000
1001	pixmap->devKind = pitch;
1002	pixmap->devPrivate.ptr = addr;
1003
1004	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
1005	     __FUNCTION__,
1006	     pixmap->drawable.serialNumber,
1007	     pixmap->drawable.width,
1008	     pixmap->drawable.height,
1009	     pixmap->usage_hint));
1010	return pixmap;
1011}
1012
1013PixmapPtr
1014sna_pixmap_create_unattached(ScreenPtr screen,
1015			     int width, int height, int depth)
1016{
1017	return create_pixmap(to_sna_from_screen(screen),
1018			     screen, width, height, depth,
1019			     -1);
1020}
1021
1022static PixmapPtr
1023sna_pixmap_create_scratch(ScreenPtr screen,
1024			  int width, int height, int depth,
1025			  uint32_t tiling)
1026{
1027	struct sna *sna = to_sna_from_screen(screen);
1028	struct sna_pixmap *priv;
1029	PixmapPtr pixmap;
1030	int bpp;
1031
1032	DBG(("%s(%d, %d, %d, tiling=%d)\n", __FUNCTION__,
1033	     width, height, depth, tiling));
1034
1035	bpp = bits_per_pixel(depth);
1036	if (tiling == I915_TILING_Y &&
1037	    (sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0)
1038		tiling = I915_TILING_X;
1039
1040	if (tiling == I915_TILING_Y &&
1041	    (width > sna->render.max_3d_size ||
1042	     height > sna->render.max_3d_size))
1043		tiling = I915_TILING_X;
1044
1045	tiling = kgem_choose_tiling(&sna->kgem, tiling, width, height, bpp);
1046
1047	/* you promise never to access this via the cpu... */
1048	pixmap = create_pixmap_hdr(sna, screen, width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH, &priv);
1049	if (pixmap == NullPixmap)
1050		return NullPixmap;
1051
1052	priv->stride = PixmapBytePad(width, depth);
1053
1054	priv->gpu_bo = kgem_create_2d(&sna->kgem,
1055				      width, height, bpp, tiling,
1056				      CREATE_TEMPORARY);
1057	if (priv->gpu_bo == NULL) {
1058		free(priv);
1059		FreePixmap(pixmap);
1060		return NullPixmap;
1061	}
1062
1063	sna_damage_all(&priv->gpu_damage, pixmap);
1064
1065	assert(to_sna_from_pixmap(pixmap) == sna);
1066	assert(pixmap->drawable.pScreen == screen);
1067	assert(pixmap->refcnt == 1);
1068
1069	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
1070	     __FUNCTION__,
1071	     pixmap->drawable.serialNumber,
1072	     pixmap->drawable.width,
1073	     pixmap->drawable.height,
1074	     pixmap->usage_hint));
1075	return pixmap;
1076}
1077
1078#ifdef CREATE_PIXMAP_USAGE_SHARED
1079static Bool
1080sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle)
1081{
1082	struct sna *sna = to_sna_from_pixmap(pixmap);
1083	struct sna_pixmap *priv;
1084	int fd;
1085
1086	DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
1087
1088	priv = sna_pixmap_move_to_gpu(pixmap,
1089				      MOVE_READ | MOVE_WRITE | __MOVE_DRI | __MOVE_FORCE);
1090	if (priv == NULL)
1091		return FALSE;
1092
1093	assert(!priv->shm);
1094	assert(priv->gpu_bo);
1095	assert(priv->stride);
1096
1097	/* XXX negotiate format and stride restrictions */
1098	if (priv->gpu_bo->tiling != I915_TILING_NONE ||
1099	    priv->gpu_bo->pitch & 255) {
1100		struct kgem_bo *bo;
1101		BoxRec box;
1102
1103		DBG(("%s: removing tiling %d, and aligning pitch  for %dx%d pixmap=%ld\n",
1104		     __FUNCTION__, priv->gpu_bo->tiling,
1105		     pixmap->drawable.width, pixmap->drawable.height,
1106		     pixmap->drawable.serialNumber));
1107
1108		if (priv->pinned) {
1109			DBG(("%s: can't convert pinned bo\n", __FUNCTION__));
1110			return FALSE;
1111		}
1112
1113		assert_pixmap_damage(pixmap);
1114
1115		bo = kgem_create_2d(&sna->kgem,
1116				    pixmap->drawable.width,
1117				    pixmap->drawable.height,
1118				    pixmap->drawable.bitsPerPixel,
1119				    I915_TILING_NONE,
1120				    CREATE_GTT_MAP | CREATE_PRIME);
1121		if (bo == NULL) {
1122			DBG(("%s: allocation failed\n", __FUNCTION__));
1123			return FALSE;
1124		}
1125
1126		box.x1 = box.y1 = 0;
1127		box.x2 = pixmap->drawable.width;
1128		box.y2 = pixmap->drawable.height;
1129
1130		assert(!wedged(sna)); /* XXX */
1131		if (!sna->render.copy_boxes(sna, GXcopy,
1132					    &pixmap->drawable, priv->gpu_bo, 0, 0,
1133					    &pixmap->drawable, bo, 0, 0,
1134					    &box, 1, 0)) {
1135			DBG(("%s: copy failed\n", __FUNCTION__));
1136			kgem_bo_destroy(&sna->kgem, bo);
1137			return FALSE;
1138		}
1139
1140		sna_pixmap_unmap(pixmap, priv);
1141		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1142		priv->gpu_bo = bo;
1143	}
1144	assert(priv->gpu_bo->tiling == I915_TILING_NONE);
1145	assert((priv->gpu_bo->pitch & 255) == 0);
1146
1147	/* And export the bo->pitch via pixmap->devKind */
1148	if (!priv->mapped) {
1149		void *ptr;
1150
1151		ptr = kgem_bo_map__async(&sna->kgem, priv->gpu_bo);
1152		if (ptr == NULL)
1153			return FALSE;
1154
1155		pixmap->devPrivate.ptr = ptr;
1156		pixmap->devKind = priv->gpu_bo->pitch;
1157		priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
1158	}
1159	assert_pixmap_map(pixmap, priv);
1160
1161	fd = kgem_bo_export_to_prime(&sna->kgem, priv->gpu_bo);
1162	if (fd == -1)
1163		return FALSE;
1164
1165	priv->pinned |= PIN_PRIME;
1166
1167	*fd_handle = (void *)(intptr_t)fd;
1168	return TRUE;
1169}
1170
1171static Bool
1172sna_set_shared_pixmap_backing(PixmapPtr pixmap, void *fd_handle)
1173{
1174	struct sna *sna = to_sna_from_pixmap(pixmap);
1175	struct sna_pixmap *priv;
1176	struct kgem_bo *bo;
1177
1178	DBG(("%s: pixmap=%ld, size=%dx%d, depth=%d/%d, stride=%d\n",
1179	     __FUNCTION__, pixmap->drawable.serialNumber,
1180	     pixmap->drawable.width, pixmap->drawable.height,
1181	     pixmap->drawable.depth, pixmap->drawable.bitsPerPixel,
1182	     pixmap->devKind));
1183
1184	priv = sna_pixmap(pixmap);
1185	if (priv == NULL)
1186		return FALSE;
1187
1188	assert(!priv->pinned);
1189	assert(priv->gpu_bo == NULL);
1190	assert(priv->cpu_bo == NULL);
1191	assert(priv->cpu_damage == NULL);
1192	assert(priv->gpu_damage == NULL);
1193
1194	bo = kgem_create_for_prime(&sna->kgem,
1195				   (intptr_t)fd_handle,
1196				   pixmap->devKind * pixmap->drawable.height);
1197	if (bo == NULL)
1198		return FALSE;
1199
1200	sna_damage_all(&priv->gpu_damage, pixmap);
1201
1202	bo->pitch = pixmap->devKind;
1203	priv->stride = pixmap->devKind;
1204
1205	assert(!priv->mapped);
1206	priv->gpu_bo = bo;
1207	priv->pinned |= PIN_PRIME;
1208
1209	close((intptr_t)fd_handle);
1210	return TRUE;
1211}
1212
1213static PixmapPtr
1214sna_create_pixmap_shared(struct sna *sna, ScreenPtr screen,
1215			 int width, int height, int depth)
1216{
1217	PixmapPtr pixmap;
1218	struct sna_pixmap *priv;
1219
1220	DBG(("%s: depth=%d\n", __FUNCTION__, depth));
1221
1222	/* Create a stub to be attached later */
1223	pixmap = create_pixmap_hdr(sna, screen,
1224				   width, height, depth, 0,
1225				   &priv);
1226	if (pixmap == NullPixmap)
1227		return NullPixmap;
1228
1229	assert(!priv->mapped);
1230	priv->stride = 0;
1231	priv->create = 0;
1232
1233	if (width|height) {
1234		priv->gpu_bo = kgem_create_2d(&sna->kgem,
1235					      width, height,
1236					      pixmap->drawable.bitsPerPixel,
1237					      I915_TILING_NONE,
1238					      CREATE_GTT_MAP | CREATE_PRIME);
1239		if (priv->gpu_bo == NULL) {
1240			free(priv);
1241			FreePixmap(pixmap);
1242			return NullPixmap;
1243		}
1244
1245		/* minimal interface for sharing is linear, 256 byte pitch */
1246		assert(priv->gpu_bo->tiling == I915_TILING_NONE);
1247		assert((priv->gpu_bo->pitch & 255) == 0);
1248
1249		pixmap->devPrivate.ptr =
1250			kgem_bo_map__async(&sna->kgem, priv->gpu_bo);
1251		if (pixmap->devPrivate.ptr == NULL) {
1252			kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1253			free(priv);
1254			FreePixmap(pixmap);
1255			return FALSE;
1256		}
1257
1258		pixmap->devKind = priv->gpu_bo->pitch;
1259
1260		priv->stride = priv->gpu_bo->pitch;
1261		priv->mapped = pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
1262		assert_pixmap_map(pixmap, priv);
1263
1264		sna_damage_all(&priv->gpu_damage, pixmap);
1265	}
1266
1267	return pixmap;
1268}
1269#endif
1270
1271static PixmapPtr sna_create_pixmap(ScreenPtr screen,
1272				   int width, int height, int depth,
1273				   unsigned int usage)
1274{
1275	struct sna *sna = to_sna_from_screen(screen);
1276	PixmapPtr pixmap;
1277	struct sna_pixmap *priv;
1278	unsigned flags;
1279	int pad;
1280	void *ptr;
1281
1282	DBG(("%s(%d, %d, %d, usage=%x)\n", __FUNCTION__,
1283	     width, height, depth, usage));
1284
1285#ifdef CREATE_PIXMAP_USAGE_SHARED
1286	if (usage == CREATE_PIXMAP_USAGE_SHARED)
1287		return sna_create_pixmap_shared(sna, screen,
1288						width, height, depth);
1289#endif
1290
1291	if ((width|height) == 0) {
1292		usage = -1;
1293		goto fallback;
1294	}
1295	assert(width && height);
1296
1297	flags = kgem_can_create_2d(&sna->kgem, width, height, depth);
1298	if (flags == 0) {
1299		DBG(("%s: can not use GPU, just creating shadow\n",
1300		     __FUNCTION__));
1301		goto fallback;
1302	}
1303
1304	if (unlikely((sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0))
1305		flags &= ~KGEM_CAN_CREATE_GPU;
1306	if (wedged(sna))
1307		flags &= ~KGEM_CAN_CREATE_GTT;
1308
1309	DBG(("%s: usage=%d, flags=%x\n", __FUNCTION__, usage, flags));
1310	switch (usage) {
1311	case CREATE_PIXMAP_USAGE_SCRATCH:
1312		if (flags & KGEM_CAN_CREATE_GPU)
1313			return sna_pixmap_create_scratch(screen,
1314							 width, height, depth,
1315							 I915_TILING_X);
1316		else
1317			goto fallback;
1318
1319	case SNA_CREATE_SCRATCH:
1320		if (flags & (KGEM_CAN_CREATE_CPU | KGEM_CAN_CREATE_GPU))
1321			return sna_pixmap_create_scratch(screen,
1322							 width, height, depth,
1323							 I915_TILING_Y);
1324		else
1325			return NullPixmap;
1326	}
1327
1328	if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE)
1329		flags &= ~KGEM_CAN_CREATE_GPU;
1330	if (usage == CREATE_PIXMAP_USAGE_BACKING_PIXMAP)
1331		usage = 0;
1332
1333	pad = PixmapBytePad(width, depth);
1334	if (pad * height < 4096) {
1335		DBG(("%s: small buffer [%d], attaching to shadow pixmap\n",
1336		     __FUNCTION__, pad * height));
1337		pixmap = create_pixmap(sna, screen,
1338				       width, height, depth, usage);
1339		if (pixmap == NullPixmap)
1340			return NullPixmap;
1341
1342		ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr);
1343		pad = pixmap->devKind;
1344		flags &= ~(KGEM_CAN_CREATE_GPU | KGEM_CAN_CREATE_CPU);
1345
1346		priv = sna_pixmap_attach(pixmap);
1347		if (priv == NULL) {
1348			free(pixmap);
1349			goto fallback;
1350		}
1351	} else {
1352		DBG(("%s: creating GPU pixmap %dx%d, stride=%d, flags=%x\n",
1353		     __FUNCTION__, width, height, pad, flags));
1354
1355		pixmap = create_pixmap_hdr(sna, screen, width, height, depth, usage, &priv);
1356		if (pixmap == NullPixmap)
1357			return NullPixmap;
1358
1359		ptr = NULL;
1360	}
1361
1362	priv->stride = pad;
1363	priv->create = flags;
1364	priv->ptr = ptr;
1365
1366	assert(to_sna_from_pixmap(pixmap) == sna);
1367	assert(pixmap->drawable.pScreen == screen);
1368	assert(pixmap->refcnt == 1);
1369
1370	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
1371	     __FUNCTION__,
1372	     pixmap->drawable.serialNumber,
1373	     pixmap->drawable.width,
1374	     pixmap->drawable.height,
1375	     pixmap->usage_hint));
1376	return pixmap;
1377
1378fallback:
1379	return create_pixmap(sna, screen, width, height, depth, usage);
1380}
1381
1382void sna_add_flush_pixmap(struct sna *sna,
1383			  struct sna_pixmap *priv,
1384			  struct kgem_bo *bo)
1385{
1386	DBG(("%s: marking pixmap=%ld for flushing\n",
1387	     __FUNCTION__, priv->pixmap->drawable.serialNumber));
1388	assert(bo);
1389	assert(bo->flush);
1390	assert(priv->gpu_damage == NULL || priv->gpu_bo);
1391	list_move(&priv->flush_list, &sna->flush_pixmaps);
1392
1393	if (bo->exec == NULL && kgem_is_idle(&sna->kgem)) {
1394		DBG(("%s: new flush bo, flushin before\n", __FUNCTION__));
1395		kgem_submit(&sna->kgem);
1396	}
1397}
1398
1399static void __sna_free_pixmap(struct sna *sna,
1400			      PixmapPtr pixmap,
1401			      struct sna_pixmap *priv)
1402{
1403	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber));
1404	list_del(&priv->flush_list);
1405
1406	assert(priv->gpu_damage == NULL);
1407	assert(priv->cpu_damage == NULL);
1408
1409	__sna_pixmap_free_cpu(sna, priv);
1410
1411	if (priv->header) {
1412		assert(pixmap->drawable.pScreen == sna->scrn->pScreen);
1413		assert(!priv->shm);
1414		pixmap->devPrivate.ptr = sna->freed_pixmap;
1415		sna->freed_pixmap = pixmap;
1416#if DEBUG_MEMORY
1417		sna->debug_memory.pixmap_cached++;
1418#endif
1419	} else {
1420		free(priv);
1421		FreePixmap(pixmap);
1422	}
1423}
1424
1425static Bool sna_destroy_pixmap(PixmapPtr pixmap)
1426{
1427	struct sna *sna;
1428	struct sna_pixmap *priv;
1429
1430	assert(pixmap->refcnt > 0);
1431	if (--pixmap->refcnt)
1432		return TRUE;
1433
1434#if DEBUG_MEMORY
1435	to_sna_from_pixmap(pixmap)->debug_memory.pixmap_allocs--;
1436#endif
1437
1438	priv = sna_pixmap(pixmap);
1439	DBG(("%s: pixmap=%ld, attached?=%d\n",
1440	     __FUNCTION__, pixmap->drawable.serialNumber, priv != NULL));
1441	if (priv == NULL) {
1442		FreePixmap(pixmap);
1443		return TRUE;
1444	}
1445
1446	assert_pixmap_damage(pixmap);
1447	sna = to_sna_from_pixmap(pixmap);
1448
1449	sna_damage_destroy(&priv->gpu_damage);
1450	sna_damage_destroy(&priv->cpu_damage);
1451
1452	list_del(&priv->cow_list);
1453	if (priv->cow) {
1454		struct sna_cow *cow = COW(priv->cow);
1455		DBG(("%s: pixmap=%ld discarding cow, refcnt=%d\n",
1456		     __FUNCTION__, pixmap->drawable.serialNumber, cow->refcnt));
1457		assert(cow->refcnt);
1458		if (!--cow->refcnt)
1459			free(cow);
1460		priv->cow = NULL;
1461	} else
1462		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
1463
1464	if (priv->move_to_gpu)
1465		(void)priv->move_to_gpu(sna, priv, 0);
1466
1467	/* Always release the gpu bo back to the lower levels of caching */
1468	if (priv->gpu_bo) {
1469		sna_pixmap_unmap(pixmap, priv);
1470		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1471		priv->gpu_bo = NULL;
1472	}
1473
1474	if (priv->shm && kgem_bo_is_busy(priv->cpu_bo)) {
1475		DBG(("%s: deferring release of active SHM pixmap=%ld\n",
1476		     __FUNCTION__, pixmap->drawable.serialNumber));
1477		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
1478		kgem_bo_submit(&sna->kgem, priv->cpu_bo); /* XXX ShmDetach */
1479	} else
1480		__sna_free_pixmap(sna, pixmap, priv);
1481	return TRUE;
1482}
1483
1484void sna_pixmap_destroy(PixmapPtr pixmap)
1485{
1486	assert(pixmap->refcnt == 1);
1487	assert(sna_pixmap(pixmap) == NULL || sna_pixmap(pixmap)->header == true);
1488
1489	sna_destroy_pixmap(pixmap);
1490}
1491
1492static inline bool has_coherent_map(struct sna *sna,
1493				    struct kgem_bo *bo,
1494				    unsigned flags)
1495{
1496	assert(bo);
1497
1498	if (kgem_bo_mapped(&sna->kgem, bo))
1499		return true;
1500
1501	if (bo->tiling == I915_TILING_Y)
1502		return false;
1503
1504	return kgem_bo_can_map__cpu(&sna->kgem, bo, flags & MOVE_WRITE);
1505}
1506
1507static inline bool has_coherent_ptr(struct sna *sna, struct sna_pixmap *priv, unsigned flags)
1508{
1509	if (priv == NULL)
1510		return true;
1511
1512	if (flags & MOVE_ASYNC_HINT) {
1513		/* Not referencing the pointer itself, so do not care */
1514		return true;
1515	}
1516
1517	if (!priv->mapped) {
1518		if (!priv->cpu_bo)
1519			return true;
1520
1521		assert(!priv->cpu_bo->needs_flush);
1522		assert(priv->pixmap->devKind == priv->cpu_bo->pitch);
1523		return priv->pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu);
1524	}
1525
1526	assert(!priv->move_to_gpu || (flags & MOVE_WRITE) == 0);
1527
1528	assert_pixmap_map(priv->pixmap, priv);
1529	assert(priv->pixmap->devKind == priv->gpu_bo->pitch);
1530
1531	if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu)) {
1532		assert(priv->mapped == MAPPED_CPU);
1533
1534		if (priv->gpu_bo->tiling != I915_TILING_NONE)
1535			return false;
1536
1537		return flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE);
1538	}
1539
1540	if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__gtt)) {
1541		assert(priv->mapped == MAPPED_GTT);
1542
1543		if (priv->gpu_bo->tiling == I915_TILING_Y && sna->kgem.gen == 0x21)
1544			return false;
1545
1546		return true;
1547	}
1548
1549	return false;
1550}
1551
1552static inline bool pixmap_inplace(struct sna *sna,
1553				  PixmapPtr pixmap,
1554				  struct sna_pixmap *priv,
1555				  unsigned flags)
1556{
1557	if (FORCE_INPLACE)
1558		return FORCE_INPLACE > 0;
1559
1560	if (wedged(sna) && !priv->pinned) {
1561		DBG(("%s: no, wedged and unpinned; pull pixmap back to CPU\n", __FUNCTION__));
1562		return false;
1563	}
1564
1565	if (priv->move_to_gpu && flags & MOVE_WRITE)
1566		return false;
1567
1568	if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) {
1569		if ((flags & (MOVE_WRITE | MOVE_READ)) == (MOVE_WRITE | MOVE_READ)) {
1570			DBG(("%s: no, GPU bo is busy\n", __FUNCTION__));
1571			return false;
1572		}
1573
1574		if ((flags & MOVE_READ) == 0) {
1575			DBG(("%s: %s, GPU bo is busy, but not reading\n", __FUNCTION__, priv->pinned ? "no" : "yes"));
1576			return !priv->pinned;
1577		}
1578	}
1579
1580	if (priv->mapped) {
1581		DBG(("%s: %s, already mapped\n", __FUNCTION__, has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no"));
1582		return has_coherent_map(sna, priv->gpu_bo, flags);
1583	}
1584
1585	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) {
1586		DBG(("%s: yes, has CPU bo and is active on CPU\n", __FUNCTION__));
1587		return true;
1588	}
1589
1590	if (priv->cpu_bo && priv->cpu) {
1591		DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__));
1592		return false;
1593	}
1594
1595	if (flags & MOVE_READ &&
1596	    (priv->cpu || priv->cpu_damage || priv->gpu_damage == NULL)) {
1597		DBG(("%s:, no, reading and has CPU damage\n", __FUNCTION__));
1598		return false;
1599	}
1600
1601	return (priv->stride * pixmap->drawable.height >> 12) >
1602		sna->kgem.half_cpu_cache_pages;
1603}
1604
1605static bool sna_pixmap_alloc_gpu(struct sna *sna,
1606				 PixmapPtr pixmap,
1607				 struct sna_pixmap *priv,
1608				 unsigned flags)
1609{
1610	uint32_t tiling;
1611
1612	/* Use tiling by default, but disable per user request */
1613	if (pixmap->usage_hint == SNA_CREATE_FB && (sna->flags & SNA_LINEAR_FB) == 0) {
1614		flags |= CREATE_SCANOUT;
1615		tiling = -I915_TILING_X;
1616	} else
1617		tiling = sna_pixmap_default_tiling(sna, pixmap);
1618
1619	DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
1620
1621	priv->gpu_bo = kgem_create_2d(&sna->kgem,
1622				      pixmap->drawable.width,
1623				      pixmap->drawable.height,
1624				      pixmap->drawable.bitsPerPixel,
1625				      tiling, flags);
1626	return priv->gpu_bo != NULL;
1627}
1628
1629static bool
1630sna_pixmap_create_mappable_gpu(PixmapPtr pixmap,
1631			       bool can_replace)
1632{
1633	struct sna *sna = to_sna_from_pixmap(pixmap);
1634	struct sna_pixmap *priv = sna_pixmap(pixmap);
1635
1636	if (wedged(sna))
1637		goto out;
1638
1639	if ((priv->create & KGEM_CAN_CREATE_GTT) == 0)
1640		goto out;
1641
1642	assert_pixmap_damage(pixmap);
1643
1644	if (can_replace && priv->gpu_bo &&
1645	    (!kgem_bo_can_map(&sna->kgem, priv->gpu_bo) ||
1646	     __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) {
1647		if (priv->pinned)
1648			return false;
1649
1650		DBG(("%s: discard busy GPU bo\n", __FUNCTION__));
1651		sna_pixmap_free_gpu(sna, priv);
1652	}
1653
1654	if (priv->gpu_bo == NULL) {
1655		assert_pixmap_damage(pixmap);
1656		assert(priv->gpu_damage == NULL);
1657		sna_pixmap_alloc_gpu(sna, pixmap, priv, CREATE_GTT_MAP | CREATE_INACTIVE);
1658	}
1659
1660out:
1661	if (priv->gpu_bo == NULL)
1662		return false;
1663
1664	return (kgem_bo_can_map(&sna->kgem, priv->gpu_bo) &&
1665		!kgem_bo_is_busy(priv->gpu_bo));
1666}
1667
1668static inline bool gpu_bo_download(struct sna *sna,
1669				   struct sna_pixmap *priv,
1670				   int n, const BoxRec *box,
1671				   bool idle)
1672{
1673	char *src;
1674
1675	if (!USE_INPLACE)
1676		return false;
1677
1678	switch (priv->gpu_bo->tiling) {
1679	case I915_TILING_Y:
1680		return false;
1681	case I915_TILING_X:
1682		if (!sna->kgem.memcpy_from_tiled_x)
1683			return false;
1684	default:
1685		break;
1686	}
1687
1688	if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC))
1689		return false;
1690
1691	if (idle) {
1692		if (__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
1693			return false;
1694
1695		if (priv->cpu_bo && __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo))
1696			return false;
1697	}
1698
1699	src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
1700	if (src == NULL)
1701		return false;
1702
1703	kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC);
1704
1705	if (priv->cpu_bo)
1706		kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
1707	assert(has_coherent_ptr(sna, priv, MOVE_WRITE));
1708
1709	if (sigtrap_get())
1710		return false;
1711
1712	if (priv->gpu_bo->tiling) {
1713		int bpp = priv->pixmap->drawable.bitsPerPixel;
1714		void *dst = priv->pixmap->devPrivate.ptr;
1715		int dst_pitch = priv->pixmap->devKind;
1716
1717		DBG(("%s: download through a tiled CPU map\n", __FUNCTION__));
1718		do {
1719			DBG(("%s: box (%d, %d), (%d, %d)\n",
1720			     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
1721			memcpy_from_tiled_x(&sna->kgem, src, dst, bpp,
1722					    priv->gpu_bo->pitch, dst_pitch,
1723					    box->x1, box->y1,
1724					    box->x1, box->y1,
1725					    box->x2 - box->x1, box->y2 - box->y1);
1726			box++;
1727		} while (--n);
1728	} else {
1729		int bpp = priv->pixmap->drawable.bitsPerPixel;
1730		void *dst = priv->pixmap->devPrivate.ptr;
1731		int dst_pitch = priv->pixmap->devKind;
1732
1733		DBG(("%s: download through a linear CPU map\n", __FUNCTION__));
1734		do {
1735			DBG(("%s: box (%d, %d), (%d, %d)\n",
1736			     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
1737			memcpy_blt(src, dst, bpp,
1738				   priv->gpu_bo->pitch, dst_pitch,
1739				   box->x1, box->y1,
1740				   box->x1, box->y1,
1741				   box->x2 - box->x1, box->y2 - box->y1);
1742			box++;
1743		} while (--n);
1744	}
1745
1746	sigtrap_put();
1747	return true;
1748}
1749
1750static inline bool cpu_bo_download(struct sna *sna,
1751				   struct sna_pixmap *priv,
1752				   int n, const BoxRec *box)
1753{
1754	if (DBG_NO_CPU_DOWNLOAD)
1755		return false;
1756
1757	if (wedged(sna))
1758		return false;
1759
1760	if (priv->cpu_bo == NULL || !sna->kgem.can_blt_cpu)
1761		return false;
1762
1763	if (!kgem_bo_is_busy(priv->gpu_bo) && !kgem_bo_is_busy(priv->cpu_bo)) {
1764		/* Is it worth detiling? */
1765		assert(box[0].y1 < box[n-1].y2);
1766		if (kgem_bo_can_map(&sna->kgem, priv->gpu_bo) &&
1767		    (box[n-1].y2 - box[0].y1 - 1) * priv->gpu_bo->pitch < 4096) {
1768			DBG(("%s: no, tiny transfer (height=%d, pitch=%d) expect to read inplace\n",
1769			     __FUNCTION__, box[n-1].y2-box[0].y1, priv->gpu_bo->pitch));
1770			return false;
1771		}
1772	}
1773
1774	DBG(("%s: using GPU write to CPU bo for download from GPU\n", __FUNCTION__));
1775	return sna->render.copy_boxes(sna, GXcopy,
1776				      &priv->pixmap->drawable, priv->gpu_bo, 0, 0,
1777				      &priv->pixmap->drawable, priv->cpu_bo, 0, 0,
1778				      box, n, COPY_LAST);
1779}
1780
1781static void download_boxes(struct sna *sna,
1782			   struct sna_pixmap *priv,
1783			   int n, const BoxRec *box)
1784{
1785	bool ok;
1786
1787	DBG(("%s: nbox=%d\n", __FUNCTION__, n));
1788
1789	ok = gpu_bo_download(sna, priv, n, box, true);
1790	if (!ok)
1791		ok = cpu_bo_download(sna, priv, n, box);
1792	if (!ok)
1793		ok = gpu_bo_download(sna, priv, n, box, false);
1794	if (!ok) {
1795		if (priv->cpu_bo)
1796			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
1797		assert(priv->mapped == MAPPED_NONE);
1798		assert(has_coherent_ptr(sna, priv, MOVE_WRITE));
1799		sna_read_boxes(sna, priv->pixmap, priv->gpu_bo, box, n);
1800	}
1801}
1802
1803static inline bool use_cpu_bo_for_upload(struct sna *sna,
1804					 struct sna_pixmap *priv,
1805					 unsigned flags)
1806{
1807	if (DBG_NO_CPU_UPLOAD)
1808		return false;
1809
1810	if (wedged(sna))
1811		return false;
1812
1813	if (priv->cpu_bo == NULL)
1814		return false;
1815
1816	DBG(("%s? flags=%x, gpu busy?=%d, cpu busy?=%d\n", __FUNCTION__,
1817	     flags,
1818	     kgem_bo_is_busy(priv->gpu_bo),
1819	     kgem_bo_is_busy(priv->cpu_bo)));
1820
1821	if (!priv->cpu)
1822		return true;
1823
1824	if (flags & (MOVE_WRITE | MOVE_ASYNC_HINT))
1825		return true;
1826
1827	if (priv->gpu_bo->tiling)
1828		return true;
1829
1830	return kgem_bo_is_busy(priv->gpu_bo) || kgem_bo_is_busy(priv->cpu_bo);
1831}
1832
1833bool
1834sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags)
1835{
1836	struct sna_cow *cow = COW(priv->cow);
1837
1838	DBG(("%s: pixmap=%ld, handle=%d [refcnt=%d], cow refcnt=%d, flags=%x\n",
1839	     __FUNCTION__,
1840	     priv->pixmap->drawable.serialNumber,
1841	     priv->gpu_bo->handle,
1842	     priv->gpu_bo->refcnt,
1843	     cow->refcnt,
1844	     flags));
1845
1846	assert(priv->gpu_bo == cow->bo);
1847	assert(cow->refcnt);
1848
1849	if (flags && (flags & MOVE_WRITE) == 0 && IS_COW_OWNER(priv->cow))
1850		return true;
1851
1852	if (!IS_COW_OWNER(priv->cow))
1853		list_del(&priv->cow_list);
1854
1855	if (!--cow->refcnt) {
1856		DBG(("%s: freeing cow\n", __FUNCTION__));
1857		assert(list_is_empty(&cow->list));
1858		free(cow);
1859	} else if (IS_COW_OWNER(priv->cow) && priv->pinned) {
1860		PixmapPtr pixmap = priv->pixmap;
1861		struct kgem_bo *bo;
1862		BoxRec box;
1863
1864		DBG(("%s: copying the Holy cow\n", __FUNCTION__));
1865
1866		box.x1 = box.y1 = 0;
1867		box.x2 = pixmap->drawable.width;
1868		box.y2 = pixmap->drawable.height;
1869
1870		bo = kgem_create_2d(&sna->kgem,
1871				    box.x2, box.y2,
1872				    pixmap->drawable.bitsPerPixel,
1873				    sna_pixmap_default_tiling(sna, pixmap),
1874				    0);
1875		if (bo == NULL) {
1876			cow->refcnt++;
1877			DBG(("%s: allocation failed\n", __FUNCTION__));
1878			return false;
1879		}
1880
1881		if (!sna->render.copy_boxes(sna, GXcopy,
1882					    &pixmap->drawable, priv->gpu_bo, 0, 0,
1883					    &pixmap->drawable, bo, 0, 0,
1884					    &box, 1, 0)) {
1885			DBG(("%s: copy failed\n", __FUNCTION__));
1886			kgem_bo_destroy(&sna->kgem, bo);
1887			cow->refcnt++;
1888			return false;
1889		}
1890
1891		assert(!list_is_empty(&cow->list));
1892		while (!list_is_empty(&cow->list)) {
1893			struct sna_pixmap *clone;
1894
1895			clone = list_first_entry(&cow->list,
1896						 struct sna_pixmap, cow_list);
1897			list_del(&clone->cow_list);
1898
1899			assert(clone->gpu_bo == cow->bo);
1900			sna_pixmap_unmap(clone->pixmap, clone);
1901			kgem_bo_destroy(&sna->kgem, clone->gpu_bo);
1902			clone->gpu_bo = kgem_bo_reference(bo);
1903		}
1904		cow->bo = bo;
1905		kgem_bo_destroy(&sna->kgem, bo);
1906	} else {
1907		struct kgem_bo *bo = NULL;
1908
1909		if (flags & MOVE_READ) {
1910			PixmapPtr pixmap = priv->pixmap;
1911			BoxRec box;
1912
1913			DBG(("%s: copying cow\n", __FUNCTION__));
1914
1915			box.x1 = box.y1 = 0;
1916			box.x2 = pixmap->drawable.width;
1917			box.y2 = pixmap->drawable.height;
1918
1919			bo = kgem_create_2d(&sna->kgem,
1920					    box.x2, box.y2,
1921					    pixmap->drawable.bitsPerPixel,
1922					    sna_pixmap_default_tiling(sna, pixmap),
1923					    0);
1924			if (bo == NULL) {
1925				cow->refcnt++;
1926				DBG(("%s: allocation failed\n", __FUNCTION__));
1927				return false;
1928			}
1929
1930			if (!sna->render.copy_boxes(sna, GXcopy,
1931						    &pixmap->drawable, priv->gpu_bo, 0, 0,
1932						    &pixmap->drawable, bo, 0, 0,
1933						    &box, 1, 0)) {
1934				DBG(("%s: copy failed\n", __FUNCTION__));
1935				kgem_bo_destroy(&sna->kgem, bo);
1936				cow->refcnt++;
1937				return false;
1938			}
1939		}
1940
1941		assert(priv->gpu_bo);
1942		sna_pixmap_unmap(priv->pixmap, priv);
1943		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1944		priv->gpu_bo = bo;
1945	}
1946
1947	priv->cow = NULL;
1948	return true;
1949}
1950
1951static bool
1952sna_pixmap_make_cow(struct sna *sna,
1953		    struct sna_pixmap *src_priv,
1954		    struct sna_pixmap *dst_priv)
1955{
1956	struct sna_cow *cow;
1957
1958	assert(src_priv->gpu_bo);
1959
1960	if (!USE_COW)
1961		return false;
1962
1963	if (src_priv->gpu_bo->proxy)
1964		return false;
1965
1966	DBG(("%s: make cow src=%ld, dst=%ld, handle=%d (already cow? src=%d, dst=%d)\n",
1967	     __FUNCTION__,
1968	     src_priv->pixmap->drawable.serialNumber,
1969	     dst_priv->pixmap->drawable.serialNumber,
1970	     src_priv->gpu_bo->handle,
1971	     src_priv->cow ? IS_COW_OWNER(src_priv->cow) ? 1 : -1 : 0,
1972	     dst_priv->cow ? IS_COW_OWNER(dst_priv->cow) ? 1 : -1 : 0));
1973
1974	if (dst_priv->pinned) {
1975		DBG(("%s: can't cow, dst_pinned=%x\n",
1976		     __FUNCTION__, dst_priv->pinned));
1977		return false;
1978	}
1979
1980	assert(dst_priv->move_to_gpu == NULL);
1981	assert(!dst_priv->flush);
1982	assert(list_is_empty(&dst_priv->cow_list));
1983
1984	cow = COW(src_priv->cow);
1985	if (cow == NULL) {
1986		cow = malloc(sizeof(*cow));
1987		if (cow == NULL)
1988			return false;
1989
1990		list_init(&cow->list);
1991
1992		cow->bo = src_priv->gpu_bo;
1993		cow->refcnt = 1;
1994
1995		DBG(("%s: moo! attaching source cow to pixmap=%ld, handle=%d\n",
1996		     __FUNCTION__,
1997		     src_priv->pixmap->drawable.serialNumber,
1998		     cow->bo->handle));
1999
2000		src_priv->cow = MAKE_COW_OWNER(cow);
2001	}
2002
2003	if (cow == COW(dst_priv->cow)) {
2004		assert(dst_priv->gpu_bo == cow->bo);
2005		return true;
2006	}
2007
2008	if (dst_priv->cow)
2009		sna_pixmap_undo_cow(sna, dst_priv, 0);
2010
2011	if (dst_priv->gpu_bo) {
2012		sna_pixmap_unmap(dst_priv->pixmap, dst_priv);
2013		kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo);
2014	}
2015	assert(!dst_priv->mapped);
2016	dst_priv->gpu_bo = kgem_bo_reference(cow->bo);
2017	dst_priv->cow = cow;
2018	list_add(&dst_priv->cow_list, &cow->list);
2019	cow->refcnt++;
2020
2021	DBG(("%s: moo! attaching clone to pixmap=%ld (source=%ld, handle=%d)\n",
2022	     __FUNCTION__,
2023	     dst_priv->pixmap->drawable.serialNumber,
2024	     src_priv->pixmap->drawable.serialNumber,
2025	     cow->bo->handle));
2026
2027	return true;
2028}
2029
2030static inline bool operate_inplace(struct sna_pixmap *priv, unsigned flags)
2031{
2032	if (!USE_INPLACE)
2033		return false;
2034
2035	if ((flags & MOVE_INPLACE_HINT) == 0) {
2036		DBG(("%s: no, inplace operation not suitable\n", __FUNCTION__));
2037		return false;
2038	}
2039
2040	assert((flags & MOVE_ASYNC_HINT) == 0 || (priv->create & KGEM_CAN_CREATE_LARGE));
2041
2042	if (priv->move_to_gpu && flags & MOVE_WRITE) {
2043		DBG(("%s: no, has pending move-to-gpu\n", __FUNCTION__));
2044		return false;
2045	}
2046
2047	if (priv->cow && flags & MOVE_WRITE) {
2048		DBG(("%s: no, has COW\n", __FUNCTION__));
2049		return false;
2050	}
2051
2052	if ((priv->create & KGEM_CAN_CREATE_GTT) == 0) {
2053		DBG(("%s: no, not accessible via GTT\n", __FUNCTION__));
2054		return false;
2055	}
2056
2057	if ((priv->gpu_damage == NULL || priv->cpu_damage) && flags & MOVE_READ) {
2058		DBG(("%s: no, has CPU damage and requires readback\n", __FUNCTION__));
2059		return false;
2060	}
2061
2062	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) {
2063		DBG(("%s: yes, CPU is busy\n", __FUNCTION__));
2064		return true;
2065	}
2066
2067	if (priv->create & KGEM_CAN_CREATE_LARGE) {
2068		DBG(("%s: large object, has GPU? %d\n",
2069		     __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0));
2070		return priv->gpu_bo != NULL;
2071	}
2072
2073	if (flags & MOVE_WRITE && priv->gpu_bo&&kgem_bo_is_busy(priv->gpu_bo)) {
2074		DBG(("%s: no, GPU is busy, so stage write\n", __FUNCTION__));
2075		return false;
2076	}
2077
2078	return true;
2079}
2080
2081bool
2082_sna_pixmap_move_to_cpu(PixmapPtr pixmap, unsigned int flags)
2083{
2084	struct sna *sna = to_sna_from_pixmap(pixmap);
2085	struct sna_pixmap *priv;
2086
2087	DBG(("%s(pixmap=%ld, %dx%d, flags=%x)\n", __FUNCTION__,
2088	     pixmap->drawable.serialNumber,
2089	     pixmap->drawable.width,
2090	     pixmap->drawable.height,
2091	     flags));
2092
2093	assert(flags & (MOVE_READ | MOVE_WRITE));
2094	assert_pixmap_damage(pixmap);
2095
2096	priv = sna_pixmap(pixmap);
2097	if (priv == NULL) {
2098		DBG(("%s: not attached\n", __FUNCTION__));
2099		return true;
2100	}
2101
2102	DBG(("%s: gpu_bo=%d, gpu_damage=%p, cpu_damage=%p, is-clear?=%d\n",
2103	     __FUNCTION__,
2104	     priv->gpu_bo ? priv->gpu_bo->handle : 0,
2105	     priv->gpu_damage, priv->cpu_damage, priv->clear));
2106
2107	assert(priv->gpu_damage == NULL || priv->gpu_bo);
2108
2109	if ((flags & MOVE_READ) == 0 && UNDO) {
2110		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
2111		if (priv->move_to_gpu)
2112			sna_pixmap_discard_shadow_damage(priv, NULL);
2113	}
2114
2115	if (kgem_bo_discard_cache(priv->gpu_bo, flags & MOVE_WRITE)) {
2116		assert(DAMAGE_IS_ALL(priv->cpu_damage));
2117		if (DAMAGE_IS_ALL(priv->gpu_damage)) {
2118			DBG(("%s: using magical upload buffer\n", __FUNCTION__));
2119			goto skip;
2120		}
2121
2122		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
2123		assert(priv->gpu_damage == NULL);
2124		assert(!priv->pinned);
2125		assert(!priv->mapped);
2126		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
2127		priv->gpu_bo = NULL;
2128	}
2129
2130	if (DAMAGE_IS_ALL(priv->cpu_damage)) {
2131		DBG(("%s: CPU all-damaged\n", __FUNCTION__));
2132		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage));
2133		assert(priv->gpu_damage == NULL || (flags & MOVE_WRITE) == 0);
2134		goto done;
2135	}
2136
2137	if (USE_INPLACE && (flags & MOVE_READ) == 0 && !(priv->cow || priv->move_to_gpu)) {
2138		assert(flags & MOVE_WRITE);
2139		DBG(("%s: no readback, discarding gpu damage [%d], pending clear[%d]\n",
2140		     __FUNCTION__, priv->gpu_damage != NULL, priv->clear));
2141
2142		if ((priv->gpu_bo || priv->create & KGEM_CAN_CREATE_GPU) &&
2143		    pixmap_inplace(sna, pixmap, priv, flags) &&
2144		    sna_pixmap_create_mappable_gpu(pixmap, true)) {
2145			void *ptr;
2146
2147			DBG(("%s: write inplace\n", __FUNCTION__));
2148			assert(!priv->shm);
2149			assert(priv->cow == NULL);
2150			assert(priv->move_to_gpu == NULL);
2151			assert(priv->gpu_bo->exec == NULL);
2152			assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL);
2153
2154			ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo);
2155			if (ptr == NULL)
2156				goto skip_inplace_map;
2157
2158			pixmap->devPrivate.ptr = ptr;
2159			pixmap->devKind = priv->gpu_bo->pitch;
2160			priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
2161			assert(has_coherent_ptr(sna, priv, flags));
2162
2163			assert(priv->gpu_bo->proxy == NULL);
2164			sna_damage_all(&priv->gpu_damage, pixmap);
2165			sna_damage_destroy(&priv->cpu_damage);
2166			priv->clear = false;
2167			list_del(&priv->flush_list);
2168
2169			assert(!priv->shm);
2170			assert(priv->cpu_bo == NULL || !priv->cpu_bo->flush);
2171			sna_pixmap_free_cpu(sna, priv, priv->cpu);
2172			priv->cpu &= priv->mapped == MAPPED_CPU;
2173
2174			assert_pixmap_damage(pixmap);
2175			return true;
2176		}
2177
2178skip_inplace_map:
2179		sna_damage_destroy(&priv->gpu_damage);
2180		priv->clear = false;
2181		if ((flags & MOVE_ASYNC_HINT) == 0 &&
2182		    priv->cpu_bo && !priv->cpu_bo->flush &&
2183		    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2184			DBG(("%s: discarding busy CPU bo\n", __FUNCTION__));
2185			assert(!priv->shm);
2186			assert(priv->gpu_bo == NULL || priv->gpu_damage == NULL);
2187
2188			sna_damage_destroy(&priv->cpu_damage);
2189			sna_pixmap_free_cpu(sna, priv, false);
2190
2191			assert(priv->mapped == MAPPED_NONE);
2192			if (!sna_pixmap_alloc_cpu(sna, pixmap, priv, 0))
2193				return false;
2194			assert(priv->mapped == MAPPED_NONE);
2195			assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2196
2197			goto mark_damage;
2198		}
2199	}
2200
2201	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2202
2203	if (operate_inplace(priv, flags) &&
2204	    pixmap_inplace(sna, pixmap, priv, flags) &&
2205	    sna_pixmap_create_mappable_gpu(pixmap, (flags & MOVE_READ) == 0)) {
2206		void *ptr;
2207
2208		DBG(("%s: try to operate inplace (GTT)\n", __FUNCTION__));
2209		assert(priv->gpu_bo);
2210		assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
2211		assert(!priv->move_to_gpu);
2212		assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2213		assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL);
2214		/* XXX only sync for writes? */
2215		kgem_bo_submit(&sna->kgem, priv->gpu_bo);
2216		assert(priv->gpu_bo->exec == NULL);
2217
2218		ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo);
2219		if (ptr != NULL) {
2220			pixmap->devPrivate.ptr = ptr;
2221			pixmap->devKind = priv->gpu_bo->pitch;
2222			priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
2223			assert(has_coherent_ptr(sna, priv, flags));
2224
2225			if (flags & MOVE_WRITE) {
2226				assert(priv->gpu_bo->proxy == NULL);
2227				sna_damage_all(&priv->gpu_damage, pixmap);
2228				sna_damage_destroy(&priv->cpu_damage);
2229				sna_pixmap_free_cpu(sna, priv, priv->cpu);
2230				list_del(&priv->flush_list);
2231				priv->clear = false;
2232			}
2233			priv->cpu &= priv->mapped == MAPPED_CPU;
2234
2235			assert_pixmap_damage(pixmap);
2236			DBG(("%s: operate inplace (GTT)\n", __FUNCTION__));
2237			return true;
2238		}
2239	}
2240
2241	sna_pixmap_unmap(pixmap, priv);
2242
2243	if (USE_INPLACE &&
2244	    (flags & MOVE_WRITE ? (void *)priv->gpu_bo : (void *)priv->gpu_damage) && priv->cpu_damage == NULL &&
2245	    priv->gpu_bo->tiling == I915_TILING_NONE &&
2246	    (flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE)) &&
2247	    ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 ||
2248	     (!priv->cow && !priv->move_to_gpu && !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)))) {
2249		void *ptr;
2250
2251		DBG(("%s: try to operate inplace (CPU)\n", __FUNCTION__));
2252		assert(priv->gpu_bo);
2253		assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
2254		assert(priv->move_to_gpu == NULL || (flags & MOVE_WRITE) == 0);
2255		assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2256
2257		assert(!priv->mapped);
2258		assert(priv->gpu_bo->tiling == I915_TILING_NONE);
2259
2260		ptr = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
2261		if (ptr != NULL) {
2262			pixmap->devPrivate.ptr = ptr;
2263			pixmap->devKind = priv->gpu_bo->pitch;
2264			priv->mapped = MAPPED_CPU;
2265			assert(has_coherent_ptr(sna, priv, flags));
2266
2267			if (flags & MOVE_WRITE) {
2268				assert(priv->gpu_bo->proxy == NULL);
2269				sna_damage_all(&priv->gpu_damage, pixmap);
2270				sna_damage_destroy(&priv->cpu_damage);
2271				sna_pixmap_free_cpu(sna, priv, priv->cpu);
2272				list_del(&priv->flush_list);
2273				priv->clear = false;
2274				priv->cpu = true;
2275			}
2276
2277			assert(pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu));
2278			kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo,
2279					       FORCE_FULL_SYNC || flags & MOVE_WRITE);
2280			assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo));
2281			assert_pixmap_damage(pixmap);
2282			assert(has_coherent_ptr(sna, priv, flags));
2283			DBG(("%s: operate inplace (CPU)\n", __FUNCTION__));
2284			return true;
2285		}
2286	}
2287
2288	assert(priv->mapped == MAPPED_NONE);
2289	if (((flags & MOVE_READ) == 0 || priv->clear) &&
2290	    priv->cpu_bo && !priv->cpu_bo->flush &&
2291	    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2292		assert(!priv->shm);
2293		sna_pixmap_free_cpu(sna, priv, false);
2294	}
2295
2296	assert(priv->mapped == MAPPED_NONE);
2297	if (pixmap->devPrivate.ptr == NULL &&
2298	    !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags))
2299		return false;
2300	assert(priv->mapped == MAPPED_NONE);
2301	assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2302
2303	if (flags & MOVE_READ) {
2304		if (priv->clear) {
2305			DBG(("%s: applying clear [%08x] size=%dx%d, stride=%d (total=%d)\n",
2306			     __FUNCTION__, priv->clear_color, pixmap->drawable.width, pixmap->drawable.height,
2307			     pixmap->devKind, pixmap->devKind * pixmap->drawable.height));
2308
2309			if (priv->cpu_bo) {
2310				if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) &&
2311				    sna->render.fill_one(sna,
2312							  pixmap, priv->cpu_bo, priv->clear_color,
2313							  0, 0,
2314							  pixmap->drawable.width,
2315							  pixmap->drawable.height,
2316							  GXcopy))
2317					goto clear_done;
2318
2319				DBG(("%s: syncing CPU bo\n", __FUNCTION__));
2320				kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
2321				assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
2322			}
2323
2324			assert(pixmap->devKind);
2325			if (priv->clear_color == 0 ||
2326			    pixmap->drawable.bitsPerPixel == 8 ||
2327			    priv->clear_color == (1 << pixmap->drawable.depth) - 1) {
2328				memset(pixmap->devPrivate.ptr, priv->clear_color,
2329				       (size_t)pixmap->devKind * pixmap->drawable.height);
2330			} else {
2331				pixman_fill(pixmap->devPrivate.ptr,
2332					    pixmap->devKind/sizeof(uint32_t),
2333					    pixmap->drawable.bitsPerPixel,
2334					    0, 0,
2335					    pixmap->drawable.width,
2336					    pixmap->drawable.height,
2337					    priv->clear_color);
2338			}
2339
2340clear_done:
2341			sna_damage_all(&priv->cpu_damage, pixmap);
2342			sna_pixmap_free_gpu(sna, priv);
2343			assert(priv->gpu_damage == NULL);
2344			assert(priv->clear == false);
2345		}
2346
2347		if (priv->gpu_damage) {
2348			const BoxRec *box;
2349			int n;
2350
2351			DBG(("%s: flushing GPU damage\n", __FUNCTION__));
2352			assert(priv->gpu_bo);
2353
2354			n = sna_damage_get_boxes(priv->gpu_damage, &box);
2355			if (n) {
2356				if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ)) {
2357					DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
2358					return false;
2359				}
2360
2361				download_boxes(sna, priv, n, box);
2362			}
2363
2364			__sna_damage_destroy(DAMAGE_PTR(priv->gpu_damage));
2365			priv->gpu_damage = NULL;
2366		}
2367	}
2368
2369	if (flags & MOVE_WRITE || priv->create & KGEM_CAN_CREATE_LARGE) {
2370mark_damage:
2371		DBG(("%s: marking as damaged\n", __FUNCTION__));
2372		sna_damage_all(&priv->cpu_damage, pixmap);
2373		sna_pixmap_free_gpu(sna, priv);
2374		assert(priv->gpu_damage == NULL);
2375		assert(priv->clear == false);
2376
2377		if (priv->flush) {
2378			assert(!priv->shm);
2379			sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
2380		}
2381	}
2382
2383done:
2384	if (flags & MOVE_WRITE) {
2385		assert(DAMAGE_IS_ALL(priv->cpu_damage));
2386		assert(priv->gpu_damage == NULL);
2387		assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
2388		if (priv->cow)
2389			sna_pixmap_undo_cow(sna, priv, 0);
2390		if (priv->gpu_bo && priv->gpu_bo->rq == NULL) {
2391			DBG(("%s: discarding idle GPU bo\n", __FUNCTION__));
2392			sna_pixmap_free_gpu(sna, priv);
2393		}
2394		priv->source_count = SOURCE_BIAS;
2395	}
2396
2397	if (priv->cpu_bo) {
2398		if ((flags & MOVE_ASYNC_HINT) == 0) {
2399			DBG(("%s: syncing CPU bo\n", __FUNCTION__));
2400			assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
2401			kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo,
2402					       FORCE_FULL_SYNC || flags & MOVE_WRITE);
2403			assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo));
2404		}
2405	}
2406skip:
2407	priv->cpu |= (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE;
2408	assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2409	assert(pixmap->devKind);
2410	assert_pixmap_damage(pixmap);
2411	assert(has_coherent_ptr(sna, sna_pixmap(pixmap), flags));
2412	return true;
2413}
2414
2415static bool
2416region_overlaps_damage(const RegionRec *region,
2417		       struct sna_damage *damage,
2418		       int dx, int dy)
2419{
2420	const BoxRec *re, *de;
2421
2422	DBG(("%s?\n", __FUNCTION__));
2423
2424	if (damage == NULL)
2425		return false;
2426
2427	if (DAMAGE_IS_ALL(damage))
2428		return true;
2429
2430	re = &region->extents;
2431	de = &DAMAGE_PTR(damage)->extents;
2432	DBG(("%s: region (%d, %d), (%d, %d), damage (%d, %d), (%d, %d)\n",
2433	     __FUNCTION__,
2434	     re->x1, re->y1, re->x2, re->y2,
2435	     de->x1, de->y1, de->x2, de->y2));
2436
2437	return (re->x1 + dx < de->x2 && re->x2 + dx > de->x1 &&
2438		re->y1 + dy < de->y2 && re->y2 + dy > de->y1);
2439}
2440
2441static inline bool region_inplace(struct sna *sna,
2442				  PixmapPtr pixmap,
2443				  RegionPtr region,
2444				  struct sna_pixmap *priv,
2445				  unsigned flags)
2446{
2447	assert_pixmap_damage(pixmap);
2448
2449	if (FORCE_INPLACE)
2450		return FORCE_INPLACE > 0;
2451
2452	if (wedged(sna) && !priv->pinned)
2453		return false;
2454
2455	if (priv->gpu_damage &&
2456	    (priv->clear || (flags & MOVE_READ) == 0) &&
2457	    kgem_bo_is_busy(priv->gpu_bo))
2458		return false;
2459
2460	if (flags & MOVE_READ &&
2461	    (priv->cpu ||
2462	     priv->gpu_damage == NULL ||
2463	     region_overlaps_damage(region, priv->cpu_damage, 0, 0))) {
2464		DBG(("%s: no, uncovered CPU damage pending\n", __FUNCTION__));
2465		return false;
2466	}
2467
2468	if (priv->mapped) {
2469		DBG(("%s: %s, already mapped, continuing\n", __FUNCTION__,
2470		     has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no"));
2471		return has_coherent_map(sna, priv->gpu_bo, flags);
2472	}
2473
2474	if (priv->flush) {
2475		DBG(("%s: yes, exported via dri, will flush\n", __FUNCTION__));
2476		return true;
2477	}
2478
2479	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
2480		DBG(("%s: yes, already wholly damaged on the GPU\n", __FUNCTION__));
2481		assert(priv->gpu_bo);
2482		return true;
2483	}
2484
2485	if (priv->cpu_bo && priv->cpu) {
2486		DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__));
2487		return false;
2488	}
2489
2490	DBG(("%s: (%dx%d), inplace? %d\n",
2491	     __FUNCTION__,
2492	     region->extents.x2 - region->extents.x1,
2493	     region->extents.y2 - region->extents.y1,
2494	     ((int)(region->extents.x2 - region->extents.x1) *
2495	      (int)(region->extents.y2 - region->extents.y1) *
2496	      pixmap->drawable.bitsPerPixel >> 12)
2497	     >= sna->kgem.half_cpu_cache_pages));
2498	return ((int)(region->extents.x2 - region->extents.x1) *
2499		(int)(region->extents.y2 - region->extents.y1) *
2500		pixmap->drawable.bitsPerPixel >> 12)
2501		>= sna->kgem.half_cpu_cache_pages;
2502}
2503
2504static bool cpu_clear_boxes(struct sna *sna,
2505			    PixmapPtr pixmap,
2506			    struct sna_pixmap *priv,
2507			    const BoxRec *box, int n)
2508{
2509	struct sna_fill_op fill;
2510
2511	if (!sna_fill_init_blt(&fill, sna,
2512			       pixmap, priv->cpu_bo,
2513			       GXcopy, priv->clear_color,
2514			       FILL_BOXES)) {
2515		DBG(("%s: unsupported fill\n",
2516		     __FUNCTION__));
2517		return false;
2518	}
2519
2520	fill.boxes(sna, &fill, box, n);
2521	fill.done(sna, &fill);
2522	return true;
2523}
2524
2525bool
2526sna_drawable_move_region_to_cpu(DrawablePtr drawable,
2527				RegionPtr region,
2528				unsigned flags)
2529{
2530	PixmapPtr pixmap = get_drawable_pixmap(drawable);
2531	struct sna *sna = to_sna_from_pixmap(pixmap);
2532	struct sna_pixmap *priv;
2533	int16_t dx, dy;
2534
2535	DBG(("%s(pixmap=%ld (%dx%d), [(%d, %d), (%d, %d)], flags=%x)\n",
2536	     __FUNCTION__, pixmap->drawable.serialNumber,
2537	     pixmap->drawable.width, pixmap->drawable.height,
2538	     RegionExtents(region)->x1, RegionExtents(region)->y1,
2539	     RegionExtents(region)->x2, RegionExtents(region)->y2,
2540	     flags));
2541
2542	assert_pixmap_damage(pixmap);
2543	if (flags & MOVE_WRITE) {
2544		assert_drawable_contains_box(drawable, &region->extents);
2545	}
2546	assert(flags & (MOVE_WRITE | MOVE_READ));
2547
2548	if (box_empty(&region->extents))
2549		return true;
2550
2551	if (MIGRATE_ALL || DBG_NO_PARTIAL_MOVE_TO_CPU) {
2552		if (!region_subsumes_pixmap(region, pixmap))
2553			flags |= MOVE_READ;
2554		return _sna_pixmap_move_to_cpu(pixmap, flags);
2555	}
2556
2557	priv = sna_pixmap(pixmap);
2558	if (priv == NULL) {
2559		DBG(("%s: not attached to pixmap %ld (depth %d)\n",
2560		     __FUNCTION__, pixmap->drawable.serialNumber, pixmap->drawable.depth));
2561		return true;
2562	}
2563
2564	assert(priv->gpu_damage == NULL || priv->gpu_bo);
2565
2566	if (kgem_bo_discard_cache(priv->gpu_bo, flags & MOVE_WRITE)) {
2567		assert(DAMAGE_IS_ALL(priv->cpu_damage));
2568		if (DAMAGE_IS_ALL(priv->gpu_damage)) {
2569			DBG(("%s: using magical upload buffer\n", __FUNCTION__));
2570			goto skip;
2571		}
2572
2573		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
2574		assert(priv->gpu_damage == NULL);
2575		assert(!priv->pinned);
2576		assert(!priv->mapped);
2577		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
2578		priv->gpu_bo = NULL;
2579	}
2580
2581	if (sna_damage_is_all(&priv->cpu_damage,
2582			      pixmap->drawable.width,
2583			      pixmap->drawable.height)) {
2584		bool discard_gpu = priv->cpu;
2585
2586		DBG(("%s: pixmap=%ld all damaged on CPU\n",
2587		     __FUNCTION__, pixmap->drawable.serialNumber));
2588		assert(!priv->clear);
2589
2590		sna_damage_destroy(&priv->gpu_damage);
2591
2592		if ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 &&
2593		    priv->cpu_bo && !priv->cpu_bo->flush &&
2594		    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2595			DBG(("%s: active CPU bo replacing\n", __FUNCTION__));
2596			assert(!priv->shm);
2597			assert(!IS_STATIC_PTR(priv->ptr));
2598
2599			if (!region_subsumes_pixmap(region, pixmap)) {
2600				DBG(("%s: partial replacement\n", __FUNCTION__));
2601				if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
2602					RegionTranslate(region, dx, dy);
2603
2604				if (sna->kgem.has_llc && !priv->pinned &&
2605				    sna_pixmap_default_tiling(sna, pixmap) == I915_TILING_NONE) {
2606#ifdef DEBUG_MEMORY
2607					sna->debug_memory.cpu_bo_allocs--;
2608					sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
2609#endif
2610					DBG(("%s: promoting CPU bo to GPU bo\n", __FUNCTION__));
2611					if (priv->gpu_bo)
2612						sna_pixmap_free_gpu(sna, priv);
2613					priv->gpu_bo = priv->cpu_bo;
2614					priv->cpu_bo = NULL;
2615					priv->ptr = NULL;
2616					pixmap->devPrivate.ptr = NULL;
2617
2618					priv->gpu_damage = priv->cpu_damage;
2619					priv->cpu_damage = NULL;
2620
2621					sna_damage_subtract(&priv->gpu_damage, region);
2622					discard_gpu = false;
2623				} else {
2624					DBG(("%s: pushing surrounding damage to GPU bo\n", __FUNCTION__));
2625					sna_damage_subtract(&priv->cpu_damage, region);
2626					assert(priv->cpu_damage);
2627					if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) {
2628						sna_pixmap_free_cpu(sna, priv, false);
2629						if (priv->flush)
2630							sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
2631
2632						assert(priv->cpu_damage == NULL);
2633						sna_damage_all(&priv->gpu_damage, pixmap);
2634						sna_damage_subtract(&priv->gpu_damage, region);
2635						discard_gpu = false;
2636					}
2637				}
2638				sna_damage_add(&priv->cpu_damage, region);
2639
2640				if (dx | dy)
2641					RegionTranslate(region, -dx, -dy);
2642			} else
2643				sna_pixmap_free_cpu(sna, priv, false);
2644		}
2645
2646		if (flags & MOVE_WRITE && discard_gpu)
2647			sna_pixmap_free_gpu(sna, priv);
2648
2649		sna_pixmap_unmap(pixmap, priv);
2650		assert(priv->mapped == MAPPED_NONE);
2651		if (pixmap->devPrivate.ptr == NULL &&
2652		    !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags))
2653			return false;
2654		assert(priv->mapped == MAPPED_NONE);
2655		assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2656
2657		goto out;
2658	}
2659
2660	if (USE_INPLACE &&
2661	    (priv->create & KGEM_CAN_CREATE_LARGE ||
2662	     ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 &&
2663	      (priv->flush ||
2664	       (flags & MOVE_WHOLE_HINT && whole_pixmap_inplace(pixmap)) ||
2665	       box_inplace(pixmap, &region->extents))))) {
2666		DBG(("%s: marking for inplace hint (%d, %d)\n",
2667		     __FUNCTION__, priv->flush, box_inplace(pixmap, &region->extents)));
2668		flags |= MOVE_INPLACE_HINT;
2669	}
2670
2671	if (region_subsumes_pixmap(region, pixmap)) {
2672		DBG(("%s: region (%d, %d), (%d, %d) + (%d, %d) subsumes pixmap (%dx%d)\n",
2673		       __FUNCTION__,
2674		       region->extents.x1,
2675		       region->extents.y1,
2676		       region->extents.x2,
2677		       region->extents.y2,
2678		       get_drawable_dx(drawable), get_drawable_dy(drawable),
2679		       pixmap->drawable.width,
2680		       pixmap->drawable.height));
2681		return _sna_pixmap_move_to_cpu(pixmap, flags);
2682	}
2683
2684	if (priv->move_to_gpu) {
2685		DBG(("%s: applying move-to-gpu override\n", __FUNCTION__));
2686		if ((flags & MOVE_READ) == 0)
2687			sna_pixmap_discard_shadow_damage(priv, region);
2688		if (!priv->move_to_gpu(sna, priv, MOVE_READ)) {
2689			DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
2690			return NULL;
2691		}
2692	}
2693
2694	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2695
2696	if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
2697		DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy));
2698		RegionTranslate(region, dx, dy);
2699	}
2700
2701	if (operate_inplace(priv, flags) &&
2702	    region_inplace(sna, pixmap, region, priv, flags) &&
2703	    sna_pixmap_create_mappable_gpu(pixmap, false)) {
2704		void *ptr;
2705
2706		DBG(("%s: try to operate inplace\n", __FUNCTION__));
2707		assert(priv->gpu_bo);
2708		assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
2709		assert(priv->move_to_gpu == NULL || (flags & MOVE_WRITE) == 0);
2710		assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2711
2712		/* XXX only sync for writes? */
2713		kgem_bo_submit(&sna->kgem, priv->gpu_bo);
2714		assert(priv->gpu_bo->exec == NULL);
2715
2716		ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo);
2717		if (ptr != NULL) {
2718			pixmap->devPrivate.ptr = ptr;
2719			pixmap->devKind = priv->gpu_bo->pitch;
2720			priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
2721			assert(has_coherent_ptr(sna, priv, flags));
2722
2723			if (flags & MOVE_WRITE) {
2724				if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
2725					assert(!priv->clear);
2726					sna_damage_add(&priv->gpu_damage, region);
2727					if (sna_damage_is_all(&priv->gpu_damage,
2728							      pixmap->drawable.width,
2729							      pixmap->drawable.height)) {
2730						DBG(("%s: replaced entire pixmap, destroying CPU shadow\n",
2731						     __FUNCTION__));
2732						sna_damage_destroy(&priv->cpu_damage);
2733						list_del(&priv->flush_list);
2734					} else
2735						sna_damage_subtract(&priv->cpu_damage,
2736								    region);
2737				}
2738				priv->clear = false;
2739			}
2740			priv->cpu &= priv->mapped == MAPPED_CPU;
2741			assert_pixmap_damage(pixmap);
2742			if (dx | dy)
2743				RegionTranslate(region, -dx, -dy);
2744			DBG(("%s: operate inplace\n", __FUNCTION__));
2745			return true;
2746		}
2747	}
2748
2749	if (priv->clear && flags & MOVE_WRITE) {
2750		DBG(("%s: pending clear, moving whole pixmap for partial write\n", __FUNCTION__));
2751demote_to_cpu:
2752		if (dx | dy)
2753			RegionTranslate(region, -dx, -dy);
2754		return _sna_pixmap_move_to_cpu(pixmap, flags | MOVE_READ);
2755	}
2756
2757	if (flags & MOVE_WHOLE_HINT) {
2758		DBG(("%s: region (%d, %d), (%d, %d) marked with WHOLE hint, pixmap %dx%d\n",
2759		       __FUNCTION__,
2760		       region->extents.x1,
2761		       region->extents.y1,
2762		       region->extents.x2,
2763		       region->extents.y2,
2764		       pixmap->drawable.width,
2765		       pixmap->drawable.height));
2766move_to_cpu:
2767		if ((flags & MOVE_READ) == 0)
2768			sna_damage_subtract(&priv->gpu_damage, region);
2769		goto demote_to_cpu;
2770	}
2771
2772	sna_pixmap_unmap(pixmap, priv);
2773
2774	if (USE_INPLACE &&
2775	    priv->gpu_damage &&
2776	    priv->gpu_bo->tiling == I915_TILING_NONE &&
2777	    ((priv->cow == NULL && priv->move_to_gpu == NULL) || (flags & MOVE_WRITE) == 0) &&
2778	    (DAMAGE_IS_ALL(priv->gpu_damage) ||
2779	     sna_damage_contains_box__no_reduce(priv->gpu_damage,
2780						&region->extents)) &&
2781	    kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE) &&
2782	    ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 ||
2783	     !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) {
2784		void *ptr;
2785
2786		DBG(("%s: try to operate inplace (CPU), read? %d, write? %d\n",
2787		     __FUNCTION__, !!(flags & MOVE_READ), !!(flags & MOVE_WRITE)));
2788		assert(priv->gpu_bo);
2789		assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0);
2790		assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
2791		assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
2792
2793		ptr = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
2794		if (ptr != NULL) {
2795			pixmap->devPrivate.ptr = ptr;
2796			pixmap->devKind = priv->gpu_bo->pitch;
2797			priv->mapped = MAPPED_CPU;
2798			assert(has_coherent_ptr(sna, priv, flags));
2799
2800			if (flags & MOVE_WRITE) {
2801				if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
2802					assert(!priv->clear);
2803					sna_damage_add(&priv->gpu_damage, region);
2804					if (sna_damage_is_all(&priv->gpu_damage,
2805							      pixmap->drawable.width,
2806							      pixmap->drawable.height)) {
2807						DBG(("%s: replaced entire pixmap, destroying CPU shadow\n",
2808						     __FUNCTION__));
2809						sna_damage_destroy(&priv->cpu_damage);
2810						list_del(&priv->flush_list);
2811					} else
2812						sna_damage_subtract(&priv->cpu_damage,
2813								    region);
2814				}
2815				priv->clear = false;
2816			}
2817			assert_pixmap_damage(pixmap);
2818
2819			kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo,
2820					       FORCE_FULL_SYNC || flags & MOVE_WRITE);
2821			priv->cpu = true;
2822
2823			assert_pixmap_map(pixmap, priv);
2824			assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo));
2825			if (dx | dy)
2826				RegionTranslate(region, -dx, -dy);
2827			DBG(("%s: operate inplace (CPU)\n", __FUNCTION__));
2828			return true;
2829		}
2830	}
2831
2832	if ((priv->clear || (flags & MOVE_READ) == 0) &&
2833	    priv->cpu_bo && !priv->cpu_bo->flush &&
2834	    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2835		sna_damage_subtract(&priv->cpu_damage, region);
2836		if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) {
2837			assert(priv->gpu_bo);
2838			sna_damage_all(&priv->gpu_damage, pixmap);
2839			sna_pixmap_free_cpu(sna, priv, false);
2840		}
2841	}
2842
2843	assert(priv->mapped == MAPPED_NONE);
2844	if (pixmap->devPrivate.ptr == NULL &&
2845	    !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags)) {
2846		DBG(("%s: CPU bo allocation failed, trying full move-to-cpu\n", __FUNCTION__));
2847		goto move_to_cpu;
2848	}
2849	assert(priv->mapped == MAPPED_NONE);
2850	assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
2851
2852	if (priv->gpu_bo == NULL) {
2853		assert(priv->gpu_damage == NULL);
2854		goto done;
2855	}
2856
2857	assert(priv->gpu_bo->proxy == NULL);
2858
2859	if ((flags & MOVE_READ) == 0) {
2860		assert(flags & MOVE_WRITE);
2861		sna_damage_subtract(&priv->gpu_damage, region);
2862		priv->clear = false;
2863		goto done;
2864	}
2865
2866	if (priv->clear) {
2867		int n = region_num_rects(region);
2868		const BoxRec *box = region_rects(region);
2869
2870		assert(DAMAGE_IS_ALL(priv->gpu_damage));
2871		assert(priv->cpu_damage == NULL);
2872
2873		DBG(("%s: pending clear, doing partial fill\n", __FUNCTION__));
2874		if (priv->cpu_bo) {
2875			if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) &&
2876			    cpu_clear_boxes(sna, pixmap, priv, box, n))
2877				goto clear_done;
2878
2879			DBG(("%s: syncing CPU bo\n", __FUNCTION__));
2880			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
2881			assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
2882		}
2883
2884		assert(pixmap->devKind);
2885		do {
2886			pixman_fill(pixmap->devPrivate.ptr,
2887				    pixmap->devKind/sizeof(uint32_t),
2888				    pixmap->drawable.bitsPerPixel,
2889				    box->x1, box->y1,
2890				    box->x2 - box->x1,
2891				    box->y2 - box->y1,
2892				    priv->clear_color);
2893			box++;
2894		} while (--n);
2895
2896clear_done:
2897		if (flags & MOVE_WRITE ||
2898		    region->extents.x2 - region->extents.x1 > 1 ||
2899		    region->extents.y2 - region->extents.y1 > 1) {
2900			sna_damage_subtract(&priv->gpu_damage, region);
2901			priv->clear = false;
2902		}
2903		goto done;
2904	}
2905
2906	if (priv->gpu_damage &&
2907	    (DAMAGE_IS_ALL(priv->gpu_damage) ||
2908	     sna_damage_overlaps_box(priv->gpu_damage, &region->extents))) {
2909		DBG(("%s: region (%dx%d) overlaps gpu damage\n",
2910		     __FUNCTION__,
2911		     region->extents.x2 - region->extents.x1,
2912		     region->extents.y2 - region->extents.y1));
2913		assert(priv->gpu_bo);
2914
2915		if (priv->cpu_damage == NULL) {
2916			if ((flags & MOVE_WRITE) == 0 &&
2917			    region->extents.x2 - region->extents.x1 == 1 &&
2918			    region->extents.y2 - region->extents.y1 == 1) {
2919				/*  Often associated with synchronisation, KISS */
2920				DBG(("%s: single pixel read\n", __FUNCTION__));
2921				sna_read_boxes(sna, pixmap, priv->gpu_bo,
2922					       &region->extents, 1);
2923				goto done;
2924			}
2925		} else {
2926			if (DAMAGE_IS_ALL(priv->cpu_damage) ||
2927			    sna_damage_contains_box__no_reduce(priv->cpu_damage,
2928							       &region->extents)) {
2929				assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_OUT);
2930				assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_IN);
2931
2932				DBG(("%s: region already in CPU damage\n",
2933				     __FUNCTION__));
2934				goto already_damaged;
2935			}
2936		}
2937
2938		if (sna_damage_contains_box(&priv->gpu_damage,
2939					    &region->extents) != PIXMAN_REGION_OUT) {
2940			RegionRec want, *r = region;
2941
2942			DBG(("%s: region (%dx%d) intersects gpu damage\n",
2943			     __FUNCTION__,
2944			     region->extents.x2 - region->extents.x1,
2945			     region->extents.y2 - region->extents.y1));
2946
2947			if ((flags & MOVE_WRITE) == 0 &&
2948			    region->extents.x2 - region->extents.x1 == 1 &&
2949			    region->extents.y2 - region->extents.y1 == 1) {
2950				sna_read_boxes(sna, pixmap, priv->gpu_bo,
2951					       &region->extents, 1);
2952				goto done;
2953			}
2954
2955			/* Expand the region to move 32x32 pixel blocks at a
2956			 * time, as we assume that we will continue writing
2957			 * afterwards and so aim to coallesce subsequent
2958			 * reads.
2959			 */
2960			if (flags & MOVE_WRITE) {
2961				int n = region_num_rects(region), i;
2962				const BoxRec *boxes = region_rects(region);
2963				BoxPtr blocks;
2964
2965				blocks = NULL;
2966				if (priv->cpu_damage == NULL)
2967					blocks = malloc(sizeof(BoxRec) * n);
2968				if (blocks) {
2969					for (i = 0; i < n; i++) {
2970						blocks[i].x1 = boxes[i].x1 & ~31;
2971						if (blocks[i].x1 < 0)
2972							blocks[i].x1 = 0;
2973
2974						blocks[i].x2 = (boxes[i].x2 + 31) & ~31;
2975						if (blocks[i].x2 > pixmap->drawable.width)
2976							blocks[i].x2 = pixmap->drawable.width;
2977
2978						blocks[i].y1 = boxes[i].y1 & ~31;
2979						if (blocks[i].y1 < 0)
2980							blocks[i].y1 = 0;
2981
2982						blocks[i].y2 = (boxes[i].y2 + 31) & ~31;
2983						if (blocks[i].y2 > pixmap->drawable.height)
2984							blocks[i].y2 = pixmap->drawable.height;
2985					}
2986					if (pixman_region_init_rects(&want, blocks, i))
2987						r = &want;
2988					free(blocks);
2989				}
2990			}
2991
2992			if (region_subsumes_damage(r, priv->gpu_damage)) {
2993				const BoxRec *box;
2994				int n;
2995
2996				DBG(("%s: region wholly contains damage\n",
2997				     __FUNCTION__));
2998
2999				n = sna_damage_get_boxes(priv->gpu_damage, &box);
3000				if (n)
3001					download_boxes(sna, priv, n, box);
3002
3003				sna_damage_destroy(&priv->gpu_damage);
3004			} else if (DAMAGE_IS_ALL(priv->gpu_damage) ||
3005				   sna_damage_contains_box__no_reduce(priv->gpu_damage,
3006								      &r->extents)) {
3007
3008				DBG(("%s: region wholly inside damage\n",
3009				     __FUNCTION__));
3010
3011				assert(sna_damage_contains_box(&priv->gpu_damage, &r->extents) == PIXMAN_REGION_IN);
3012				assert(sna_damage_contains_box(&priv->cpu_damage, &r->extents) == PIXMAN_REGION_OUT);
3013
3014				download_boxes(sna, priv,
3015					       region_num_rects(r),
3016					       region_rects(r));
3017				sna_damage_subtract(&priv->gpu_damage, r);
3018			} else {
3019				RegionRec need;
3020
3021				pixman_region_init(&need);
3022				if (sna_damage_intersect(priv->gpu_damage, r, &need)) {
3023					DBG(("%s: region intersects damage\n",
3024					     __FUNCTION__));
3025
3026					download_boxes(sna, priv,
3027						       region_num_rects(&need),
3028						       region_rects(&need));
3029					sna_damage_subtract(&priv->gpu_damage, r);
3030					RegionUninit(&need);
3031				}
3032			}
3033			if (r == &want)
3034				pixman_region_fini(&want);
3035		}
3036	}
3037
3038done:
3039	if ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE) {
3040		DBG(("%s: applying cpu damage\n", __FUNCTION__));
3041		assert(!DAMAGE_IS_ALL(priv->cpu_damage));
3042		assert_pixmap_contains_box(pixmap, RegionExtents(region));
3043		sna_damage_add(&priv->cpu_damage, region);
3044		sna_damage_reduce_all(&priv->cpu_damage, pixmap);
3045		if (DAMAGE_IS_ALL(priv->cpu_damage)) {
3046			DBG(("%s: replaced entire pixmap\n", __FUNCTION__));
3047			sna_pixmap_free_gpu(sna, priv);
3048		}
3049		if (priv->flush) {
3050			assert(!priv->shm);
3051			sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
3052		}
3053	}
3054
3055already_damaged:
3056	if (dx | dy)
3057		RegionTranslate(region, -dx, -dy);
3058
3059out:
3060	if (flags & MOVE_WRITE) {
3061		assert(!DAMAGE_IS_ALL(priv->gpu_damage));
3062		priv->source_count = SOURCE_BIAS;
3063		assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
3064		assert(priv->gpu_bo || priv->gpu_damage == NULL);
3065		assert(!priv->flush || !list_is_empty(&priv->flush_list));
3066		assert(!priv->clear);
3067	}
3068	if ((flags & MOVE_ASYNC_HINT) == 0 && priv->cpu_bo) {
3069		DBG(("%s: syncing cpu bo\n", __FUNCTION__));
3070		assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
3071		kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo,
3072				       FORCE_FULL_SYNC || flags & MOVE_WRITE);
3073		assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo));
3074	}
3075skip:
3076	priv->cpu |= (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE;
3077	assert(pixmap->devPrivate.ptr == PTR(priv->ptr));
3078	assert(pixmap->devKind);
3079	assert_pixmap_damage(pixmap);
3080	assert(has_coherent_ptr(sna, priv, flags));
3081	return true;
3082}
3083
3084bool
3085sna_drawable_move_to_cpu(DrawablePtr drawable, unsigned flags)
3086{
3087	RegionRec region;
3088	PixmapPtr pixmap;
3089	int16_t dx, dy;
3090
3091	if (drawable->type == DRAWABLE_PIXMAP)
3092		return sna_pixmap_move_to_cpu((PixmapPtr)drawable, flags);
3093
3094	pixmap = get_window_pixmap((WindowPtr)drawable);
3095	get_drawable_deltas(drawable, pixmap, &dx, &dy);
3096
3097	DBG(("%s: (%d, %d)x(%d, %d) + (%d, %d), flags=%x\n",
3098	     __FUNCTION__,
3099	     drawable->x, drawable->y,
3100	     drawable->width, drawable->height,
3101	     dx, dy, flags));
3102
3103	region.extents.x1 = drawable->x + dx;
3104	region.extents.y1 = drawable->y + dy;
3105	region.extents.x2 = region.extents.x1 + drawable->width;
3106	region.extents.y2 = region.extents.y1 + drawable->height;
3107	region.data = NULL;
3108
3109	if (region.extents.x1 < 0)
3110		region.extents.x1 = 0;
3111	if (region.extents.y1 < 0)
3112		region.extents.y1 = 0;
3113	if (region.extents.x2 > pixmap->drawable.width)
3114		region.extents.x2 = pixmap->drawable.width;
3115	if (region.extents.y2 > pixmap->drawable.height)
3116		region.extents.y2 = pixmap->drawable.height;
3117
3118	if (box_empty(&region.extents))
3119		return true;
3120
3121	return sna_drawable_move_region_to_cpu(&pixmap->drawable, &region, flags);
3122}
3123
3124pure static bool alu_overwrites(uint8_t alu)
3125{
3126	switch (alu) {
3127	case GXclear:
3128	case GXcopy:
3129	case GXcopyInverted:
3130	case GXset:
3131		return true;
3132	default:
3133		return false;
3134	}
3135}
3136
3137inline static bool drawable_gc_inplace_hint(DrawablePtr draw, GCPtr gc)
3138{
3139	if (!alu_overwrites(gc->alu))
3140		return false;
3141
3142	if (!PM_IS_SOLID(draw, gc->planemask))
3143		return false;
3144
3145	if (gc->fillStyle == FillStippled)
3146		return false;
3147
3148	return true;
3149}
3150
3151inline static unsigned
3152drawable_gc_flags(DrawablePtr draw, GCPtr gc, bool partial)
3153{
3154	assert(sna_gc(gc)->changes == 0);
3155
3156	if (gc->fillStyle == FillStippled) {
3157		DBG(("%s: read due to fill %d\n",
3158		     __FUNCTION__, gc->fillStyle));
3159		return MOVE_READ | MOVE_WRITE;
3160	}
3161
3162	if (fb_gc(gc)->and | fb_gc(gc)->bgand) {
3163		DBG(("%s: read due to rrop %d:%x\n",
3164		     __FUNCTION__, gc->alu, (unsigned)fb_gc(gc)->and));
3165		return MOVE_READ | MOVE_WRITE;
3166	}
3167
3168	DBG(("%s: try operating on drawable inplace [hint? %d]\n",
3169	     __FUNCTION__, drawable_gc_inplace_hint(draw, gc)));
3170
3171	return (partial ? MOVE_READ : 0) | MOVE_WRITE | MOVE_INPLACE_HINT;
3172}
3173
3174static inline struct sna_pixmap *
3175sna_pixmap_mark_active(struct sna *sna, struct sna_pixmap *priv)
3176{
3177	assert(priv->gpu_bo);
3178	DBG(("%s: pixmap=%ld, handle=%u\n", __FUNCTION__,
3179	     priv->pixmap->drawable.serialNumber,
3180	     priv->gpu_bo->handle));
3181	return priv;
3182}
3183
3184inline static struct sna_pixmap *
3185__sna_pixmap_for_gpu(struct sna *sna, PixmapPtr pixmap, unsigned flags)
3186{
3187	struct sna_pixmap *priv;
3188
3189	if ((flags & __MOVE_FORCE) == 0 && wedged(sna))
3190		return NULL;
3191
3192	priv = sna_pixmap(pixmap);
3193	if (priv == NULL) {
3194		DBG(("%s: not attached\n", __FUNCTION__));
3195		if ((flags & __MOVE_DRI) == 0)
3196			return NULL;
3197
3198		if (pixmap->usage_hint == -1) {
3199			DBG(("%s: not promoting SHM Pixmap for DRI\n", __FUNCTION__));
3200			return NULL;
3201		}
3202
3203		DBG(("%s: forcing the creation on the GPU\n", __FUNCTION__));
3204
3205		priv = sna_pixmap_attach(pixmap);
3206		if (priv == NULL)
3207			return NULL;
3208
3209		sna_damage_all(&priv->cpu_damage, pixmap);
3210
3211		assert(priv->gpu_bo == NULL);
3212		assert(priv->gpu_damage == NULL);
3213	}
3214
3215	return priv;
3216}
3217
3218struct sna_pixmap *
3219sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int flags)
3220{
3221	struct sna *sna = to_sna_from_pixmap(pixmap);
3222	struct sna_pixmap *priv;
3223	RegionRec i, r;
3224
3225	DBG(("%s: pixmap=%ld box=(%d, %d), (%d, %d), flags=%x\n",
3226	     __FUNCTION__, pixmap->drawable.serialNumber,
3227	     box->x1, box->y1, box->x2, box->y2, flags));
3228
3229	priv = __sna_pixmap_for_gpu(sna, pixmap, flags);
3230	if (priv == NULL)
3231		return NULL;
3232
3233	assert(box->x2 > box->x1 && box->y2 > box->y1);
3234	assert_pixmap_damage(pixmap);
3235	assert_pixmap_contains_box(pixmap, box);
3236	assert(priv->gpu_damage == NULL || priv->gpu_bo);
3237
3238	if ((flags & MOVE_READ) == 0)
3239		sna_damage_subtract_box(&priv->cpu_damage, box);
3240
3241	if (priv->move_to_gpu) {
3242		unsigned int hint;
3243
3244		DBG(("%s: applying move-to-gpu override\n", __FUNCTION__));
3245		hint = flags | MOVE_READ;
3246		if ((flags & MOVE_READ) == 0) {
3247			RegionRec region;
3248
3249			region.extents = *box;
3250			region.data = NULL;
3251			sna_pixmap_discard_shadow_damage(priv, &region);
3252			if (region_subsumes_pixmap(&region, pixmap))
3253				hint &= ~MOVE_READ;
3254		} else {
3255			if (priv->cpu_damage)
3256				hint |= MOVE_WRITE;
3257		}
3258		if (!priv->move_to_gpu(sna, priv, hint)) {
3259			DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
3260			return NULL;
3261		}
3262	}
3263
3264	if (priv->cow) {
3265		unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE);
3266
3267		if ((flags & MOVE_READ) == 0) {
3268			if (priv->gpu_damage) {
3269				r.extents = *box;
3270				r.data = NULL;
3271				if (!region_subsumes_damage(&r, priv->gpu_damage))
3272					cow |= MOVE_READ;
3273			}
3274		} else {
3275			if (priv->cpu_damage) {
3276				r.extents = *box;
3277				r.data = NULL;
3278				if (region_overlaps_damage(&r, priv->cpu_damage, 0, 0))
3279					cow |= MOVE_WRITE;
3280			}
3281		}
3282
3283		if (cow) {
3284			if (!sna_pixmap_undo_cow(sna, priv, cow))
3285				return NULL;
3286
3287			if (priv->gpu_bo == NULL)
3288				sna_damage_destroy(&priv->gpu_damage);
3289		}
3290	}
3291
3292	if (sna_damage_is_all(&priv->gpu_damage,
3293			      pixmap->drawable.width,
3294			      pixmap->drawable.height)) {
3295		assert(priv->gpu_bo);
3296		assert(priv->gpu_bo->proxy == NULL);
3297		sna_damage_destroy(&priv->cpu_damage);
3298		list_del(&priv->flush_list);
3299		goto done;
3300	}
3301
3302	if (kgem_bo_discard_cache(priv->gpu_bo, flags & (MOVE_WRITE | __MOVE_FORCE))) {
3303		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
3304		assert(DAMAGE_IS_ALL(priv->cpu_damage));
3305		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */
3306		assert(!priv->pinned);
3307		assert(!priv->mapped);
3308		sna_damage_destroy(&priv->gpu_damage);
3309		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
3310		priv->gpu_bo = NULL;
3311	}
3312
3313	sna_damage_reduce(&priv->cpu_damage);
3314	assert_pixmap_damage(pixmap);
3315
3316	if (priv->cpu_damage == NULL) {
3317		list_del(&priv->flush_list);
3318		return sna_pixmap_move_to_gpu(pixmap, MOVE_READ | flags);
3319	}
3320
3321	if (priv->gpu_bo == NULL) {
3322		assert(priv->gpu_damage == NULL);
3323
3324		if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU)
3325			sna_pixmap_alloc_gpu(sna, pixmap, priv, CREATE_INACTIVE);
3326
3327		if (priv->gpu_bo == NULL)
3328			return NULL;
3329
3330		DBG(("%s: created gpu bo\n", __FUNCTION__));
3331	}
3332
3333	if (priv->gpu_bo->proxy) {
3334		DBG(("%s: reusing cached upload\n", __FUNCTION__));
3335		assert((flags & MOVE_WRITE) == 0);
3336		assert(priv->gpu_damage == NULL);
3337		return priv;
3338	}
3339
3340	if (priv->shm) {
3341		assert(!priv->flush);
3342		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
3343	}
3344
3345	assert(priv->cpu_damage);
3346	region_set(&r, box);
3347	if (MIGRATE_ALL || region_subsumes_damage(&r, priv->cpu_damage)) {
3348		bool ok = false;
3349		int n;
3350
3351		n = sna_damage_get_boxes(priv->cpu_damage, &box);
3352		assert(n);
3353		if (use_cpu_bo_for_upload(sna, priv, 0)) {
3354			DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__));
3355			ok = sna->render.copy_boxes(sna, GXcopy,
3356						    &pixmap->drawable, priv->cpu_bo, 0, 0,
3357						    &pixmap->drawable, priv->gpu_bo, 0, 0,
3358						    box, n, 0);
3359		}
3360		if (!ok) {
3361			sna_pixmap_unmap(pixmap, priv);
3362			if (pixmap->devPrivate.ptr == NULL)
3363				return NULL;
3364
3365			assert(pixmap->devKind);
3366			if (n == 1 && !priv->pinned &&
3367			    box->x1 <= 0 && box->y1 <= 0 &&
3368			    box->x2 >= pixmap->drawable.width &&
3369			    box->y2 >= pixmap->drawable.height) {
3370				ok = sna_replace(sna, pixmap,
3371						 pixmap->devPrivate.ptr,
3372						 pixmap->devKind);
3373			} else {
3374				ok = sna_write_boxes(sna, pixmap,
3375						     priv->gpu_bo, 0, 0,
3376						     pixmap->devPrivate.ptr,
3377						     pixmap->devKind,
3378						     0, 0,
3379						     box, n);
3380			}
3381			if (!ok)
3382				return NULL;
3383		}
3384
3385		sna_damage_destroy(&priv->cpu_damage);
3386	} else if (DAMAGE_IS_ALL(priv->cpu_damage) ||
3387		   sna_damage_contains_box__no_reduce(priv->cpu_damage, box)) {
3388		bool ok = false;
3389
3390		assert(sna_damage_contains_box(&priv->gpu_damage, box) == PIXMAN_REGION_OUT);
3391		assert(sna_damage_contains_box(&priv->cpu_damage, box) == PIXMAN_REGION_IN);
3392
3393		if (use_cpu_bo_for_upload(sna, priv, 0)) {
3394			DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__));
3395			ok = sna->render.copy_boxes(sna, GXcopy,
3396						    &pixmap->drawable, priv->cpu_bo, 0, 0,
3397						    &pixmap->drawable, priv->gpu_bo, 0, 0,
3398						    box, 1, 0);
3399		}
3400		if (!ok) {
3401			sna_pixmap_unmap(pixmap, priv);
3402			if (pixmap->devPrivate.ptr != NULL) {
3403				assert(pixmap->devKind);
3404				ok = sna_write_boxes(sna, pixmap,
3405						priv->gpu_bo, 0, 0,
3406						pixmap->devPrivate.ptr,
3407						pixmap->devKind,
3408						0, 0,
3409						box, 1);
3410			}
3411		}
3412		if (!ok)
3413			return NULL;
3414
3415		sna_damage_subtract(&priv->cpu_damage, &r);
3416	} else if (sna_damage_intersect(priv->cpu_damage, &r, &i)) {
3417		int n = region_num_rects(&i);
3418		bool ok;
3419
3420		box = region_rects(&i);
3421		ok = false;
3422		if (use_cpu_bo_for_upload(sna, priv, 0)) {
3423			DBG(("%s: using CPU bo for upload to GPU, %d boxes\n", __FUNCTION__, n));
3424			ok = sna->render.copy_boxes(sna, GXcopy,
3425						    &pixmap->drawable, priv->cpu_bo, 0, 0,
3426						    &pixmap->drawable, priv->gpu_bo, 0, 0,
3427						    box, n, 0);
3428		}
3429		if (!ok) {
3430			sna_pixmap_unmap(pixmap, priv);
3431			if (pixmap->devPrivate.ptr != NULL) {
3432				assert(pixmap->devKind);
3433				ok = sna_write_boxes(sna, pixmap,
3434						priv->gpu_bo, 0, 0,
3435						pixmap->devPrivate.ptr,
3436						pixmap->devKind,
3437						0, 0,
3438						box, n);
3439			}
3440		}
3441		if (!ok)
3442			return NULL;
3443
3444		sna_damage_subtract(&priv->cpu_damage, &r);
3445		RegionUninit(&i);
3446	}
3447
3448done:
3449	if (priv->cpu_damage == NULL && priv->flush)
3450		list_del(&priv->flush_list);
3451	if (flags & MOVE_WRITE) {
3452		priv->clear = false;
3453		if (!DAMAGE_IS_ALL(priv->gpu_damage) &&
3454		    priv->cpu_damage == NULL &&
3455		    (box_covers_pixmap(pixmap, &r.extents) ||
3456		     box_inplace(pixmap, &r.extents))) {
3457			DBG(("%s: large operation on undamaged, promoting to full GPU\n",
3458			     __FUNCTION__));
3459			assert(priv->gpu_bo);
3460			assert(priv->gpu_bo->proxy == NULL);
3461			if (sna_pixmap_free_cpu(sna, priv, priv->cpu))
3462				sna_damage_all(&priv->gpu_damage, pixmap);
3463		}
3464		if (DAMAGE_IS_ALL(priv->gpu_damage)) {
3465			sna_pixmap_free_cpu(sna, priv, priv->cpu);
3466			sna_damage_destroy(&priv->cpu_damage);
3467			list_del(&priv->flush_list);
3468		}
3469		priv->cpu = false;
3470	}
3471
3472	assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0);
3473	return sna_pixmap_mark_active(sna, priv);
3474}
3475
3476struct kgem_bo *
3477sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box,
3478		    struct sna_damage ***damage)
3479{
3480	PixmapPtr pixmap = get_drawable_pixmap(drawable);
3481	struct sna_pixmap *priv = sna_pixmap(pixmap);
3482	struct sna *sna;
3483	RegionRec region;
3484	int16_t dx, dy;
3485	int ret;
3486
3487	DBG(("%s pixmap=%ld, box=((%d, %d), (%d, %d)), flags=%x...\n",
3488	     __FUNCTION__,
3489	     pixmap->drawable.serialNumber,
3490	     box->x1, box->y1, box->x2, box->y2,
3491	     flags));
3492
3493	assert(box->x2 > box->x1 && box->y2 > box->y1);
3494	assert(pixmap->refcnt);
3495	assert_pixmap_damage(pixmap);
3496	assert_drawable_contains_box(drawable, box);
3497
3498	if (priv == NULL) {
3499		DBG(("%s: not attached\n", __FUNCTION__));
3500		return NULL;
3501	}
3502
3503	if (priv->cow) {
3504		unsigned cow = MOVE_WRITE | MOVE_READ;
3505
3506		if (flags & IGNORE_DAMAGE) {
3507			if (priv->gpu_damage) {
3508				region.extents = *box;
3509				if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3510					region.extents.x1 += dx;
3511					region.extents.x2 += dx;
3512					region.extents.y1 += dy;
3513					region.extents.y2 += dy;
3514				}
3515				region.data = NULL;
3516				if (region_subsumes_damage(&region,
3517							   priv->gpu_damage))
3518					cow &= ~MOVE_READ;
3519			} else
3520				cow &= ~MOVE_READ;
3521		}
3522
3523		if (!sna_pixmap_undo_cow(to_sna_from_pixmap(pixmap), priv, cow))
3524			return NULL;
3525
3526		if (priv->gpu_bo == NULL)
3527			sna_damage_destroy(&priv->gpu_damage);
3528	}
3529
3530	if (kgem_bo_discard_cache(priv->gpu_bo, true)) {
3531		DBG(("%s: cached upload proxy, discard and revert to GPU\n", __FUNCTION__));
3532		assert(DAMAGE_IS_ALL(priv->cpu_damage));
3533		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */
3534		assert(!priv->pinned);
3535		assert(!priv->mapped);
3536		sna_damage_destroy(&priv->gpu_damage);
3537		kgem_bo_destroy(&to_sna_from_pixmap(pixmap)->kgem,
3538				priv->gpu_bo);
3539		priv->gpu_bo = NULL;
3540		goto use_cpu_bo;
3541	}
3542
3543	if (priv->flush) {
3544		DBG(("%s: exported target, set PREFER_GPU\n", __FUNCTION__));
3545		flags |= PREFER_GPU;
3546	}
3547	if (priv->shm) {
3548		DBG(("%s: shm target, discard PREFER_GPU\n", __FUNCTION__));
3549		flags &= ~PREFER_GPU;
3550	}
3551	if (priv->pinned) {
3552		DBG(("%s: pinned, never REPLACES\n", __FUNCTION__));
3553		flags &= ~REPLACES;
3554	}
3555	if (priv->cpu && (flags & (FORCE_GPU | IGNORE_DAMAGE)) == 0) {
3556		DBG(("%s: last on cpu and needs damage, discard PREFER_GPU\n", __FUNCTION__));
3557		flags &= ~PREFER_GPU;
3558	}
3559
3560	if ((flags & (PREFER_GPU | IGNORE_DAMAGE)) == IGNORE_DAMAGE) {
3561		if (priv->gpu_bo && (box_covers_pixmap(pixmap, box) || box_inplace(pixmap, box))) {
3562			DBG(("%s: not reading damage and large, set PREFER_GPU\n", __FUNCTION__));
3563			flags |= PREFER_GPU;
3564		}
3565	}
3566
3567	DBG(("%s: flush=%d, shm=%d, cpu=%d => flags=%x\n",
3568	     __FUNCTION__, priv->flush, priv->shm, priv->cpu, flags));
3569
3570	if ((flags & PREFER_GPU) == 0 &&
3571	    (flags & (REPLACES | IGNORE_DAMAGE) || !priv->gpu_damage || !kgem_bo_is_busy(priv->gpu_bo))) {
3572		DBG(("%s: try cpu as GPU bo is idle\n", __FUNCTION__));
3573		goto use_cpu_bo;
3574	}
3575
3576	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
3577		DBG(("%s: use GPU fast path (all-damaged)\n", __FUNCTION__));
3578		assert(priv->cpu_damage == NULL);
3579		assert(priv->gpu_bo);
3580		assert(priv->gpu_bo->proxy == NULL);
3581		goto use_gpu_bo;
3582	}
3583
3584	if (DAMAGE_IS_ALL(priv->cpu_damage)) {
3585		assert(priv->gpu_damage == NULL);
3586		if ((flags & FORCE_GPU) == 0 || priv->cpu_bo) {
3587			DBG(("%s: use CPU fast path (all-damaged), and not forced-gpu\n",
3588			     __FUNCTION__));
3589			goto use_cpu_bo;
3590		}
3591	}
3592
3593	DBG(("%s: gpu? %d, damaged? %d; cpu? %d, damaged? %d\n", __FUNCTION__,
3594	     priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->gpu_damage != NULL,
3595	     priv->cpu_bo ? priv->cpu_bo->handle : 0, priv->cpu_damage != NULL));
3596	if (priv->gpu_bo == NULL) {
3597		unsigned int move;
3598
3599		if ((flags & FORCE_GPU) == 0 &&
3600		    (priv->create & KGEM_CAN_CREATE_GPU) == 0) {
3601			DBG(("%s: untiled, will not force allocation\n",
3602			     __FUNCTION__));
3603			goto use_cpu_bo;
3604		}
3605
3606		if ((flags & IGNORE_DAMAGE) == 0) {
3607			if (priv->cpu_bo) {
3608				if (to_sna_from_pixmap(pixmap)->kgem.can_blt_cpu) {
3609					if (kgem_bo_is_busy(priv->cpu_bo)) {
3610						DBG(("%s: already using CPU bo, will not force allocation\n",
3611						     __FUNCTION__));
3612						goto use_cpu_bo;
3613					}
3614
3615					if ((flags & RENDER_GPU) == 0) {
3616						DBG(("%s: prefer cpu", __FUNCTION__));
3617						goto use_cpu_bo;
3618					}
3619				} else {
3620					if (kgem_bo_is_busy(priv->cpu_bo)) {
3621						DBG(("%s: CPU bo active, must force allocation\n",
3622						     __FUNCTION__));
3623						goto create_gpu_bo;
3624					}
3625				}
3626			}
3627
3628			if ((flags & FORCE_GPU) == 0 && priv->cpu_damage) {
3629				if ((flags & PREFER_GPU) == 0) {
3630					DBG(("%s: already damaged and prefer cpu",
3631					     __FUNCTION__));
3632					goto use_cpu_bo;
3633				}
3634
3635				if (!box_inplace(pixmap, box)) {
3636					DBG(("%s: damaged with a small operation, will not force allocation\n",
3637					     __FUNCTION__));
3638					goto use_cpu_bo;
3639				}
3640			}
3641		} else if (priv->cpu_damage) {
3642			region.extents = *box;
3643			if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3644				region.extents.x1 += dx;
3645				region.extents.x2 += dx;
3646				region.extents.y1 += dy;
3647				region.extents.y2 += dy;
3648			}
3649			region.data = NULL;
3650
3651			sna_damage_subtract(&priv->cpu_damage, &region);
3652			if (priv->cpu_damage == NULL) {
3653				list_del(&priv->flush_list);
3654				priv->cpu = false;
3655			}
3656		}
3657
3658create_gpu_bo:
3659		move = MOVE_WRITE | MOVE_READ;
3660		if (flags & FORCE_GPU)
3661			move |= __MOVE_FORCE;
3662		if (!sna_pixmap_move_to_gpu(pixmap, move))
3663			goto use_cpu_bo;
3664
3665		DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__));
3666		goto done;
3667	}
3668
3669
3670	region.extents = *box;
3671	if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3672		region.extents.x1 += dx;
3673		region.extents.x2 += dx;
3674		region.extents.y1 += dy;
3675		region.extents.y2 += dy;
3676	}
3677	region.data = NULL;
3678
3679	DBG(("%s extents (%d, %d), (%d, %d)\n", __FUNCTION__,
3680	     region.extents.x1, region.extents.y1,
3681	     region.extents.x2, region.extents.y2));
3682
3683	if (priv->gpu_damage) {
3684		assert(priv->gpu_bo);
3685		if (!priv->cpu_damage || flags & IGNORE_DAMAGE) {
3686			if (flags & REPLACES || box_covers_pixmap(pixmap, &region.extents)) {
3687				unsigned int move;
3688
3689				if (flags & IGNORE_DAMAGE)
3690					move = MOVE_WRITE;
3691				else
3692					move = MOVE_WRITE | MOVE_READ;
3693
3694				if (sna_pixmap_move_to_gpu(pixmap, move))
3695					goto use_gpu_bo;
3696			}
3697
3698			if (DAMAGE_IS_ALL(priv->gpu_damage) ||
3699			    sna_damage_contains_box__no_reduce(priv->gpu_damage,
3700							       &region.extents)) {
3701				DBG(("%s: region wholly contained within GPU damage\n",
3702				     __FUNCTION__));
3703				assert(sna_damage_contains_box(&priv->gpu_damage, &region.extents) == PIXMAN_REGION_IN);
3704				assert(sna_damage_contains_box(&priv->cpu_damage, &region.extents) == PIXMAN_REGION_OUT);
3705				goto use_gpu_bo;
3706			} else {
3707				DBG(("%s: partial GPU damage with no CPU damage, continuing to use GPU\n",
3708				     __FUNCTION__));
3709				goto move_to_gpu;
3710			}
3711		}
3712
3713		ret = sna_damage_contains_box(&priv->gpu_damage, &region.extents);
3714		if (ret == PIXMAN_REGION_IN) {
3715			DBG(("%s: region wholly contained within GPU damage\n",
3716			     __FUNCTION__));
3717			goto use_gpu_bo;
3718		}
3719
3720		if (ret != PIXMAN_REGION_OUT) {
3721			DBG(("%s: region partially contained within GPU damage\n",
3722			     __FUNCTION__));
3723			goto move_to_gpu;
3724		}
3725	}
3726
3727	if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_damage) {
3728		ret = sna_damage_contains_box(&priv->cpu_damage, &region.extents);
3729		if (ret == PIXMAN_REGION_IN) {
3730			DBG(("%s: region wholly contained within CPU damage\n",
3731			     __FUNCTION__));
3732			goto use_cpu_bo;
3733		}
3734
3735		if (box_inplace(pixmap, box)) {
3736			DBG(("%s: forcing inplace\n", __FUNCTION__));
3737			goto move_to_gpu;
3738		}
3739
3740		if (ret != PIXMAN_REGION_OUT) {
3741			DBG(("%s: region partially contained within CPU damage\n",
3742			     __FUNCTION__));
3743			goto use_cpu_bo;
3744		}
3745	}
3746
3747move_to_gpu:
3748	if (!sna_pixmap_move_area_to_gpu(pixmap, &region.extents,
3749					 flags & IGNORE_DAMAGE ? MOVE_WRITE : MOVE_READ | MOVE_WRITE)) {
3750		DBG(("%s: failed to move-to-gpu, fallback\n", __FUNCTION__));
3751		assert(priv->gpu_bo == NULL);
3752		goto use_cpu_bo;
3753	}
3754
3755done:
3756	assert(priv->move_to_gpu == NULL);
3757	assert(priv->gpu_bo != NULL);
3758	assert(priv->gpu_bo->refcnt);
3759	if (sna_damage_is_all(&priv->gpu_damage,
3760			      pixmap->drawable.width,
3761			      pixmap->drawable.height)) {
3762		sna_damage_destroy(&priv->cpu_damage);
3763		list_del(&priv->flush_list);
3764		*damage = NULL;
3765	} else
3766		*damage = &priv->gpu_damage;
3767
3768	DBG(("%s: using GPU bo with damage? %d\n",
3769	     __FUNCTION__, *damage != NULL));
3770	assert(*damage == NULL || !DAMAGE_IS_ALL(*damage));
3771	assert(priv->gpu_bo->proxy == NULL);
3772	assert(priv->clear == false);
3773	assert(priv->cpu == false);
3774	assert(!priv->shm);
3775	return priv->gpu_bo;
3776
3777use_gpu_bo:
3778	if (priv->move_to_gpu) {
3779		unsigned hint = MOVE_READ | MOVE_WRITE;
3780
3781		sna = to_sna_from_pixmap(pixmap);
3782
3783		DBG(("%s: applying move-to-gpu override\n", __FUNCTION__));
3784		if (flags & IGNORE_DAMAGE) {
3785			region.extents = *box;
3786			region.data = NULL;
3787			if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3788				region.extents.x1 += dx;
3789				region.extents.x2 += dx;
3790				region.extents.y1 += dy;
3791				region.extents.y2 += dy;
3792			}
3793			sna_pixmap_discard_shadow_damage(priv, &region);
3794			if (region_subsumes_pixmap(&region, pixmap)) {
3795				DBG(("%s: discarding move-to-gpu READ for subsumed pixmap\n", __FUNCTION__));
3796				hint = MOVE_WRITE;
3797			}
3798		}
3799
3800		if (!priv->move_to_gpu(sna, priv, hint)) {
3801			DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
3802			goto use_cpu_bo;
3803		}
3804	}
3805
3806	if (priv->shm) {
3807		assert(!priv->flush);
3808		list_move(&priv->flush_list, &sna->flush_pixmaps);
3809	}
3810
3811	DBG(("%s: using whole GPU bo\n", __FUNCTION__));
3812	assert(priv->gpu_bo != NULL);
3813	assert(priv->gpu_bo->refcnt);
3814	assert(priv->gpu_bo->proxy == NULL);
3815	assert(priv->gpu_damage);
3816	priv->cpu = false;
3817	priv->clear = false;
3818	*damage = NULL;
3819	return priv->gpu_bo;
3820
3821use_cpu_bo:
3822	if (!USE_CPU_BO || priv->cpu_bo == NULL) {
3823		if ((flags & FORCE_GPU) == 0) {
3824			DBG(("%s: no CPU bo, and GPU not forced\n", __FUNCTION__));
3825			return NULL;
3826		}
3827
3828		flags &= ~FORCE_GPU;
3829
3830		region.extents = *box;
3831		if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3832			region.extents.x1 += dx;
3833			region.extents.x2 += dx;
3834			region.extents.y1 += dy;
3835			region.extents.y2 += dy;
3836		}
3837		region.data = NULL;
3838
3839		if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, &region,
3840						     (flags & IGNORE_DAMAGE ? 0 : MOVE_READ) | MOVE_WRITE | MOVE_ASYNC_HINT) ||
3841		    priv->cpu_bo == NULL) {
3842			DBG(("%s: did not create CPU bo\n", __FUNCTION__));
3843cpu_fail:
3844			if (priv->gpu_bo)
3845				goto move_to_gpu;
3846
3847			return NULL;
3848		}
3849	}
3850
3851	assert(priv->cpu_bo->refcnt);
3852
3853	sna = to_sna_from_pixmap(pixmap);
3854	if ((flags & FORCE_GPU) == 0 &&
3855	    !__kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
3856		DBG(("%s: has CPU bo, but is idle and acceleration not forced\n",
3857		     __FUNCTION__));
3858		return NULL;
3859	}
3860
3861	region.extents = *box;
3862	if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3863		region.extents.x1 += dx;
3864		region.extents.x2 += dx;
3865		region.extents.y1 += dy;
3866		region.extents.y2 += dy;
3867	}
3868	region.data = NULL;
3869
3870	if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) {
3871		DBG(("%s: both CPU and GPU are busy, prefer to use the GPU\n",
3872		     __FUNCTION__));
3873		goto move_to_gpu;
3874	}
3875
3876	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
3877
3878	if (flags & RENDER_GPU) {
3879		flags &= ~RENDER_GPU;
3880
3881		if ((flags & IGNORE_DAMAGE) == 0 && priv->gpu_damage) {
3882			DBG(("%s: prefer to use GPU bo for rendering whilst reading from GPU damage\n", __FUNCTION__));
3883
3884prefer_gpu_bo:
3885			if (priv->gpu_bo == NULL) {
3886				if ((flags & FORCE_GPU) == 0) {
3887					DBG(("%s: untiled, will not force allocation\n",
3888					     __FUNCTION__));
3889					return NULL;
3890				}
3891
3892				if (flags & IGNORE_DAMAGE) {
3893					sna_damage_subtract(&priv->cpu_damage, &region);
3894					if (priv->cpu_damage == NULL) {
3895						list_del(&priv->flush_list);
3896						priv->cpu = false;
3897					}
3898				}
3899
3900				if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | __MOVE_FORCE))
3901					return NULL;
3902
3903				sna_damage_all(&priv->gpu_damage, pixmap);
3904
3905				DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__));
3906				goto done;
3907			}
3908			goto move_to_gpu;
3909		}
3910
3911		if ((priv->cpu_damage == NULL || flags & IGNORE_DAMAGE)) {
3912			if (priv->gpu_bo && priv->gpu_bo->tiling) {
3913				DBG(("%s: prefer to use GPU bo for rendering large pixmaps\n", __FUNCTION__));
3914				goto prefer_gpu_bo;
3915			}
3916
3917			if (priv->cpu_bo->pitch >= 4096) {
3918				DBG(("%s: prefer to use GPU bo for rendering wide pixmaps\n", __FUNCTION__));
3919				goto prefer_gpu_bo;
3920			}
3921		}
3922
3923		if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_bo->snoop) {
3924			DBG(("%s: prefer to use GPU bo for reading from snooped target bo\n", __FUNCTION__));
3925			goto prefer_gpu_bo;
3926		}
3927
3928		if (!sna->kgem.can_blt_cpu) {
3929			DBG(("%s: can't render to CPU bo, try to use GPU bo\n", __FUNCTION__));
3930			goto prefer_gpu_bo;
3931		}
3932	}
3933
3934	if (!sna->kgem.can_blt_cpu)
3935		goto cpu_fail;
3936
3937	if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, &region,
3938					     (flags & IGNORE_DAMAGE ? 0 : MOVE_READ) | MOVE_WRITE | MOVE_ASYNC_HINT)) {
3939		DBG(("%s: failed to move-to-cpu, fallback\n", __FUNCTION__));
3940		goto cpu_fail;
3941	}
3942
3943	if (priv->shm) {
3944		assert(!priv->flush);
3945		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
3946
3947		/* As we may have flushed and retired,, recheck for busy bo */
3948		if ((flags & FORCE_GPU) == 0 && !kgem_bo_is_busy(priv->cpu_bo))
3949			return NULL;
3950	}
3951	if (priv->flush) {
3952		assert(!priv->shm);
3953		sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
3954	}
3955
3956	if (sna_damage_is_all(&priv->cpu_damage,
3957			      pixmap->drawable.width,
3958			      pixmap->drawable.height)) {
3959		sna_damage_destroy(&priv->gpu_damage);
3960		*damage = NULL;
3961	} else {
3962		assert(!DAMAGE_IS_ALL(priv->cpu_damage));
3963		if (priv->cpu_damage &&
3964		    sna_damage_contains_box__no_reduce(priv->cpu_damage,
3965						       &region.extents)) {
3966			assert(sna_damage_contains_box(&priv->gpu_damage, &region.extents) == PIXMAN_REGION_OUT);
3967			assert(sna_damage_contains_box(&priv->cpu_damage, &region.extents) == PIXMAN_REGION_IN);
3968			*damage = NULL;
3969		} else
3970			*damage = &priv->cpu_damage;
3971	}
3972
3973	DBG(("%s: using CPU bo with damage? %d\n",
3974	     __FUNCTION__, *damage != NULL));
3975	assert(damage == NULL || !DAMAGE_IS_ALL(*damage));
3976	assert(priv->clear == false);
3977	priv->cpu = false;
3978	return priv->cpu_bo;
3979}
3980
3981PixmapPtr
3982sna_pixmap_create_upload(ScreenPtr screen,
3983			 int width, int height, int depth,
3984			 unsigned flags)
3985{
3986	struct sna *sna = to_sna_from_screen(screen);
3987	PixmapPtr pixmap;
3988	struct sna_pixmap *priv;
3989	void *ptr;
3990
3991	DBG(("%s(%d, %d, %d, flags=%x)\n", __FUNCTION__,
3992	     width, height, depth, flags));
3993	assert(width);
3994	assert(height);
3995
3996	if (depth == 1)
3997		return create_pixmap(sna, screen, width, height, depth,
3998				     CREATE_PIXMAP_USAGE_SCRATCH);
3999
4000	pixmap = create_pixmap_hdr(sna, screen,
4001				   width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH,
4002				   &priv);
4003	if (!pixmap)
4004		return NullPixmap;
4005
4006	priv->gpu_bo = kgem_create_buffer_2d(&sna->kgem,
4007					     width, height,
4008					     pixmap->drawable.bitsPerPixel,
4009					     flags, &ptr);
4010	if (!priv->gpu_bo) {
4011		free(priv);
4012		FreePixmap(pixmap);
4013		return NullPixmap;
4014	}
4015
4016	/* Marking both the shadow and the GPU bo is a little dubious,
4017	 * but will work so long as we always check before doing the
4018	 * transfer.
4019	 */
4020	sna_damage_all(&priv->gpu_damage, pixmap);
4021	sna_damage_all(&priv->cpu_damage, pixmap);
4022
4023	pixmap->devKind = priv->gpu_bo->pitch;
4024	pixmap->devPrivate.ptr = ptr;
4025	priv->ptr = MAKE_STATIC_PTR(ptr);
4026	priv->stride = priv->gpu_bo->pitch;
4027	priv->create = 0;
4028
4029	pixmap->usage_hint = 0;
4030	if (!kgem_buffer_is_inplace(priv->gpu_bo))
4031		pixmap->usage_hint = 1;
4032
4033	DBG(("%s: serial=%ld, %dx%d, usage=%d\n",
4034	     __FUNCTION__,
4035	     pixmap->drawable.serialNumber,
4036	     pixmap->drawable.width,
4037	     pixmap->drawable.height,
4038	     pixmap->usage_hint));
4039	return pixmap;
4040}
4041
4042struct sna_pixmap *
4043sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
4044{
4045	struct sna *sna = to_sna_from_pixmap(pixmap);
4046	struct sna_pixmap *priv;
4047	const BoxRec *box;
4048	int n;
4049
4050	DBG(("%s(pixmap=%ld, usage=%d), flags=%x\n",
4051	     __FUNCTION__,
4052	     pixmap->drawable.serialNumber,
4053	     pixmap->usage_hint,
4054	     flags));
4055
4056	priv = __sna_pixmap_for_gpu(sna, pixmap, flags);
4057	if (priv == NULL)
4058		return NULL;
4059
4060	assert_pixmap_damage(pixmap);
4061
4062	if (priv->move_to_gpu &&
4063	    !priv->move_to_gpu(sna, priv, flags | ((priv->cpu_damage && (flags & MOVE_READ)) ? MOVE_WRITE : 0))) {
4064		DBG(("%s: move-to-gpu override failed\n", __FUNCTION__));
4065		return NULL;
4066	}
4067
4068	if ((flags & MOVE_READ) == 0 && UNDO)
4069		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
4070
4071	if (priv->cow) {
4072		unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE);
4073		if (flags & MOVE_READ && priv->cpu_damage)
4074			cow |= MOVE_WRITE;
4075		if (cow) {
4076			if (!sna_pixmap_undo_cow(sna, priv, cow))
4077				return NULL;
4078
4079			if (priv->gpu_bo == NULL)
4080				sna_damage_destroy(&priv->gpu_damage);
4081		}
4082	}
4083
4084	if (sna_damage_is_all(&priv->gpu_damage,
4085			      pixmap->drawable.width,
4086			      pixmap->drawable.height)) {
4087		DBG(("%s: already all-damaged\n", __FUNCTION__));
4088		assert(DAMAGE_IS_ALL(priv->gpu_damage));
4089		assert(priv->gpu_bo);
4090		assert(priv->gpu_bo->proxy == NULL);
4091		assert_pixmap_map(pixmap, priv);
4092		sna_damage_destroy(&priv->cpu_damage);
4093		list_del(&priv->flush_list);
4094		goto active;
4095	}
4096
4097	if ((flags & MOVE_READ) == 0)
4098		sna_damage_destroy(&priv->cpu_damage);
4099
4100	sna_damage_reduce(&priv->cpu_damage);
4101	assert_pixmap_damage(pixmap);
4102	DBG(("%s: CPU damage? %d\n", __FUNCTION__, priv->cpu_damage != NULL));
4103	if (priv->gpu_bo == NULL ||
4104	    kgem_bo_discard_cache(priv->gpu_bo, flags & (MOVE_WRITE | __MOVE_FORCE))) {
4105		struct kgem_bo *proxy;
4106
4107		proxy = priv->gpu_bo;
4108		priv->gpu_bo = NULL;
4109
4110		DBG(("%s: creating GPU bo (%dx%d@%d), create=%x\n",
4111		     __FUNCTION__,
4112		     pixmap->drawable.width,
4113		     pixmap->drawable.height,
4114		     pixmap->drawable.bitsPerPixel,
4115		     priv->create));
4116		assert(!priv->mapped);
4117		assert(list_is_empty(&priv->flush_list));
4118
4119		if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU) {
4120			bool is_linear;
4121
4122			assert(pixmap->drawable.width > 0);
4123			assert(pixmap->drawable.height > 0);
4124			assert(pixmap->drawable.bitsPerPixel >= 8);
4125
4126			is_linear = sna_pixmap_default_tiling(sna, pixmap) == I915_TILING_NONE;
4127			if (is_linear && flags & __MOVE_TILED) {
4128				DBG(("%s: not creating linear GPU bo\n", __FUNCTION__));
4129				return NULL;
4130			}
4131
4132			if (is_linear && priv->cpu_bo && !priv->shm &&
4133			    kgem_bo_convert_to_gpu(&sna->kgem, priv->cpu_bo, flags)) {
4134				assert(!priv->mapped);
4135				assert(!IS_STATIC_PTR(priv->ptr));
4136#ifdef DEBUG_MEMORY
4137				sna->debug_memory.cpu_bo_allocs--;
4138				sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
4139#endif
4140				priv->gpu_bo = priv->cpu_bo;
4141				priv->cpu_bo = NULL;
4142				priv->ptr = NULL;
4143				pixmap->devPrivate.ptr = NULL;
4144				sna_damage_all(&priv->gpu_damage, pixmap);
4145				sna_damage_destroy(&priv->cpu_damage);
4146			} else {
4147				unsigned create = 0;
4148				if (flags & MOVE_INPLACE_HINT || (priv->cpu_damage && priv->cpu_bo == NULL))
4149					create = CREATE_GTT_MAP | CREATE_INACTIVE;
4150
4151				sna_pixmap_alloc_gpu(sna, pixmap, priv, create);
4152			}
4153		}
4154
4155		if (priv->gpu_bo == NULL) {
4156			DBG(("%s: not creating GPU bo\n", __FUNCTION__));
4157			assert(priv->gpu_damage == NULL);
4158			priv->gpu_bo = proxy;
4159			if (proxy)
4160				sna_damage_all(&priv->cpu_damage, pixmap);
4161			return NULL;
4162		}
4163
4164		if (proxy) {
4165			DBG(("%s: promoting upload proxy handle=%d to GPU\n", __FUNCTION__, proxy->handle));
4166
4167			if (priv->cpu_damage &&
4168			    sna->render.copy_boxes(sna, GXcopy,
4169						   &pixmap->drawable, proxy, 0, 0,
4170						   &pixmap->drawable, priv->gpu_bo, 0, 0,
4171						   region_rects(DAMAGE_REGION(priv->cpu_damage)),
4172						   region_num_rects(DAMAGE_REGION(priv->cpu_damage)),
4173						   0))
4174				sna_damage_destroy(&priv->cpu_damage);
4175
4176			kgem_bo_destroy(&sna->kgem, proxy);
4177		}
4178
4179		if (flags & MOVE_WRITE && priv->cpu_damage == NULL) {
4180			/* Presume that we will only ever write to the GPU
4181			 * bo. Readbacks are expensive but fairly constant
4182			 * in cost for all sizes i.e. it is the act of
4183			 * synchronisation that takes the most time. This is
4184			 * mitigated by avoiding fallbacks in the first place.
4185			 */
4186			assert(priv->gpu_bo);
4187			assert(priv->gpu_bo->proxy == NULL);
4188			sna_damage_all(&priv->gpu_damage, pixmap);
4189			DBG(("%s: marking as all-damaged for GPU\n",
4190			     __FUNCTION__));
4191			goto active;
4192		}
4193	}
4194
4195	if (priv->gpu_bo->proxy) {
4196		DBG(("%s: reusing cached upload\n", __FUNCTION__));
4197		assert((flags & MOVE_WRITE) == 0);
4198		assert(priv->gpu_damage == NULL);
4199		return priv;
4200	}
4201
4202	if (priv->cpu_damage == NULL)
4203		goto done;
4204
4205	if (DAMAGE_IS_ALL(priv->cpu_damage) && priv->cpu_bo &&
4206	    !priv->pinned && !priv->shm &&
4207	    priv->gpu_bo->tiling == I915_TILING_NONE &&
4208	    kgem_bo_convert_to_gpu(&sna->kgem, priv->cpu_bo, flags)) {
4209		assert(!priv->mapped);
4210		assert(!IS_STATIC_PTR(priv->ptr));
4211#ifdef DEBUG_MEMORY
4212		sna->debug_memory.cpu_bo_allocs--;
4213		sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
4214#endif
4215		sna_pixmap_free_gpu(sna, priv);
4216		priv->gpu_bo = priv->cpu_bo;
4217		priv->cpu_bo = NULL;
4218		priv->ptr = NULL;
4219		pixmap->devPrivate.ptr = NULL;
4220		sna_damage_all(&priv->gpu_damage, pixmap);
4221		sna_damage_destroy(&priv->cpu_damage);
4222		goto done;
4223	}
4224
4225	if (priv->shm) {
4226		assert(!priv->flush);
4227		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
4228	}
4229
4230	n = sna_damage_get_boxes(priv->cpu_damage, &box);
4231	assert(n);
4232	if (n) {
4233		bool ok;
4234
4235		assert_pixmap_contains_damage(pixmap, priv->cpu_damage);
4236		DBG(("%s: uploading %d damage boxes\n", __FUNCTION__, n));
4237
4238		ok = false;
4239		if (use_cpu_bo_for_upload(sna, priv, flags)) {
4240			DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__));
4241			ok = sna->render.copy_boxes(sna, GXcopy,
4242						    &pixmap->drawable, priv->cpu_bo, 0, 0,
4243						    &pixmap->drawable, priv->gpu_bo, 0, 0,
4244						    box, n, 0);
4245		}
4246		if (!ok) {
4247			sna_pixmap_unmap(pixmap, priv);
4248			if (pixmap->devPrivate.ptr == NULL)
4249				return NULL;
4250
4251			assert(pixmap->devKind);
4252			if (n == 1 && !priv->pinned &&
4253			    (box->x2 - box->x1) >= pixmap->drawable.width &&
4254			    (box->y2 - box->y1) >= pixmap->drawable.height) {
4255				ok = sna_replace(sna, pixmap,
4256						 pixmap->devPrivate.ptr,
4257						 pixmap->devKind);
4258			} else {
4259				ok = sna_write_boxes(sna, pixmap,
4260						     priv->gpu_bo, 0, 0,
4261						     pixmap->devPrivate.ptr,
4262						     pixmap->devKind,
4263						     0, 0,
4264						     box, n);
4265			}
4266			if (!ok)
4267				return NULL;
4268		}
4269	}
4270
4271	__sna_damage_destroy(DAMAGE_PTR(priv->cpu_damage));
4272	priv->cpu_damage = NULL;
4273
4274	/* For large bo, try to keep only a single copy around */
4275	if (priv->create & KGEM_CAN_CREATE_LARGE || flags & MOVE_SOURCE_HINT) {
4276		DBG(("%s: disposing of system copy for large/source\n",
4277		     __FUNCTION__));
4278		assert(!priv->shm);
4279		assert(priv->gpu_bo);
4280		assert(priv->gpu_bo->proxy == NULL);
4281		sna_damage_all(&priv->gpu_damage, pixmap);
4282		sna_pixmap_free_cpu(sna, priv,
4283				    (priv->create & KGEM_CAN_CREATE_LARGE) ? false : priv->cpu);
4284	}
4285done:
4286	list_del(&priv->flush_list);
4287
4288	sna_damage_reduce_all(&priv->gpu_damage, pixmap);
4289	if (DAMAGE_IS_ALL(priv->gpu_damage))
4290		sna_pixmap_free_cpu(sna, priv, priv->cpu);
4291
4292active:
4293	if (flags & MOVE_WRITE) {
4294		priv->clear = false;
4295		priv->cpu = false;
4296	}
4297	assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0);
4298	return sna_pixmap_mark_active(sna, priv);
4299}
4300
4301static bool must_check sna_validate_pixmap(DrawablePtr draw, PixmapPtr pixmap)
4302{
4303	DBG(("%s: target bpp=%d, source bpp=%d\n",
4304	     __FUNCTION__, draw->bitsPerPixel, pixmap->drawable.bitsPerPixel));
4305
4306	if (draw->bitsPerPixel == pixmap->drawable.bitsPerPixel &&
4307	    FbEvenTile(pixmap->drawable.width *
4308		       pixmap->drawable.bitsPerPixel)) {
4309		DBG(("%s: flushing pixmap\n", __FUNCTION__));
4310		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
4311			return false;
4312
4313		fbPadPixmap(pixmap);
4314	}
4315
4316	return true;
4317}
4318
4319static bool must_check sna_gc_move_to_cpu(GCPtr gc,
4320					  DrawablePtr drawable,
4321					  RegionPtr region)
4322{
4323	struct sna_gc *sgc = sna_gc(gc);
4324	long changes = sgc->changes;
4325
4326	DBG(("%s(%p) changes=%lx\n", __FUNCTION__, gc, changes));
4327	assert(drawable);
4328	assert(region);
4329
4330	assert(gc->ops == (GCOps *)&sna_gc_ops);
4331	gc->ops = (GCOps *)&sna_gc_ops__cpu;
4332
4333	assert(gc->funcs);
4334	sgc->old_funcs = gc->funcs;
4335	gc->funcs = (GCFuncs *)&sna_gc_funcs__cpu;
4336
4337	assert(gc->pCompositeClip);
4338	sgc->priv = gc->pCompositeClip;
4339	gc->pCompositeClip = region;
4340
4341	if (gc->clientClipType == CT_PIXMAP) {
4342		PixmapPtr clip = gc->clientClip;
4343		gc->clientClip = region_from_bitmap(gc->pScreen, clip);
4344		gc->pScreen->DestroyPixmap(clip);
4345		gc->clientClipType = gc->clientClip ? CT_REGION : CT_NONE;
4346		changes |= GCClipMask;
4347	} else
4348		changes &= ~GCClipMask;
4349
4350	if (changes || drawable->serialNumber != (sgc->serial & DRAWABLE_SERIAL_BITS)) {
4351		long tmp = gc->serialNumber;
4352		gc->serialNumber = sgc->serial;
4353
4354		if (fb_gc(gc)->bpp != drawable->bitsPerPixel) {
4355			changes |= GCStipple | GCForeground | GCBackground | GCPlaneMask;
4356			fb_gc(gc)->bpp = drawable->bitsPerPixel;
4357		}
4358
4359		if (changes & GCTile && !gc->tileIsPixel) {
4360			DBG(("%s: flushing tile pixmap\n", __FUNCTION__));
4361			if (!sna_validate_pixmap(drawable, gc->tile.pixmap))
4362				return false;
4363		}
4364
4365		if (changes & GCStipple && gc->stipple) {
4366			DBG(("%s: flushing stipple pixmap\n", __FUNCTION__));
4367			if (!sna_validate_pixmap(drawable, gc->stipple))
4368				return false;
4369		}
4370
4371		fbValidateGC(gc, changes, drawable);
4372		gc->serialNumber = tmp;
4373	}
4374	sgc->changes = 0;
4375
4376	switch (gc->fillStyle) {
4377	case FillTiled:
4378		DBG(("%s: moving tile to cpu\n", __FUNCTION__));
4379		return sna_drawable_move_to_cpu(&gc->tile.pixmap->drawable, MOVE_READ);
4380	case FillStippled:
4381	case FillOpaqueStippled:
4382		DBG(("%s: moving stipple to cpu\n", __FUNCTION__));
4383		return sna_drawable_move_to_cpu(&gc->stipple->drawable, MOVE_READ);
4384	default:
4385		return true;
4386	}
4387}
4388
4389static void sna_gc_move_to_gpu(GCPtr gc)
4390{
4391	DBG(("%s(%p)\n", __FUNCTION__, gc));
4392
4393	assert(gc->ops == (GCOps *)&sna_gc_ops__cpu);
4394	assert(gc->funcs == (GCFuncs *)&sna_gc_funcs__cpu);
4395
4396	gc->ops = (GCOps *)&sna_gc_ops;
4397	gc->funcs = (GCFuncs *)sna_gc(gc)->old_funcs;
4398	assert(gc->funcs);
4399	gc->pCompositeClip = sna_gc(gc)->priv;
4400	assert(gc->pCompositeClip);
4401}
4402
4403static inline bool clip_box(BoxPtr box, GCPtr gc)
4404{
4405	const BoxRec *clip;
4406	bool clipped;
4407
4408	assert(gc->pCompositeClip);
4409	clip = &gc->pCompositeClip->extents;
4410
4411	clipped = !region_is_singular(gc->pCompositeClip);
4412	if (box->x1 < clip->x1)
4413		box->x1 = clip->x1, clipped = true;
4414	if (box->x2 > clip->x2)
4415		box->x2 = clip->x2, clipped = true;
4416
4417	if (box->y1 < clip->y1)
4418		box->y1 = clip->y1, clipped = true;
4419	if (box->y2 > clip->y2)
4420		box->y2 = clip->y2, clipped = true;
4421
4422	return clipped;
4423}
4424
4425static inline void translate_box(BoxPtr box, DrawablePtr d)
4426{
4427	box->x1 += d->x;
4428	box->x2 += d->x;
4429
4430	box->y1 += d->y;
4431	box->y2 += d->y;
4432}
4433
4434static inline bool trim_and_translate_box(BoxPtr box, DrawablePtr d, GCPtr gc)
4435{
4436	translate_box(box, d);
4437	return clip_box(box, gc);
4438}
4439
4440static inline bool box32_clip(Box32Rec *box, GCPtr gc)
4441{
4442	bool clipped = !region_is_singular(gc->pCompositeClip);
4443	const BoxRec *clip = &gc->pCompositeClip->extents;
4444
4445	if (box->x1 < clip->x1)
4446		box->x1 = clip->x1, clipped = true;
4447	if (box->x2 > clip->x2)
4448		box->x2 = clip->x2, clipped = true;
4449
4450	if (box->y1 < clip->y1)
4451		box->y1 = clip->y1, clipped = true;
4452	if (box->y2 > clip->y2)
4453		box->y2 = clip->y2, clipped = true;
4454
4455	return clipped;
4456}
4457
4458static inline void box32_translate(Box32Rec *box, DrawablePtr d)
4459{
4460	box->x1 += d->x;
4461	box->x2 += d->x;
4462
4463	box->y1 += d->y;
4464	box->y2 += d->y;
4465}
4466
4467static inline bool box32_trim_and_translate(Box32Rec *box, DrawablePtr d, GCPtr gc)
4468{
4469	box32_translate(box, d);
4470	return box32_clip(box, gc);
4471}
4472
4473static inline void box_add_pt(BoxPtr box, int16_t x, int16_t y)
4474{
4475	if (box->x1 > x)
4476		box->x1 = x;
4477	else if (box->x2 < x)
4478		box->x2 = x;
4479
4480	if (box->y1 > y)
4481		box->y1 = y;
4482	else if (box->y2 < y)
4483		box->y2 = y;
4484}
4485
4486static inline bool box32_to_box16(const Box32Rec *b32, BoxRec *b16)
4487{
4488	b16->x1 = b32->x1;
4489	b16->y1 = b32->y1;
4490	b16->x2 = b32->x2;
4491	b16->y2 = b32->y2;
4492
4493	return b16->x2 > b16->x1 && b16->y2 > b16->y1;
4494}
4495
4496static inline void box32_add_rect(Box32Rec *box, const xRectangle *r)
4497{
4498	int32_t v;
4499
4500	v = r->x;
4501	if (box->x1 > v)
4502		box->x1 = v;
4503	v += r->width;
4504	if (box->x2 < v)
4505		box->x2 = v;
4506
4507	v = r->y;
4508	if (box->y1 > v)
4509		box->y1 = v;
4510	v += r->height;
4511	if (box->y2 < v)
4512		box->y2 = v;
4513}
4514
4515static bool
4516can_create_upload_tiled_x(struct sna *sna,
4517			  PixmapPtr pixmap,
4518			  struct sna_pixmap *priv,
4519			  bool replaces)
4520{
4521	if (priv->shm || (priv->cpu && !replaces))
4522		return false;
4523
4524	if ((priv->create & KGEM_CAN_CREATE_GPU) == 0)
4525		return false;
4526
4527	if (sna->kgem.has_llc)
4528		return true;
4529
4530	if (sna_pixmap_default_tiling(sna, pixmap))
4531		return false;
4532
4533	return true;
4534}
4535
4536static bool
4537create_upload_tiled_x(struct sna *sna,
4538		      PixmapPtr pixmap,
4539		      struct sna_pixmap *priv,
4540		      bool replaces)
4541{
4542	unsigned create;
4543
4544	if (!can_create_upload_tiled_x(sna, pixmap, priv, replaces))
4545		return false;
4546
4547	assert(priv->gpu_bo == NULL);
4548	assert(priv->gpu_damage == NULL);
4549
4550	create = CREATE_CPU_MAP | CREATE_INACTIVE;
4551	if (!sna->kgem.has_llc)
4552		create |= CREATE_CACHED;
4553
4554	return sna_pixmap_alloc_gpu(sna, pixmap, priv, create);
4555}
4556
4557static bool
4558try_upload__tiled_x(PixmapPtr pixmap, RegionRec *region,
4559		    int x, int y, int w, int  h, char *bits, int stride)
4560{
4561	struct sna *sna = to_sna_from_pixmap(pixmap);
4562	struct sna_pixmap *priv = sna_pixmap(pixmap);
4563	const BoxRec *box;
4564	uint8_t *dst;
4565	int n;
4566
4567	if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true)) {
4568		DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__));
4569		return false;
4570	}
4571
4572	if (!sna_pixmap_move_area_to_gpu(pixmap, &region->extents,
4573					 MOVE_WRITE | (region->data ? MOVE_READ : 0)))
4574		return false;
4575
4576	if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 &&
4577	    __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
4578		return false;
4579
4580	dst = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
4581	if (dst == NULL)
4582		return false;
4583
4584	kgem_bo_sync__cpu(&sna->kgem, priv->gpu_bo);
4585
4586	box = region_rects(region);
4587	n = region_num_rects(region);
4588
4589	DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n));
4590
4591	if (sigtrap_get())
4592		return false;
4593
4594	if (priv->gpu_bo->tiling) {
4595		do {
4596			DBG(("%s: copy tiled box (%d, %d)->(%d, %d)x(%d, %d)\n",
4597			     __FUNCTION__,
4598			     box->x1 - x, box->y1 - y,
4599			     box->x1, box->y1,
4600			     box->x2 - box->x1, box->y2 - box->y1));
4601
4602			assert(box->x2 > box->x1);
4603			assert(box->y2 > box->y1);
4604
4605			assert(box->x1 >= 0);
4606			assert(box->y1 >= 0);
4607			assert(box->x2 <= pixmap->drawable.width);
4608			assert(box->y2 <= pixmap->drawable.height);
4609
4610			assert(box->x1 - x >= 0);
4611			assert(box->y1 - y >= 0);
4612			assert(box->x2 - x <= w);
4613			assert(box->y2 - y <= h);
4614
4615			memcpy_to_tiled_x(&sna->kgem, bits, dst,
4616					  pixmap->drawable.bitsPerPixel,
4617					  stride, priv->gpu_bo->pitch,
4618					  box->x1 - x, box->y1 - y,
4619					  box->x1, box->y1,
4620					  box->x2 - box->x1, box->y2 - box->y1);
4621			box++;
4622		} while (--n);
4623	} else {
4624		do {
4625			DBG(("%s: copy lined box (%d, %d)->(%d, %d)x(%d, %d)\n",
4626			     __FUNCTION__,
4627			     box->x1 - x, box->y1 - y,
4628			     box->x1, box->y1,
4629			     box->x2 - box->x1, box->y2 - box->y1));
4630
4631			assert(box->x2 > box->x1);
4632			assert(box->y2 > box->y1);
4633
4634			assert(box->x1 >= 0);
4635			assert(box->y1 >= 0);
4636			assert(box->x2 <= pixmap->drawable.width);
4637			assert(box->y2 <= pixmap->drawable.height);
4638
4639			assert(box->x1 - x >= 0);
4640			assert(box->y1 - y >= 0);
4641			assert(box->x2 - x <= w);
4642			assert(box->y2 - y <= h);
4643
4644			memcpy_blt(bits, dst,
4645				   pixmap->drawable.bitsPerPixel,
4646				   stride, priv->gpu_bo->pitch,
4647				   box->x1 - x, box->y1 - y,
4648				   box->x1, box->y1,
4649				   box->x2 - box->x1, box->y2 - box->y1);
4650			box++;
4651		} while (--n);
4652
4653		if (!priv->shm) {
4654			assert(dst == MAP(priv->gpu_bo->map__cpu));
4655			pixmap->devPrivate.ptr = dst;
4656			pixmap->devKind = priv->gpu_bo->pitch;
4657			priv->mapped = MAPPED_CPU;
4658			assert_pixmap_map(pixmap, priv);
4659			priv->cpu = true;
4660		}
4661	}
4662
4663	sigtrap_put();
4664	return true;
4665}
4666
4667static bool
4668try_upload__inplace(PixmapPtr pixmap, RegionRec *region,
4669		    int x, int y, int w, int  h, char *bits, int stride)
4670{
4671	struct sna *sna = to_sna_from_pixmap(pixmap);
4672	struct sna_pixmap *priv = sna_pixmap(pixmap);
4673	bool ignore_cpu = false;
4674	bool replaces;
4675	const BoxRec *box;
4676	uint8_t *dst;
4677	int n;
4678
4679	if (!USE_INPLACE)
4680		return false;
4681
4682	assert(priv);
4683
4684	if (priv->shm && priv->gpu_damage == NULL)
4685		return false;
4686
4687	replaces = region_subsumes_pixmap(region, pixmap);
4688
4689	DBG(("%s: bo? %d, can map? %d, replaces? %d\n", __FUNCTION__,
4690	     priv->gpu_bo != NULL,
4691	     priv->gpu_bo ? kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true) : 0,
4692	     replaces));
4693
4694	if (kgem_bo_discard_cache(priv->gpu_bo, true)) {
4695		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
4696		assert(DAMAGE_IS_ALL(priv->cpu_damage));
4697		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */
4698		assert(!priv->pinned);
4699		assert(!priv->mapped);
4700		sna_damage_destroy(&priv->gpu_damage);
4701		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
4702		priv->gpu_bo = NULL;
4703	}
4704
4705	if (priv->gpu_bo && replaces) {
4706		if (UNDO) kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
4707		if (can_create_upload_tiled_x(sna, pixmap, priv, true) &&
4708		    (priv->cow ||
4709		     __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo) ||
4710		     !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))) {
4711			DBG(("%s: discarding unusable target bo (busy? %d, mappable? %d)\n", __FUNCTION__,
4712			     kgem_bo_is_busy(priv->gpu_bo),
4713			     kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true)));
4714			sna_pixmap_free_gpu(sna, priv);
4715			ignore_cpu = true;
4716		}
4717	}
4718	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
4719
4720	if (priv->cow ||
4721	    (priv->move_to_gpu && !sna_pixmap_discard_shadow_damage(priv, replaces ? NULL : region))) {
4722		DBG(("%s: no, has pending COW? %d or move-to-gpu? %d\n",
4723		     __FUNCTION__, priv->cow != NULL, priv->move_to_gpu != NULL));
4724		return false;
4725	}
4726
4727	if (priv->gpu_damage &&
4728	    region_subsumes_damage(region, priv->gpu_damage)) {
4729		if (UNDO) kgem_bo_undo(&sna->kgem, priv->gpu_bo);
4730		if (can_create_upload_tiled_x(sna, pixmap, priv, priv->cpu_damage == NULL) &&
4731		    (__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo) ||
4732		     !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))) {
4733			DBG(("%s: discarding unusable partial target bo (busy? %d, mappable? %d)\n", __FUNCTION__,
4734			     kgem_bo_is_busy(priv->gpu_bo),
4735			     kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true)));
4736			sna_pixmap_free_gpu(sna, priv);
4737			ignore_cpu = priv->cpu_damage == NULL;
4738			if (priv->ptr)
4739				sna_damage_all(&priv->cpu_damage, pixmap);
4740		}
4741	}
4742
4743	if (priv->gpu_bo == NULL &&
4744	    !create_upload_tiled_x(sna, pixmap, priv, ignore_cpu))
4745		return false;
4746
4747	DBG(("%s: tiling=%d\n", __FUNCTION__, priv->gpu_bo->tiling));
4748	switch (priv->gpu_bo->tiling) {
4749	case I915_TILING_Y:
4750		break;
4751	case I915_TILING_X:
4752		if (!sna->kgem.memcpy_to_tiled_x)
4753			break;
4754	default:
4755		if (try_upload__tiled_x(pixmap, region, x, y, w, h, bits, stride))
4756			goto done;
4757		break;
4758	}
4759
4760	if (priv->gpu_damage == NULL && !box_inplace(pixmap, &region->extents)) {
4761		DBG(("%s: no, too small to bother with using the GTT\n", __FUNCTION__));
4762		return false;
4763	}
4764
4765	if (!kgem_bo_can_map(&sna->kgem, priv->gpu_bo)) {
4766		DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__));
4767		return false;
4768	}
4769
4770	if (!sna_pixmap_move_area_to_gpu(pixmap, &region->extents,
4771					 MOVE_WRITE | (region->data ? MOVE_READ : 0)))
4772		return false;
4773
4774	if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 &&
4775	    __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
4776		return false;
4777
4778	dst = kgem_bo_map(&sna->kgem, priv->gpu_bo);
4779	if (dst == NULL)
4780		return false;
4781
4782	pixmap->devPrivate.ptr = dst;
4783	pixmap->devKind = priv->gpu_bo->pitch;
4784	priv->mapped = dst == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
4785	assert(has_coherent_ptr(sna, priv, MOVE_WRITE));
4786
4787	box = region_rects(region);
4788	n = region_num_rects(region);
4789
4790	DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n));
4791
4792	if (sigtrap_get())
4793		return false;
4794
4795	do {
4796		DBG(("%s: copy lined box (%d, %d)->(%d, %d)x(%d, %d)\n",
4797		     __FUNCTION__,
4798		     box->x1 - x, box->y1 - y,
4799		     box->x1, box->y1,
4800		     box->x2 - box->x1, box->y2 - box->y1));
4801
4802		assert(box->x2 > box->x1);
4803		assert(box->y2 > box->y1);
4804
4805		assert(box->x1 >= 0);
4806		assert(box->y1 >= 0);
4807		assert(box->x2 <= pixmap->drawable.width);
4808		assert(box->y2 <= pixmap->drawable.height);
4809
4810		assert(box->x1 - x >= 0);
4811		assert(box->y1 - y >= 0);
4812		assert(box->x2 - x <= w);
4813		assert(box->y2 - y <= h);
4814
4815		memcpy_blt(bits, dst,
4816			   pixmap->drawable.bitsPerPixel,
4817			   stride, priv->gpu_bo->pitch,
4818			   box->x1 - x, box->y1 - y,
4819			   box->x1, box->y1,
4820			   box->x2 - box->x1, box->y2 - box->y1);
4821		box++;
4822	} while (--n);
4823
4824	sigtrap_put();
4825
4826done:
4827	if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
4828		if (replaces) {
4829			sna_damage_all(&priv->gpu_damage, pixmap);
4830		} else {
4831			sna_damage_add(&priv->gpu_damage, region);
4832			sna_damage_reduce_all(&priv->gpu_damage, pixmap);
4833		}
4834		if (DAMAGE_IS_ALL(priv->gpu_damage))
4835			sna_damage_destroy(&priv->cpu_damage);
4836		else
4837			sna_damage_subtract(&priv->cpu_damage, region);
4838
4839		if (priv->cpu_damage == NULL) {
4840			list_del(&priv->flush_list);
4841			sna_damage_all(&priv->gpu_damage, pixmap);
4842		}
4843
4844		if (priv->shm)
4845			sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
4846	}
4847
4848	assert(!priv->clear);
4849	return true;
4850}
4851
4852static bool
4853try_upload__blt(PixmapPtr pixmap, RegionRec *region,
4854		int x, int y, int w, int  h, char *bits, int stride)
4855{
4856	struct sna *sna = to_sna_from_pixmap(pixmap);
4857	struct sna_pixmap *priv;
4858	struct kgem_bo *src_bo;
4859	bool ok;
4860
4861	if (!sna->kgem.has_userptr || !USE_USERPTR_UPLOADS)
4862		return false;
4863
4864	priv = sna_pixmap(pixmap);
4865	assert(priv);
4866	assert(priv->gpu_bo);
4867	assert(priv->gpu_bo->proxy == NULL);
4868
4869	if (priv->cpu_damage &&
4870	    (DAMAGE_IS_ALL(priv->cpu_damage) ||
4871	     sna_damage_contains_box__no_reduce(priv->cpu_damage,
4872						&region->extents)) &&
4873	    !box_inplace(pixmap, &region->extents)) {
4874		DBG(("%s: no, damage on CPU and too small\n", __FUNCTION__));
4875		return false;
4876	}
4877
4878	src_bo = kgem_create_map(&sna->kgem, bits, stride * h, true);
4879	if (src_bo == NULL)
4880		return false;
4881
4882	src_bo->pitch = stride;
4883	kgem_bo_mark_unreusable(src_bo);
4884
4885	if (!sna_pixmap_move_area_to_gpu(pixmap, &region->extents,
4886					 MOVE_WRITE | MOVE_ASYNC_HINT | (region->data ? MOVE_READ : 0))) {
4887		kgem_bo_destroy(&sna->kgem, src_bo);
4888		return false;
4889	}
4890
4891	DBG(("%s: upload(%d, %d, %d, %d) x %d through a temporary map\n",
4892	     __FUNCTION__, x, y, w, h, region_num_rects(region)));
4893
4894	if (sigtrap_get() == 0) {
4895		ok = sna->render.copy_boxes(sna, GXcopy,
4896					    &pixmap->drawable, src_bo, -x, -y,
4897					    &pixmap->drawable, priv->gpu_bo, 0, 0,
4898					    region_rects(region),
4899					    region_num_rects(region),
4900					    COPY_LAST);
4901		sigtrap_put();
4902	} else
4903		ok = false;
4904
4905	kgem_bo_sync__cpu(&sna->kgem, src_bo);
4906	assert(src_bo->rq == NULL);
4907	kgem_bo_destroy(&sna->kgem, src_bo);
4908
4909	if (!ok) {
4910		DBG(("%s: copy failed!\n", __FUNCTION__));
4911		return false;
4912	}
4913
4914	if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
4915		assert(!priv->clear);
4916		if (region_subsumes_drawable(region, &pixmap->drawable)) {
4917			sna_damage_all(&priv->gpu_damage, pixmap);
4918		} else {
4919			sna_damage_add(&priv->gpu_damage, region);
4920			sna_damage_reduce_all(&priv->gpu_damage, pixmap);
4921		}
4922		if (DAMAGE_IS_ALL(priv->gpu_damage))
4923			sna_damage_destroy(&priv->cpu_damage);
4924		else
4925			sna_damage_subtract(&priv->cpu_damage, region);
4926		if (priv->cpu_damage == NULL) {
4927			list_del(&priv->flush_list);
4928			if (sna_pixmap_free_cpu(sna, priv, priv->cpu))
4929				sna_damage_all(&priv->gpu_damage, pixmap);
4930		}
4931	}
4932	priv->cpu = false;
4933	priv->clear = false;
4934
4935	return true;
4936}
4937
4938static bool ignore_cpu_damage(struct sna *sna, struct sna_pixmap *priv, const RegionRec *region)
4939{
4940	if (region_subsumes_pixmap(region, priv->pixmap))
4941		return true;
4942
4943	if (priv->cpu_damage != NULL) {
4944		if (DAMAGE_IS_ALL(priv->cpu_damage))
4945			return false;
4946
4947		if (!box_inplace(priv->pixmap, &region->extents))
4948			return false;
4949
4950		if (sna_damage_contains_box__no_reduce(priv->cpu_damage, &region->extents))
4951			return false;
4952	}
4953
4954	return priv->gpu_bo == NULL || !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo);
4955
4956}
4957
4958static bool
4959try_upload__fast(PixmapPtr pixmap, RegionRec *region,
4960		 int x, int y, int w, int  h, char *bits, int stride)
4961{
4962	struct sna *sna = to_sna_from_pixmap(pixmap);
4963	struct sna_pixmap *priv;
4964
4965	if (wedged(sna))
4966		return false;
4967
4968	priv = sna_pixmap(pixmap);
4969	if (priv == NULL)
4970		return false;
4971
4972	if (ignore_cpu_damage(sna, priv, region)) {
4973		DBG(("%s: ignore existing cpu damage (if any)\n", __FUNCTION__));
4974		if (try_upload__inplace(pixmap, region, x, y, w, h, bits, stride))
4975			return true;
4976	}
4977
4978	if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL || priv->cpu) {
4979		DBG(("%s: no, no gpu damage\n", __FUNCTION__));
4980		return false;
4981	}
4982
4983	assert(priv->gpu_bo);
4984	assert(priv->gpu_bo->proxy == NULL);
4985
4986	if (try_upload__blt(pixmap, region, x, y, w, h, bits, stride))
4987		return true;
4988
4989	if (try_upload__inplace(pixmap, region, x, y, w, h, bits, stride))
4990		return true;
4991
4992	return false;
4993}
4994
4995static bool
4996sna_put_zpixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
4997		    int x, int y, int w, int  h, char *bits, int stride)
4998{
4999	PixmapPtr pixmap = get_drawable_pixmap(drawable);
5000	unsigned int hint;
5001	const BoxRec *box;
5002	int16_t dx, dy;
5003	int n;
5004
5005	assert_pixmap_contains_box(pixmap, RegionExtents(region));
5006
5007	if (gc->alu != GXcopy)
5008		return false;
5009
5010	if (drawable->depth < 8)
5011		return false;
5012
5013	get_drawable_deltas(drawable, pixmap, &dx, &dy);
5014	x += dx + drawable->x;
5015	y += dy + drawable->y;
5016	assert(region->extents.x1 >= x);
5017	assert(region->extents.y1 >= y);
5018	assert(region->extents.x2 <= x + w);
5019	assert(region->extents.y2 <= y + h);
5020
5021	if (try_upload__fast(pixmap, region, x, y, w, h, bits, stride))
5022		return true;
5023
5024	hint = MOVE_WRITE;
5025	if (region_is_unclipped(region, pixmap->drawable.width, h) &&
5026	    (h+1)*stride > 65536) {
5027		DBG(("%s: segmented, unclipped large upload (%d bytes), marking WHOLE_HINT\n",
5028		     __FUNCTION__, h*stride));
5029		hint |= MOVE_WHOLE_HINT;
5030	}
5031
5032	if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, region, hint))
5033		return false;
5034
5035	if (sigtrap_get())
5036		return false;
5037
5038	/* Region is pre-clipped and translated into pixmap space */
5039	box = region_rects(region);
5040	n = region_num_rects(region);
5041	DBG(("%s: upload(%d, %d, %d, %d) x %d boxes\n", __FUNCTION__, x, y, w, h, n));
5042	do {
5043		DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n",
5044		     __FUNCTION__,
5045		     box->x1 - x, box->y1 - y,
5046		     box->x1, box->y1,
5047		     box->x2 - box->x1, box->y2 - box->y1));
5048
5049		assert(box->x2 > box->x1);
5050		assert(box->y2 > box->y1);
5051
5052		assert(box->x1 >= 0);
5053		assert(box->y1 >= 0);
5054		assert(box->x2 <= pixmap->drawable.width);
5055		assert(box->y2 <= pixmap->drawable.height);
5056
5057		assert(box->x1 - x >= 0);
5058		assert(box->y1 - y >= 0);
5059		assert(box->x2 - x <= w);
5060		assert(box->y2 - y <= h);
5061
5062		assert(has_coherent_ptr(to_sna_from_pixmap(pixmap), sna_pixmap(pixmap), MOVE_WRITE));
5063		assert(pixmap->devKind);
5064		memcpy_blt(bits, pixmap->devPrivate.ptr,
5065			   pixmap->drawable.bitsPerPixel,
5066			   stride, pixmap->devKind,
5067			   box->x1 - x, box->y1 - y,
5068			   box->x1, box->y1,
5069			   box->x2 - box->x1, box->y2 - box->y1);
5070		box++;
5071	} while (--n);
5072
5073	sigtrap_put();
5074	assert_pixmap_damage(pixmap);
5075	return true;
5076}
5077
5078static inline uint8_t byte_reverse(uint8_t b)
5079{
5080	return ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
5081}
5082
5083static inline uint8_t blt_depth(int depth)
5084{
5085	switch (depth) {
5086	case 8: return 0;
5087	case 15: return 0x2;
5088	case 16: return 0x1;
5089	default: return 0x3;
5090	}
5091}
5092
5093static bool
5094sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
5095		     int x, int y, int w, int  h, char *bits)
5096{
5097	PixmapPtr pixmap = get_drawable_pixmap(drawable);
5098	struct sna *sna = to_sna_from_pixmap(pixmap);
5099	struct sna_damage **damage;
5100	struct kgem_bo *bo;
5101	const BoxRec *box;
5102	int16_t dx, dy;
5103	int n;
5104	uint8_t rop = copy_ROP[gc->alu];
5105
5106	bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU,
5107				 &region->extents, &damage);
5108	if (bo == NULL)
5109		return false;
5110
5111	if (bo->tiling == I915_TILING_Y) {
5112		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
5113		assert(bo == __sna_pixmap_get_bo(pixmap));
5114		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
5115		if (bo == NULL) {
5116			DBG(("%s: fallback -- unable to change tiling\n",
5117			     __FUNCTION__));
5118			return false;
5119		}
5120	}
5121
5122	assert_pixmap_contains_box(pixmap, RegionExtents(region));
5123	if (damage)
5124		sna_damage_add(damage, region);
5125	assert_pixmap_damage(pixmap);
5126
5127	DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h));
5128
5129	get_drawable_deltas(drawable, pixmap, &dx, &dy);
5130	x += dx + drawable->x;
5131	y += dy + drawable->y;
5132
5133	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
5134
5135	/* Region is pre-clipped and translated into pixmap space */
5136	box = region_rects(region);
5137	n = region_num_rects(region);
5138	do {
5139		int bx1 = (box->x1 - x) & ~7;
5140		int bx2 = (box->x2 - x + 7) & ~7;
5141		int bw = (bx2 - bx1)/8;
5142		int bh = box->y2 - box->y1;
5143		int bstride = ALIGN(bw, 2);
5144		struct kgem_bo *upload;
5145		void *ptr;
5146
5147		if (!kgem_check_batch(&sna->kgem, 10) ||
5148		    !kgem_check_bo_fenced(&sna->kgem, bo) ||
5149		    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
5150			kgem_submit(&sna->kgem);
5151			if (!kgem_check_bo_fenced(&sna->kgem, bo))
5152				return false;
5153			_kgem_set_mode(&sna->kgem, KGEM_BLT);
5154		}
5155
5156		upload = kgem_create_buffer(&sna->kgem,
5157					    bstride*bh,
5158					    KGEM_BUFFER_WRITE_INPLACE,
5159					    &ptr);
5160		if (!upload)
5161			break;
5162
5163
5164		if (sigtrap_get() == 0) {
5165			int src_stride = BitmapBytePad(w);
5166			uint8_t *dst = ptr;
5167			uint8_t *src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8;
5168			uint32_t *b;
5169
5170			bstride -= bw;
5171			src_stride -= bw;
5172
5173			do {
5174				int i = bw;
5175				assert(src >= (uint8_t *)bits);
5176				do {
5177					*dst++ = byte_reverse(*src++);
5178				} while (--i);
5179				assert(src <= (uint8_t *)bits + BitmapBytePad(w) * h);
5180				assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload));
5181				dst += bstride;
5182				src += src_stride;
5183			} while (--bh);
5184
5185			assert(sna->kgem.mode == KGEM_BLT);
5186			if (sna->kgem.gen >= 0100) {
5187				b = sna->kgem.batch + sna->kgem.nbatch;
5188				b[0] = XY_MONO_SRC_COPY | 3 << 20 | 8;
5189				b[0] |= ((box->x1 - x) & 7) << 17;
5190				b[1] = bo->pitch;
5191				if (bo->tiling) {
5192					b[0] |= BLT_DST_TILED;
5193					b[1] >>= 2;
5194				}
5195				b[1] |= blt_depth(drawable->depth) << 24;
5196				b[1] |= rop << 16;
5197				b[2] = box->y1 << 16 | box->x1;
5198				b[3] = box->y2 << 16 | box->x2;
5199				*(uint64_t *)(b+4) =
5200					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
5201							I915_GEM_DOMAIN_RENDER << 16 |
5202							I915_GEM_DOMAIN_RENDER |
5203							KGEM_RELOC_FENCED,
5204							0);
5205				*(uint64_t *)(b+6) =
5206					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
5207							I915_GEM_DOMAIN_RENDER << 16 |
5208							KGEM_RELOC_FENCED,
5209							0);
5210				b[8] = gc->bgPixel;
5211				b[9] = gc->fgPixel;
5212
5213				sna->kgem.nbatch += 10;
5214			} else {
5215				b = sna->kgem.batch + sna->kgem.nbatch;
5216				b[0] = XY_MONO_SRC_COPY | 3 << 20 | 6;
5217				b[0] |= ((box->x1 - x) & 7) << 17;
5218				b[1] = bo->pitch;
5219				if (sna->kgem.gen >= 040 && bo->tiling) {
5220					b[0] |= BLT_DST_TILED;
5221					b[1] >>= 2;
5222				}
5223				b[1] |= blt_depth(drawable->depth) << 24;
5224				b[1] |= rop << 16;
5225				b[2] = box->y1 << 16 | box->x1;
5226				b[3] = box->y2 << 16 | box->x2;
5227				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
5228						I915_GEM_DOMAIN_RENDER << 16 |
5229						I915_GEM_DOMAIN_RENDER |
5230						KGEM_RELOC_FENCED,
5231						0);
5232				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
5233						I915_GEM_DOMAIN_RENDER << 16 |
5234						KGEM_RELOC_FENCED,
5235						0);
5236				b[6] = gc->bgPixel;
5237				b[7] = gc->fgPixel;
5238
5239				sna->kgem.nbatch += 8;
5240			}
5241			sigtrap_put();
5242		}
5243		kgem_bo_destroy(&sna->kgem, upload);
5244
5245		box++;
5246	} while (--n);
5247
5248	sna->blt_state.fill_bo = 0;
5249	return true;
5250}
5251
5252static bool
5253sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
5254		     int x, int y, int w, int  h, int left,char *bits)
5255{
5256	PixmapPtr pixmap = get_drawable_pixmap(drawable);
5257	struct sna *sna = to_sna_from_pixmap(pixmap);
5258	struct sna_damage **damage;
5259	struct kgem_bo *bo;
5260	int16_t dx, dy;
5261	unsigned i, skip;
5262
5263	if (gc->alu != GXcopy)
5264		return false;
5265
5266	bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU,
5267				 &region->extents, &damage);
5268	if (bo == NULL)
5269		return false;
5270
5271	if (bo->tiling == I915_TILING_Y) {
5272		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
5273		assert(bo == __sna_pixmap_get_bo(pixmap));
5274		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
5275		if (bo == NULL) {
5276			DBG(("%s: fallback -- unable to change tiling\n",
5277			     __FUNCTION__));
5278			return false;
5279		}
5280	}
5281
5282	assert_pixmap_contains_box(pixmap, RegionExtents(region));
5283	if (damage)
5284		sna_damage_add(damage, region);
5285	assert_pixmap_damage(pixmap);
5286
5287	DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h));
5288
5289	get_drawable_deltas(drawable, pixmap, &dx, &dy);
5290	x += dx + drawable->x;
5291	y += dy + drawable->y;
5292
5293	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
5294
5295	skip = h * BitmapBytePad(w + left);
5296	for (i = 1 << (gc->depth-1); i; i >>= 1, bits += skip) {
5297		const BoxRec *box = region_rects(region);
5298		int n = region_num_rects(region);
5299
5300		if ((gc->planemask & i) == 0)
5301			continue;
5302
5303		/* Region is pre-clipped and translated into pixmap space */
5304		do {
5305			int bx1 = (box->x1 - x) & ~7;
5306			int bx2 = (box->x2 - x + 7) & ~7;
5307			int bw = (bx2 - bx1)/8;
5308			int bh = box->y2 - box->y1;
5309			int bstride = ALIGN(bw, 2);
5310			struct kgem_bo *upload;
5311			void *ptr;
5312
5313			if (!kgem_check_batch(&sna->kgem, 14) ||
5314			    !kgem_check_bo_fenced(&sna->kgem, bo) ||
5315			    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
5316				kgem_submit(&sna->kgem);
5317				if (!kgem_check_bo_fenced(&sna->kgem, bo))
5318					return false;
5319				_kgem_set_mode(&sna->kgem, KGEM_BLT);
5320			}
5321
5322			upload = kgem_create_buffer(&sna->kgem,
5323						    bstride*bh,
5324						    KGEM_BUFFER_WRITE_INPLACE,
5325						    &ptr);
5326			if (!upload)
5327				break;
5328
5329			if (sigtrap_get() == 0) {
5330				int src_stride = BitmapBytePad(w);
5331				uint8_t *src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8;
5332				uint8_t *dst = ptr;
5333				uint32_t *b;
5334
5335				bstride -= bw;
5336				src_stride -= bw;
5337				do {
5338					int j = bw;
5339					assert(src >= (uint8_t *)bits);
5340					do {
5341						*dst++ = byte_reverse(*src++);
5342					} while (--j);
5343					assert(src <= (uint8_t *)bits + BitmapBytePad(w) * h);
5344					assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload));
5345					dst += bstride;
5346					src += src_stride;
5347				} while (--bh);
5348
5349				assert(sna->kgem.mode == KGEM_BLT);
5350				if (sna->kgem.gen >= 0100) {
5351					assert(sna->kgem.mode == KGEM_BLT);
5352					b = sna->kgem.batch + sna->kgem.nbatch;
5353					b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20 | 12;
5354					b[0] |= ((box->x1 - x) & 7) << 17;
5355					b[1] = bo->pitch;
5356					if (bo->tiling) {
5357						b[0] |= BLT_DST_TILED;
5358						b[1] >>= 2;
5359					}
5360					b[1] |= 1 << 31; /* solid pattern */
5361					b[1] |= blt_depth(drawable->depth) << 24;
5362					b[1] |= 0xce << 16; /* S or (D and !P) */
5363					b[2] = box->y1 << 16 | box->x1;
5364					b[3] = box->y2 << 16 | box->x2;
5365					*(uint64_t *)(b+4) =
5366						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
5367								I915_GEM_DOMAIN_RENDER << 16 |
5368								I915_GEM_DOMAIN_RENDER |
5369								KGEM_RELOC_FENCED,
5370								0);
5371					*(uint64_t *)(b+6) =
5372						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
5373								I915_GEM_DOMAIN_RENDER << 16 |
5374								KGEM_RELOC_FENCED,
5375								0);
5376					b[8] = 0;
5377					b[9] = i;
5378					b[10] = i;
5379					b[11] = i;
5380					b[12] = -1;
5381					b[13] = -1;
5382					sna->kgem.nbatch += 14;
5383				} else {
5384					b = sna->kgem.batch + sna->kgem.nbatch;
5385					b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20 | 10;
5386					b[0] |= ((box->x1 - x) & 7) << 17;
5387					b[1] = bo->pitch;
5388					if (sna->kgem.gen >= 040 && bo->tiling) {
5389						b[0] |= BLT_DST_TILED;
5390						b[1] >>= 2;
5391					}
5392					b[1] |= 1 << 31; /* solid pattern */
5393					b[1] |= blt_depth(drawable->depth) << 24;
5394					b[1] |= 0xce << 16; /* S or (D and !P) */
5395					b[2] = box->y1 << 16 | box->x1;
5396					b[3] = box->y2 << 16 | box->x2;
5397					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
5398							I915_GEM_DOMAIN_RENDER << 16 |
5399							I915_GEM_DOMAIN_RENDER |
5400							KGEM_RELOC_FENCED,
5401							0);
5402					b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
5403							I915_GEM_DOMAIN_RENDER << 16 |
5404							KGEM_RELOC_FENCED,
5405							0);
5406					b[6] = 0;
5407					b[7] = i;
5408					b[8] = i;
5409					b[9] = i;
5410					b[10] = -1;
5411					b[11] = -1;
5412					sna->kgem.nbatch += 12;
5413				}
5414				sigtrap_put();
5415			}
5416			kgem_bo_destroy(&sna->kgem, upload);
5417
5418			box++;
5419		} while (--n);
5420	}
5421
5422	sna->blt_state.fill_bo = 0;
5423	return true;
5424}
5425
5426static void
5427sna_put_image(DrawablePtr drawable, GCPtr gc, int depth,
5428	      int x, int y, int w, int h, int left, int format,
5429	      char *bits)
5430{
5431	PixmapPtr pixmap = get_drawable_pixmap(drawable);
5432	struct sna *sna = to_sna_from_pixmap(pixmap);
5433	struct sna_pixmap *priv = sna_pixmap(pixmap);
5434	RegionRec region;
5435	int16_t dx, dy;
5436
5437	DBG(("%s((%d, %d)x(%d, %d), depth=%d, format=%d)\n",
5438	     __FUNCTION__, x, y, w, h, depth, format));
5439
5440	if (w == 0 || h == 0)
5441		return;
5442
5443	region.extents.x1 = x + drawable->x;
5444	region.extents.y1 = y + drawable->y;
5445	region.extents.x2 = region.extents.x1 + w;
5446	region.extents.y2 = region.extents.y1 + h;
5447	region.data = NULL;
5448
5449	if (!region_is_singular(gc->pCompositeClip) ||
5450	    gc->pCompositeClip->extents.x1 > region.extents.x1 ||
5451	    gc->pCompositeClip->extents.y1 > region.extents.y1 ||
5452	    gc->pCompositeClip->extents.x2 < region.extents.x2 ||
5453	    gc->pCompositeClip->extents.y2 < region.extents.y2) {
5454		if (!RegionIntersect(&region, &region, gc->pCompositeClip) ||
5455		    box_empty(&region.extents))
5456			return;
5457	}
5458
5459	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
5460		RegionTranslate(&region, dx, dy);
5461
5462	if (priv == NULL) {
5463		DBG(("%s: fallback -- unattached(%d, %d, %d, %d)\n",
5464		     __FUNCTION__, x, y, w, h));
5465		goto fallback;
5466	}
5467
5468	if (FORCE_FALLBACK)
5469		goto fallback;
5470
5471	if (wedged(sna))
5472		goto fallback;
5473
5474	if (!ACCEL_PUT_IMAGE)
5475		goto fallback;
5476
5477	switch (format) {
5478	case ZPixmap:
5479		if (!PM_IS_SOLID(drawable, gc->planemask))
5480			goto fallback;
5481
5482		if (sna_put_zpixmap_blt(drawable, gc, &region,
5483					x, y, w, h,
5484					bits, PixmapBytePad(w, depth)))
5485			return;
5486		break;
5487
5488	case XYBitmap:
5489		if (!PM_IS_SOLID(drawable, gc->planemask))
5490			goto fallback;
5491
5492		if (sna_put_xybitmap_blt(drawable, gc, &region,
5493					 x, y, w, h,
5494					 bits))
5495			return;
5496		break;
5497
5498	case XYPixmap:
5499		if (sna_put_xypixmap_blt(drawable, gc, &region,
5500					 x, y, w, h, left,
5501					 bits))
5502			return;
5503		break;
5504
5505	default:
5506		return;
5507	}
5508
5509fallback:
5510	DBG(("%s: fallback\n", __FUNCTION__));
5511	RegionTranslate(&region, -dx, -dy);
5512
5513	if (!sna_gc_move_to_cpu(gc, drawable, &region))
5514		goto out;
5515	if (!sna_drawable_move_region_to_cpu(drawable, &region,
5516					      format == XYPixmap ?
5517					      MOVE_READ | MOVE_WRITE :
5518					      drawable_gc_flags(drawable, gc, false)))
5519		goto out;
5520
5521	if (sigtrap_get() == 0) {
5522		DBG(("%s: fbPutImage(%d, %d, %d, %d)\n",
5523		     __FUNCTION__, x, y, w, h));
5524		fbPutImage(drawable, gc, depth, x, y, w, h, left, format, bits);
5525		FALLBACK_FLUSH(drawable);
5526		sigtrap_put();
5527	}
5528out:
5529	sna_gc_move_to_gpu(gc);
5530	RegionUninit(&region);
5531}
5532
5533static bool
5534source_contains_region(struct sna_damage *damage,
5535		       const RegionRec *region, int16_t dx, int16_t dy)
5536{
5537	BoxRec box;
5538
5539	if (DAMAGE_IS_ALL(damage))
5540		return true;
5541
5542	if (damage == NULL)
5543		return false;
5544
5545	box = region->extents;
5546	box.x1 += dx;
5547	box.x2 += dx;
5548	box.y1 += dy;
5549	box.y2 += dy;
5550	return sna_damage_contains_box__no_reduce(damage, &box);
5551}
5552
5553static bool
5554move_to_gpu(PixmapPtr pixmap, struct sna_pixmap *priv,
5555	    RegionRec *region, int16_t dx, int16_t dy,
5556	    uint8_t alu, bool dst_is_gpu)
5557{
5558	int w = region->extents.x2 - region->extents.x1;
5559	int h = region->extents.y2 - region->extents.y1;
5560	int count;
5561
5562	assert_pixmap_map(pixmap, priv);
5563	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
5564		assert(priv->gpu_bo);
5565		return true;
5566	}
5567
5568	if (dst_is_gpu && priv->cpu_bo && priv->cpu_damage) {
5569		DBG(("%s: can use CPU bo? cpu_damage=%d, gpu_damage=%d, cpu hint=%d\n",
5570		     __FUNCTION__,
5571		     priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0,
5572		     priv->gpu_damage ? DAMAGE_IS_ALL(priv->gpu_damage) ? -1 : 1 : 0,
5573		     priv->cpu));
5574		if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL)
5575			return false;
5576
5577		if (priv->cpu &&
5578		    source_contains_region(priv->cpu_damage, region, dx, dy))
5579			return false;
5580	}
5581
5582	if (priv->gpu_bo) {
5583		DBG(("%s: has gpu bo (cpu damage?=%d, cpu=%d, gpu tiling=%d)\n",
5584		     __FUNCTION__,
5585		     priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0,
5586		     priv->cpu, priv->gpu_bo->tiling));
5587
5588		if (priv->cpu_damage == NULL)
5589			return true;
5590
5591		if (alu != GXcopy)
5592			return true;
5593
5594		if (!priv->cpu)
5595			return true;
5596
5597		if (priv->gpu_bo->tiling)
5598			return true;
5599
5600		RegionTranslate(region, dx, dy);
5601		count = region_subsumes_damage(region, priv->cpu_damage);
5602		RegionTranslate(region, -dx, -dy);
5603		if (count)
5604			return true;
5605	} else {
5606		if ((priv->create & KGEM_CAN_CREATE_GPU) == 0)
5607			return false;
5608		if (priv->shm)
5609			return false;
5610	}
5611
5612	count = priv->source_count++;
5613	if (priv->cpu_bo) {
5614		if (priv->cpu_bo->flush && count > SOURCE_BIAS)
5615			return true;
5616
5617		if (sna_pixmap_default_tiling(to_sna_from_pixmap(pixmap), pixmap) == I915_TILING_NONE)
5618			return false;
5619
5620		if (priv->cpu)
5621			return false;
5622
5623		return count > SOURCE_BIAS;
5624	} else {
5625		if (w == pixmap->drawable.width && h == pixmap->drawable.height)
5626			return count > SOURCE_BIAS;
5627
5628		return count * w*h >= (SOURCE_BIAS+2) * (int)pixmap->drawable.width * pixmap->drawable.height;
5629	}
5630}
5631
5632static const BoxRec *
5633reorder_boxes(const BoxRec *box, int n, int dx, int dy)
5634{
5635	const BoxRec *next, *base;
5636	BoxRec *new;
5637
5638	DBG(("%s x %d dx=%d, dy=%d\n", __FUNCTION__, n, dx, dy));
5639
5640	if (dy <= 0 && dx <= 0) {
5641		BoxRec *tmp;
5642
5643		new = malloc(sizeof(BoxRec) * n);
5644		if (new == NULL)
5645			return NULL;
5646
5647		tmp = new;
5648		next = box + n;
5649		do {
5650			*tmp++ = *--next;
5651		} while (next != box);
5652	} else if (dy < 0) {
5653		new = malloc(sizeof(BoxRec) * n);
5654		if (new == NULL)
5655			return NULL;
5656
5657		base = next = box + n - 1;
5658		while (base >= box) {
5659			const BoxRec *tmp;
5660
5661			while (next >= box && base->y1 == next->y1)
5662				next--;
5663			tmp = next + 1;
5664			while (tmp <= base)
5665				*new++ = *tmp++;
5666			base = next;
5667		}
5668		new -= n;
5669	} else {
5670		new = malloc(sizeof(BoxRec) * n);
5671		if (!new)
5672			return NULL;
5673
5674		base = next = box;
5675		while (base < box + n) {
5676			const BoxRec *tmp;
5677
5678			while (next < box + n && next->y1 == base->y1)
5679				next++;
5680			tmp = next;
5681			while (tmp != base)
5682				*new++ = *--tmp;
5683			base = next;
5684		}
5685		new -= n;
5686	}
5687
5688	return new;
5689}
5690
5691static void
5692sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
5693		    RegionPtr region,int dx, int dy,
5694		    Pixel bitplane, void *closure)
5695{
5696	PixmapPtr pixmap = get_drawable_pixmap(src);
5697	struct sna *sna = to_sna_from_pixmap(pixmap);
5698	struct sna_pixmap *priv = sna_pixmap(pixmap);
5699	const BoxRec *box = region_rects(region);
5700	int n = region_num_rects(region);
5701	int alu = gc ? gc->alu : GXcopy;
5702	int16_t tx, ty, sx, sy;
5703
5704	assert(pixmap == get_drawable_pixmap(dst));
5705
5706	assert(region_num_rects(region));
5707	if (((dx | dy) == 0 && alu == GXcopy))
5708		return;
5709
5710	if (n > 1 && (dx | dy) < 0) {
5711		box = reorder_boxes(box, n, dx, dy);
5712		if (box == NULL)
5713			return;
5714	}
5715
5716	DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d, pix.size=%dx%d)\n",
5717	     __FUNCTION__, n,
5718	     region->extents.x1, region->extents.y1,
5719	     region->extents.x2, region->extents.y2,
5720	     dx, dy, alu,
5721	     pixmap->drawable.width, pixmap->drawable.height));
5722
5723	get_drawable_deltas(dst, pixmap, &tx, &ty);
5724	get_drawable_deltas(src, pixmap, &sx, &sy);
5725	sx += dx;
5726	sy += dy;
5727
5728	if (priv == NULL || DAMAGE_IS_ALL(priv->cpu_damage)) {
5729		DBG(("%s: unattached, or all damaged on CPU\n", __FUNCTION__));
5730		goto fallback;
5731	}
5732
5733	if (priv->gpu_damage || (priv->cpu_damage == NULL && priv->gpu_bo)) {
5734		assert(priv->gpu_bo);
5735
5736		if (alu == GXcopy && priv->clear)
5737			goto free_boxes;
5738
5739		assert(priv->gpu_bo->proxy == NULL);
5740		if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT)) {
5741			DBG(("%s: fallback - not a pure copy and failed to move dst to GPU\n",
5742			     __FUNCTION__));
5743			goto fallback;
5744		}
5745		assert(priv->cpu_damage == NULL);
5746
5747		if (!sna->render.copy_boxes(sna, alu,
5748					    &pixmap->drawable, priv->gpu_bo, sx, sy,
5749					    &pixmap->drawable, priv->gpu_bo, tx, ty,
5750					    box, n, 0)) {
5751			DBG(("%s: fallback - accelerated copy boxes failed\n",
5752			     __FUNCTION__));
5753			goto fallback;
5754		}
5755
5756		if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
5757			assert(!priv->clear);
5758			if (sna_pixmap_free_cpu(sna, priv, false)) {
5759				sna_damage_all(&priv->gpu_damage, pixmap);
5760			} else {
5761				RegionTranslate(region, tx, ty);
5762				sna_damage_add(&priv->gpu_damage, region);
5763			}
5764		}
5765		assert_pixmap_damage(pixmap);
5766	} else {
5767fallback:
5768		DBG(("%s: fallback\n", __FUNCTION__));
5769		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE))
5770			goto free_boxes;
5771
5772		if (alu == GXcopy && pixmap->drawable.bitsPerPixel >= 8) {
5773			assert(pixmap->devKind);
5774			if (sigtrap_get() == 0) {
5775				FbBits *dst_bits, *src_bits;
5776				int stride = pixmap->devKind;
5777				int bpp = pixmap->drawable.bitsPerPixel;
5778				int i;
5779
5780				dst_bits = (FbBits *)
5781					((char *)pixmap->devPrivate.ptr +
5782					 ty * stride + tx * bpp / 8);
5783				src_bits = (FbBits *)
5784					((char *)pixmap->devPrivate.ptr +
5785					 sy * stride + sx * bpp / 8);
5786
5787				for (i = 0; i < n; i++)
5788					memmove_box(src_bits, dst_bits,
5789						    bpp, stride, box+i,
5790						    dx, dy);
5791				sigtrap_put();
5792			}
5793		} else {
5794			if (gc && !sna_gc_move_to_cpu(gc, dst, region))
5795				goto out;
5796
5797			if (sigtrap_get() == 0) {
5798				miCopyRegion(src, dst, gc,
5799					     region, dx, dy,
5800					     fbCopyNtoN, 0, NULL);
5801				sigtrap_put();
5802			}
5803
5804			if (gc)
5805out:
5806				sna_gc_move_to_gpu(gc);
5807		}
5808	}
5809
5810free_boxes:
5811	if (box != region_rects(region))
5812		free((void *)box);
5813}
5814
5815static inline bool
5816sna_pixmap_is_gpu(PixmapPtr pixmap)
5817{
5818	struct sna_pixmap *priv = sna_pixmap(pixmap);
5819
5820	if (priv == NULL || priv->clear)
5821		return false;
5822
5823	if (DAMAGE_IS_ALL(priv->gpu_damage) ||
5824	    (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo) && !priv->gpu_bo->proxy))
5825		return true;
5826
5827	return priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo);
5828}
5829
5830static int
5831copy_prefer_gpu(struct sna *sna,
5832		struct sna_pixmap *dst_priv,
5833		struct sna_pixmap *src_priv,
5834		RegionRec *region,
5835		int16_t dx, int16_t dy)
5836{
5837	assert(dst_priv);
5838
5839	if (wedged(sna) && !dst_priv->pinned)
5840		return 0;
5841
5842	if (src_priv == NULL) {
5843		DBG(("%s: source unattached, use cpu\n", __FUNCTION__));
5844		return 0;
5845	}
5846
5847	if (src_priv->clear) {
5848		DBG(("%s: source is clear, don't force use of GPU\n", __FUNCTION__));
5849		return 0;
5850	}
5851
5852	if (src_priv->gpu_damage &&
5853	    !source_contains_region(src_priv->cpu_damage, region, dx, dy)) {
5854		DBG(("%s: source has gpu damage, force gpu? %d\n",
5855		     __FUNCTION__, src_priv->cpu_damage == NULL));
5856		assert(src_priv->gpu_bo);
5857		return src_priv->cpu_damage ? PREFER_GPU : PREFER_GPU | FORCE_GPU;
5858	}
5859
5860	if (src_priv->cpu_bo && kgem_bo_is_busy(src_priv->cpu_bo)) {
5861		DBG(("%s: source has busy CPU bo, force gpu\n", __FUNCTION__));
5862		return PREFER_GPU | FORCE_GPU;
5863	}
5864
5865	if (source_contains_region(src_priv->cpu_damage, region, dx, dy))
5866		return src_priv->cpu_bo && kgem_is_idle(&sna->kgem);
5867
5868	DBG(("%s: source has GPU bo? %d\n",
5869	     __FUNCTION__, src_priv->gpu_bo != NULL));
5870	return src_priv->gpu_bo != NULL;
5871}
5872
5873static bool use_shm_bo(struct sna *sna,
5874		       struct kgem_bo *bo,
5875		       struct sna_pixmap *priv,
5876		       int alu, bool replaces)
5877{
5878	if (priv == NULL || priv->cpu_bo == NULL) {
5879		DBG(("%s: no, not attached\n", __FUNCTION__));
5880		return false;
5881	}
5882
5883	if (!priv->shm && !priv->cpu) {
5884		DBG(("%s: yes, ordinary CPU bo\n", __FUNCTION__));
5885		return true;
5886	}
5887
5888	if (alu != GXcopy) {
5889		DBG(("%s: yes, complex alu=%d\n", __FUNCTION__, alu));
5890		return true;
5891	}
5892
5893	if (!replaces && __kgem_bo_is_busy(&sna->kgem, bo)) {
5894		DBG(("%s: yes, dst is busy\n", __FUNCTION__));
5895		return true;
5896	}
5897
5898	if (priv->cpu_bo->needs_flush &&
5899	    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
5900		DBG(("%s: yes, src is busy\n", __FUNCTION__));
5901		return true;
5902	}
5903
5904	return false;
5905}
5906
5907static bool
5908sna_damage_contains_box__no_reduce__offset(struct sna_damage *damage,
5909					   const BoxRec *extents,
5910					   int16_t dx, int16_t dy)
5911{
5912	BoxRec _extents;
5913
5914	if (dx | dy) {
5915		_extents.x1 = extents->x1 + dx;
5916		_extents.x2 = extents->x2 + dx;
5917		_extents.y1 = extents->y1 + dy;
5918		_extents.y2 = extents->y2 + dy;
5919		extents = &_extents;
5920	}
5921
5922	return sna_damage_contains_box__no_reduce(damage, extents);
5923}
5924
5925static bool
5926sna_copy_boxes__inplace(struct sna *sna, RegionPtr region, int alu,
5927			PixmapPtr src_pixmap, struct sna_pixmap *src_priv,
5928			int dx, int dy,
5929			PixmapPtr dst_pixmap, struct sna_pixmap *dst_priv,
5930			bool replaces)
5931{
5932	const BoxRec *box;
5933	char *ptr;
5934	int n;
5935
5936	assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel);
5937
5938	if (alu != GXcopy) {
5939		DBG(("%s - no, complex alu [%d]\n", __FUNCTION__, alu));
5940		return false;
5941	}
5942
5943	if (!USE_INPLACE) {
5944		DBG(("%s - no, compile time disabled\n", __FUNCTION__));
5945		return false;
5946	}
5947
5948	if (dst_priv == src_priv) {
5949		DBG(("%s - no, dst == src\n", __FUNCTION__));
5950		return false;
5951	}
5952
5953	if (src_priv == NULL || src_priv->gpu_bo == NULL) {
5954		if (dst_priv && dst_priv->gpu_bo)
5955			goto upload_inplace;
5956
5957		DBG(("%s - no, no src or dst GPU bo\n", __FUNCTION__));
5958		return false;
5959	}
5960
5961	switch (src_priv->gpu_bo->tiling) {
5962	case I915_TILING_Y:
5963		DBG(("%s - no, bad src tiling [Y]\n", __FUNCTION__));
5964		return false;
5965	case I915_TILING_X:
5966		if (!sna->kgem.memcpy_from_tiled_x) {
5967			DBG(("%s - no, bad src tiling [X]\n", __FUNCTION__));
5968			return false;
5969		}
5970	default:
5971		break;
5972	}
5973
5974	if (src_priv->move_to_gpu && !src_priv->move_to_gpu(sna, src_priv, MOVE_READ)) {
5975		DBG(("%s - no, pending src move-to-gpu failed\n", __FUNCTION__));
5976		return false;
5977	}
5978
5979	if (!kgem_bo_can_map__cpu(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC)) {
5980		DBG(("%s - no, cannot map src for reads into the CPU\n", __FUNCTION__));
5981		return false;
5982	}
5983
5984	if (src_priv->gpu_damage == NULL ||
5985	    !(DAMAGE_IS_ALL(src_priv->gpu_damage) ||
5986	      sna_damage_contains_box__no_reduce__offset(src_priv->gpu_damage,
5987							 &region->extents,
5988							 dx, dy))) {
5989		DBG(("%s - no, src is not damaged on the GPU\n", __FUNCTION__));
5990		return false;
5991	}
5992
5993	assert(sna_damage_contains_box__offset(&src_priv->gpu_damage, &region->extents, dx, dy) == PIXMAN_REGION_IN);
5994	assert(sna_damage_contains_box__offset(&src_priv->cpu_damage, &region->extents, dx, dy) == PIXMAN_REGION_OUT);
5995
5996	ptr = kgem_bo_map__cpu(&sna->kgem, src_priv->gpu_bo);
5997	if (ptr == NULL) {
5998		DBG(("%s - no, map failed\n", __FUNCTION__));
5999		return false;
6000	}
6001
6002	if (dst_priv &&
6003	    !sna_drawable_move_region_to_cpu(&dst_pixmap->drawable,
6004					     region, MOVE_WRITE | MOVE_INPLACE_HINT)) {
6005		DBG(("%s - no, dst sync failed\n", __FUNCTION__));
6006		return false;
6007	}
6008
6009	kgem_bo_sync__cpu_full(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC);
6010
6011	box = region_rects(region);
6012	n = region_num_rects(region);
6013	if (src_priv->gpu_bo->tiling) {
6014		DBG(("%s: copy from a tiled CPU map\n", __FUNCTION__));
6015		assert(dst_pixmap->devKind);
6016		do {
6017			memcpy_from_tiled_x(&sna->kgem, ptr, dst_pixmap->devPrivate.ptr,
6018					    src_pixmap->drawable.bitsPerPixel,
6019					    src_priv->gpu_bo->pitch,
6020					    dst_pixmap->devKind,
6021					    box->x1 + dx, box->y1 + dy,
6022					    box->x1, box->y1,
6023					    box->x2 - box->x1, box->y2 - box->y1);
6024			box++;
6025		} while (--n);
6026	} else {
6027		DBG(("%s: copy from a linear CPU map\n", __FUNCTION__));
6028		assert(dst_pixmap->devKind);
6029		do {
6030			memcpy_blt(ptr, dst_pixmap->devPrivate.ptr,
6031				   src_pixmap->drawable.bitsPerPixel,
6032				   src_priv->gpu_bo->pitch,
6033				   dst_pixmap->devKind,
6034				   box->x1 + dx, box->y1 + dy,
6035				   box->x1, box->y1,
6036				   box->x2 - box->x1, box->y2 - box->y1);
6037			box++;
6038		} while (--n);
6039
6040		if (!src_priv->shm) {
6041			assert(ptr == MAP(src_priv->gpu_bo->map__cpu));
6042			src_pixmap->devPrivate.ptr = ptr;
6043			src_pixmap->devKind = src_priv->gpu_bo->pitch;
6044			src_priv->mapped = MAPPED_CPU;
6045			assert_pixmap_map(src_pixmap, src_priv);
6046			src_priv->cpu = true;
6047		}
6048	}
6049
6050	return true;
6051
6052upload_inplace:
6053	switch (dst_priv->gpu_bo->tiling) {
6054	case I915_TILING_Y:
6055		DBG(("%s - no, bad dst tiling [Y]\n", __FUNCTION__));
6056		return false;
6057	case I915_TILING_X:
6058		if (!sna->kgem.memcpy_to_tiled_x) {
6059			DBG(("%s - no, bad dst tiling [X]\n", __FUNCTION__));
6060			return false;
6061		}
6062	default:
6063		break;
6064	}
6065
6066	if (dst_priv->move_to_gpu) {
6067		DBG(("%s - no, pending dst move-to-gpu\n", __FUNCTION__));
6068		return false;
6069	}
6070
6071	if (!kgem_bo_can_map__cpu(&sna->kgem, dst_priv->gpu_bo, true) ||
6072	    __kgem_bo_is_busy(&sna->kgem, dst_priv->gpu_bo)) {
6073		if (replaces && !dst_priv->pinned) {
6074			unsigned create;
6075			struct kgem_bo *bo;
6076
6077			create = CREATE_CPU_MAP | CREATE_INACTIVE;
6078			if (dst_priv->gpu_bo->scanout)
6079				create |= CREATE_SCANOUT;
6080
6081			bo = kgem_create_2d(&sna->kgem,
6082					    dst_pixmap->drawable.width,
6083					    dst_pixmap->drawable.height,
6084					    dst_pixmap->drawable.bitsPerPixel,
6085					    dst_priv->gpu_bo->tiling,
6086					    create);
6087			if (bo == NULL)
6088				return false;
6089
6090			sna_pixmap_unmap(dst_pixmap, dst_priv);
6091			kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo);
6092			dst_priv->gpu_bo = bo;
6093		} else {
6094			DBG(("%s - no, dst is busy\n", __FUNCTION__));
6095			return false;
6096		}
6097
6098		if (!kgem_bo_can_map__cpu(&sna->kgem, dst_priv->gpu_bo, true)) {
6099			DBG(("%s - no, cannot map dst for reads into the CPU\n", __FUNCTION__));
6100			return false;
6101		}
6102	}
6103
6104	if (src_priv &&
6105	    !sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
6106					     region, MOVE_READ)) {
6107		DBG(("%s - no, src sync failed\n", __FUNCTION__));
6108		return false;
6109	}
6110
6111	ptr = kgem_bo_map__cpu(&sna->kgem, dst_priv->gpu_bo);
6112	if (ptr == NULL) {
6113		DBG(("%s - no, map failed\n", __FUNCTION__));
6114		return false;
6115	}
6116
6117	kgem_bo_sync__cpu(&sna->kgem, dst_priv->gpu_bo);
6118
6119	if (!DAMAGE_IS_ALL(dst_priv->gpu_damage)) {
6120		assert(!dst_priv->clear);
6121		sna_damage_add(&dst_priv->gpu_damage, region);
6122		if (sna_damage_is_all(&dst_priv->gpu_damage,
6123				      dst_pixmap->drawable.width,
6124				      dst_pixmap->drawable.height)) {
6125			DBG(("%s: replaced entire pixmap, destroying CPU shadow\n",
6126			     __FUNCTION__));
6127			sna_damage_destroy(&dst_priv->cpu_damage);
6128			list_del(&dst_priv->flush_list);
6129		} else
6130			sna_damage_subtract(&dst_priv->cpu_damage,
6131					    region);
6132	}
6133	dst_priv->clear = false;
6134
6135	assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
6136
6137	box = region_rects(region);
6138	n = region_num_rects(region);
6139	if (dst_priv->gpu_bo->tiling) {
6140		DBG(("%s: copy to a tiled CPU map\n", __FUNCTION__));
6141		assert(dst_priv->gpu_bo->tiling == I915_TILING_X);
6142		assert(src_pixmap->devKind);
6143		do {
6144			memcpy_to_tiled_x(&sna->kgem, src_pixmap->devPrivate.ptr, ptr,
6145					  src_pixmap->drawable.bitsPerPixel,
6146					  src_pixmap->devKind,
6147					  dst_priv->gpu_bo->pitch,
6148					  box->x1 + dx, box->y1 + dy,
6149					  box->x1, box->y1,
6150					  box->x2 - box->x1, box->y2 - box->y1);
6151			box++;
6152		} while (--n);
6153	} else {
6154		DBG(("%s: copy to a linear CPU map\n", __FUNCTION__));
6155		assert(src_pixmap->devKind);
6156		do {
6157			memcpy_blt(src_pixmap->devPrivate.ptr, ptr,
6158				   src_pixmap->drawable.bitsPerPixel,
6159				   src_pixmap->devKind,
6160				   dst_priv->gpu_bo->pitch,
6161				   box->x1 + dx, box->y1 + dy,
6162				   box->x1, box->y1,
6163				   box->x2 - box->x1, box->y2 - box->y1);
6164			box++;
6165		} while (--n);
6166
6167		if (!dst_priv->shm) {
6168			assert(ptr == MAP(dst_priv->gpu_bo->map__cpu));
6169			dst_pixmap->devPrivate.ptr = ptr;
6170			dst_pixmap->devKind = dst_priv->gpu_bo->pitch;
6171			dst_priv->mapped = MAPPED_CPU;
6172			assert_pixmap_map(dst_pixmap, dst_priv);
6173			dst_priv->cpu = true;
6174		}
6175	}
6176
6177	return true;
6178}
6179
6180static void discard_cpu_damage(struct sna *sna, struct sna_pixmap *priv)
6181{
6182	if (priv->cpu_damage == NULL && !priv->shm)
6183		return;
6184
6185	DBG(("%s: discarding existing CPU damage\n", __FUNCTION__));
6186
6187	if (kgem_bo_discard_cache(priv->gpu_bo, true)) {
6188		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
6189		assert(DAMAGE_IS_ALL(priv->cpu_damage));
6190		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */
6191		assert(!priv->pinned);
6192		assert(!priv->mapped);
6193		sna_damage_destroy(&priv->gpu_damage);
6194		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
6195		priv->gpu_bo = NULL;
6196	}
6197
6198	sna_damage_destroy(&priv->cpu_damage);
6199	list_del(&priv->flush_list);
6200
6201	if (priv->gpu_bo && sna_pixmap_free_cpu(sna, priv, priv->cpu))
6202		sna_damage_all(&priv->gpu_damage, priv->pixmap);
6203	priv->cpu = false;
6204}
6205
6206static void
6207sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
6208	       RegionPtr region, int dx, int dy,
6209	       Pixel bitplane, void *closure)
6210{
6211	PixmapPtr src_pixmap = get_drawable_pixmap(src);
6212	struct sna_pixmap *src_priv = sna_pixmap(src_pixmap);
6213	PixmapPtr dst_pixmap = get_drawable_pixmap(dst);
6214	struct sna_pixmap *dst_priv = sna_pixmap(dst_pixmap);
6215	struct sna *sna = to_sna_from_pixmap(src_pixmap);
6216	struct sna_damage **damage;
6217	struct kgem_bo *bo;
6218	int16_t src_dx, src_dy;
6219	int16_t dst_dx, dst_dy;
6220	const BoxRec *box = region_rects(region);
6221	int n = region_num_rects(region);
6222	int alu = gc->alu;
6223	int stride, bpp;
6224	char *bits;
6225	bool replaces;
6226
6227	assert(region_num_rects(region));
6228
6229	if (src_pixmap == dst_pixmap)
6230		return sna_self_copy_boxes(src, dst, gc,
6231					   region, dx, dy,
6232					   bitplane, closure);
6233
6234	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",
6235	     __FUNCTION__, n,
6236	     box[0].x1, box[0].y1, box[0].x2, box[0].y2,
6237	     src_pixmap->drawable.serialNumber, dx, dy,
6238	     dst_pixmap->drawable.serialNumber, get_drawable_dx(dst), get_drawable_dy(dst),
6239	     alu,
6240	     src_pixmap->drawable.width, src_pixmap->drawable.height,
6241	     dst_pixmap->drawable.width, dst_pixmap->drawable.height));
6242
6243	assert_pixmap_damage(dst_pixmap);
6244	assert_pixmap_damage(src_pixmap);
6245
6246	bpp = dst_pixmap->drawable.bitsPerPixel;
6247
6248	if (get_drawable_deltas(dst, dst_pixmap, &dst_dx, &dst_dy))
6249		RegionTranslate(region, dst_dx, dst_dy);
6250	get_drawable_deltas(src, src_pixmap, &src_dx, &src_dy);
6251	src_dx += dx - dst_dx;
6252	src_dy += dy - dst_dy;
6253
6254	assert_pixmap_contains_box(dst_pixmap, RegionExtents(region));
6255	assert_pixmap_contains_box_with_offset(src_pixmap,
6256					       RegionExtents(region),
6257					       src_dx, src_dy);
6258
6259	replaces = n == 1 &&
6260		alu_overwrites(alu) &&
6261		box->x1 <= 0 &&
6262		box->y1 <= 0 &&
6263		box->x2 >= dst_pixmap->drawable.width &&
6264		box->y2 >= dst_pixmap->drawable.height;
6265
6266	DBG(("%s: dst=(priv=%p, gpu_bo=%d, cpu_bo=%d), src=(priv=%p, gpu_bo=%d, cpu_bo=%d), replaces=%d\n",
6267	     __FUNCTION__,
6268	     dst_priv,
6269	     dst_priv && dst_priv->gpu_bo ? dst_priv->gpu_bo->handle : 0,
6270	     dst_priv && dst_priv->cpu_bo ? dst_priv->cpu_bo->handle : 0,
6271	     src_priv,
6272	     src_priv && src_priv->gpu_bo ? src_priv->gpu_bo->handle : 0,
6273	     src_priv && src_priv->cpu_bo ? src_priv->cpu_bo->handle : 0,
6274	     replaces));
6275
6276	if (dst_priv == NULL) {
6277		DBG(("%s: unattached dst failed, fallback\n", __FUNCTION__));
6278		goto fallback;
6279	}
6280
6281	if (alu == GXcopy &&
6282	    src_priv && src_priv->cow &&
6283	    COW(src_priv->cow) == COW(dst_priv->cow)) {
6284		if ((dx | dy) == 0) {
6285			DBG(("%s: ignoring cow for no op\n",
6286			     __FUNCTION__));
6287			return;
6288		} else if (IS_COW_OWNER(dst_priv->cow)) {
6289			/* XXX hack for firefox -- subsequent uses of src will be corrupt! */
6290			DBG(("%s: ignoring cow reference for cousin copy\n",
6291			     __FUNCTION__));
6292			assert(src_priv->cpu_damage == NULL);
6293			assert(dst_priv->move_to_gpu == NULL);
6294			bo = dst_priv->gpu_bo;
6295			damage = NULL;
6296		} else
6297			goto discard_cow;
6298	} else {
6299		unsigned hint;
6300discard_cow:
6301		hint = copy_prefer_gpu(sna, dst_priv, src_priv, region, src_dx, src_dy);
6302		if (replaces) {
6303			discard_cpu_damage(sna, dst_priv);
6304			hint |= REPLACES | IGNORE_DAMAGE;
6305		} else if (alu_overwrites(alu)) {
6306			if (region->data == NULL)
6307				hint |= IGNORE_DAMAGE;
6308			if (dst_priv->cpu_damage &&
6309			    region_subsumes_damage(region,
6310						   dst_priv->cpu_damage))
6311				discard_cpu_damage(sna, dst_priv);
6312		}
6313		bo = sna_drawable_use_bo(&dst_pixmap->drawable, hint,
6314					 &region->extents, &damage);
6315	}
6316	if (bo) {
6317		if (alu == GXset || alu == GXclear || (src_priv && src_priv->clear)) {
6318			uint32_t color;
6319
6320			if (alu == GXset)
6321				color = (1 << dst_pixmap->drawable.depth) - 1;
6322			else if (alu == GXclear)
6323				color = 0;
6324			else
6325				color = src_priv->clear_color;
6326			DBG(("%s: applying src clear [%08x] to dst\n",
6327			     __FUNCTION__, src_priv->clear_color));
6328
6329			if (n == 1) {
6330				if (replaces && UNDO)
6331					kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
6332
6333				if (!sna->render.fill_one(sna,
6334							  dst_pixmap, bo, color,
6335							  box->x1, box->y1,
6336							  box->x2, box->y2,
6337							  alu)) {
6338					DBG(("%s: unsupported fill\n",
6339					     __FUNCTION__));
6340					goto fallback;
6341				}
6342
6343				if (replaces && bo == dst_priv->gpu_bo) {
6344					DBG(("%s: marking dst handle=%d as all clear [%08x]\n",
6345					     __FUNCTION__,
6346					     dst_priv->gpu_bo->handle,
6347					     src_priv->clear_color));
6348					dst_priv->clear = true;
6349					dst_priv->clear_color = color;
6350					sna_damage_all(&dst_priv->gpu_damage, dst_pixmap);
6351					sna_damage_destroy(&dst_priv->cpu_damage);
6352					list_del(&dst_priv->flush_list);
6353					return;
6354				}
6355			} else {
6356				struct sna_fill_op fill;
6357
6358				if (!sna_fill_init_blt(&fill, sna,
6359						       dst_pixmap, bo,
6360						       alu, color,
6361						       FILL_BOXES)) {
6362					DBG(("%s: unsupported fill\n",
6363					     __FUNCTION__));
6364					goto fallback;
6365				}
6366
6367				fill.boxes(sna, &fill, box, n);
6368				fill.done(sna, &fill);
6369			}
6370
6371			if (damage)
6372				sna_damage_add(damage, region);
6373			return;
6374		}
6375
6376		if (src_priv &&
6377		    move_to_gpu(src_pixmap, src_priv, region, src_dx, src_dy, alu, bo == dst_priv->gpu_bo) &&
6378		    sna_pixmap_move_to_gpu(src_pixmap, MOVE_READ | MOVE_ASYNC_HINT)) {
6379			DBG(("%s: move whole src_pixmap to GPU and copy\n",
6380			     __FUNCTION__));
6381			if (replaces && UNDO)
6382				kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
6383
6384			if (replaces &&
6385			    src_pixmap->drawable.width == dst_pixmap->drawable.width &&
6386			    src_pixmap->drawable.height == dst_pixmap->drawable.height) {
6387				assert(src_pixmap->drawable.depth == dst_pixmap->drawable.depth);
6388				assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel);
6389				if (sna_pixmap_make_cow(sna, src_priv, dst_priv)) {
6390					assert(dst_priv->gpu_bo == src_priv->gpu_bo);
6391					sna_damage_all(&dst_priv->gpu_damage, dst_pixmap);
6392					sna_damage_destroy(&dst_priv->cpu_damage);
6393					list_del(&dst_priv->flush_list);
6394					if (dst_priv->shm)
6395						sna_add_flush_pixmap(sna, dst_priv, dst_priv->cpu_bo);
6396					return;
6397				}
6398			}
6399			if (!sna->render.copy_boxes(sna, alu,
6400						    &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy,
6401						    &dst_pixmap->drawable, bo, 0, 0,
6402						    box, n, 0)) {
6403				DBG(("%s: fallback - accelerated copy boxes failed\n",
6404				     __FUNCTION__));
6405				goto fallback;
6406			}
6407
6408			if (damage)
6409				sna_damage_add(damage, region);
6410			return;
6411		}
6412
6413		if (src_priv &&
6414		    region_overlaps_damage(region, src_priv->gpu_damage,
6415					   src_dx, src_dy)) {
6416			BoxRec area;
6417
6418			DBG(("%s: region overlaps GPU damage, upload and copy\n",
6419			     __FUNCTION__));
6420
6421			area = region->extents;
6422			area.x1 += src_dx;
6423			area.x2 += src_dx;
6424			area.y1 += src_dy;
6425			area.y2 += src_dy;
6426
6427			if (!sna_pixmap_move_area_to_gpu(src_pixmap, &area,
6428							 MOVE_READ | MOVE_ASYNC_HINT)) {
6429				DBG(("%s: move-to-gpu(src) failed, fallback\n", __FUNCTION__));
6430				goto fallback;
6431			}
6432
6433			if (replaces && UNDO)
6434				kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
6435
6436			if (!sna->render.copy_boxes(sna, alu,
6437						    &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy,
6438						    &dst_pixmap->drawable, bo, 0, 0,
6439						    box, n, 0)) {
6440				DBG(("%s: fallback - accelerated copy boxes failed\n",
6441				     __FUNCTION__));
6442				goto fallback;
6443			}
6444
6445			if (damage)
6446				sna_damage_add(damage, region);
6447			return;
6448		}
6449
6450		if (bo != dst_priv->gpu_bo)
6451			goto fallback;
6452
6453		if (use_shm_bo(sna, bo, src_priv, alu, replaces && !dst_priv->pinned)) {
6454			bool ret;
6455
6456			DBG(("%s: region overlaps CPU damage, copy from CPU bo (shm? %d)\n",
6457			     __FUNCTION__, src_priv->shm));
6458
6459			assert(bo != dst_priv->cpu_bo);
6460
6461			RegionTranslate(region, src_dx, src_dy);
6462			ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
6463							      region,
6464							      MOVE_READ | MOVE_ASYNC_HINT);
6465			RegionTranslate(region, -src_dx, -src_dy);
6466			if (!ret) {
6467				DBG(("%s: move-to-cpu(src) failed, fallback\n", __FUNCTION__));
6468				goto fallback;
6469			}
6470
6471			if (replaces && UNDO)
6472				kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
6473
6474			if (src_priv->shm) {
6475				assert(!src_priv->flush);
6476				sna_add_flush_pixmap(sna, src_priv, src_priv->cpu_bo);
6477			}
6478
6479			if (!sna->render.copy_boxes(sna, alu,
6480						    &src_pixmap->drawable, src_priv->cpu_bo, src_dx, src_dy,
6481						    &dst_pixmap->drawable, bo, 0, 0,
6482						    box, n, src_priv->shm ? COPY_LAST : 0)) {
6483				DBG(("%s: fallback - accelerated copy boxes failed\n",
6484				     __FUNCTION__));
6485				goto fallback;
6486			}
6487
6488			if (damage)
6489				sna_damage_add(damage, region);
6490			return;
6491		}
6492
6493		if (src_priv) {
6494			bool ret;
6495
6496			RegionTranslate(region, src_dx, src_dy);
6497			ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
6498							      region, MOVE_READ);
6499			RegionTranslate(region, -src_dx, -src_dy);
6500			if (!ret) {
6501				DBG(("%s: move-to-cpu(src) failed, fallback\n", __FUNCTION__));
6502				goto fallback;
6503			}
6504
6505			assert(!src_priv->mapped);
6506			if (src_pixmap->devPrivate.ptr == NULL)
6507				/* uninitialised!*/
6508				return;
6509		}
6510
6511		if (USE_USERPTR_UPLOADS &&
6512		    sna->kgem.has_userptr &&
6513		    (alu != GXcopy ||
6514		     (box_inplace(src_pixmap, &region->extents) &&
6515		      __kgem_bo_is_busy(&sna->kgem, bo)))) {
6516			struct kgem_bo *src_bo;
6517			bool ok = false;
6518
6519			DBG(("%s: upload through a temporary map\n",
6520			     __FUNCTION__));
6521
6522			assert(src_pixmap->devKind);
6523			src_bo = kgem_create_map(&sna->kgem,
6524						 src_pixmap->devPrivate.ptr,
6525						 src_pixmap->devKind * src_pixmap->drawable.height,
6526						 true);
6527			if (src_bo) {
6528				src_bo->pitch = src_pixmap->devKind;
6529				kgem_bo_mark_unreusable(src_bo);
6530
6531				ok = sna->render.copy_boxes(sna, alu,
6532							    &src_pixmap->drawable, src_bo, src_dx, src_dy,
6533							    &dst_pixmap->drawable, bo, 0, 0,
6534							    box, n, COPY_LAST);
6535
6536				kgem_bo_sync__cpu(&sna->kgem, src_bo);
6537				assert(src_bo->rq == NULL);
6538				kgem_bo_destroy(&sna->kgem, src_bo);
6539			}
6540
6541			if (ok) {
6542				if (damage)
6543					sna_damage_add(damage, region);
6544				return;
6545			}
6546		}
6547
6548		if (alu != GXcopy) {
6549			PixmapPtr tmp;
6550			struct kgem_bo *src_bo;
6551			int i;
6552
6553			assert(src_pixmap->drawable.depth != 1);
6554
6555			DBG(("%s: creating temporary source upload for non-copy alu [%d]\n",
6556			     __FUNCTION__, alu));
6557
6558			tmp = sna_pixmap_create_upload(src->pScreen,
6559						       region->extents.x2 - region->extents.x1,
6560						       region->extents.y2 - region->extents.y1,
6561						       src->depth,
6562						       KGEM_BUFFER_WRITE_INPLACE);
6563			if (tmp == NullPixmap)
6564				return;
6565
6566			src_bo = __sna_pixmap_get_bo(tmp);
6567			assert(src_bo != NULL);
6568
6569			dx = -region->extents.x1;
6570			dy = -region->extents.y1;
6571			for (i = 0; i < n; i++) {
6572				assert(box[i].x1 + src_dx >= 0);
6573				assert(box[i].y1 + src_dy >= 0);
6574				assert(box[i].x2 + src_dx <= src_pixmap->drawable.width);
6575				assert(box[i].y2 + src_dy <= src_pixmap->drawable.height);
6576
6577				assert(box[i].x1 + dx >= 0);
6578				assert(box[i].y1 + dy >= 0);
6579				assert(box[i].x2 + dx <= tmp->drawable.width);
6580				assert(box[i].y2 + dy <= tmp->drawable.height);
6581
6582				assert(has_coherent_ptr(sna, sna_pixmap(src_pixmap), MOVE_READ));
6583				assert(has_coherent_ptr(sna, sna_pixmap(tmp), MOVE_WRITE));
6584				assert(src_pixmap->devKind);
6585				assert(tmp->devKind);
6586				memcpy_blt(src_pixmap->devPrivate.ptr,
6587					   tmp->devPrivate.ptr,
6588					   src_pixmap->drawable.bitsPerPixel,
6589					   src_pixmap->devKind,
6590					   tmp->devKind,
6591					   box[i].x1 + src_dx,
6592					   box[i].y1 + src_dy,
6593					   box[i].x1 + dx,
6594					   box[i].y1 + dy,
6595					   box[i].x2 - box[i].x1,
6596					   box[i].y2 - box[i].y1);
6597			}
6598
6599			if (n == 1 &&
6600			    tmp->drawable.width == src_pixmap->drawable.width &&
6601			    tmp->drawable.height == src_pixmap->drawable.height) {
6602				DBG(("%s: caching upload for src bo\n",
6603				     __FUNCTION__));
6604				assert(src_priv->gpu_damage == NULL);
6605				assert(src_priv->gpu_bo == NULL);
6606				kgem_proxy_bo_attach(src_bo, &src_priv->gpu_bo);
6607			}
6608
6609			if (!sna->render.copy_boxes(sna, alu,
6610						    &tmp->drawable, src_bo, dx, dy,
6611						    &dst_pixmap->drawable, bo, 0, 0,
6612						    box, n, 0)) {
6613				DBG(("%s: fallback - accelerated copy boxes failed\n",
6614				     __FUNCTION__));
6615				tmp->drawable.pScreen->DestroyPixmap(tmp);
6616				goto fallback;
6617			}
6618			tmp->drawable.pScreen->DestroyPixmap(tmp);
6619
6620			if (damage)
6621				sna_damage_add(damage, region);
6622			return;
6623		} else {
6624			DBG(("%s: dst is on the GPU, src is on the CPU, uploading into dst\n",
6625			     __FUNCTION__));
6626
6627			assert(src_pixmap->devKind);
6628			if (!dst_priv->pinned && replaces) {
6629				stride = src_pixmap->devKind;
6630				bits = src_pixmap->devPrivate.ptr;
6631				bits += (src_dy + box->y1) * stride + (src_dx + box->x1) * bpp / 8;
6632
6633				if (!sna_replace(sna, dst_pixmap, bits, stride)) {
6634					DBG(("%s: replace failed, fallback\n", __FUNCTION__));
6635					goto fallback;
6636				}
6637			} else {
6638				assert(!DAMAGE_IS_ALL(dst_priv->cpu_damage));
6639				if (!sna_write_boxes(sna, dst_pixmap,
6640						     dst_priv->gpu_bo, 0, 0,
6641						     src_pixmap->devPrivate.ptr,
6642						     src_pixmap->devKind,
6643						     src_dx, src_dy,
6644						     box, n)) {
6645					DBG(("%s: write failed, fallback\n", __FUNCTION__));
6646					goto fallback;
6647				}
6648			}
6649
6650			assert(dst_priv->clear == false);
6651			dst_priv->cpu = false;
6652			if (damage) {
6653				assert(!dst_priv->clear);
6654				assert(dst_priv->gpu_bo);
6655				assert(dst_priv->gpu_bo->proxy == NULL);
6656				assert(*damage == dst_priv->gpu_damage);
6657				if (replaces) {
6658					sna_damage_destroy(&dst_priv->cpu_damage);
6659					sna_damage_all(&dst_priv->gpu_damage, dst_pixmap);
6660					list_del(&dst_priv->flush_list);
6661				} else
6662					sna_damage_add(&dst_priv->gpu_damage,
6663						       region);
6664				assert_pixmap_damage(dst_pixmap);
6665			}
6666		}
6667
6668		return;
6669	}
6670
6671fallback:
6672	if (alu == GXcopy && src_priv && src_priv->clear) {
6673		DBG(("%s: copying clear [%08x]\n",
6674		     __FUNCTION__, src_priv->clear_color));
6675
6676		if (dst_priv) {
6677			if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable,
6678							     region,
6679							     MOVE_WRITE | MOVE_INPLACE_HINT))
6680				return;
6681		}
6682
6683		assert(dst_pixmap->devPrivate.ptr);
6684		assert(dst_pixmap->devKind);
6685		do {
6686			pixman_fill(dst_pixmap->devPrivate.ptr,
6687				    dst_pixmap->devKind/sizeof(uint32_t),
6688				    dst_pixmap->drawable.bitsPerPixel,
6689				    box->x1, box->y1,
6690				    box->x2 - box->x1,
6691				    box->y2 - box->y1,
6692				    src_priv->clear_color);
6693			box++;
6694		} while (--n);
6695	} else if (!sna_copy_boxes__inplace(sna, region, alu,
6696					    src_pixmap, src_priv,
6697					    src_dx, src_dy,
6698					    dst_pixmap, dst_priv,
6699					    replaces)) {
6700		FbBits *dst_bits, *src_bits;
6701		int dst_stride, src_stride;
6702
6703		DBG(("%s: fallback -- src=(%d, %d), dst=(%d, %d)\n",
6704		     __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy));
6705		if (src_priv) {
6706			unsigned mode;
6707
6708			RegionTranslate(region, src_dx, src_dy);
6709
6710			assert_pixmap_contains_box(src_pixmap,
6711						   RegionExtents(region));
6712
6713			mode = MOVE_READ;
6714			if (!sna->kgem.can_blt_cpu ||
6715			    (src_priv->cpu_bo == NULL &&
6716			     (src_priv->create & KGEM_CAN_CREATE_CPU) == 0))
6717				mode |= MOVE_INPLACE_HINT;
6718
6719			if (!sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
6720							     region, mode))
6721				return;
6722
6723			RegionTranslate(region, -src_dx, -src_dy);
6724		}
6725		assert(src_priv == sna_pixmap(src_pixmap));
6726
6727		if (dst_priv) {
6728			unsigned mode;
6729
6730			if (alu_overwrites(alu))
6731				mode = MOVE_WRITE | MOVE_INPLACE_HINT;
6732			else
6733				mode = MOVE_WRITE | MOVE_READ;
6734			if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable,
6735							     region, mode))
6736				return;
6737		}
6738		assert(dst_priv == sna_pixmap(dst_pixmap));
6739
6740		assert(dst_pixmap->devKind);
6741		assert(src_pixmap->devKind);
6742		dst_stride = dst_pixmap->devKind;
6743		src_stride = src_pixmap->devKind;
6744
6745		if (alu == GXcopy && bpp >= 8) {
6746			dst_bits = (FbBits *)dst_pixmap->devPrivate.ptr;
6747			src_bits = (FbBits *)
6748				((char *)src_pixmap->devPrivate.ptr +
6749				 src_dy * src_stride + src_dx * bpp / 8);
6750
6751			do {
6752				DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n",
6753				     __FUNCTION__,
6754				     box->x1, box->y1,
6755				     box->x2 - box->x1,
6756				     box->y2 - box->y1,
6757				     src_dx, src_dy,
6758				     src_stride, dst_stride));
6759
6760				assert(box->x1 >= 0);
6761				assert(box->y1 >= 0);
6762				assert(box->x2 <= dst_pixmap->drawable.width);
6763				assert(box->y2 <= dst_pixmap->drawable.height);
6764
6765				assert(box->x1 + src_dx >= 0);
6766				assert(box->y1 + src_dy >= 0);
6767				assert(box->x2 + src_dx <= src_pixmap->drawable.width);
6768				assert(box->y2 + src_dy <= src_pixmap->drawable.height);
6769				assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
6770				assert(has_coherent_ptr(sna, dst_priv, MOVE_WRITE));
6771				assert(src_stride);
6772				assert(dst_stride);
6773				memcpy_blt(src_bits, dst_bits, bpp,
6774					   src_stride, dst_stride,
6775					   box->x1, box->y1,
6776					   box->x1, box->y1,
6777					   box->x2 - box->x1,
6778					   box->y2 - box->y1);
6779				box++;
6780			} while (--n);
6781		} else {
6782			DBG(("%s: fallback -- miCopyRegion\n", __FUNCTION__));
6783
6784			RegionTranslate(region, -dst_dx, -dst_dy);
6785
6786			if (sna_gc_move_to_cpu(gc, dst, region) &&
6787			    sigtrap_get() == 0) {
6788				miCopyRegion(src, dst, gc,
6789					     region, dx, dy,
6790					     fbCopyNtoN, 0, NULL);
6791				sigtrap_put();
6792			}
6793
6794			sna_gc_move_to_gpu(gc);
6795		}
6796	}
6797}
6798
6799typedef void (*sna_copy_func)(DrawablePtr src, DrawablePtr dst, GCPtr gc,
6800			      RegionPtr region, int dx, int dy,
6801			      Pixel bitPlane, void *closure);
6802
6803static inline bool box_equal(const BoxRec *a, const BoxRec *b)
6804{
6805	return *(const uint64_t *)a == *(const uint64_t *)b;
6806}
6807
6808static RegionPtr
6809sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc,
6810	    int sx, int sy,
6811	    int width, int height,
6812	    int dx, int dy,
6813	    sna_copy_func copy, Pixel bitPlane, void *closure)
6814{
6815	RegionPtr clip;
6816	RegionRec region;
6817	BoxRec src_extents;
6818	bool expose;
6819
6820	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n",
6821	     __FUNCTION__, sx, sy, dx, dy, width, height));
6822
6823	/* Short cut for unmapped windows */
6824	if (dst->type == DRAWABLE_WINDOW && !((WindowPtr)dst)->realized) {
6825		DBG(("%s: unmapped\n", __FUNCTION__));
6826		return NULL;
6827	}
6828
6829	SourceValidate(src, sx, sy, width, height, gc->subWindowMode);
6830
6831	sx += src->x;
6832	sy += src->y;
6833
6834	dx += dst->x;
6835	dy += dst->y;
6836
6837	DBG(("%s: after drawable: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n",
6838	     __FUNCTION__, sx, sy, dx, dy, width, height));
6839
6840	region.extents.x1 = dx;
6841	region.extents.y1 = dy;
6842	region.extents.x2 = bound(dx, width);
6843	region.extents.y2 = bound(dy, height);
6844	region.data = NULL;
6845
6846	DBG(("%s: dst extents (%d, %d), (%d, %d), dst clip extents (%d, %d), (%d, %d), dst size=%dx%d\n", __FUNCTION__,
6847	     region.extents.x1, region.extents.y1,
6848	     region.extents.x2, region.extents.y2,
6849	     gc->pCompositeClip->extents.x1, gc->pCompositeClip->extents.y1,
6850	     gc->pCompositeClip->extents.x2, gc->pCompositeClip->extents.y2,
6851	     dst->width, dst->height));
6852
6853	if (!box_intersect(&region.extents, &gc->pCompositeClip->extents)) {
6854		DBG(("%s: dst clipped out\n", __FUNCTION__));
6855		return NULL;
6856	}
6857
6858	DBG(("%s: clipped dst extents (%d, %d), (%d, %d)\n", __FUNCTION__,
6859	     region.extents.x1, region.extents.y1,
6860	     region.extents.x2, region.extents.y2));
6861	assert_drawable_contains_box(dst, &region.extents);
6862
6863	region.extents.x1 = clamp(region.extents.x1, sx - dx);
6864	region.extents.x2 = clamp(region.extents.x2, sx - dx);
6865	region.extents.y1 = clamp(region.extents.y1, sy - dy);
6866	region.extents.y2 = clamp(region.extents.y2, sy - dy);
6867
6868	src_extents = region.extents;
6869	expose = true;
6870
6871	DBG(("%s: unclipped src extents (%d, %d), (%d, %d)\n", __FUNCTION__,
6872	     region.extents.x1, region.extents.y1,
6873	     region.extents.x2, region.extents.y2));
6874
6875	if (region.extents.x1 < src->x)
6876		region.extents.x1 = src->x;
6877	if (region.extents.y1 < src->y)
6878		region.extents.y1 = src->y;
6879	if (region.extents.x2 > src->x + (int) src->width)
6880		region.extents.x2 = src->x + (int) src->width;
6881	if (region.extents.y2 > src->y + (int) src->height)
6882		region.extents.y2 = src->y + (int) src->height;
6883
6884	DBG(("%s: clipped src extents (%d, %d), (%d, %d)\n", __FUNCTION__,
6885	     region.extents.x1, region.extents.y1,
6886	     region.extents.x2, region.extents.y2));
6887	if (box_empty(&region.extents)) {
6888		DBG(("%s: src clipped out\n", __FUNCTION__));
6889		return NULL;
6890	}
6891
6892	/* Compute source clip region */
6893	if (src->type == DRAWABLE_PIXMAP) {
6894		if (src == dst && gc->clientClipType == CT_NONE) {
6895			DBG(("%s: pixmap -- using gc clip\n", __FUNCTION__));
6896			clip = gc->pCompositeClip;
6897		} else {
6898			DBG(("%s: pixmap -- no source clipping\n", __FUNCTION__));
6899			expose = false;
6900			clip = NULL;
6901		}
6902	} else {
6903		WindowPtr w = (WindowPtr)src;
6904		if (gc->subWindowMode == IncludeInferiors) {
6905			DBG(("%s: window -- include inferiors\n", __FUNCTION__));
6906
6907			if (w->winSize.data)
6908				RegionIntersect(&region, &region, &w->winSize);
6909			else
6910				box_intersect(&region.extents, &w->winSize.extents);
6911			clip = &w->borderClip;
6912		} else {
6913			DBG(("%s: window -- clip by children\n", __FUNCTION__));
6914			clip = &w->clipList;
6915		}
6916	}
6917	if (clip != NULL) {
6918		if (clip->data == NULL) {
6919			box_intersect(&region.extents, &clip->extents);
6920			if (box_equal(&src_extents, &region.extents))
6921				expose = false;
6922		} else
6923			RegionIntersect(&region, &region, clip);
6924	}
6925	DBG(("%s: src extents (%d, %d), (%d, %d) x %d\n", __FUNCTION__,
6926	     region.extents.x1, region.extents.y1,
6927	     region.extents.x2, region.extents.y2,
6928	     region_num_rects(&region)));
6929
6930	RegionTranslate(&region, dx-sx, dy-sy);
6931	if (gc->pCompositeClip->data)
6932		RegionIntersect(&region, &region, gc->pCompositeClip);
6933	DBG(("%s: copy region (%d, %d), (%d, %d) x %d + (%d, %d)\n",
6934	     __FUNCTION__,
6935	     region.extents.x1, region.extents.y1,
6936	     region.extents.x2, region.extents.y2,
6937	     region_num_rects(&region),
6938	     sx-dx, sy-dy));
6939
6940	if (!box_empty(&region.extents))
6941		copy(src, dst, gc, &region, sx-dx, sy-dy, bitPlane, closure);
6942	assert(gc->pCompositeClip != &region);
6943	RegionUninit(&region);
6944
6945	/* Pixmap sources generate a NoExposed (we return NULL to do this) */
6946	clip = NULL;
6947	if (expose && gc->fExpose)
6948		clip = miHandleExposures(src, dst, gc,
6949					 sx - src->x, sy - src->y,
6950					 width, height,
6951					 dx - dst->x, dy - dst->y,
6952					 (unsigned long) bitPlane);
6953	return clip;
6954}
6955
6956static void
6957sna_fallback_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
6958			RegionPtr region, int dx, int dy,
6959			Pixel bitplane, void *closure)
6960{
6961	DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d\n",
6962	     __FUNCTION__, region_num_rects(region),
6963	     region->extents.x1, region->extents.y1,
6964	     region->extents.x2, region->extents.y2,
6965	     dx, dy, gc->alu));
6966
6967	if (!sna_gc_move_to_cpu(gc, dst, region))
6968		goto out;
6969
6970	RegionTranslate(region, dx, dy);
6971	if (!sna_drawable_move_region_to_cpu(src, region, MOVE_READ))
6972		goto out;
6973	RegionTranslate(region, -dx, -dy);
6974
6975	if (src == dst ||
6976	    get_drawable_pixmap(src) == get_drawable_pixmap(dst)) {
6977		DBG(("%s: self-copy\n", __FUNCTION__));
6978		if (!sna_drawable_move_to_cpu(dst, MOVE_WRITE | MOVE_READ))
6979			goto out;
6980	} else {
6981		if (!sna_drawable_move_region_to_cpu(dst, region,
6982						     drawable_gc_flags(dst, gc, false)))
6983			goto out;
6984	}
6985
6986	if (sigtrap_get() == 0) {
6987		miCopyRegion(src, dst, gc,
6988			     region, dx, dy,
6989			     fbCopyNtoN, 0, NULL);
6990		FALLBACK_FLUSH(dst);
6991		sigtrap_put();
6992	}
6993out:
6994	sna_gc_move_to_gpu(gc);
6995}
6996
6997static RegionPtr
6998sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
6999	      int src_x, int src_y,
7000	      int width, int height,
7001	      int dst_x, int dst_y)
7002{
7003	struct sna *sna = to_sna_from_drawable(dst);
7004	sna_copy_func copy;
7005
7006	if (gc->planemask == 0)
7007		return NULL;
7008
7009	DBG(("%s: src=(%d, %d)x(%d, %d)+(%d, %d) -> dst=(%d, %d)+(%d, %d); alu=%d, pm=%lx, depth=%d\n",
7010	     __FUNCTION__,
7011	     src_x, src_y, width, height, src->x, src->y,
7012	     dst_x, dst_y, dst->x, dst->y,
7013	     gc->alu, gc->planemask, gc->depth));
7014
7015	if (FORCE_FALLBACK || !ACCEL_COPY_AREA || wedged(sna) ||
7016	    !PM_IS_SOLID(dst, gc->planemask) || gc->depth < 8)
7017		copy = sna_fallback_copy_boxes;
7018	else if (src == dst)
7019		copy = sna_self_copy_boxes;
7020	else
7021		copy = sna_copy_boxes;
7022
7023	return sna_do_copy(src, dst, gc,
7024			   src_x, src_y,
7025			   width, height,
7026			   dst_x, dst_y,
7027			   copy, 0, NULL);
7028}
7029
7030static const BoxRec *
7031find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y)
7032{
7033    const BoxRec *mid;
7034
7035    if (end == begin)
7036	return end;
7037
7038    if (end - begin == 1) {
7039	if (begin->y2 > y)
7040	    return begin;
7041	else
7042	    return end;
7043    }
7044
7045    mid = begin + (end - begin) / 2;
7046    if (mid->y2 > y)
7047	/* If no box is found in [begin, mid], the function
7048	 * will return @mid, which is then known to be the
7049	 * correct answer.
7050	 */
7051	return find_clip_box_for_y(begin, mid, y);
7052    else
7053	return find_clip_box_for_y(mid, end, y);
7054}
7055
7056struct sna_fill_spans {
7057	struct sna *sna;
7058	PixmapPtr pixmap;
7059	RegionRec region;
7060	unsigned flags;
7061	uint32_t phase;
7062	struct kgem_bo *bo;
7063	struct sna_damage **damage;
7064	int16_t dx, dy;
7065	void *op;
7066};
7067
7068static void
7069sna_poly_point__cpu(DrawablePtr drawable, GCPtr gc,
7070		    int mode, int n, DDXPointPtr pt)
7071{
7072	fbPolyPoint(drawable, gc, mode, n, pt, -1);
7073}
7074
7075static void
7076sna_poly_point__fill(DrawablePtr drawable, GCPtr gc,
7077		     int mode, int n, DDXPointPtr pt)
7078{
7079	struct sna_fill_spans *data = sna_gc(gc)->priv;
7080	struct sna_fill_op *op = data->op;
7081	BoxRec box[512];
7082	DDXPointRec last;
7083
7084	DBG(("%s: count=%d\n", __FUNCTION__, n));
7085	if (n == 0)
7086		return;
7087
7088	last.x = drawable->x + data->dx;
7089	last.y = drawable->y + data->dy;
7090	if (op->points && mode != CoordModePrevious) {
7091		op->points(data->sna, op, last.x, last.y, pt, n);
7092	} else do {
7093		BoxRec *b = box;
7094		unsigned nbox = n;
7095		if (nbox > ARRAY_SIZE(box))
7096			nbox = ARRAY_SIZE(box);
7097		n -= nbox;
7098		do {
7099			*(DDXPointRec *)b = *pt++;
7100
7101			b->x1 += last.x;
7102			b->y1 += last.y;
7103			if (mode == CoordModePrevious)
7104				last = *(DDXPointRec *)b;
7105
7106			b->x2 = b->x1 + 1;
7107			b->y2 = b->y1 + 1;
7108			b++;
7109		} while (--nbox);
7110		op->boxes(data->sna, op, box, b - box);
7111	} while (n);
7112}
7113
7114static void
7115sna_poly_point__gpu(DrawablePtr drawable, GCPtr gc,
7116		     int mode, int n, DDXPointPtr pt)
7117{
7118	struct sna_fill_spans *data = sna_gc(gc)->priv;
7119	struct sna_fill_op fill;
7120	BoxRec box[512];
7121	DDXPointRec last;
7122
7123	if (!sna_fill_init_blt(&fill,
7124			       data->sna, data->pixmap,
7125			       data->bo, gc->alu, gc->fgPixel,
7126			       FILL_POINTS))
7127		return;
7128
7129	DBG(("%s: count=%d\n", __FUNCTION__, n));
7130
7131	last.x = drawable->x;
7132	last.y = drawable->y;
7133	while (n) {
7134		BoxRec *b = box;
7135		unsigned nbox = n;
7136		if (nbox > ARRAY_SIZE(box))
7137			nbox = ARRAY_SIZE(box);
7138		n -= nbox;
7139		do {
7140			*(DDXPointRec *)b = *pt++;
7141
7142			b->x1 += last.x;
7143			b->y1 += last.y;
7144			if (mode == CoordModePrevious)
7145				last = *(DDXPointRec *)b;
7146
7147			if (RegionContainsPoint(&data->region,
7148						b->x1, b->y1, NULL)) {
7149				b->x1 += data->dx;
7150				b->y1 += data->dy;
7151				b->x2 = b->x1 + 1;
7152				b->y2 = b->y1 + 1;
7153				b++;
7154			}
7155		} while (--nbox);
7156		fill.boxes(data->sna, &fill, box, b - box);
7157	}
7158	fill.done(data->sna, &fill);
7159}
7160
7161static void
7162sna_poly_point__fill_clip_extents(DrawablePtr drawable, GCPtr gc,
7163				  int mode, int n, DDXPointPtr pt)
7164{
7165	struct sna_fill_spans *data = sna_gc(gc)->priv;
7166	struct sna_fill_op *op = data->op;
7167	const BoxRec *extents = &data->region.extents;
7168	BoxRec box[512], *b = box;
7169	const BoxRec *const last_box = b + ARRAY_SIZE(box);
7170	DDXPointRec last;
7171
7172	DBG(("%s: count=%d\n", __FUNCTION__, n));
7173
7174	last.x = drawable->x + data->dx;
7175	last.y = drawable->y + data->dy;
7176	while (n--) {
7177		*(DDXPointRec *)b = *pt++;
7178
7179		b->x1 += last.x;
7180		b->y1 += last.y;
7181		if (mode == CoordModePrevious)
7182			last = *(DDXPointRec *)b;
7183
7184		if (b->x1 >= extents->x1 && b->x1 < extents->x2 &&
7185		    b->y1 >= extents->y1 && b->y1 < extents->y2) {
7186			b->x2 = b->x1 + 1;
7187			b->y2 = b->y1 + 1;
7188			if (++b == last_box) {
7189				op->boxes(data->sna, op, box, last_box - box);
7190				b = box;
7191			}
7192		}
7193	}
7194	if (b != box)
7195		op->boxes(data->sna, op, box, b - box);
7196}
7197
7198static void
7199sna_poly_point__fill_clip_boxes(DrawablePtr drawable, GCPtr gc,
7200				int mode, int n, DDXPointPtr pt)
7201{
7202	struct sna_fill_spans *data = sna_gc(gc)->priv;
7203	struct sna_fill_op *op = data->op;
7204	RegionRec *clip = &data->region;
7205	BoxRec box[512], *b = box;
7206	const BoxRec *const last_box = b + ARRAY_SIZE(box);
7207	DDXPointRec last;
7208
7209	DBG(("%s: count=%d\n", __FUNCTION__, n));
7210
7211	last.x = drawable->x + data->dx;
7212	last.y = drawable->y + data->dy;
7213	while (n--) {
7214		*(DDXPointRec *)b = *pt++;
7215
7216		b->x1 += last.x;
7217		b->y1 += last.y;
7218		if (mode == CoordModePrevious)
7219			last = *(DDXPointRec *)b;
7220
7221		if (RegionContainsPoint(clip, b->x1, b->y1, NULL)) {
7222			b->x2 = b->x1 + 1;
7223			b->y2 = b->y1 + 1;
7224			if (++b == last_box) {
7225				op->boxes(data->sna, op, box, last_box - box);
7226				b = box;
7227			}
7228		}
7229	}
7230	if (b != box)
7231		op->boxes(data->sna, op, box, b - box);
7232}
7233
7234static void
7235sna_poly_point__dash(DrawablePtr drawable, GCPtr gc,
7236		     int mode, int n, DDXPointPtr pt)
7237{
7238	struct sna_fill_spans *data = sna_gc(gc)->priv;
7239	if (data->phase == gc->fgPixel)
7240		sna_poly_point__fill(drawable, gc, mode, n, pt);
7241}
7242
7243static void
7244sna_poly_point__dash_clip_extents(DrawablePtr drawable, GCPtr gc,
7245				  int mode, int n, DDXPointPtr pt)
7246{
7247	struct sna_fill_spans *data = sna_gc(gc)->priv;
7248	if (data->phase == gc->fgPixel)
7249		sna_poly_point__fill_clip_extents(drawable, gc, mode, n, pt);
7250}
7251
7252static void
7253sna_poly_point__dash_clip_boxes(DrawablePtr drawable, GCPtr gc,
7254				  int mode, int n, DDXPointPtr pt)
7255{
7256	struct sna_fill_spans *data = sna_gc(gc)->priv;
7257	if (data->phase == gc->fgPixel)
7258		sna_poly_point__fill_clip_boxes(drawable, gc, mode, n, pt);
7259}
7260
7261static void
7262sna_fill_spans__fill(DrawablePtr drawable,
7263		     GCPtr gc, int n,
7264		     DDXPointPtr pt, int *width, int sorted)
7265{
7266	struct sna_fill_spans *data = sna_gc(gc)->priv;
7267	struct sna_fill_op *op = data->op;
7268	BoxRec box[512];
7269
7270	DBG(("%s: alu=%d, fg=%08lx, count=%d\n",
7271	     __FUNCTION__, gc->alu, gc->fgPixel, n));
7272
7273	while (n) {
7274		BoxRec *b = box;
7275		int nbox = n;
7276		if (nbox > ARRAY_SIZE(box))
7277			nbox = ARRAY_SIZE(box);
7278		n -= nbox;
7279		do {
7280			*(DDXPointRec *)b = *pt++;
7281			b->x2 = b->x1 + (int)*width++;
7282			b->y2 = b->y1 + 1;
7283			DBG(("%s: (%d, %d), (%d, %d)\n",
7284			     __FUNCTION__, b->x1, b->y1, b->x2, b->y2));
7285			assert(b->x1 >= drawable->x);
7286			assert(b->x2 <= drawable->x + drawable->width);
7287			assert(b->y1 >= drawable->y);
7288			assert(b->y2 <= drawable->y + drawable->height);
7289			if (b->x2 > b->x1) {
7290				if (b != box &&
7291				    b->y1 == b[-1].y2 &&
7292				    b->x1 == b[-1].x1 &&
7293				    b->x2 == b[-1].x2)
7294					b[-1].y2 = b->y2;
7295				else
7296					b++;
7297			}
7298		} while (--nbox);
7299		if (b != box)
7300			op->boxes(data->sna, op, box, b - box);
7301	}
7302}
7303
7304static void
7305sna_fill_spans__dash(DrawablePtr drawable,
7306		     GCPtr gc, int n,
7307		     DDXPointPtr pt, int *width, int sorted)
7308{
7309	struct sna_fill_spans *data = sna_gc(gc)->priv;
7310	if (data->phase == gc->fgPixel)
7311		sna_fill_spans__fill(drawable, gc, n, pt, width, sorted);
7312}
7313
7314static void
7315sna_fill_spans__fill_offset(DrawablePtr drawable,
7316			    GCPtr gc, int n,
7317			    DDXPointPtr pt, int *width, int sorted)
7318{
7319	struct sna_fill_spans *data = sna_gc(gc)->priv;
7320	struct sna_fill_op *op = data->op;
7321	BoxRec box[512];
7322
7323	DBG(("%s: alu=%d, fg=%08lx\n", __FUNCTION__, gc->alu, gc->fgPixel));
7324
7325	while (n) {
7326		BoxRec *b = box;
7327		int nbox = n;
7328		if (nbox > ARRAY_SIZE(box))
7329			nbox = ARRAY_SIZE(box);
7330		n -= nbox;
7331		do {
7332			*(DDXPointRec *)b = *pt++;
7333			b->x1 += data->dx;
7334			b->y1 += data->dy;
7335			b->x2 = b->x1 + (int)*width++;
7336			b->y2 = b->y1 + 1;
7337			if (b->x2 > b->x1)
7338				b++;
7339		} while (--nbox);
7340		if (b != box)
7341			op->boxes(data->sna, op, box, b - box);
7342	}
7343}
7344
7345static void
7346sna_fill_spans__dash_offset(DrawablePtr drawable,
7347			    GCPtr gc, int n,
7348			    DDXPointPtr pt, int *width, int sorted)
7349{
7350	struct sna_fill_spans *data = sna_gc(gc)->priv;
7351	if (data->phase == gc->fgPixel)
7352		sna_fill_spans__fill_offset(drawable, gc, n, pt, width, sorted);
7353}
7354
7355static void
7356sna_fill_spans__fill_clip_extents(DrawablePtr drawable,
7357				  GCPtr gc, int n,
7358				  DDXPointPtr pt, int *width, int sorted)
7359{
7360	struct sna_fill_spans *data = sna_gc(gc)->priv;
7361	struct sna_fill_op *op = data->op;
7362	const BoxRec *extents = &data->region.extents;
7363	BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box);
7364
7365	DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n",
7366	     __FUNCTION__, gc->alu, gc->fgPixel, n,
7367	     extents->x1, extents->y1,
7368	     extents->x2, extents->y2));
7369
7370	while (n--) {
7371		DBG(("%s: [%d] pt=(%d, %d), width=%d\n",
7372		     __FUNCTION__, n, pt->x, pt->y, *width));
7373		*(DDXPointRec *)b = *pt++;
7374		b->x2 = b->x1 + (int)*width++;
7375		b->y2 = b->y1 + 1;
7376		if (box_intersect(b, extents)) {
7377			DBG(("%s: [%d] clipped=(%d, %d), (%d, %d)\n",
7378			     __FUNCTION__, n, b->x1, b->y1, b->x2, b->y2));
7379			if (data->dx|data->dy) {
7380				b->x1 += data->dx; b->x2 += data->dx;
7381				b->y1 += data->dy; b->y2 += data->dy;
7382			}
7383			if (b != box &&
7384			    b->y1 == b[-1].y2 &&
7385			    b->x1 == b[-1].x1 &&
7386			    b->x2 == b[-1].x2) {
7387				b[-1].y2 = b->y2;
7388			} else if (++b == last_box) {
7389				op->boxes(data->sna, op, box, last_box - box);
7390				b = box;
7391			}
7392		}
7393	}
7394	if (b != box)
7395		op->boxes(data->sna, op, box, b - box);
7396}
7397
7398static void
7399sna_fill_spans__dash_clip_extents(DrawablePtr drawable,
7400				  GCPtr gc, int n,
7401				  DDXPointPtr pt, int *width, int sorted)
7402{
7403	struct sna_fill_spans *data = sna_gc(gc)->priv;
7404	if (data->phase == gc->fgPixel)
7405		sna_fill_spans__fill_clip_extents(drawable, gc, n, pt, width, sorted);
7406}
7407
7408static void
7409sna_fill_spans__fill_clip_boxes(DrawablePtr drawable,
7410				GCPtr gc, int n,
7411				DDXPointPtr pt, int *width, int sorted)
7412{
7413	struct sna_fill_spans *data = sna_gc(gc)->priv;
7414	struct sna_fill_op *op = data->op;
7415	BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box);
7416	const BoxRec * const clip_start = RegionBoxptr(&data->region);
7417	const BoxRec * const clip_end = clip_start + data->region.data->numRects;
7418
7419	DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n",
7420	     __FUNCTION__, gc->alu, gc->fgPixel, n,
7421	     data->region.extents.x1, data->region.extents.y1,
7422	     data->region.extents.x2, data->region.extents.y2));
7423
7424	while (n--) {
7425		int16_t X1 = pt->x;
7426		int16_t y = pt->y;
7427		int16_t X2 = X1 + (int)*width;
7428		const BoxRec *c;
7429
7430		pt++;
7431		width++;
7432
7433		if (y < data->region.extents.y1 || data->region.extents.y2 <= y)
7434			continue;
7435
7436		if (X1 < data->region.extents.x1)
7437			X1 = data->region.extents.x1;
7438
7439		if (X2 > data->region.extents.x2)
7440			X2 = data->region.extents.x2;
7441
7442		if (X1 >= X2)
7443			continue;
7444
7445		c = find_clip_box_for_y(clip_start, clip_end, y);
7446		while (c != clip_end) {
7447			if (y + 1 <= c->y1 || X2 <= c->x1)
7448				break;
7449
7450			if (X1 >= c->x2) {
7451				c++;
7452				continue;
7453			}
7454
7455			b->x1 = c->x1;
7456			b->x2 = c->x2;
7457			c++;
7458
7459			if (b->x1 < X1)
7460				b->x1 = X1;
7461			if (b->x2 > X2)
7462				b->x2 = X2;
7463			if (b->x2 <= b->x1)
7464				continue;
7465
7466			b->x1 += data->dx;
7467			b->x2 += data->dx;
7468			b->y1 = y + data->dy;
7469			b->y2 = b->y1 + 1;
7470			if (++b == last_box) {
7471				op->boxes(data->sna, op, box, last_box - box);
7472				b = box;
7473			}
7474		}
7475	}
7476	if (b != box)
7477		op->boxes(data->sna, op, box, b - box);
7478}
7479
7480static void
7481sna_fill_spans__dash_clip_boxes(DrawablePtr drawable,
7482				GCPtr gc, int n,
7483				DDXPointPtr pt, int *width, int sorted)
7484{
7485	struct sna_fill_spans *data = sna_gc(gc)->priv;
7486	if (data->phase == gc->fgPixel)
7487		sna_fill_spans__fill_clip_boxes(drawable, gc, n, pt, width, sorted);
7488}
7489
7490static bool
7491sna_fill_spans_blt(DrawablePtr drawable,
7492		   struct kgem_bo *bo, struct sna_damage **damage,
7493		   GCPtr gc, uint32_t pixel,
7494		   int n, DDXPointPtr pt, int *width, int sorted,
7495		   const BoxRec *extents, unsigned clipped)
7496{
7497	PixmapPtr pixmap = get_drawable_pixmap(drawable);
7498	struct sna *sna = to_sna_from_pixmap(pixmap);
7499	int16_t dx, dy;
7500	struct sna_fill_op fill;
7501	BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box);
7502	static void * const jump[] = {
7503		&&no_damage,
7504		&&damage,
7505		&&no_damage_clipped,
7506		&&damage_clipped,
7507	};
7508	unsigned v;
7509
7510	DBG(("%s: alu=%d, fg=%08lx, damge=%p, clipped?=%d\n",
7511	     __FUNCTION__, gc->alu, gc->fgPixel, damage, clipped));
7512
7513	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_SPANS))
7514		return false;
7515
7516	get_drawable_deltas(drawable, pixmap, &dx, &dy);
7517
7518	v = (damage != NULL) | clipped;
7519	goto *jump[v];
7520
7521no_damage:
7522	if (dx|dy) {
7523		do {
7524			int nbox = n;
7525			if (nbox > last_box - box)
7526				nbox = last_box - box;
7527			n -= nbox;
7528			do {
7529				*(DDXPointRec *)b = *pt++;
7530				b->x1 += dx;
7531				b->y1 += dy;
7532				b->x2 = b->x1 + (int)*width++;
7533				b->y2 = b->y1 + 1;
7534				b++;
7535			} while (--nbox);
7536			fill.boxes(sna, &fill, box, b - box);
7537			b = box;
7538		} while (n);
7539	} else {
7540		do {
7541			int nbox = n;
7542			if (nbox > last_box - box)
7543				nbox = last_box - box;
7544			n -= nbox;
7545			do {
7546				*(DDXPointRec *)b = *pt++;
7547				b->x2 = b->x1 + (int)*width++;
7548				b->y2 = b->y1 + 1;
7549				b++;
7550			} while (--nbox);
7551			fill.boxes(sna, &fill, box, b - box);
7552			b = box;
7553		} while (n);
7554	}
7555	goto done;
7556
7557damage:
7558	do {
7559		*(DDXPointRec *)b = *pt++;
7560		b->x1 += dx;
7561		b->y1 += dy;
7562		b->x2 = b->x1 + (int)*width++;
7563		b->y2 = b->y1 + 1;
7564
7565		if (++b == last_box) {
7566			assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0);
7567			fill.boxes(sna, &fill, box, last_box - box);
7568			sna_damage_add_boxes(damage, box, last_box - box, 0, 0);
7569			b = box;
7570		}
7571	} while (--n);
7572	if (b != box) {
7573		assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
7574		fill.boxes(sna, &fill, box, b - box);
7575		sna_damage_add_boxes(damage, box, b - box, 0, 0);
7576	}
7577	goto done;
7578
7579no_damage_clipped:
7580	{
7581		RegionRec clip;
7582
7583		region_set(&clip, extents);
7584		if (!region_maybe_clip(&clip, gc->pCompositeClip))
7585			return true;
7586
7587		assert(dx + clip.extents.x1 >= 0);
7588		assert(dy + clip.extents.y1 >= 0);
7589		assert(dx + clip.extents.x2 <= pixmap->drawable.width);
7590		assert(dy + clip.extents.y2 <= pixmap->drawable.height);
7591
7592		DBG(("%s: clip %d x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n",
7593		     __FUNCTION__,
7594		     region_num_rects(&clip),
7595		     clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2,
7596		     n, pt->x, pt->y));
7597
7598		if (clip.data == NULL) {
7599			do {
7600				*(DDXPointRec *)b = *pt++;
7601				b->x2 = b->x1 + (int)*width++;
7602				b->y2 = b->y1 + 1;
7603
7604				if (box_intersect(b, &clip.extents)) {
7605					if (dx|dy) {
7606						b->x1 += dx; b->x2 += dx;
7607						b->y1 += dy; b->y2 += dy;
7608					}
7609					if (++b == last_box) {
7610						fill.boxes(sna, &fill, box, last_box - box);
7611						b = box;
7612					}
7613				}
7614			} while (--n);
7615		} else {
7616			const BoxRec * const clip_start = RegionBoxptr(&clip);
7617			const BoxRec * const clip_end = clip_start + clip.data->numRects;
7618			do {
7619				int16_t X1 = pt->x;
7620				int16_t y = pt->y;
7621				int16_t X2 = X1 + (int)*width;
7622				const BoxRec *c;
7623
7624				pt++;
7625				width++;
7626
7627				if (y < extents->y1 || extents->y2 <= y)
7628					continue;
7629
7630				if (X1 < extents->x1)
7631					X1 = extents->x1;
7632
7633				if (X2 > extents->x2)
7634					X2 = extents->x2;
7635
7636				if (X1 >= X2)
7637					continue;
7638
7639				c = find_clip_box_for_y(clip_start,
7640							clip_end,
7641							y);
7642				while (c != clip_end) {
7643					if (y + 1 <= c->y1 || X2 <= c->x1)
7644						break;
7645
7646					if (X1 >= c->x2) {
7647						c++;
7648						continue;
7649					}
7650
7651					b->x1 = c->x1;
7652					b->x2 = c->x2;
7653					c++;
7654
7655					if (b->x1 < X1)
7656						b->x1 = X1;
7657					if (b->x2 > X2)
7658						b->x2 = X2;
7659					if (b->x2 <= b->x1)
7660						continue;
7661
7662					b->x1 += dx;
7663					b->x2 += dx;
7664					b->y1 = y + dy;
7665					b->y2 = b->y1 + 1;
7666					if (++b == last_box) {
7667						fill.boxes(sna, &fill, box, last_box - box);
7668						b = box;
7669					}
7670				}
7671			} while (--n);
7672			RegionUninit(&clip);
7673		}
7674		if (b != box)
7675			fill.boxes(sna, &fill, box, b - box);
7676		goto done;
7677	}
7678
7679damage_clipped:
7680	{
7681		RegionRec clip;
7682
7683		region_set(&clip, extents);
7684		if (!region_maybe_clip(&clip, gc->pCompositeClip))
7685			return true;
7686
7687		assert(dx + clip.extents.x1 >= 0);
7688		assert(dy + clip.extents.y1 >= 0);
7689		assert(dx + clip.extents.x2 <= pixmap->drawable.width);
7690		assert(dy + clip.extents.y2 <= pixmap->drawable.height);
7691
7692		DBG(("%s: clip %d x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n",
7693		     __FUNCTION__,
7694		     region_num_rects(&clip),
7695		     clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2,
7696		     n, pt->x, pt->y));
7697
7698		if (clip.data == NULL) {
7699			do {
7700				*(DDXPointRec *)b = *pt++;
7701				b->x2 = b->x1 + (int)*width++;
7702				b->y2 = b->y1 + 1;
7703
7704				if (box_intersect(b, &clip.extents)) {
7705					b->x1 += dx;
7706					b->x2 += dx;
7707					b->y1 += dy;
7708					b->y2 += dy;
7709					if (++b == last_box) {
7710						assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
7711						fill.boxes(sna, &fill, box, last_box - box);
7712						sna_damage_add_boxes(damage, box, b - box, 0, 0);
7713						b = box;
7714					}
7715				}
7716			} while (--n);
7717		} else {
7718			const BoxRec * const clip_start = RegionBoxptr(&clip);
7719			const BoxRec * const clip_end = clip_start + clip.data->numRects;
7720			do {
7721				int16_t X1 = pt->x;
7722				int16_t y = pt->y;
7723				int16_t X2 = X1 + (int)*width;
7724				const BoxRec *c;
7725
7726				pt++;
7727				width++;
7728
7729				if (y < extents->y1 || extents->y2 <= y)
7730					continue;
7731
7732				if (X1 < extents->x1)
7733					X1 = extents->x1;
7734
7735				if (X2 > extents->x2)
7736					X2 = extents->x2;
7737
7738				if (X1 >= X2)
7739					continue;
7740
7741				c = find_clip_box_for_y(clip_start,
7742							clip_end,
7743							y);
7744				while (c != clip_end) {
7745					if (y + 1 <= c->y1 || X2 <= c->x1)
7746						break;
7747
7748					if (X1 >= c->x2) {
7749						c++;
7750						continue;
7751					}
7752
7753					b->x1 = c->x1;
7754					b->x2 = c->x2;
7755					c++;
7756
7757					if (b->x1 < X1)
7758						b->x1 = X1;
7759					if (b->x2 > X2)
7760						b->x2 = X2;
7761					if (b->x2 <= b->x1)
7762						continue;
7763
7764					b->x1 += dx;
7765					b->x2 += dx;
7766					b->y1 = y + dy;
7767					b->y2 = b->y1 + 1;
7768					if (++b == last_box) {
7769						assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0);
7770						fill.boxes(sna, &fill, box, last_box - box);
7771						sna_damage_add_boxes(damage, box, last_box - box, 0, 0);
7772						b = box;
7773					}
7774				}
7775			} while (--n);
7776			RegionUninit(&clip);
7777		}
7778		if (b != box) {
7779			assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
7780			fill.boxes(sna, &fill, box, b - box);
7781			sna_damage_add_boxes(damage, box, b - box, 0, 0);
7782		}
7783		goto done;
7784	}
7785
7786done:
7787	fill.done(sna, &fill);
7788	assert_pixmap_damage(pixmap);
7789	return true;
7790}
7791
7792static bool
7793sna_poly_fill_rect_tiled_blt(DrawablePtr drawable,
7794			     struct kgem_bo *bo,
7795			     struct sna_damage **damage,
7796			     GCPtr gc, int n, xRectangle *rect,
7797			     const BoxRec *extents, unsigned clipped);
7798
7799static bool
7800sna_poly_fill_rect_stippled_blt(DrawablePtr drawable,
7801				struct kgem_bo *bo,
7802				struct sna_damage **damage,
7803				GCPtr gc, int n, xRectangle *rect,
7804				const BoxRec *extents, unsigned clipped);
7805
7806static inline bool
7807gc_is_solid(GCPtr gc, uint32_t *color)
7808{
7809	assert(FbFullMask(gc->depth) == (FbFullMask(gc->depth) & gc->planemask));
7810
7811	if (gc->alu == GXclear) {
7812		*color = 0;
7813		return true;
7814	}
7815	if (gc->alu == GXset) {
7816		*color = (1 << gc->depth) - 1;
7817		return true;
7818	}
7819
7820	if (gc->fillStyle == FillSolid ||
7821	    (gc->fillStyle == FillTiled && gc->tileIsPixel) ||
7822	    (gc->fillStyle == FillOpaqueStippled && gc->bgPixel == gc->fgPixel)) {
7823		*color = gc->fillStyle == FillTiled ? gc->tile.pixel : gc->fgPixel;
7824		return true;
7825	}
7826
7827	return false;
7828}
7829
7830static void
7831sna_fill_spans__gpu(DrawablePtr drawable, GCPtr gc, int n,
7832		    DDXPointPtr pt, int *width, int sorted)
7833{
7834	struct sna_fill_spans *data = sna_gc(gc)->priv;
7835	uint32_t color;
7836
7837	DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n",
7838	     __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted));
7839
7840	assert(PM_IS_SOLID(drawable, gc->planemask));
7841	if (n == 0)
7842		return;
7843
7844	/* The mi routines do not attempt to keep the spans it generates
7845	 * within the clip, so we must run them through the clipper.
7846	 */
7847
7848	if (gc_is_solid(gc, &color)) {
7849		sna_fill_spans_blt(drawable,
7850				   data->bo, NULL,
7851				   gc, color, n, pt, width, sorted,
7852				   &data->region.extents, 2);
7853	} else {
7854		/* Try converting these to a set of rectangles instead */
7855		xRectangle *rect;
7856		int i;
7857
7858		DBG(("%s: converting to rectagnles\n", __FUNCTION__));
7859
7860		rect = malloc (n * sizeof (xRectangle));
7861		if (rect == NULL)
7862			return;
7863
7864		for (i = 0; i < n; i++) {
7865			rect[i].x = pt[i].x - drawable->x;
7866			rect[i].width = width[i];
7867			rect[i].y = pt[i].y - drawable->y;
7868			rect[i].height = 1;
7869		}
7870
7871		if (gc->fillStyle == FillTiled) {
7872			(void)sna_poly_fill_rect_tiled_blt(drawable,
7873							   data->bo, NULL,
7874							   gc, n, rect,
7875							   &data->region.extents, 2);
7876		} else {
7877			(void)sna_poly_fill_rect_stippled_blt(drawable,
7878							      data->bo, NULL,
7879							      gc, n, rect,
7880							      &data->region.extents, 2);
7881		}
7882		free (rect);
7883	}
7884}
7885
7886static unsigned
7887sna_spans_extents(DrawablePtr drawable, GCPtr gc,
7888		  int n, DDXPointPtr pt, int *width,
7889		  BoxPtr out)
7890{
7891	BoxRec box;
7892	bool clipped = false;
7893
7894	if (n == 0)
7895		return 0;
7896
7897	box.x1 = pt->x;
7898	box.x2 = box.x1 + *width;
7899	box.y2 = box.y1 = pt->y;
7900
7901	while (--n) {
7902		pt++;
7903		width++;
7904		if (box.x1 > pt->x)
7905			box.x1 = pt->x;
7906		if (box.x2 < pt->x + *width)
7907			box.x2 = pt->x + *width;
7908
7909		if (box.y1 > pt->y)
7910			box.y1 = pt->y;
7911		else if (box.y2 < pt->y)
7912			box.y2 = pt->y;
7913	}
7914	box.y2++;
7915
7916	if (gc)
7917		clipped = clip_box(&box, gc);
7918	if (box_empty(&box))
7919		return 0;
7920
7921	*out = box;
7922	return 1 | clipped << 1;
7923}
7924
7925static void
7926sna_fill_spans(DrawablePtr drawable, GCPtr gc, int n,
7927	       DDXPointPtr pt, int *width, int sorted)
7928{
7929	PixmapPtr pixmap = get_drawable_pixmap(drawable);
7930	struct sna *sna = to_sna_from_pixmap(pixmap);
7931	struct sna_damage **damage;
7932	struct kgem_bo *bo;
7933	RegionRec region;
7934	unsigned flags;
7935	uint32_t color;
7936
7937	DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n",
7938	     __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted));
7939
7940	flags = sna_spans_extents(drawable, gc, n, pt, width, &region.extents);
7941	if (flags == 0)
7942		return;
7943
7944	DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__,
7945	     region.extents.x1, region.extents.y1,
7946	     region.extents.x2, region.extents.y2));
7947
7948	if (FORCE_FALLBACK)
7949		goto fallback;
7950
7951	if (!ACCEL_FILL_SPANS)
7952		goto fallback;
7953
7954	if (wedged(sna)) {
7955		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
7956		goto fallback;
7957	}
7958
7959	DBG(("%s: fillStyle=%x [%d], mask=%lx [%d]\n", __FUNCTION__,
7960	     gc->fillStyle, gc->fillStyle == FillSolid,
7961	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask)));
7962	if (!PM_IS_SOLID(drawable, gc->planemask))
7963		goto fallback;
7964
7965	bo = sna_drawable_use_bo(drawable, PREFER_GPU,
7966				 &region.extents, &damage);
7967	if (bo) {
7968		if (gc_is_solid(gc, &color)) {
7969			DBG(("%s: trying solid fill [alu=%d, pixel=%08lx] blt paths\n",
7970			     __FUNCTION__, gc->alu, gc->fgPixel));
7971
7972			sna_fill_spans_blt(drawable,
7973					   bo, damage,
7974					   gc, color, n, pt, width, sorted,
7975					   &region.extents, flags & 2);
7976		} else {
7977			/* Try converting these to a set of rectangles instead */
7978			xRectangle *rect;
7979			int i;
7980
7981			DBG(("%s: converting to rectagnles\n", __FUNCTION__));
7982
7983			rect = malloc (n * sizeof (xRectangle));
7984			if (rect == NULL)
7985				return;
7986
7987			for (i = 0; i < n; i++) {
7988				rect[i].x = pt[i].x - drawable->x;
7989				rect[i].width = width[i];
7990				rect[i].y = pt[i].y - drawable->y;
7991				rect[i].height = 1;
7992			}
7993
7994			if (gc->fillStyle == FillTiled) {
7995				i = sna_poly_fill_rect_tiled_blt(drawable,
7996								 bo, damage,
7997								 gc, n, rect,
7998								 &region.extents, flags & 2);
7999			} else {
8000				i = sna_poly_fill_rect_stippled_blt(drawable,
8001								    bo, damage,
8002								    gc, n, rect,
8003								    &region.extents, flags & 2);
8004			}
8005			free (rect);
8006
8007			if (i)
8008				return;
8009		}
8010	}
8011
8012fallback:
8013	DBG(("%s: fallback\n", __FUNCTION__));
8014	region.data = NULL;
8015	if (!region_maybe_clip(&region, gc->pCompositeClip))
8016		return;
8017
8018	if (!sna_gc_move_to_cpu(gc, drawable, &region))
8019		goto out;
8020	if (!sna_drawable_move_region_to_cpu(drawable, &region,
8021					     drawable_gc_flags(drawable, gc, n > 1)))
8022		goto out;
8023
8024	if (sigtrap_get() == 0) {
8025		DBG(("%s: fbFillSpans\n", __FUNCTION__));
8026		fbFillSpans(drawable, gc, n, pt, width, sorted);
8027		FALLBACK_FLUSH(drawable);
8028		sigtrap_put();
8029	}
8030out:
8031	sna_gc_move_to_gpu(gc);
8032	RegionUninit(&region);
8033}
8034
8035static void
8036sna_set_spans(DrawablePtr drawable, GCPtr gc, char *src,
8037	      DDXPointPtr pt, int *width, int n, int sorted)
8038{
8039	RegionRec region;
8040
8041	if (sna_spans_extents(drawable, gc, n, pt, width, &region.extents) == 0)
8042		return;
8043
8044	DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__,
8045	     region.extents.x1, region.extents.y1,
8046	     region.extents.x2, region.extents.y2));
8047
8048	if (FORCE_FALLBACK)
8049		goto fallback;
8050
8051	if (!ACCEL_SET_SPANS)
8052		goto fallback;
8053
8054fallback:
8055	region.data = NULL;
8056	if (!region_maybe_clip(&region, gc->pCompositeClip))
8057		return;
8058
8059	if (!sna_gc_move_to_cpu(gc, drawable, &region))
8060		goto out;
8061	if (!sna_drawable_move_region_to_cpu(drawable, &region,
8062					     drawable_gc_flags(drawable, gc, n > 1)))
8063		goto out;
8064
8065	if (sigtrap_get() == 0) {
8066		DBG(("%s: fbSetSpans\n", __FUNCTION__));
8067		fbSetSpans(drawable, gc, src, pt, width, n, sorted);
8068		FALLBACK_FLUSH(drawable);
8069		sigtrap_put();
8070	}
8071out:
8072	sna_gc_move_to_gpu(gc);
8073	RegionUninit(&region);
8074}
8075
8076struct sna_copy_plane {
8077	struct sna_damage **damage;
8078	struct kgem_bo *bo;
8079};
8080
8081static void
8082sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
8083		    RegionRec *region, int sx, int sy,
8084		    Pixel bitplane, void *closure)
8085{
8086	PixmapPtr pixmap = get_drawable_pixmap(drawable);
8087	struct sna *sna = to_sna_from_pixmap(pixmap);
8088	struct sna_copy_plane *arg = closure;
8089	PixmapPtr bitmap = (PixmapPtr)_bitmap;
8090	uint32_t br00, br13;
8091	int16_t dx, dy;
8092	const BoxRec *box;
8093	int n;
8094
8095	DBG(("%s: plane=%x (%d,%d),(%d,%d)xld\n",
8096	     __FUNCTION__, (unsigned)bitplane,
8097	     region->extents.x1, region->extents.y1,
8098	     region->extents.x2, region->extents.y2,
8099	     region_num_rects(region)));
8100
8101	box = region_rects(region);
8102	n = region_num_rects(region);
8103	assert(n);
8104
8105	get_drawable_deltas(drawable, pixmap, &dx, &dy);
8106	assert_pixmap_contains_boxes(pixmap, box, n, dx, dy);
8107
8108	br00 = 3 << 20;
8109	br13 = arg->bo->pitch;
8110	if (sna->kgem.gen >= 040 && arg->bo->tiling) {
8111		br00 |= BLT_DST_TILED;
8112		br13 >>= 2;
8113	}
8114	br13 |= blt_depth(drawable->depth) << 24;
8115	br13 |= copy_ROP[gc->alu] << 16;
8116
8117	kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo);
8118	do {
8119		int bx1 = (box->x1 + sx) & ~7;
8120		int bx2 = (box->x2 + sx + 7) & ~7;
8121		int bw = (bx2 - bx1)/8;
8122		int bh = box->y2 - box->y1;
8123		int bstride = ALIGN(bw, 2);
8124		int src_stride;
8125		uint8_t *dst, *src;
8126		uint32_t *b;
8127
8128		DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n",
8129		     __FUNCTION__,
8130		     box->x1, box->y1,
8131		     box->x2, box->y2,
8132		     sx, sy, bx1, bx2));
8133
8134		src_stride = bstride*bh;
8135		assert(src_stride > 0);
8136		if (src_stride <= 128) {
8137			src_stride = ALIGN(src_stride, 8) / 4;
8138			assert(src_stride <= 32);
8139			if (!kgem_check_batch(&sna->kgem, 8+src_stride) ||
8140			    !kgem_check_bo_fenced(&sna->kgem, arg->bo) ||
8141			    !kgem_check_reloc(&sna->kgem, 1)) {
8142				kgem_submit(&sna->kgem);
8143				if (!kgem_check_bo_fenced(&sna->kgem, arg->bo))
8144					return; /* XXX fallback? */
8145				_kgem_set_mode(&sna->kgem, KGEM_BLT);
8146			}
8147
8148			assert(sna->kgem.mode == KGEM_BLT);
8149			if (sna->kgem.gen >= 0100) {
8150				b = sna->kgem.batch + sna->kgem.nbatch;
8151				b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00;
8152				b[0] |= ((box->x1 + sx) & 7) << 17;
8153				b[1] = br13;
8154				b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8155				b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8156				*(uint64_t *)(b+4) =
8157					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8158							 I915_GEM_DOMAIN_RENDER << 16 |
8159							 I915_GEM_DOMAIN_RENDER |
8160							 KGEM_RELOC_FENCED,
8161							 0);
8162				b[5] = gc->bgPixel;
8163				b[6] = gc->fgPixel;
8164
8165				dst = (uint8_t *)&b[8];
8166				sna->kgem.nbatch += 8 + src_stride;
8167			} else {
8168				b = sna->kgem.batch + sna->kgem.nbatch;
8169				b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
8170				b[0] |= ((box->x1 + sx) & 7) << 17;
8171				b[1] = br13;
8172				b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8173				b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8174				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8175						      I915_GEM_DOMAIN_RENDER << 16 |
8176						      I915_GEM_DOMAIN_RENDER |
8177						      KGEM_RELOC_FENCED,
8178						      0);
8179				b[5] = gc->bgPixel;
8180				b[6] = gc->fgPixel;
8181
8182				dst = (uint8_t *)&b[7];
8183				sna->kgem.nbatch += 7 + src_stride;
8184			}
8185
8186			assert(bitmap->devKind);
8187			src_stride = bitmap->devKind;
8188			src = bitmap->devPrivate.ptr;
8189			src += (box->y1 + sy) * src_stride + bx1/8;
8190			src_stride -= bstride;
8191			do {
8192				int i = bstride;
8193				assert(src >= (uint8_t *)bitmap->devPrivate.ptr);
8194				do {
8195					*dst++ = byte_reverse(*src++);
8196					*dst++ = byte_reverse(*src++);
8197					i -= 2;
8198				} while (i);
8199				assert(src <= (uint8_t *)bitmap->devPrivate.ptr + bitmap->devKind * bitmap->drawable.height);
8200				src += src_stride;
8201			} while (--bh);
8202		} else {
8203			struct kgem_bo *upload;
8204			void *ptr;
8205
8206			if (!kgem_check_batch(&sna->kgem, 10) ||
8207			    !kgem_check_bo_fenced(&sna->kgem, arg->bo) ||
8208			    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
8209				kgem_submit(&sna->kgem);
8210				if (!kgem_check_bo_fenced(&sna->kgem, arg->bo))
8211					return; /* XXX fallback? */
8212				_kgem_set_mode(&sna->kgem, KGEM_BLT);
8213			}
8214
8215			upload = kgem_create_buffer(&sna->kgem,
8216						    bstride*bh,
8217						    KGEM_BUFFER_WRITE_INPLACE,
8218						    &ptr);
8219			if (!upload)
8220				break;
8221
8222			if (sigtrap_get() == 0) {
8223				assert(sna->kgem.mode == KGEM_BLT);
8224				b = sna->kgem.batch + sna->kgem.nbatch;
8225				if (sna->kgem.gen >= 0100) {
8226					b[0] = XY_MONO_SRC_COPY | br00 | 8;
8227					b[0] |= ((box->x1 + sx) & 7) << 17;
8228					b[1] = br13;
8229					b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8230					b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8231					*(uint64_t *)(b+4) =
8232						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8233								I915_GEM_DOMAIN_RENDER << 16 |
8234								I915_GEM_DOMAIN_RENDER |
8235								KGEM_RELOC_FENCED,
8236								0);
8237					*(uint64_t *)(b+6) =
8238						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
8239								I915_GEM_DOMAIN_RENDER << 16 |
8240								KGEM_RELOC_FENCED,
8241								0);
8242					b[8] = gc->bgPixel;
8243					b[9] = gc->fgPixel;
8244
8245					sna->kgem.nbatch += 10;
8246				} else {
8247					b[0] = XY_MONO_SRC_COPY | br00 | 6;
8248					b[0] |= ((box->x1 + sx) & 7) << 17;
8249					b[1] = br13;
8250					b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8251					b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8252					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8253							I915_GEM_DOMAIN_RENDER << 16 |
8254							I915_GEM_DOMAIN_RENDER |
8255							KGEM_RELOC_FENCED,
8256							0);
8257					b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
8258							I915_GEM_DOMAIN_RENDER << 16 |
8259							KGEM_RELOC_FENCED,
8260							0);
8261					b[6] = gc->bgPixel;
8262					b[7] = gc->fgPixel;
8263
8264					sna->kgem.nbatch += 8;
8265				}
8266
8267				dst = ptr;
8268				assert(bitmap->devKind);
8269				src_stride = bitmap->devKind;
8270				src = bitmap->devPrivate.ptr;
8271				src += (box->y1 + sy) * src_stride + bx1/8;
8272				src_stride -= bstride;
8273				do {
8274					int i = bstride;
8275					assert(src >= (uint8_t *)bitmap->devPrivate.ptr);
8276					do {
8277						*dst++ = byte_reverse(*src++);
8278						*dst++ = byte_reverse(*src++);
8279						i -= 2;
8280					} while (i);
8281					assert(src <= (uint8_t *)bitmap->devPrivate.ptr + bitmap->devKind * bitmap->drawable.height);
8282					assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload));
8283					src += src_stride;
8284				} while (--bh);
8285
8286				sigtrap_put();
8287			}
8288
8289			kgem_bo_destroy(&sna->kgem, upload);
8290		}
8291
8292		box++;
8293	} while (--n);
8294
8295	if (arg->damage) {
8296		RegionTranslate(region, dx, dy);
8297		sna_damage_add(arg->damage, region);
8298	}
8299	assert_pixmap_damage(pixmap);
8300	sna->blt_state.fill_bo = 0;
8301}
8302
8303static void
8304sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc,
8305		   RegionPtr region, int sx, int sy,
8306		   Pixel bitplane, void *closure)
8307{
8308	PixmapPtr dst_pixmap = get_drawable_pixmap(drawable);
8309	PixmapPtr src_pixmap = get_drawable_pixmap(source);
8310	struct sna *sna = to_sna_from_pixmap(dst_pixmap);
8311	struct sna_copy_plane *arg = closure;
8312	int16_t dx, dy;
8313	int bit = ffs(bitplane) - 1;
8314	uint32_t br00, br13;
8315	const BoxRec *box = region_rects(region);
8316	int n = region_num_rects(region);
8317
8318	DBG(("%s: plane=%x [%d] x%d\n", __FUNCTION__,
8319	     (unsigned)bitplane, bit, n));
8320
8321	if (n == 0)
8322		return;
8323
8324	if (get_drawable_deltas(source, src_pixmap, &dx, &dy))
8325		sx += dx, sy += dy;
8326
8327	get_drawable_deltas(drawable, dst_pixmap, &dx, &dy);
8328	assert_pixmap_contains_boxes(dst_pixmap, box, n, dx, dy);
8329
8330	br00 = XY_MONO_SRC_COPY | 3 << 20;
8331	br13 = arg->bo->pitch;
8332	if (sna->kgem.gen >= 040 && arg->bo->tiling) {
8333		br00 |= BLT_DST_TILED;
8334		br13 >>= 2;
8335	}
8336	br13 |= blt_depth(drawable->depth) << 24;
8337	br13 |= copy_ROP[gc->alu] << 16;
8338
8339	kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo);
8340	do {
8341		int bx1 = (box->x1 + sx) & ~7;
8342		int bx2 = (box->x2 + sx + 7) & ~7;
8343		int bw = (bx2 - bx1)/8;
8344		int bh = box->y2 - box->y1;
8345		int bstride = ALIGN(bw, 2);
8346		struct kgem_bo *upload;
8347		void *ptr;
8348
8349		DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n",
8350		     __FUNCTION__,
8351		     box->x1, box->y1,
8352		     box->x2, box->y2,
8353		     sx, sy, bx1, bx2));
8354
8355		if (!kgem_check_batch(&sna->kgem, 10) ||
8356		    !kgem_check_bo_fenced(&sna->kgem, arg->bo) ||
8357		    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
8358			kgem_submit(&sna->kgem);
8359			if (!kgem_check_bo_fenced(&sna->kgem, arg->bo))
8360				return; /* XXX fallback? */
8361			_kgem_set_mode(&sna->kgem, KGEM_BLT);
8362		}
8363
8364		upload = kgem_create_buffer(&sna->kgem,
8365					    bstride*bh,
8366					    KGEM_BUFFER_WRITE_INPLACE,
8367					    &ptr);
8368		if (!upload)
8369			break;
8370
8371		if (sigtrap_get() == 0) {
8372			uint32_t *b;
8373
8374			assert(src_pixmap->devKind);
8375			switch (source->bitsPerPixel) {
8376			case 32:
8377				{
8378					uint32_t *src = src_pixmap->devPrivate.ptr;
8379					int src_stride = src_pixmap->devKind/sizeof(uint32_t);
8380					uint8_t *dst = ptr;
8381
8382					src += (box->y1 + sy) * src_stride;
8383					src += bx1;
8384
8385					src_stride -= bw * 8;
8386					bstride -= bw;
8387
8388					do {
8389						int i = bw;
8390						do {
8391							uint8_t v = 0;
8392
8393							v |= ((*src++ >> bit) & 1) << 7;
8394							v |= ((*src++ >> bit) & 1) << 6;
8395							v |= ((*src++ >> bit) & 1) << 5;
8396							v |= ((*src++ >> bit) & 1) << 4;
8397							v |= ((*src++ >> bit) & 1) << 3;
8398							v |= ((*src++ >> bit) & 1) << 2;
8399							v |= ((*src++ >> bit) & 1) << 1;
8400							v |= ((*src++ >> bit) & 1) << 0;
8401
8402							*dst++ = v;
8403						} while (--i);
8404						dst += bstride;
8405						src += src_stride;
8406					} while (--bh);
8407					break;
8408				}
8409			case 16:
8410				{
8411					uint16_t *src = src_pixmap->devPrivate.ptr;
8412					int src_stride = src_pixmap->devKind/sizeof(uint16_t);
8413					uint8_t *dst = ptr;
8414
8415					src += (box->y1 + sy) * src_stride;
8416					src += bx1;
8417
8418					src_stride -= bw * 8;
8419					bstride -= bw;
8420
8421					do {
8422						int i = bw;
8423						do {
8424							uint8_t v = 0;
8425
8426							v |= ((*src++ >> bit) & 1) << 7;
8427							v |= ((*src++ >> bit) & 1) << 6;
8428							v |= ((*src++ >> bit) & 1) << 5;
8429							v |= ((*src++ >> bit) & 1) << 4;
8430							v |= ((*src++ >> bit) & 1) << 3;
8431							v |= ((*src++ >> bit) & 1) << 2;
8432							v |= ((*src++ >> bit) & 1) << 1;
8433							v |= ((*src++ >> bit) & 1) << 0;
8434
8435							*dst++ = v;
8436						} while (--i);
8437						dst += bstride;
8438						src += src_stride;
8439					} while (--bh);
8440					break;
8441				}
8442			default:
8443				assert(0);
8444			case 8:
8445				{
8446					uint8_t *src = src_pixmap->devPrivate.ptr;
8447					int src_stride = src_pixmap->devKind/sizeof(uint8_t);
8448					uint8_t *dst = ptr;
8449
8450					src += (box->y1 + sy) * src_stride;
8451					src += bx1;
8452
8453					src_stride -= bw * 8;
8454					bstride -= bw;
8455
8456					do {
8457						int i = bw;
8458						do {
8459							uint8_t v = 0;
8460
8461							v |= ((*src++ >> bit) & 1) << 7;
8462							v |= ((*src++ >> bit) & 1) << 6;
8463							v |= ((*src++ >> bit) & 1) << 5;
8464							v |= ((*src++ >> bit) & 1) << 4;
8465							v |= ((*src++ >> bit) & 1) << 3;
8466							v |= ((*src++ >> bit) & 1) << 2;
8467							v |= ((*src++ >> bit) & 1) << 1;
8468							v |= ((*src++ >> bit) & 1) << 0;
8469
8470							*dst++ = v;
8471						} while (--i);
8472						dst += bstride;
8473						src += src_stride;
8474					} while (--bh);
8475					break;
8476				}
8477			}
8478
8479			assert(sna->kgem.mode == KGEM_BLT);
8480			b = sna->kgem.batch + sna->kgem.nbatch;
8481			if (sna->kgem.gen >= 0100) {
8482				b[0] = br00 | ((box->x1 + sx) & 7) << 17 | 8;
8483				b[1] = br13;
8484				b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8485				b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8486				*(uint64_t *)(b+4) =
8487					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8488							I915_GEM_DOMAIN_RENDER << 16 |
8489							I915_GEM_DOMAIN_RENDER |
8490							KGEM_RELOC_FENCED,
8491							0);
8492				*(uint64_t *)(b+6) =
8493					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
8494							I915_GEM_DOMAIN_RENDER << 16 |
8495							KGEM_RELOC_FENCED,
8496							0);
8497				b[8] = gc->bgPixel;
8498				b[9] = gc->fgPixel;
8499
8500				sna->kgem.nbatch += 10;
8501			} else {
8502				b[0] = br00 | ((box->x1 + sx) & 7) << 17 | 6;
8503				b[1] = br13;
8504				b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
8505				b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
8506				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo,
8507						I915_GEM_DOMAIN_RENDER << 16 |
8508						I915_GEM_DOMAIN_RENDER |
8509						KGEM_RELOC_FENCED,
8510						0);
8511				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
8512						I915_GEM_DOMAIN_RENDER << 16 |
8513						KGEM_RELOC_FENCED,
8514						0);
8515				b[6] = gc->bgPixel;
8516				b[7] = gc->fgPixel;
8517
8518				sna->kgem.nbatch += 8;
8519			}
8520			sigtrap_put();
8521		}
8522		kgem_bo_destroy(&sna->kgem, upload);
8523
8524		box++;
8525	} while (--n);
8526
8527	if (arg->damage) {
8528		RegionTranslate(region, dx, dy);
8529		sna_damage_add(arg->damage, region);
8530	}
8531	assert_pixmap_damage(dst_pixmap);
8532	sna->blt_state.fill_bo = 0;
8533}
8534
8535static RegionPtr
8536sna_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc,
8537	       int src_x, int src_y,
8538	       int w, int h,
8539	       int dst_x, int dst_y,
8540	       unsigned long bit)
8541{
8542	PixmapPtr pixmap = get_drawable_pixmap(dst);
8543	struct sna *sna = to_sna_from_pixmap(pixmap);
8544	RegionRec region, *ret = NULL;
8545	struct sna_copy_plane arg;
8546
8547	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=%dx%d\n", __FUNCTION__,
8548	     src_x, src_y, dst_x, dst_y, w, h));
8549
8550	if (gc->planemask == 0)
8551		goto empty;
8552
8553	if (src->bitsPerPixel == 1 && (bit&1) == 0)
8554		goto empty;
8555
8556	region.extents.x1 = dst_x + dst->x;
8557	region.extents.y1 = dst_y + dst->y;
8558	region.extents.x2 = region.extents.x1 + w;
8559	region.extents.y2 = region.extents.y1 + h;
8560	region.data = NULL;
8561	RegionIntersect(&region, &region, gc->pCompositeClip);
8562
8563	DBG(("%s: dst extents (%d, %d), (%d, %d)\n",
8564	     __FUNCTION__,
8565	     region.extents.x1, region.extents.y1,
8566	     region.extents.x2, region.extents.y2));
8567
8568	{
8569		RegionRec clip;
8570
8571		clip.extents.x1 = src->x - (src->x + src_x) + (dst->x + dst_x);
8572		clip.extents.y1 = src->y - (src->y + src_y) + (dst->y + dst_y);
8573		clip.extents.x2 = clip.extents.x1 + src->width;
8574		clip.extents.y2 = clip.extents.y1 + src->height;
8575		clip.data = NULL;
8576
8577		DBG(("%s: src extents (%d, %d), (%d, %d)\n",
8578		     __FUNCTION__,
8579		     clip.extents.x1, clip.extents.y1,
8580		     clip.extents.x2, clip.extents.y2));
8581
8582		RegionIntersect(&region, &region, &clip);
8583	}
8584	DBG(("%s: dst^src extents (%d, %d), (%d, %d)\n",
8585	     __FUNCTION__,
8586	     region.extents.x1, region.extents.y1,
8587	     region.extents.x2, region.extents.y2));
8588	if (box_empty(&region.extents))
8589		goto empty;
8590
8591	RegionTranslate(&region,
8592			src_x - dst_x - dst->x + src->x,
8593			src_y - dst_y - dst->y + src->y);
8594
8595	if (!sna_drawable_move_region_to_cpu(src, &region, MOVE_READ))
8596		goto out;
8597
8598	RegionTranslate(&region,
8599			-(src_x - dst_x - dst->x + src->x),
8600			-(src_y - dst_y - dst->y + src->y));
8601
8602	if (FORCE_FALLBACK)
8603		goto fallback;
8604
8605	if (!ACCEL_COPY_PLANE)
8606		goto fallback;
8607
8608	if (wedged(sna))
8609		goto fallback;
8610
8611	if (!PM_IS_SOLID(dst, gc->planemask))
8612		goto fallback;
8613
8614	arg.bo = sna_drawable_use_bo(dst, PREFER_GPU,
8615				     &region.extents, &arg.damage);
8616	if (arg.bo) {
8617		if (arg.bo->tiling == I915_TILING_Y) {
8618			assert(arg.bo == __sna_pixmap_get_bo(pixmap));
8619			arg.bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
8620			if (arg.bo == NULL) {
8621				DBG(("%s: fallback -- unable to change tiling\n",
8622				     __FUNCTION__));
8623				goto fallback;
8624			}
8625		}
8626		RegionUninit(&region);
8627		return sna_do_copy(src, dst, gc,
8628				   src_x, src_y,
8629				   w, h,
8630				   dst_x, dst_y,
8631				   src->depth == 1 ? sna_copy_bitmap_blt : sna_copy_plane_blt,
8632				   (Pixel)bit, &arg);
8633	}
8634
8635fallback:
8636	DBG(("%s: fallback\n", __FUNCTION__));
8637	if (!sna_gc_move_to_cpu(gc, dst, &region))
8638		goto out;
8639	if (!sna_drawable_move_region_to_cpu(dst, &region,
8640					     drawable_gc_flags(dst, gc, false)))
8641		goto out;
8642
8643	if (sigtrap_get() == 0) {
8644		DBG(("%s: fbCopyPlane(%d, %d, %d, %d, %d,%d) %x\n",
8645		     __FUNCTION__, src_x, src_y, w, h, dst_x, dst_y, (unsigned)bit));
8646		ret = miDoCopy(src, dst, gc,
8647			       src_x, src_y, w, h, dst_x, dst_y,
8648			       src->bitsPerPixel > 1 ? fbCopyNto1 : fbCopy1toN,
8649			       bit, 0);
8650		FALLBACK_FLUSH(dst);
8651		sigtrap_put();
8652	}
8653out:
8654	sna_gc_move_to_gpu(gc);
8655	RegionUninit(&region);
8656	return ret;
8657empty:
8658	return miHandleExposures(src, dst, gc,
8659				 src_x, src_y,
8660				 w, h,
8661				 dst_x, dst_y, bit);
8662}
8663
8664static bool
8665sna_poly_point_blt(DrawablePtr drawable,
8666		   struct kgem_bo *bo,
8667		   struct sna_damage **damage,
8668		   GCPtr gc, int mode, int n, DDXPointPtr pt,
8669		   bool clipped)
8670{
8671	PixmapPtr pixmap = get_drawable_pixmap(drawable);
8672	struct sna *sna = to_sna_from_pixmap(pixmap);
8673	BoxRec box[512], *b = box, * const last_box = box + ARRAY_SIZE(box);
8674	struct sna_fill_op fill;
8675	DDXPointRec last;
8676	int16_t dx, dy;
8677
8678	DBG(("%s: alu=%d, pixel=%08lx, clipped?=%d\n",
8679	     __FUNCTION__, gc->alu, gc->fgPixel, clipped));
8680
8681	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_POINTS))
8682		return false;
8683
8684	get_drawable_deltas(drawable, pixmap, &dx, &dy);
8685
8686	last.x = drawable->x;
8687	last.y = drawable->y;
8688
8689	if (!clipped) {
8690		last.x += dx;
8691		last.y += dy;
8692
8693		assert_pixmap_contains_points(pixmap, pt, n, last.x, last.y);
8694		sna_damage_add_points(damage, pt, n, last.x, last.y);
8695		if (fill.points && mode != CoordModePrevious) {
8696			fill.points(sna, &fill, last.x, last.y, pt, n);
8697		} else {
8698			do {
8699				unsigned nbox = n;
8700				if (nbox > ARRAY_SIZE(box))
8701					nbox = ARRAY_SIZE(box);
8702				n -= nbox;
8703				do {
8704					*(DDXPointRec *)b = *pt++;
8705
8706					b->x1 += last.x;
8707					b->y1 += last.y;
8708					if (mode == CoordModePrevious)
8709						last = *(DDXPointRec *)b;
8710
8711					b->x2 = b->x1 + 1;
8712					b->y2 = b->y1 + 1;
8713					b++;
8714				} while (--nbox);
8715				fill.boxes(sna, &fill, box, b - box);
8716				b = box;
8717			} while (n);
8718		}
8719	} else {
8720		RegionPtr clip = gc->pCompositeClip;
8721
8722		while (n--) {
8723			int x, y;
8724
8725			x = pt->x;
8726			y = pt->y;
8727			pt++;
8728			if (mode == CoordModePrevious) {
8729				x += last.x;
8730				y += last.y;
8731				last.x = x;
8732				last.y = y;
8733			} else {
8734				x += drawable->x;
8735				y += drawable->y;
8736			}
8737
8738			if (RegionContainsPoint(clip, x, y, NULL)) {
8739				b->x1 = x + dx;
8740				b->y1 = y + dy;
8741				b->x2 = b->x1 + 1;
8742				b->y2 = b->y1 + 1;
8743				if (++b == last_box){
8744					assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0);
8745					fill.boxes(sna, &fill, box, last_box - box);
8746					if (damage)
8747						sna_damage_add_boxes(damage, box, last_box-box, 0, 0);
8748					b = box;
8749				}
8750			}
8751		}
8752		if (b != box){
8753			assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
8754			fill.boxes(sna, &fill, box, b - box);
8755			if (damage)
8756				sna_damage_add_boxes(damage, box, b-box, 0, 0);
8757		}
8758	}
8759	fill.done(sna, &fill);
8760	assert_pixmap_damage(pixmap);
8761	return true;
8762}
8763
8764static unsigned
8765sna_poly_point_extents(DrawablePtr drawable, GCPtr gc,
8766		       int mode, int n, DDXPointPtr pt, BoxPtr out)
8767{
8768	BoxRec box;
8769	bool clipped;
8770
8771	if (n == 0)
8772		return 0;
8773
8774	box.x2 = box.x1 = pt->x;
8775	box.y2 = box.y1 = pt->y;
8776	if (mode == CoordModePrevious) {
8777		DDXPointRec last = *pt++;
8778		while (--n) {
8779			last.x += pt->x;
8780			last.y += pt->y;
8781			pt++;
8782			box_add_pt(&box, last.x, last.y);
8783		}
8784	} else {
8785		--n; ++pt;
8786		while (n >= 8) {
8787			box_add_pt(&box, pt[0].x, pt[0].y);
8788			box_add_pt(&box, pt[1].x, pt[1].y);
8789			box_add_pt(&box, pt[2].x, pt[2].y);
8790			box_add_pt(&box, pt[3].x, pt[3].y);
8791			box_add_pt(&box, pt[4].x, pt[4].y);
8792			box_add_pt(&box, pt[5].x, pt[5].y);
8793			box_add_pt(&box, pt[6].x, pt[6].y);
8794			box_add_pt(&box, pt[7].x, pt[7].y);
8795			pt += 8;
8796			n -= 8;
8797		}
8798		if (n & 4) {
8799			box_add_pt(&box, pt[0].x, pt[0].y);
8800			box_add_pt(&box, pt[1].x, pt[1].y);
8801			box_add_pt(&box, pt[2].x, pt[2].y);
8802			box_add_pt(&box, pt[3].x, pt[3].y);
8803			pt += 4;
8804		}
8805		if (n & 2) {
8806			box_add_pt(&box, pt[0].x, pt[0].y);
8807			box_add_pt(&box, pt[1].x, pt[1].y);
8808			pt += 2;
8809		}
8810		if (n & 1)
8811			box_add_pt(&box, pt[0].x, pt[0].y);
8812	}
8813	box.x2++;
8814	box.y2++;
8815
8816	clipped = trim_and_translate_box(&box, drawable, gc);
8817	if (box_empty(&box))
8818		return 0;
8819
8820	*out = box;
8821	return 1 | clipped << 1;
8822}
8823
8824static void
8825sna_poly_point(DrawablePtr drawable, GCPtr gc,
8826	       int mode, int n, DDXPointPtr pt)
8827{
8828	PixmapPtr pixmap = get_drawable_pixmap(drawable);
8829	struct sna *sna = to_sna_from_pixmap(pixmap);
8830	RegionRec region;
8831	unsigned flags;
8832
8833	DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d)\n",
8834	     __FUNCTION__, mode, n, pt[0].x, pt[0].y));
8835
8836	flags = sna_poly_point_extents(drawable, gc, mode, n, pt, &region.extents);
8837	if (flags == 0)
8838		return;
8839
8840	DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
8841	     region.extents.x1, region.extents.y1,
8842	     region.extents.x2, region.extents.y2,
8843	     flags));
8844
8845	if (FORCE_FALLBACK)
8846		goto fallback;
8847
8848	if (!ACCEL_POLY_POINT)
8849		goto fallback;
8850
8851	if (wedged(sna)) {
8852		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
8853		goto fallback;
8854	}
8855
8856	if (PM_IS_SOLID(drawable, gc->planemask)) {
8857		struct sna_damage **damage;
8858		struct kgem_bo *bo;
8859
8860		DBG(("%s: trying solid fill [%08lx] blt paths\n",
8861		     __FUNCTION__, gc->fgPixel));
8862
8863		if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU,
8864					      &region.extents, &damage)) &&
8865		    sna_poly_point_blt(drawable, bo, damage,
8866				       gc, mode, n, pt, flags & 2))
8867			return;
8868	}
8869
8870fallback:
8871	DBG(("%s: fallback\n", __FUNCTION__));
8872	region.data = NULL;
8873	if (!region_maybe_clip(&region, gc->pCompositeClip))
8874		return;
8875
8876	if (!sna_gc_move_to_cpu(gc, drawable, &region))
8877		goto out;
8878	if (!sna_drawable_move_region_to_cpu(drawable, &region,
8879					     MOVE_READ | MOVE_WRITE))
8880		goto out;
8881
8882	if (sigtrap_get() == 0) {
8883		DBG(("%s: fbPolyPoint\n", __FUNCTION__));
8884		fbPolyPoint(drawable, gc, mode, n, pt, flags);
8885		FALLBACK_FLUSH(drawable);
8886		sigtrap_put();
8887	}
8888out:
8889	sna_gc_move_to_gpu(gc);
8890	RegionUninit(&region);
8891}
8892
8893static bool
8894sna_poly_zero_line_blt(DrawablePtr drawable,
8895		       struct kgem_bo *bo,
8896		       struct sna_damage **damage,
8897		       GCPtr gc, int mode, const int _n, const DDXPointRec * const _pt,
8898		       const BoxRec *extents, unsigned clipped)
8899{
8900	static void * const _jump[] = {
8901		&&no_damage,
8902		&&damage,
8903
8904		&&no_damage_offset,
8905		&&damage_offset,
8906	};
8907
8908	PixmapPtr pixmap = get_drawable_pixmap(drawable);
8909	struct sna *sna = to_sna_from_pixmap(pixmap);
8910	int x2, y2, xstart, ystart, oc2;
8911	unsigned int bias = miGetZeroLineBias(drawable->pScreen);
8912	bool degenerate = true;
8913	struct sna_fill_op fill;
8914	RegionRec clip;
8915	BoxRec box[512], *b, * const last_box = box + ARRAY_SIZE(box);
8916	const BoxRec *last_extents;
8917	int16_t dx, dy;
8918	void *jump, *ret;
8919
8920	DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n",
8921	     __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage));
8922	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_SPANS))
8923		return false;
8924
8925	get_drawable_deltas(drawable, pixmap, &dx, &dy);
8926
8927	region_set(&clip, extents);
8928	if (clipped) {
8929		if (!region_maybe_clip(&clip, gc->pCompositeClip))
8930			return true;
8931	}
8932
8933	jump = _jump[(damage != NULL) | !!(dx|dy) << 1];
8934	DBG(("%s: [clipped=%x] extents=(%d, %d), (%d, %d), delta=(%d, %d), damage=%p\n",
8935	     __FUNCTION__, clipped,
8936	     clip.extents.x1, clip.extents.y1,
8937	     clip.extents.x2, clip.extents.y2,
8938	     dx, dy, damage));
8939
8940	extents = region_rects(&clip);
8941	last_extents = extents + region_num_rects(&clip);
8942
8943	b = box;
8944	do {
8945		int n = _n;
8946		const DDXPointRec *pt = _pt;
8947
8948		xstart = pt->x + drawable->x;
8949		ystart = pt->y + drawable->y;
8950
8951		x2 = xstart;
8952		y2 = ystart;
8953		oc2 = 0;
8954		OUTCODES(oc2, x2, y2, extents);
8955
8956		while (--n) {
8957			int16_t sdx, sdy;
8958			int adx, ady, length;
8959			int e, e1, e2, e3;
8960			int x1 = x2, x;
8961			int y1 = y2, y;
8962			int oc1 = oc2;
8963			int octant;
8964
8965			++pt;
8966
8967			x2 = pt->x;
8968			y2 = pt->y;
8969			if (mode == CoordModePrevious) {
8970				x2 += x1;
8971				y2 += y1;
8972			} else {
8973				x2 += drawable->x;
8974				y2 += drawable->y;
8975			}
8976			DBG(("%s: segment (%d, %d) to (%d, %d)\n",
8977			     __FUNCTION__, x1, y1, x2, y2));
8978			if (x2 == x1 && y2 == y1)
8979				continue;
8980
8981			degenerate = false;
8982
8983			oc2 = 0;
8984			OUTCODES(oc2, x2, y2, extents);
8985			if (oc1 & oc2)
8986				continue;
8987
8988			CalcLineDeltas(x1, y1, x2, y2,
8989				       adx, ady, sdx, sdy,
8990				       1, 1, octant);
8991
8992			DBG(("%s: adx=(%d, %d), sdx=(%d, %d), oc1=%x, oc2=%x\n",
8993			     __FUNCTION__, adx, ady, sdx, sdy, oc1, oc2));
8994			if (adx == 0 || ady == 0) {
8995				if (x1 <= x2) {
8996					b->x1 = x1;
8997					b->x2 = x2;
8998				} else {
8999					b->x1 = x2;
9000					b->x2 = x1;
9001				}
9002				if (y1 <= y2) {
9003					b->y1 = y1;
9004					b->y2 = y2;
9005				} else {
9006					b->y1 = y2;
9007					b->y2 = y1;
9008				}
9009				b->x2++;
9010				b->y2++;
9011				if (oc1 | oc2) {
9012					bool intersects;
9013
9014					intersects = box_intersect(b, extents);
9015					assert(intersects);
9016				}
9017				if (++b == last_box) {
9018					ret = &&rectangle_continue;
9019					goto *jump;
9020rectangle_continue:
9021					b = box;
9022				}
9023			} else if (adx >= ady) {
9024				int x2_clipped = x2, y2_clipped = y2;
9025				bool dirty;
9026
9027				/* X-major segment */
9028				e1 = ady << 1;
9029				e2 = e1 - (adx << 1);
9030				e  = e1 - adx;
9031				length = adx;
9032
9033				FIXUP_ERROR(e, octant, bias);
9034
9035				x = x1;
9036				y = y1;
9037
9038				if (oc1 | oc2) {
9039					int pt1_clipped, pt2_clipped;
9040
9041					if (miZeroClipLine(extents->x1, extents->y1,
9042							   extents->x2-1, extents->y2-1,
9043							   &x, &y, &x2_clipped, &y2_clipped,
9044							   adx, ady,
9045							   &pt1_clipped, &pt2_clipped,
9046							   octant, bias, oc1, oc2) == -1)
9047						continue;
9048
9049					length = abs(x2_clipped - x);
9050					if (length == 0)
9051						continue;
9052
9053					if (pt1_clipped) {
9054						int clipdx = abs(x - x1);
9055						int clipdy = abs(y - y1);
9056						e += clipdy * e2 + (clipdx - clipdy) * e1;
9057					}
9058				}
9059
9060				e3 = e2 - e1;
9061				e  = e - e1;
9062
9063				b->x1 = x;
9064				b->y1 = y;
9065				dirty = false;
9066				while (length--) {
9067					e += e1;
9068					dirty = true;
9069					if (e >= 0) {
9070						e += e3;
9071
9072						if (sdx < 0) {
9073							b->x2 = b->x1 + 1;
9074							b->x1 = x;
9075						} else
9076							b->x2 = x + 1;
9077						b->y2 = b->y1 + 1;
9078
9079						if (++b == last_box) {
9080							ret = &&X_continue;
9081							goto *jump;
9082X_continue:
9083							b = box;
9084						}
9085
9086						b->x1 = x + sdx;
9087						b->y1 = y += sdy;
9088						dirty = false;
9089					}
9090					x += sdx;
9091				}
9092				if (dirty) {
9093					x -= sdx;
9094					if (sdx < 0) {
9095						b->x2 = b->x1 + 1;
9096						b->x1 = x;
9097					} else
9098						b->x2 = x + 1;
9099					b->y2 = b->y1 + 1;
9100
9101					if (++b == last_box) {
9102						ret = &&X2_continue;
9103						goto *jump;
9104X2_continue:
9105						b = box;
9106					}
9107				}
9108			} else {
9109				int x2_clipped = x2, y2_clipped = y2;
9110				bool dirty;
9111
9112				/* Y-major segment */
9113				e1 = adx << 1;
9114				e2 = e1 - (ady << 1);
9115				e  = e1 - ady;
9116				length  = ady;
9117
9118				SetYMajorOctant(octant);
9119				FIXUP_ERROR(e, octant, bias);
9120
9121				x = x1;
9122				y = y1;
9123
9124				if (oc1 | oc2) {
9125					int pt1_clipped, pt2_clipped;
9126
9127					if (miZeroClipLine(extents->x1, extents->y1,
9128							   extents->x2-1, extents->y2-1,
9129							   &x, &y, &x2_clipped, &y2_clipped,
9130							   adx, ady,
9131							   &pt1_clipped, &pt2_clipped,
9132							   octant, bias, oc1, oc2) == -1)
9133						continue;
9134
9135					length = abs(y2_clipped - y);
9136					if (length == 0)
9137						continue;
9138
9139					if (pt1_clipped) {
9140						int clipdx = abs(x - x1);
9141						int clipdy = abs(y - y1);
9142						e += clipdx * e2 + (clipdy - clipdx) * e1;
9143					}
9144				}
9145
9146				e3 = e2 - e1;
9147				e  = e - e1;
9148
9149				b->x1 = x;
9150				b->y1 = y;
9151				dirty = false;
9152				while (length--) {
9153					e += e1;
9154					dirty = true;
9155					if (e >= 0) {
9156						e += e3;
9157
9158						if (sdy < 0) {
9159							b->y2 = b->y1 + 1;
9160							b->y1 = y;
9161						} else
9162							b->y2 = y + 1;
9163						b->x2 = x + 1;
9164
9165						if (++b == last_box) {
9166							ret = &&Y_continue;
9167							goto *jump;
9168Y_continue:
9169							b = box;
9170						}
9171
9172						b->x1 = x += sdx;
9173						b->y1 = y + sdy;
9174						dirty = false;
9175					}
9176					y += sdy;
9177				}
9178
9179				if (dirty) {
9180					y -= sdy;
9181					if (sdy < 0) {
9182						b->y2 = b->y1 + 1;
9183						b->y1 = y;
9184					} else
9185						b->y2 = y + 1;
9186					b->x2 = x + 1;
9187
9188					if (++b == last_box) {
9189						ret = &&Y2_continue;
9190						goto *jump;
9191Y2_continue:
9192						b = box;
9193					}
9194				}
9195			}
9196		}
9197
9198#if 0
9199		/* Only do the CapNotLast check on the last segment
9200		 * and only if the endpoint wasn't clipped.  And then, if the last
9201		 * point is the same as the first point, do not draw it, unless the
9202		 * line is degenerate
9203		 */
9204		if (!pt2_clipped &&
9205		    gc->capStyle != CapNotLast &&
9206		    !(xstart == x2 && ystart == y2 && !degenerate))
9207		{
9208			b->x2 = x2;
9209			b->y2 = y2;
9210			if (b->x2 < b->x1) {
9211				int16_t t = b->x1;
9212				b->x1 = b->x2;
9213				b->x2 = t;
9214			}
9215			if (b->y2 < b->y1) {
9216				int16_t t = b->y1;
9217				b->y1 = b->y2;
9218				b->y2 = t;
9219			}
9220			b->x2++;
9221			b->y2++;
9222			b++;
9223		}
9224#endif
9225	} while (++extents != last_extents);
9226
9227	if (b != box) {
9228		ret = &&done;
9229		goto *jump;
9230	}
9231
9232done:
9233	fill.done(sna, &fill);
9234	assert_pixmap_damage(pixmap);
9235	RegionUninit(&clip);
9236	return true;
9237
9238damage:
9239	assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
9240	sna_damage_add_boxes(damage, box, b-box, 0, 0);
9241no_damage:
9242	fill.boxes(sna, &fill, box, b-box);
9243	goto *ret;
9244
9245no_damage_offset:
9246	{
9247		BoxRec *bb = box;
9248		do {
9249			bb->x1 += dx;
9250			bb->x2 += dx;
9251			bb->y1 += dy;
9252			bb->y2 += dy;
9253		} while (++bb != b);
9254		assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
9255		fill.boxes(sna, &fill, box, b - box);
9256	}
9257	goto *ret;
9258
9259damage_offset:
9260	{
9261		BoxRec *bb = box;
9262		do {
9263			bb->x1 += dx;
9264			bb->x2 += dx;
9265			bb->y1 += dy;
9266			bb->y2 += dy;
9267		} while (++bb != b);
9268		assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
9269		fill.boxes(sna, &fill, box, b - box);
9270		sna_damage_add_boxes(damage, box, b - box, 0, 0);
9271	}
9272	goto *ret;
9273}
9274
9275static bool
9276sna_poly_line_blt(DrawablePtr drawable,
9277		  struct kgem_bo *bo,
9278		  struct sna_damage **damage,
9279		  GCPtr gc, uint32_t pixel,
9280		  int mode, int n, DDXPointPtr pt,
9281		  const BoxRec *extents, bool clipped)
9282{
9283	PixmapPtr pixmap = get_drawable_pixmap(drawable);
9284	struct sna *sna = to_sna_from_pixmap(pixmap);
9285	BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes);
9286	struct sna_fill_op fill;
9287	DDXPointRec last;
9288	int16_t dx, dy;
9289
9290	DBG(("%s: alu=%d, fg=%08x, clipped=%d\n", __FUNCTION__, gc->alu, (unsigned)pixel, clipped));
9291
9292	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_BOXES))
9293		return false;
9294
9295	get_drawable_deltas(drawable, pixmap, &dx, &dy);
9296
9297	if (!clipped) {
9298		dx += drawable->x;
9299		dy += drawable->y;
9300
9301		last.x = pt->x + dx;
9302		last.y = pt->y + dy;
9303		pt++;
9304
9305		while (--n) {
9306			DDXPointRec p;
9307
9308			p = *pt++;
9309			if (mode == CoordModePrevious) {
9310				p.x += last.x;
9311				p.y += last.y;
9312			} else {
9313				p.x += dx;
9314				p.y += dy;
9315			}
9316			DBG(("%s: line (%d, %d) -> (%d, %d)\n", __FUNCTION__, last.x, last.y, p.x, p.y));
9317
9318			if (last.x == p.x) {
9319				b->x1 = last.x;
9320				b->x2 = last.x + 1;
9321			} else if (last.x < p.x) {
9322				b->x1 = last.x;
9323				b->x2 = p.x;
9324			} else {
9325				b->x1 = p.x;
9326				b->x2 = last.x;
9327			}
9328
9329			if (last.y == p.y) {
9330				b->y1 = last.y;
9331				b->y2 = last.y + 1;
9332			} else if (last.y < p.y) {
9333				b->y1 = last.y;
9334				b->y2 = p.y;
9335			} else {
9336				b->y1 = p.y;
9337				b->y2 = last.y;
9338			}
9339			b->y2 += last.x == p.x && last.y != p.y;
9340			b->x2 += last.y == p.y && last.x != p.x;
9341			DBG(("%s: blt (%d, %d), (%d, %d)\n",
9342			     __FUNCTION__,
9343			     b->x1, b->y1, b->x2, b->y2));
9344
9345			if (++b == last_box) {
9346				assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0);
9347				fill.boxes(sna, &fill, boxes, last_box - boxes);
9348				if (damage)
9349					sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0);
9350				b = boxes;
9351			}
9352
9353			last = p;
9354		}
9355	} else {
9356		RegionRec clip;
9357
9358		region_set(&clip, extents);
9359		if (!region_maybe_clip(&clip, gc->pCompositeClip))
9360			return true;
9361
9362		last.x = pt->x + drawable->x;
9363		last.y = pt->y + drawable->y;
9364		pt++;
9365
9366		if (clip.data == NULL) {
9367			while (--n) {
9368				DDXPointRec p;
9369
9370				p = *pt++;
9371				if (mode == CoordModePrevious) {
9372					p.x += last.x;
9373					p.y += last.y;
9374				} else {
9375					p.x += drawable->x;
9376					p.y += drawable->y;
9377				}
9378				if (last.x == p.x) {
9379					b->x1 = last.x;
9380					b->x2 = last.x + 1;
9381				} else if (last.x < p.x) {
9382					b->x1 = last.x;
9383					b->x2 = p.x;
9384				} else {
9385					b->x1 = p.x;
9386					b->x2 = last.x;
9387				}
9388				if (last.y == p.y) {
9389					b->y1 = last.y;
9390					b->y2 = last.y + 1;
9391				} else if (last.y < p.y) {
9392					b->y1 = last.y;
9393					b->y2 = p.y;
9394				} else {
9395					b->y1 = p.y;
9396					b->y2 = last.y;
9397				}
9398				b->y2 += last.x == p.x && last.y != p.y;
9399				b->x2 += last.y == p.y && last.x != p.x;
9400				DBG(("%s: blt (%d, %d), (%d, %d)\n",
9401				     __FUNCTION__,
9402				     b->x1, b->y1, b->x2, b->y2));
9403				if (box_intersect(b, &clip.extents)) {
9404					b->x1 += dx;
9405					b->x2 += dx;
9406					b->y1 += dy;
9407					b->y2 += dy;
9408					if (++b == last_box) {
9409						assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0);
9410						fill.boxes(sna, &fill, boxes, last_box - boxes);
9411						if (damage)
9412							sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0);
9413						b = boxes;
9414					}
9415				}
9416
9417				last = p;
9418			}
9419		} else {
9420			const BoxRec * const clip_start = RegionBoxptr(&clip);
9421			const BoxRec * const clip_end = clip_start + clip.data->numRects;
9422			const BoxRec *c;
9423
9424			while (--n) {
9425				DDXPointRec p;
9426				BoxRec box;
9427
9428				p = *pt++;
9429				if (mode == CoordModePrevious) {
9430					p.x += last.x;
9431					p.y += last.y;
9432				} else {
9433					p.x += drawable->x;
9434					p.y += drawable->y;
9435				}
9436				if (last.x == p.x) {
9437					box.x1 = last.x;
9438					box.x2 = last.x + 1;
9439				} else if (last.x < p.x) {
9440					box.x1 = last.x;
9441					box.x2 = p.x;
9442				} else {
9443					box.x1 = p.x;
9444					box.x2 = last.x;
9445				}
9446				if (last.y == p.y) {
9447					box.y1 = last.y;
9448					box.y2 = last.y + 1;
9449				} else if (last.y < p.y) {
9450					box.y1 = last.y;
9451					box.y2 = p.y;
9452				} else {
9453					box.y1 = p.y;
9454					box.y2 = last.y;
9455				}
9456				b->y2 += last.x == p.x && last.y != p.y;
9457				b->x2 += last.y == p.y && last.x != p.x;
9458				DBG(("%s: blt (%d, %d), (%d, %d)\n",
9459				     __FUNCTION__,
9460				     box.x1, box.y1, box.x2, box.y2));
9461
9462				c = find_clip_box_for_y(clip_start,
9463							clip_end,
9464							box.y1);
9465				while (c != clip_end) {
9466					if (box.y2 <= c->y1)
9467						break;
9468
9469					*b = box;
9470					if (box_intersect(b, c++)) {
9471						b->x1 += dx;
9472						b->x2 += dx;
9473						b->y1 += dy;
9474						b->y2 += dy;
9475						if (++b == last_box) {
9476							assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0);
9477							fill.boxes(sna, &fill, boxes, last_box-boxes);
9478							if (damage)
9479								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
9480							b = boxes;
9481						}
9482					}
9483				}
9484
9485				last = p;
9486			}
9487		}
9488		RegionUninit(&clip);
9489	}
9490	if (b != boxes) {
9491		assert_pixmap_contains_boxes(pixmap, boxes, b-boxes, 0, 0);
9492		fill.boxes(sna, &fill, boxes, b - boxes);
9493		if (damage)
9494			sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0);
9495	}
9496	fill.done(sna, &fill);
9497	assert_pixmap_damage(pixmap);
9498	return true;
9499}
9500
9501static unsigned
9502sna_poly_line_extents(DrawablePtr drawable, GCPtr gc,
9503		      int mode, int n, DDXPointPtr pt,
9504		      BoxPtr out)
9505{
9506	BoxRec box;
9507	bool clip, blt = true;
9508
9509	if (n == 0)
9510		return 0;
9511
9512	box.x2 = box.x1 = pt->x;
9513	box.y2 = box.y1 = pt->y;
9514	if (mode == CoordModePrevious) {
9515		int x = box.x1;
9516		int y = box.y1;
9517		while (--n) {
9518			pt++;
9519			x += pt->x;
9520			y += pt->y;
9521			if (blt)
9522				blt &= pt->x == 0 || pt->y == 0;
9523			box_add_pt(&box, x, y);
9524		}
9525	} else {
9526		int x = box.x1;
9527		int y = box.y1;
9528		while (--n) {
9529			pt++;
9530			if (blt) {
9531				blt &= pt->x == x || pt->y == y;
9532				x = pt->x;
9533				y = pt->y;
9534			}
9535			box_add_pt(&box, pt->x, pt->y);
9536		}
9537	}
9538	box.x2++;
9539	box.y2++;
9540
9541	if (gc->lineWidth) {
9542		int extra = gc->lineWidth >> 1;
9543		if (n > 1) {
9544			if (gc->joinStyle == JoinMiter)
9545				extra = 6 * gc->lineWidth;
9546			else if (gc->capStyle == CapProjecting)
9547				extra = gc->lineWidth;
9548		}
9549		if (extra) {
9550			box.x1 -= extra;
9551			box.x2 += extra;
9552			box.y1 -= extra;
9553			box.y2 += extra;
9554		}
9555	}
9556
9557	clip = trim_and_translate_box(&box, drawable, gc);
9558	if (box_empty(&box))
9559		return 0;
9560
9561	*out = box;
9562	return 1 | blt << 2 | clip << 1;
9563}
9564
9565/* Only use our spans code if the destination is busy and we can't perform
9566 * the operation in place.
9567 *
9568 * Currently it looks to be faster to use the GPU for zero spans on all
9569 * platforms.
9570 */
9571inline static int
9572_use_zero_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents)
9573{
9574	if (USE_ZERO_SPANS)
9575		return USE_ZERO_SPANS > 0;
9576
9577	return !drawable_gc_inplace_hint(drawable, gc);
9578}
9579
9580static int
9581use_zero_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents)
9582{
9583	bool ret = _use_zero_spans(drawable, gc, extents);
9584	DBG(("%s? %d\n", __FUNCTION__, ret));
9585	return ret;
9586}
9587
9588/* Only use our spans code if the destination is busy and we can't perform
9589 * the operation in place.
9590 *
9591 * Currently it looks to be faster to use the CPU for wide spans on all
9592 * platforms, slow MI code. But that does not take into account the true
9593 * cost of readback?
9594 */
9595inline static int
9596_use_wide_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents)
9597{
9598	if (USE_WIDE_SPANS)
9599		return USE_WIDE_SPANS > 0;
9600
9601	return !drawable_gc_inplace_hint(drawable, gc);
9602}
9603
9604static int
9605use_wide_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents)
9606{
9607	int ret = _use_wide_spans(drawable, gc, extents);
9608	DBG(("%s? %d\n", __FUNCTION__, ret));
9609	return ret;
9610}
9611
9612static void
9613sna_poly_line(DrawablePtr drawable, GCPtr gc,
9614	      int mode, int n, DDXPointPtr pt)
9615{
9616	struct sna_pixmap *priv;
9617	struct sna_fill_spans data;
9618	uint32_t color;
9619
9620	DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d), lineWidth=%d\n",
9621	     __FUNCTION__, mode, n, pt[0].x, pt[0].y, gc->lineWidth));
9622
9623	data.flags = sna_poly_line_extents(drawable, gc, mode, n, pt,
9624					   &data.region.extents);
9625	if (data.flags == 0)
9626		return;
9627
9628	DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
9629	     data.region.extents.x1, data.region.extents.y1,
9630	     data.region.extents.x2, data.region.extents.y2,
9631	     data.flags));
9632
9633	data.region.data = NULL;
9634
9635	if (FORCE_FALLBACK)
9636		goto fallback;
9637
9638	if (!ACCEL_POLY_LINE)
9639		goto fallback;
9640
9641	data.pixmap = get_drawable_pixmap(drawable);
9642	data.sna = to_sna_from_pixmap(data.pixmap);
9643	if (wedged(data.sna)) {
9644		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
9645		goto fallback;
9646	}
9647
9648	DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lx [%d], rectlinear=%d\n",
9649	     __FUNCTION__,
9650	     gc->fillStyle, gc->fillStyle == FillSolid,
9651	     gc->lineStyle, gc->lineStyle == LineSolid,
9652	     gc->lineWidth,
9653	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask),
9654	     data.flags & 4));
9655
9656	if (!PM_IS_SOLID(drawable, gc->planemask))
9657		goto fallback;
9658
9659	priv = sna_pixmap(data.pixmap);
9660	if (!priv) {
9661		DBG(("%s: not attached to pixmap %ld\n",
9662		     __FUNCTION__, data.pixmap->drawable.serialNumber));
9663		goto fallback;
9664	}
9665
9666	if (gc->lineStyle != LineSolid) {
9667		DBG(("%s: lineStyle, %d, is not solid\n",
9668		     __FUNCTION__, gc->lineStyle));
9669		goto spans_fallback;
9670	}
9671	if (!(gc->lineWidth == 0 ||
9672	      (gc->lineWidth == 1 && (n == 1 || gc->alu == GXcopy)))) {
9673		DBG(("%s: non-zero lineWidth %d\n",
9674		     __FUNCTION__, gc->lineWidth));
9675		goto spans_fallback;
9676	}
9677
9678	if (gc_is_solid(gc, &color)) {
9679		DBG(("%s: trying solid fill [%08x]\n",
9680		     __FUNCTION__, (unsigned)color));
9681
9682		if (data.flags & 4) {
9683			data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
9684						      &data.region.extents,
9685						      &data.damage);
9686			if (data.bo &&
9687			    sna_poly_line_blt(drawable,
9688					      data.bo, data.damage,
9689					      gc, color, mode, n, pt,
9690					      &data.region.extents,
9691					      data.flags & 2))
9692				return;
9693		} else { /* !rectilinear */
9694			if ((data.bo = sna_drawable_use_bo(drawable,
9695							   use_zero_spans(drawable, gc, &data.region.extents),
9696							   &data.region.extents,
9697							   &data.damage)) &&
9698			    sna_poly_zero_line_blt(drawable,
9699						   data.bo, data.damage,
9700						   gc, mode, n, pt,
9701						   &data.region.extents,
9702						   data.flags & 2))
9703				return;
9704
9705		}
9706	} else if (data.flags & 4) {
9707		/* Try converting these to a set of rectangles instead */
9708		data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
9709					      &data.region.extents, &data.damage);
9710		if (data.bo) {
9711			DDXPointRec p1, p2;
9712			xRectangle *rect;
9713			int i;
9714
9715			DBG(("%s: converting to rectagnles\n", __FUNCTION__));
9716
9717			rect = malloc (n * sizeof (xRectangle));
9718			if (rect == NULL)
9719				return;
9720
9721			p1 = pt[0];
9722			for (i = 1; i < n; i++) {
9723				if (mode == CoordModePrevious) {
9724					p2.x = p1.x + pt[i].x;
9725					p2.y = p1.y + pt[i].y;
9726				} else
9727					p2 = pt[i];
9728				if (p1.x < p2.x) {
9729					rect[i].x = p1.x;
9730					rect[i].width = p2.x - p1.x + 1;
9731				} else if (p1.x > p2.x) {
9732					rect[i].x = p2.x;
9733					rect[i].width = p1.x - p2.x + 1;
9734				} else {
9735					rect[i].x = p1.x;
9736					rect[i].width = 1;
9737				}
9738				if (p1.y < p2.y) {
9739					rect[i].y = p1.y;
9740					rect[i].height = p2.y - p1.y + 1;
9741				} else if (p1.y > p2.y) {
9742					rect[i].y = p2.y;
9743					rect[i].height = p1.y - p2.y + 1;
9744				} else {
9745					rect[i].y = p1.y;
9746					rect[i].height = 1;
9747				}
9748
9749				/* don't paint last pixel */
9750				if (gc->capStyle == CapNotLast) {
9751					if (p1.x == p2.x)
9752						rect[i].height--;
9753					else
9754						rect[i].width--;
9755				}
9756				p1 = p2;
9757			}
9758
9759			if (gc->fillStyle == FillTiled) {
9760				i = sna_poly_fill_rect_tiled_blt(drawable,
9761								 data.bo, data.damage,
9762								 gc, n - 1, rect + 1,
9763								 &data.region.extents,
9764								 data.flags & 2);
9765			} else {
9766				i = sna_poly_fill_rect_stippled_blt(drawable,
9767								    data.bo, data.damage,
9768								    gc, n - 1, rect + 1,
9769								    &data.region.extents,
9770								    data.flags & 2);
9771			}
9772			free (rect);
9773
9774			if (i)
9775				return;
9776		}
9777	}
9778
9779spans_fallback:
9780	if ((data.bo = sna_drawable_use_bo(drawable,
9781					   use_wide_spans(drawable, gc, &data.region.extents),
9782					   &data.region.extents, &data.damage))) {
9783		DBG(("%s: converting line into spans\n", __FUNCTION__));
9784		get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy);
9785		sna_gc(gc)->priv = &data;
9786
9787		if (gc->lineWidth == 0 && gc_is_solid(gc, &color)) {
9788			struct sna_fill_op fill;
9789
9790			if (gc->lineStyle == LineSolid) {
9791				if (!sna_fill_init_blt(&fill,
9792						       data.sna, data.pixmap,
9793						       data.bo, gc->alu, color,
9794						       FILL_POINTS | FILL_SPANS))
9795					goto fallback;
9796
9797				data.op = &fill;
9798
9799				if ((data.flags & 2) == 0) {
9800					if (data.dx | data.dy)
9801						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
9802					else
9803						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
9804					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill;
9805				} else {
9806					if (!region_maybe_clip(&data.region,
9807							       gc->pCompositeClip))
9808						return;
9809
9810					if (region_is_singular(&data.region)) {
9811						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
9812						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents;
9813					} else {
9814						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
9815						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes;
9816					}
9817				}
9818				assert(gc->miTranslate);
9819
9820				gc->ops = &sna_gc_ops__tmp;
9821				DBG(("%s: miZeroLine (solid fill)\n", __FUNCTION__));
9822				miZeroLine(drawable, gc, mode, n, pt);
9823				fill.done(data.sna, &fill);
9824			} else {
9825				data.op = &fill;
9826
9827				if ((data.flags & 2) == 0) {
9828					if (data.dx | data.dy)
9829						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_offset;
9830					else
9831						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash;
9832					sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash;
9833				} else {
9834					if (!region_maybe_clip(&data.region,
9835							       gc->pCompositeClip))
9836						return;
9837
9838					if (region_is_singular(&data.region)) {
9839						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_extents;
9840						sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_extents;
9841					} else {
9842						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_boxes;
9843						sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_boxes;
9844					}
9845				}
9846				assert(gc->miTranslate);
9847
9848				DBG(("%s: miZeroLine (solid dash, clipped? %d (complex? %d)), fg pass [%08x]\n",
9849				     __FUNCTION__,
9850				     !!(data.flags & 2), data.flags & 2 && !region_is_singular(&data.region),
9851				     gc->fgPixel));
9852
9853				if (!sna_fill_init_blt(&fill,
9854						       data.sna, data.pixmap,
9855						       data.bo, gc->alu, color,
9856						       FILL_POINTS | FILL_SPANS))
9857					goto fallback;
9858
9859				gc->ops = &sna_gc_ops__tmp;
9860				data.phase = gc->fgPixel;
9861				miZeroDashLine(drawable, gc, mode, n, pt);
9862				fill.done(data.sna, &fill);
9863
9864				DBG(("%s: miZeroLine (solid dash, clipped? %d (complex? %d)), bg pass [%08x]\n",
9865				     __FUNCTION__,
9866				     !!(data.flags & 2), data.flags & 2 && !region_is_singular(&data.region),
9867				     gc->bgPixel));
9868
9869				if (sna_fill_init_blt(&fill,
9870						      data.sna, data.pixmap,
9871						      data.bo, gc->alu,
9872						      gc->bgPixel,
9873						      FILL_POINTS | FILL_SPANS)) {
9874					data.phase = gc->bgPixel;
9875					miZeroDashLine(drawable, gc, mode, n, pt);
9876					fill.done(data.sna, &fill);
9877				}
9878			}
9879		} else {
9880			/* Note that the WideDash functions alternate
9881			 * between filling using fgPixel and bgPixel
9882			 * so we need to reset state between FillSpans and
9883			 * cannot use the fill fast paths.
9884			 */
9885			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
9886			sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu;
9887			sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu;
9888			gc->ops = &sna_gc_ops__tmp;
9889
9890			switch (gc->lineStyle) {
9891			default:
9892				assert(0);
9893			case LineSolid:
9894				if (gc->lineWidth == 0) {
9895					DBG(("%s: miZeroLine\n", __FUNCTION__));
9896					miZeroLine(drawable, gc, mode, n, pt);
9897				} else {
9898					DBG(("%s: miWideLine\n", __FUNCTION__));
9899					miWideLine(drawable, gc, mode, n, pt);
9900				}
9901				break;
9902			case LineOnOffDash:
9903			case LineDoubleDash:
9904				if (gc->lineWidth == 0) {
9905					DBG(("%s: miZeroDashLine\n", __FUNCTION__));
9906					miZeroDashLine(drawable, gc, mode, n, pt);
9907				} else {
9908					DBG(("%s: miWideDash\n", __FUNCTION__));
9909					miWideDash(drawable, gc, mode, n, pt);
9910				}
9911				break;
9912			}
9913		}
9914
9915		gc->ops = (GCOps *)&sna_gc_ops;
9916		if (data.damage) {
9917			if (data.dx | data.dy)
9918				pixman_region_translate(&data.region, data.dx, data.dy);
9919			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
9920			sna_damage_add(data.damage, &data.region);
9921			assert_pixmap_damage(data.pixmap);
9922		}
9923		RegionUninit(&data.region);
9924		return;
9925	}
9926
9927fallback:
9928	DBG(("%s: fallback\n", __FUNCTION__));
9929	if (!region_maybe_clip(&data.region, gc->pCompositeClip))
9930		return;
9931
9932	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
9933		goto out;
9934	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
9935					     drawable_gc_flags(drawable, gc,
9936							       !(data.flags & 4 && n == 2))))
9937		goto out;
9938
9939	if (sigtrap_get() == 0) {
9940		DBG(("%s: fbPolyLine\n", __FUNCTION__));
9941		fbPolyLine(drawable, gc, mode, n, pt);
9942		FALLBACK_FLUSH(drawable);
9943		sigtrap_put();
9944	}
9945out:
9946	sna_gc_move_to_gpu(gc);
9947	RegionUninit(&data.region);
9948}
9949
9950static inline void box_from_seg(BoxPtr b, xSegment *seg, GCPtr gc)
9951{
9952	if (seg->x1 == seg->x2) {
9953		if (seg->y1 > seg->y2) {
9954			b->y2 = seg->y1 + 1;
9955			b->y1 = seg->y2 + 1;
9956			if (gc->capStyle != CapNotLast)
9957				b->y1--;
9958		} else {
9959			b->y1 = seg->y1;
9960			b->y2 = seg->y2;
9961			if (gc->capStyle != CapNotLast)
9962				b->y2++;
9963		}
9964		b->x1 = seg->x1;
9965		b->x2 = seg->x1 + 1;
9966	} else {
9967		if (seg->x1 > seg->x2) {
9968			b->x2 = seg->x1 + 1;
9969			b->x1 = seg->x2 + 1;
9970			if (gc->capStyle != CapNotLast)
9971				b->x1--;
9972		} else {
9973			b->x1 = seg->x1;
9974			b->x2 = seg->x2;
9975			if (gc->capStyle != CapNotLast)
9976				b->x2++;
9977		}
9978		b->y1 = seg->y1;
9979		b->y2 = seg->y1 + 1;
9980	}
9981
9982	DBG(("%s: seg=(%d,%d),(%d,%d); box=(%d,%d),(%d,%d)\n",
9983	     __FUNCTION__,
9984	     seg->x1, seg->y1, seg->x2, seg->y2,
9985	     b->x1, b->y1, b->x2, b->y2));
9986}
9987
9988static bool
9989sna_poly_segment_blt(DrawablePtr drawable,
9990		     struct kgem_bo *bo,
9991		     struct sna_damage **damage,
9992		     GCPtr gc, uint32_t pixel,
9993		     int n, xSegment *seg,
9994		     const BoxRec *extents, unsigned clipped)
9995{
9996	PixmapPtr pixmap = get_drawable_pixmap(drawable);
9997	struct sna *sna = to_sna_from_pixmap(pixmap);
9998	BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes);
9999	struct sna_fill_op fill;
10000	int16_t dx, dy;
10001
10002	DBG(("%s: n=%d, alu=%d, fg=%08lx, clipped=%d\n",
10003	     __FUNCTION__, n, gc->alu, gc->fgPixel, clipped));
10004
10005	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_SPANS))
10006		return false;
10007
10008	get_drawable_deltas(drawable, pixmap, &dx, &dy);
10009
10010	if (!clipped) {
10011		dx += drawable->x;
10012		dy += drawable->y;
10013		if (dx|dy) {
10014			do {
10015				unsigned nbox = n;
10016				if (nbox > ARRAY_SIZE(boxes))
10017					nbox = ARRAY_SIZE(boxes);
10018				n -= nbox;
10019				do {
10020					box_from_seg(b, seg++, gc);
10021					if (b->y2 > b->y1 && b->x2 > b->x1) {
10022						b->x1 += dx;
10023						b->x2 += dx;
10024						b->y1 += dy;
10025						b->y2 += dy;
10026						b++;
10027					}
10028				} while (--nbox);
10029
10030				if (b != boxes) {
10031					fill.boxes(sna, &fill, boxes, b-boxes);
10032					if (damage)
10033						sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
10034					b = boxes;
10035				}
10036			} while (n);
10037		} else {
10038			do {
10039				unsigned nbox = n;
10040				if (nbox > ARRAY_SIZE(boxes))
10041					nbox = ARRAY_SIZE(boxes);
10042				n -= nbox;
10043				do {
10044					box_from_seg(b++, seg++, gc);
10045				} while (--nbox);
10046
10047				if (b != boxes) {
10048					fill.boxes(sna, &fill, boxes, b-boxes);
10049					if (damage)
10050						sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
10051					b = boxes;
10052				}
10053			} while (n);
10054		}
10055	} else {
10056		RegionRec clip;
10057
10058		region_set(&clip, extents);
10059		if (!region_maybe_clip(&clip, gc->pCompositeClip))
10060			goto done;
10061
10062		if (clip.data) {
10063			const BoxRec * const clip_start = RegionBoxptr(&clip);
10064			const BoxRec * const clip_end = clip_start + clip.data->numRects;
10065			const BoxRec *c;
10066			do {
10067				BoxRec box;
10068
10069				box_from_seg(&box, seg++, gc);
10070				box.x1 += drawable->x;
10071				box.x2 += drawable->x;
10072				box.y1 += drawable->y;
10073				box.y2 += drawable->y;
10074				c = find_clip_box_for_y(clip_start,
10075							clip_end,
10076							box.y1);
10077				while (c != clip_end) {
10078					if (box.y2 <= c->y1)
10079						break;
10080
10081					*b = box;
10082					if (box_intersect(b, c++)) {
10083						b->x1 += dx;
10084						b->x2 += dx;
10085						b->y1 += dy;
10086						b->y2 += dy;
10087						if (++b == last_box) {
10088							fill.boxes(sna, &fill, boxes, last_box-boxes);
10089							if (damage)
10090								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
10091							b = boxes;
10092						}
10093					}
10094				}
10095			} while (--n);
10096		} else {
10097			do {
10098				box_from_seg(b, seg++, gc);
10099				b->x1 += drawable->x;
10100				b->x2 += drawable->x;
10101				b->y1 += drawable->y;
10102				b->y2 += drawable->y;
10103				if (box_intersect(b, &clip.extents)) {
10104					b->x1 += dx;
10105					b->x2 += dx;
10106					b->y1 += dy;
10107					b->y2 += dy;
10108					if (++b == last_box) {
10109						fill.boxes(sna, &fill, boxes, last_box-boxes);
10110						if (damage)
10111							sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
10112						b = boxes;
10113					}
10114				}
10115			} while (--n);
10116		}
10117		RegionUninit(&clip);
10118	}
10119	if (b != boxes) {
10120		fill.boxes(sna, &fill, boxes, b - boxes);
10121		if (damage)
10122			sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0);
10123	}
10124done:
10125	fill.done(sna, &fill);
10126	assert_pixmap_damage(pixmap);
10127	return true;
10128}
10129
10130static bool
10131sna_poly_zero_segment_blt(DrawablePtr drawable,
10132			  struct kgem_bo *bo,
10133			  struct sna_damage **damage,
10134			  GCPtr gc, const int _n, const xSegment *_s,
10135			  const BoxRec *extents, unsigned clipped)
10136{
10137	static void * const _jump[] = {
10138		&&no_damage,
10139		&&damage,
10140
10141		&&no_damage_offset,
10142		&&damage_offset,
10143	};
10144
10145	PixmapPtr pixmap = get_drawable_pixmap(drawable);
10146	struct sna *sna = to_sna_from_pixmap(pixmap);
10147	unsigned int bias = miGetZeroLineBias(drawable->pScreen);
10148	struct sna_fill_op fill;
10149	RegionRec clip;
10150	const BoxRec *last_extents;
10151	BoxRec box[512], *b;
10152	BoxRec *const last_box = box + ARRAY_SIZE(box);
10153	int16_t dx, dy;
10154	void *jump, *ret;
10155
10156	DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n",
10157	     __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage));
10158	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_BOXES))
10159		return false;
10160
10161	get_drawable_deltas(drawable, pixmap, &dx, &dy);
10162
10163	region_set(&clip, extents);
10164	if (clipped) {
10165		if (!region_maybe_clip(&clip, gc->pCompositeClip))
10166			return true;
10167	}
10168	DBG(("%s: [clipped] extents=(%d, %d), (%d, %d), delta=(%d, %d)\n",
10169	     __FUNCTION__,
10170	     clip.extents.x1, clip.extents.y1,
10171	     clip.extents.x2, clip.extents.y2,
10172	     dx, dy));
10173
10174	jump = _jump[(damage != NULL) | !!(dx|dy) << 1];
10175
10176	b = box;
10177	extents = region_rects(&clip);
10178	last_extents = extents + region_num_rects(&clip);
10179	do {
10180		int n = _n;
10181		const xSegment *s = _s;
10182		do {
10183			int16_t sdx, sdy;
10184			int adx, ady, length;
10185			int e, e1, e2, e3;
10186			int x1, x2;
10187			int y1, y2;
10188			int oc1, oc2;
10189			int octant;
10190
10191			x1 = s->x1 + drawable->x;
10192			y1 = s->y1 + drawable->y;
10193			x2 = s->x2 + drawable->x;
10194			y2 = s->y2 + drawable->y;
10195			s++;
10196
10197			DBG(("%s: segment (%d, %d) to (%d, %d)\n",
10198			     __FUNCTION__, x1, y1, x2, y2));
10199			if (x2 == x1 && y2 == y1)
10200				continue;
10201
10202			oc1 = 0;
10203			OUTCODES(oc1, x1, y1, extents);
10204			oc2 = 0;
10205			OUTCODES(oc2, x2, y2, extents);
10206			if (oc1 & oc2)
10207				continue;
10208
10209			CalcLineDeltas(x1, y1, x2, y2,
10210				       adx, ady, sdx, sdy,
10211				       1, 1, octant);
10212
10213			DBG(("%s: adx=(%d, %d), sdx=(%d, %d)\n",
10214			     __FUNCTION__, adx, ady, sdx, sdy));
10215			if (adx == 0 || ady == 0) {
10216				if (x1 <= x2) {
10217					b->x1 = x1;
10218					b->x2 = x2;
10219				} else {
10220					b->x1 = x2;
10221					b->x2 = x1;
10222				}
10223				if (y1 <= y2) {
10224					b->y1 = y1;
10225					b->y2 = y2;
10226				} else {
10227					b->y1 = y2;
10228					b->y2 = y1;
10229				}
10230				b->x2++;
10231				b->y2++;
10232				if (oc1 | oc2)
10233					box_intersect(b, extents);
10234				if (++b == last_box) {
10235					ret = &&rectangle_continue;
10236					goto *jump;
10237rectangle_continue:
10238					b = box;
10239				}
10240			} else if (adx >= ady) {
10241				bool dirty;
10242
10243				/* X-major segment */
10244				e1 = ady << 1;
10245				e2 = e1 - (adx << 1);
10246				e  = e1 - adx;
10247				length = adx;	/* don't draw endpoint in main loop */
10248
10249				FIXUP_ERROR(e, octant, bias);
10250
10251				if (oc1 | oc2) {
10252					int pt1_clipped, pt2_clipped;
10253					int x = x1, y = y1;
10254
10255					if (miZeroClipLine(extents->x1, extents->y1,
10256							   extents->x2-1, extents->y2-1,
10257							   &x1, &y1, &x2, &y2,
10258							   adx, ady,
10259							   &pt1_clipped, &pt2_clipped,
10260							   octant, bias, oc1, oc2) == -1)
10261						continue;
10262
10263					length = abs(x2 - x1);
10264					if (length == 0)
10265						continue;
10266
10267					if (pt1_clipped) {
10268						int clipdx = abs(x1 - x);
10269						int clipdy = abs(y1 - y);
10270						e += clipdy * e2 + (clipdx - clipdy) * e1;
10271					}
10272				}
10273				e3 = e2 - e1;
10274				e  = e - e1;
10275
10276				b->x1 = x1;
10277				b->y1 = y1;
10278				dirty = false;
10279				while (length--) {
10280					dirty = true;
10281					e += e1;
10282					if (e >= 0) {
10283						e += e3;
10284
10285						if (sdx < 0) {
10286							b->x2 = b->x1 + 1;
10287							b->x1 = x1;
10288						} else
10289							b->x2 = x1 + 1;
10290						b->y2 = b->y1 + 1;
10291
10292						DBG(("%s: horizontal step: (%d, %d), box: (%d, %d), (%d, %d)\n",
10293						     __FUNCTION__, x1, y1,
10294						     b->x1, b->y1, b->x2, b->y2));
10295
10296						if (++b == last_box) {
10297							ret = &&X_continue;
10298							goto *jump;
10299X_continue:
10300							b = box;
10301						}
10302
10303						b->x1 = x1 + sdx;
10304						b->y1 = y1 += sdy;
10305						dirty = false;
10306					}
10307					x1 += sdx;
10308				}
10309				if (dirty) {
10310					x1 -= sdx;
10311					DBG(("%s: horizontal tail: (%d, %d)\n",
10312					     __FUNCTION__, x1, y1));
10313					if (sdx < 0) {
10314						b->x2 = b->x1 + 1;
10315						b->x1 = x1;
10316					} else
10317						b->x2 = x1 + 1;
10318					b->y2 = b->y1 + 1;
10319
10320					if (++b == last_box) {
10321						ret = &&X2_continue;
10322						goto *jump;
10323X2_continue:
10324						b = box;
10325					}
10326				}
10327			} else {
10328				bool dirty;
10329
10330				/* Y-major segment */
10331				e1 = adx << 1;
10332				e2 = e1 - (ady << 1);
10333				e  = e1 - ady;
10334				length  = ady;	/* don't draw endpoint in main loop */
10335
10336				SetYMajorOctant(octant);
10337				FIXUP_ERROR(e, octant, bias);
10338
10339				if (oc1 | oc2) {
10340					int pt1_clipped, pt2_clipped;
10341					int x = x1, y = y1;
10342
10343					if (miZeroClipLine(extents->x1, extents->y1,
10344							   extents->x2-1, extents->y2-1,
10345							   &x1, &y1, &x2, &y2,
10346							   adx, ady,
10347							   &pt1_clipped, &pt2_clipped,
10348							   octant, bias, oc1, oc2) == -1)
10349						continue;
10350
10351					length = abs(y2 - y1);
10352					if (length == 0)
10353						continue;
10354
10355					if (pt1_clipped) {
10356						int clipdx = abs(x1 - x);
10357						int clipdy = abs(y1 - y);
10358						e += clipdx * e2 + (clipdy - clipdx) * e1;
10359					}
10360				}
10361
10362				e3 = e2 - e1;
10363				e  = e - e1;
10364
10365				b->x1 = x1;
10366				b->y1 = y1;
10367				dirty = false;
10368				while (length--) {
10369					e += e1;
10370					dirty = true;
10371					if (e >= 0) {
10372						e += e3;
10373
10374						if (sdy < 0) {
10375							b->y2 = b->y1 + 1;
10376							b->y1 = y1;
10377						} else
10378							b->y2 = y1 + 1;
10379						b->x2 = x1 + 1;
10380
10381						if (++b == last_box) {
10382							ret = &&Y_continue;
10383							goto *jump;
10384Y_continue:
10385							b = box;
10386						}
10387
10388						b->x1 = x1 += sdx;
10389						b->y1 = y1 + sdy;
10390						dirty = false;
10391					}
10392					y1 += sdy;
10393				}
10394
10395				if (dirty) {
10396					y1 -= sdy;
10397					if (sdy < 0) {
10398						b->y2 = b->y1 + 1;
10399						b->y1 = y1;
10400					} else
10401						b->y2 = y1 + 1;
10402					b->x2 = x1 + 1;
10403
10404					if (++b == last_box) {
10405						ret = &&Y2_continue;
10406						goto *jump;
10407Y2_continue:
10408						b = box;
10409					}
10410				}
10411			}
10412		} while (--n);
10413	} while (++extents != last_extents);
10414
10415	if (b != box) {
10416		ret = &&done;
10417		goto *jump;
10418	}
10419
10420done:
10421	fill.done(sna, &fill);
10422	assert_pixmap_damage(pixmap);
10423	RegionUninit(&clip);
10424	return true;
10425
10426damage:
10427	sna_damage_add_boxes(damage, box, b-box, 0, 0);
10428no_damage:
10429	fill.boxes(sna, &fill, box, b-box);
10430	goto *ret;
10431
10432no_damage_offset:
10433	{
10434		BoxRec *bb = box;
10435		do {
10436			bb->x1 += dx;
10437			bb->x2 += dx;
10438			bb->y1 += dy;
10439			bb->y2 += dy;
10440		} while (++bb != b);
10441		fill.boxes(sna, &fill, box, b - box);
10442	}
10443	goto *ret;
10444
10445damage_offset:
10446	{
10447		BoxRec *bb = box;
10448		do {
10449			bb->x1 += dx;
10450			bb->x2 += dx;
10451			bb->y1 += dy;
10452			bb->y2 += dy;
10453		} while (++bb != b);
10454		fill.boxes(sna, &fill, box, b - box);
10455		sna_damage_add_boxes(damage, box, b - box, 0, 0);
10456	}
10457	goto *ret;
10458}
10459
10460static unsigned
10461sna_poly_segment_extents(DrawablePtr drawable, GCPtr gc,
10462			 int n, xSegment *seg,
10463			 BoxPtr out)
10464{
10465	BoxRec box;
10466	bool clipped, can_blit;
10467
10468	if (n == 0)
10469		return 0;
10470
10471	if (seg->x2 >= seg->x1) {
10472		box.x1 = seg->x1;
10473		box.x2 = seg->x2;
10474	} else {
10475		box.x2 = seg->x1;
10476		box.x1 = seg->x2;
10477	}
10478
10479	if (seg->y2 >= seg->y1) {
10480		box.y1 = seg->y1;
10481		box.y2 = seg->y2;
10482	} else {
10483		box.y2 = seg->y1;
10484		box.y1 = seg->y2;
10485	}
10486
10487	can_blit = seg->x1 == seg->x2 || seg->y1 == seg->y2;
10488	while (--n) {
10489		seg++;
10490		if (seg->x2 > seg->x1) {
10491			if (seg->x1 < box.x1) box.x1 = seg->x1;
10492			if (seg->x2 > box.x2) box.x2 = seg->x2;
10493		} else {
10494			if (seg->x2 < box.x1) box.x1 = seg->x2;
10495			if (seg->x1 > box.x2) box.x2 = seg->x1;
10496		}
10497
10498		if (seg->y2 > seg->y1) {
10499			if (seg->y1 < box.y1) box.y1 = seg->y1;
10500			if (seg->y2 > box.y2) box.y2 = seg->y2;
10501		} else {
10502			if (seg->y2 < box.y1) box.y1 = seg->y2;
10503			if (seg->y1 > box.y2) box.y2 = seg->y1;
10504		}
10505
10506		if (can_blit && !(seg->x1 == seg->x2 || seg->y1 == seg->y2))
10507			can_blit = false;
10508	}
10509
10510	box.x2++;
10511	box.y2++;
10512
10513	if (gc->lineWidth) {
10514		int extra = gc->lineWidth;
10515		if (gc->capStyle != CapProjecting)
10516			extra >>= 1;
10517		if (extra) {
10518			box.x1 -= extra;
10519			box.x2 += extra;
10520			box.y1 -= extra;
10521			box.y2 += extra;
10522		}
10523	}
10524
10525	DBG(("%s: unclipped, untranslated extents (%d, %d), (%d, %d)\n",
10526	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
10527
10528	clipped = trim_and_translate_box(&box, drawable, gc);
10529	if (box_empty(&box))
10530		return 0;
10531
10532	*out = box;
10533	return 1 | clipped << 1 | can_blit << 2;
10534}
10535
10536static void
10537sna_poly_segment(DrawablePtr drawable, GCPtr gc, int n, xSegment *seg)
10538{
10539	struct sna_pixmap *priv;
10540	struct sna_fill_spans data;
10541	uint32_t color;
10542
10543	DBG(("%s(n=%d, first=((%d, %d), (%d, %d)), lineWidth=%d\n",
10544	     __FUNCTION__,
10545	     n, seg->x1, seg->y1, seg->x2, seg->y2,
10546	     gc->lineWidth));
10547
10548	data.flags = sna_poly_segment_extents(drawable, gc, n, seg,
10549					      &data.region.extents);
10550	if (data.flags == 0)
10551		return;
10552
10553	DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__,
10554	     data.region.extents.x1, data.region.extents.y1,
10555	     data.region.extents.x2, data.region.extents.y2));
10556
10557	data.region.data = NULL;
10558
10559	if (FORCE_FALLBACK)
10560		goto fallback;
10561
10562	if (!ACCEL_POLY_SEGMENT)
10563		goto fallback;
10564
10565	data.pixmap = get_drawable_pixmap(drawable);
10566	data.sna = to_sna_from_pixmap(data.pixmap);
10567	priv = sna_pixmap(data.pixmap);
10568	if (priv == NULL) {
10569		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
10570		goto fallback;
10571	}
10572
10573	if (wedged(data.sna)) {
10574		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
10575		goto fallback;
10576	}
10577
10578	DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lu [%d], rectlinear=%d\n",
10579	     __FUNCTION__,
10580	     gc->fillStyle, gc->fillStyle == FillSolid,
10581	     gc->lineStyle, gc->lineStyle == LineSolid,
10582	     gc->lineWidth,
10583	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask),
10584	     data.flags & 4));
10585	if (!PM_IS_SOLID(drawable, gc->planemask))
10586		goto fallback;
10587
10588	if (gc->lineStyle != LineSolid || gc->lineWidth > 1)
10589		goto spans_fallback;
10590	if (gc_is_solid(gc, &color)) {
10591		DBG(("%s: trying blt solid fill [%08x, flags=%x] paths\n",
10592		     __FUNCTION__, (unsigned)color, data.flags));
10593
10594		if (data.flags & 4) {
10595			if ((data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
10596							   &data.region.extents,
10597							   &data.damage)) &&
10598			     sna_poly_segment_blt(drawable,
10599						 data.bo, data.damage,
10600						 gc, color, n, seg,
10601						 &data.region.extents,
10602						 data.flags & 2))
10603				return;
10604		} else {
10605			if ((data.bo = sna_drawable_use_bo(drawable,
10606							   use_zero_spans(drawable, gc, &data.region.extents),
10607							   &data.region.extents,
10608							   &data.damage)) &&
10609			    sna_poly_zero_segment_blt(drawable,
10610						      data.bo, data.damage,
10611						      gc, n, seg,
10612						      &data.region.extents,
10613						      data.flags & 2))
10614				return;
10615		}
10616	} else if (data.flags & 4) {
10617		/* Try converting these to a set of rectangles instead */
10618		xRectangle *rect;
10619		int i;
10620
10621		data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
10622					      &data.region.extents,
10623					      &data.damage);
10624		if (data.bo == NULL)
10625			goto fallback;
10626
10627		DBG(("%s: converting to rectagnles\n", __FUNCTION__));
10628
10629		rect = malloc (n * sizeof (xRectangle));
10630		if (rect == NULL)
10631			return;
10632
10633		for (i = 0; i < n; i++) {
10634			if (seg[i].x1 < seg[i].x2) {
10635				rect[i].x = seg[i].x1;
10636				rect[i].width = seg[i].x2 - seg[i].x1 + 1;
10637			} else if (seg[i].x1 > seg[i].x2) {
10638				rect[i].x = seg[i].x2;
10639				rect[i].width = seg[i].x1 - seg[i].x2 + 1;
10640			} else {
10641				rect[i].x = seg[i].x1;
10642				rect[i].width = 1;
10643			}
10644			if (seg[i].y1 < seg[i].y2) {
10645				rect[i].y = seg[i].y1;
10646				rect[i].height = seg[i].y2 - seg[i].y1 + 1;
10647			} else if (seg[i].y1 > seg[i].y2) {
10648				rect[i].y = seg[i].y2;
10649				rect[i].height = seg[i].y1 - seg[i].y2 + 1;
10650			} else {
10651				rect[i].y = seg[i].y1;
10652				rect[i].height = 1;
10653			}
10654
10655			/* don't paint last pixel */
10656			if (gc->capStyle == CapNotLast) {
10657				if (seg[i].x1 == seg[i].x2)
10658					rect[i].height--;
10659				else
10660					rect[i].width--;
10661			}
10662		}
10663
10664		if (gc->fillStyle == FillTiled) {
10665			i = sna_poly_fill_rect_tiled_blt(drawable,
10666							 data.bo, data.damage,
10667							 gc, n, rect,
10668							 &data.region.extents,
10669							 data.flags & 2);
10670		} else {
10671			i = sna_poly_fill_rect_stippled_blt(drawable,
10672							    data.bo, data.damage,
10673							    gc, n, rect,
10674							    &data.region.extents,
10675							    data.flags & 2);
10676		}
10677		free (rect);
10678
10679		if (i)
10680			return;
10681	}
10682
10683spans_fallback:
10684	if ((data.bo = sna_drawable_use_bo(drawable,
10685					   use_wide_spans(drawable, gc, &data.region.extents),
10686					   &data.region.extents,
10687					   &data.damage))) {
10688		void (*line)(DrawablePtr, GCPtr, int, int, DDXPointPtr);
10689		int i;
10690
10691		DBG(("%s: converting segments into spans\n", __FUNCTION__));
10692
10693		switch (gc->lineStyle) {
10694		default:
10695		case LineSolid:
10696			if (gc->lineWidth == 0)
10697				line = miZeroLine;
10698			else
10699				line = miWideLine;
10700			break;
10701		case LineOnOffDash:
10702		case LineDoubleDash:
10703			if (gc->lineWidth == 0)
10704				line = miZeroDashLine;
10705			else
10706				line = miWideDash;
10707			break;
10708		}
10709
10710		get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy);
10711		sna_gc(gc)->priv = &data;
10712
10713		if (gc->lineWidth == 0 &&
10714		    gc->lineStyle == LineSolid &&
10715		    gc_is_solid(gc, &color)) {
10716			struct sna_fill_op fill;
10717
10718			if (!sna_fill_init_blt(&fill,
10719					       data.sna, data.pixmap,
10720					       data.bo, gc->alu, color,
10721					       FILL_POINTS | FILL_SPANS))
10722				goto fallback;
10723
10724			data.op = &fill;
10725
10726			if ((data.flags & 2) == 0) {
10727				if (data.dx | data.dy)
10728					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
10729				else
10730					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
10731				sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill;
10732			} else {
10733				if (!region_maybe_clip(&data.region,
10734						       gc->pCompositeClip))
10735					return;
10736
10737				if (region_is_singular(&data.region)) {
10738					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
10739					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents;
10740				} else {
10741					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
10742					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes;
10743				}
10744			}
10745			assert(gc->miTranslate);
10746			gc->ops = &sna_gc_ops__tmp;
10747			for (i = 0; i < n; i++)
10748				line(drawable, gc, CoordModeOrigin, 2,
10749				     (DDXPointPtr)&seg[i]);
10750
10751			fill.done(data.sna, &fill);
10752		} else {
10753			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
10754			sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu;
10755			sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu;
10756			gc->ops = &sna_gc_ops__tmp;
10757
10758			for (i = 0; i < n; i++)
10759				line(drawable, gc, CoordModeOrigin, 2,
10760				     (DDXPointPtr)&seg[i]);
10761		}
10762
10763		gc->ops = (GCOps *)&sna_gc_ops;
10764		if (data.damage) {
10765			if (data.dx | data.dy)
10766				pixman_region_translate(&data.region, data.dx, data.dy);
10767			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
10768			sna_damage_add(data.damage, &data.region);
10769		}
10770		assert_pixmap_damage(data.pixmap);
10771		RegionUninit(&data.region);
10772		return;
10773	}
10774
10775fallback:
10776	DBG(("%s: fallback\n", __FUNCTION__));
10777	if (!region_maybe_clip(&data.region, gc->pCompositeClip))
10778		return;
10779
10780	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
10781		goto out;
10782	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
10783					     drawable_gc_flags(drawable, gc,
10784							       !(data.flags & 4 && n == 1))))
10785		goto out;
10786
10787	if (sigtrap_get() == 0) {
10788		DBG(("%s: fbPolySegment\n", __FUNCTION__));
10789		fbPolySegment(drawable, gc, n, seg);
10790		FALLBACK_FLUSH(drawable);
10791		sigtrap_put();
10792	}
10793out:
10794	sna_gc_move_to_gpu(gc);
10795	RegionUninit(&data.region);
10796}
10797
10798static unsigned
10799sna_poly_rectangle_extents(DrawablePtr drawable, GCPtr gc,
10800			   int n, xRectangle *r,
10801			   BoxPtr out)
10802{
10803	Box32Rec box;
10804	int extra = gc->lineWidth >> 1;
10805	bool clipped;
10806	bool zero = false;
10807
10808	if (n == 0)
10809		return 0;
10810
10811	box.x1 = r->x;
10812	box.y1 = r->y;
10813	box.x2 = box.x1 + r->width;
10814	box.y2 = box.y1 + r->height;
10815	zero |= (r->width | r->height) == 0;
10816
10817	while (--n) {
10818		r++;
10819		zero |= (r->width | r->height) == 0;
10820		box32_add_rect(&box, r);
10821	}
10822
10823	box.x2++;
10824	box.y2++;
10825
10826	if (extra) {
10827		box.x1 -= extra;
10828		box.x2 += extra;
10829		box.y1 -= extra;
10830		box.y2 += extra;
10831		zero = !zero;
10832	} else
10833		zero = true;
10834
10835	DBG(("%s: unclipped original extents: (%d, %d), (%d, %d)\n",
10836	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
10837	clipped = box32_trim_and_translate(&box, drawable, gc);
10838	if (!box32_to_box16(&box, out))
10839		return 0;
10840
10841	DBG(("%s: extents: (%d, %d), (%d, %d), clipped? %d\n",
10842	     __FUNCTION__, out->x1, out->y1, out->x2, out->y2, clipped));
10843	return 1 | clipped << 1 | zero << 2;
10844}
10845
10846static bool
10847sna_poly_rectangle_blt(DrawablePtr drawable,
10848		       struct kgem_bo *bo,
10849		       struct sna_damage **damage,
10850		       GCPtr gc, int n, xRectangle *r,
10851		       const BoxRec *extents, unsigned clipped)
10852{
10853	PixmapPtr pixmap = get_drawable_pixmap(drawable);
10854	struct sna *sna = to_sna_from_pixmap(pixmap);
10855	struct sna_fill_op fill;
10856	BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes);
10857	int16_t dx, dy;
10858	static void * const jump[] = {
10859		&&wide,
10860		&&zero,
10861		&&wide_clipped,
10862		&&zero_clipped,
10863	};
10864
10865	DBG(("%s: n=%d, alu=%d, width=%d, fg=%08lx, damge=%p, clipped?=%d\n",
10866	     __FUNCTION__, n, gc->alu, gc->lineWidth, gc->fgPixel, damage, clipped));
10867	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_BOXES))
10868		return false;
10869
10870	get_drawable_deltas(drawable, pixmap, &dx, &dy);
10871
10872	goto *jump[(gc->lineWidth <= 1) | clipped];
10873
10874zero:
10875	dx += drawable->x;
10876	dy += drawable->y;
10877
10878	do {
10879		xRectangle rr = *r++;
10880
10881		if ((rr.width | rr.height) == 0)
10882			continue; /* XXX -> PolyLine */
10883
10884		DBG(("%s - zero : r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__,
10885		     n, rr.x, rr.y, rr.width, rr.height));
10886		rr.x += dx;
10887		rr.y += dy;
10888
10889		if (b+4 > last_box) {
10890			fill.boxes(sna, &fill, boxes, b-boxes);
10891			if (damage)
10892				sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
10893			b = boxes;
10894		}
10895
10896		if (rr.width <= 1 || rr.height <= 1) {
10897			b->x1 = rr.x;
10898			b->y1 = rr.y;
10899			b->x2 = rr.x + rr.width + (rr.height != 0);
10900			b->y2 = rr.y + rr.height + (rr.width != 0);
10901			DBG(("%s: blt (%d, %d), (%d, %d)\n",
10902			     __FUNCTION__,
10903			     b->x1, b->y1, b->x2,b->y2));
10904			b++;
10905		} else {
10906			b[0].x1 = rr.x;
10907			b[0].y1 = rr.y;
10908			b[0].x2 = rr.x + rr.width + 1;
10909			b[0].y2 = rr.y + 1;
10910
10911			b[1] = b[0];
10912			b[1].y1 += rr.height;
10913			b[1].y2 += rr.height;
10914
10915			b[2].y1 = rr.y + 1;
10916			b[2].y2 = rr.y + rr.height;
10917			b[2].x1 = rr.x;
10918			b[2].x2 = rr.x + 1;
10919
10920			b[3] = b[2];
10921			b[3].x1 += rr.width;
10922			b[3].x2 += rr.width;
10923
10924			b += 4;
10925		}
10926	} while (--n);
10927	goto done;
10928
10929zero_clipped:
10930	{
10931		RegionRec clip;
10932		BoxRec box[4];
10933		int count;
10934
10935		region_set(&clip, extents);
10936		if (!region_maybe_clip(&clip, gc->pCompositeClip))
10937			goto done;
10938
10939		if (clip.data) {
10940			const BoxRec * const clip_start = RegionBoxptr(&clip);
10941			const BoxRec * const clip_end = clip_start + clip.data->numRects;
10942			const BoxRec *c;
10943			do {
10944				xRectangle rr = *r++;
10945
10946				DBG(("%s - zero, clipped complex: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__,
10947				     n, rr.x, rr.y, rr.width, rr.height));
10948
10949				if ((rr.width | rr.height) == 0)
10950					continue; /* XXX -> PolyLine */
10951
10952				rr.x += drawable->x;
10953				rr.y += drawable->y;
10954
10955				if (rr.width <= 1 || rr.height <= 1) {
10956					box[0].x1 = rr.x;
10957					box[0].y1 = rr.y;
10958					box[0].x2 = rr.x + rr.width + (rr.height != 0);
10959					box[0].y2 = rr.y + rr.height + (rr.width != 0);
10960					count = 1;
10961				} else {
10962					box[0].x1 = rr.x;
10963					box[0].y1 = rr.y;
10964					box[0].x2 = rr.x + rr.width + 1;
10965					box[0].y2 = rr.y + 1;
10966
10967					box[1] = box[0];
10968					box[1].y1 += rr.height;
10969					box[1].y2 += rr.height;
10970
10971					box[2].y1 = rr.y + 1;
10972					box[2].y2 = rr.y + rr.height;
10973					box[2].x1 = rr.x;
10974					box[2].x2 = rr.x + 1;
10975
10976					box[3] = box[2];
10977					box[3].x1 += rr.width;
10978					box[3].x2 += rr.width;
10979					count = 4;
10980				}
10981
10982				while (count--) {
10983					c = find_clip_box_for_y(clip_start,
10984								clip_end,
10985								box[count].y1);
10986					while (c != clip_end) {
10987						if (box[count].y2 <= c->y1)
10988							break;
10989
10990						*b = box[count];
10991						if (box_intersect(b, c++)) {
10992							b->x1 += dx;
10993							b->x2 += dx;
10994							b->y1 += dy;
10995							b->y2 += dy;
10996							if (++b == last_box) {
10997								fill.boxes(sna, &fill, boxes, last_box-boxes);
10998								if (damage)
10999									sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11000								b = boxes;
11001							}
11002						}
11003
11004					}
11005				}
11006			} while (--n);
11007		} else {
11008			do {
11009				xRectangle rr = *r++;
11010				DBG(("%s - zero, clip: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__,
11011				     n, rr.x, rr.y, rr.width, rr.height));
11012
11013				if ((rr.width | rr.height) == 0)
11014					continue; /* XXX -> PolyLine */
11015
11016				rr.x += drawable->x;
11017				rr.y += drawable->y;
11018
11019				if (rr.width <= 1 || rr.height <= 1) {
11020					box[0].x1 = rr.x;
11021					box[0].y1 = rr.y;
11022					box[0].x2 = rr.x + rr.width + (rr.height != 0);
11023					box[0].y2 = rr.y + rr.height + (rr.width != 0);
11024					count = 1;
11025				} else {
11026					box[0].x1 = rr.x;
11027					box[0].y1 = rr.y;
11028					box[0].x2 = rr.x + rr.width + 1;
11029					box[0].y2 = rr.y + 1;
11030
11031					box[1] = box[0];
11032					box[1].y1 += rr.height;
11033					box[1].y2 += rr.height;
11034
11035					box[2].y1 = rr.y + 1;
11036					box[2].y2 = rr.y + rr.height;
11037					box[2].x1 = rr.x;
11038					box[2].x2 = rr.x + 1;
11039
11040					box[3] = box[2];
11041					box[3].x1 += rr.width;
11042					box[3].x2 += rr.width;
11043					count = 4;
11044				}
11045
11046				while (count--) {
11047					*b = box[count];
11048					if (box_intersect(b, &clip.extents)) {
11049						b->x1 += dx;
11050						b->x2 += dx;
11051						b->y1 += dy;
11052						b->y2 += dy;
11053						if (++b == last_box) {
11054							fill.boxes(sna, &fill, boxes, last_box-boxes);
11055							if (damage)
11056								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11057							b = boxes;
11058						}
11059					}
11060
11061				}
11062			} while (--n);
11063		}
11064		RegionUninit(&clip);
11065	}
11066	goto done;
11067
11068wide_clipped:
11069	{
11070		RegionRec clip;
11071		BoxRec box[4];
11072		int16_t offset2 = gc->lineWidth;
11073		int16_t offset1 = offset2 >> 1;
11074		int16_t offset3 = offset2 - offset1;
11075
11076		region_set(&clip, extents);
11077		if (!region_maybe_clip(&clip, gc->pCompositeClip))
11078			goto done;
11079
11080		DBG(("%s: wide clipped: extents=((%d, %d), (%d, %d))\n",
11081		     __FUNCTION__,
11082		     clip.extents.x1, clip.extents.y1,
11083		     clip.extents.x2, clip.extents.y2));
11084
11085		if (clip.data) {
11086			const BoxRec * const clip_start = RegionBoxptr(&clip);
11087			const BoxRec * const clip_end = clip_start + clip.data->numRects;
11088			const BoxRec *c;
11089			do {
11090				xRectangle rr = *r++;
11091				int count;
11092
11093				if ((rr.width | rr.height) == 0)
11094					continue; /* XXX -> PolyLine */
11095
11096				rr.x += drawable->x;
11097				rr.y += drawable->y;
11098
11099				if (rr.height <= offset2 || rr.width <= offset2) {
11100					if (rr.height == 0) {
11101						box[0].x1 = rr.x;
11102						box[0].x2 = rr.x + rr.width;
11103					} else {
11104						box[0].x1 = rr.x - offset1;
11105						box[0].x2 = rr.x + rr.width + offset3;
11106					}
11107					if (rr.width == 0) {
11108						box[0].y1 = rr.y;
11109						box[0].y2 = rr.y + rr.height;
11110					} else {
11111						box[0].y1 = rr.y - offset1;
11112						box[0].y2 = rr.y + rr.height + offset3;
11113					}
11114					count = 1;
11115				} else {
11116					box[0].x1 = rr.x - offset1;
11117					box[0].x2 = box[0].x1 + rr.width + offset2;
11118					box[0].y1 = rr.y - offset1;
11119					box[0].y2 = box[0].y1 + offset2;
11120
11121					box[1].x1 = rr.x - offset1;
11122					box[1].x2 = box[1].x1 + offset2;
11123					box[1].y1 = rr.y + offset3;
11124					box[1].y2 = rr.y + rr.height - offset1;
11125
11126					box[2] = box[1];
11127					box[2].x1 += rr.width;
11128					box[2].x2 += rr.width;
11129
11130					box[3] = box[0];
11131					box[3].y1 += rr.height;
11132					box[3].y2 += rr.height;
11133					count = 4;
11134				}
11135
11136				while (count--) {
11137					c = find_clip_box_for_y(clip_start,
11138								clip_end,
11139								box[count].y1);
11140					while (c != clip_end) {
11141						if (box[count].y2 <= c->y1)
11142							break;
11143
11144						*b = box[count];
11145						if (box_intersect(b, c++)) {
11146							b->x1 += dx;
11147							b->x2 += dx;
11148							b->y1 += dy;
11149							b->y2 += dy;
11150							if (++b == last_box) {
11151								fill.boxes(sna, &fill, boxes, last_box-boxes);
11152								if (damage)
11153									sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11154								b = boxes;
11155							}
11156						}
11157					}
11158				}
11159			} while (--n);
11160		} else {
11161			DBG(("%s: singular clip offset1=%d, offset2=%d, offset3=%d\n",
11162			     __FUNCTION__, offset1, offset2, offset3));
11163			do {
11164				xRectangle rr = *r++;
11165				int count;
11166				rr.x += drawable->x;
11167				rr.y += drawable->y;
11168
11169				DBG(("%s: r=(%d, %d)x(%d, %d)\n",
11170				     __FUNCTION__, rr.x, rr.y, rr.width, rr.height));
11171				if (rr.height <= offset2 || rr.width <= offset2) {
11172					if (rr.height == 0) {
11173						box[0].x1 = rr.x;
11174						box[0].x2 = rr.x + rr.width;
11175					} else {
11176						box[0].x1 = rr.x - offset1;
11177						box[0].x2 = box[0].x1 + rr.width + offset2;
11178					}
11179					if (rr.width == 0) {
11180						box[0].y1 = rr.y;
11181						box[0].y2 = rr.y + rr.height;
11182					} else {
11183						box[0].y1 = rr.y - offset1;
11184						box[0].y2 = box[0].y1 + rr.height + offset2;
11185					}
11186					count = 1;
11187				} else {
11188					box[0].x1 = rr.x - offset1;
11189					box[0].x2 = box[0].x1 + rr.width + offset2;
11190					box[0].y1 = rr.y - offset1;
11191					box[0].y2 = box[0].y1 + offset2;
11192					DBG(("%s: box[0]=(%d, %d), (%d, %d)\n",
11193					     __FUNCTION__,
11194					     box[0].x1, box[0].y1,
11195					     box[0].x2, box[0].y2));
11196
11197					box[1].x1 = rr.x - offset1;
11198					box[1].x2 = box[1].x1 + offset2;
11199					box[1].y1 = rr.y + offset3;
11200					box[1].y2 = rr.y + rr.height - offset1;
11201					DBG(("%s: box[1]=(%d, %d), (%d, %d)\n",
11202					     __FUNCTION__,
11203					     box[1].x1, box[1].y1,
11204					     box[1].x2, box[1].y2));
11205
11206					box[2] = box[1];
11207					box[2].x1 += rr.width;
11208					box[2].x2 += rr.width;
11209					DBG(("%s: box[2]=(%d, %d), (%d, %d)\n",
11210					     __FUNCTION__,
11211					     box[2].x1, box[2].y1,
11212					     box[2].x2, box[2].y2));
11213
11214					box[3] = box[0];
11215					box[3].y1 += rr.height;
11216					box[3].y2 += rr.height;
11217					DBG(("%s: box[3]=(%d, %d), (%d, %d)\n",
11218					     __FUNCTION__,
11219					     box[3].x1, box[3].y1,
11220					     box[3].x2, box[3].y2));
11221
11222					count = 4;
11223				}
11224
11225				while (count--) {
11226					*b = box[count];
11227					if (box_intersect(b, &clip.extents)) {
11228						b->x1 += dx;
11229						b->x2 += dx;
11230						b->y1 += dy;
11231						b->y2 += dy;
11232						if (++b == last_box) {
11233							fill.boxes(sna, &fill, boxes, last_box-boxes);
11234							if (damage)
11235								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11236							b = boxes;
11237						}
11238					}
11239				}
11240			} while (--n);
11241		}
11242		RegionUninit(&clip);
11243	}
11244	goto done;
11245
11246wide:
11247	{
11248		int offset2 = gc->lineWidth;
11249		int offset1 = offset2 >> 1;
11250		int offset3 = offset2 - offset1;
11251
11252		dx += drawable->x;
11253		dy += drawable->y;
11254
11255		do {
11256			xRectangle rr = *r++;
11257
11258			if ((rr.width | rr.height) == 0)
11259				continue; /* XXX -> PolyLine */
11260
11261			rr.x += dx;
11262			rr.y += dy;
11263
11264			if (b+4 > last_box) {
11265				fill.boxes(sna, &fill, boxes, last_box-boxes);
11266				if (damage)
11267					sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11268				b = boxes;
11269			}
11270
11271			if (rr.height <= offset2 || rr.width <= offset2) {
11272				if (rr.height == 0) {
11273					b->x1 = rr.x;
11274					b->x2 = rr.x + rr.width;
11275				} else {
11276					b->x1 = rr.x - offset1;
11277					b->x2 = rr.x + rr.width + offset3;
11278				}
11279				if (rr.width == 0) {
11280					b->y1 = rr.y;
11281					b->y2 = rr.y + rr.height;
11282				} else {
11283					b->y1 = rr.y - offset1;
11284					b->y2 = rr.y + rr.height + offset3;
11285				}
11286				b++;
11287			} else {
11288				b[0].x1 = rr.x - offset1;
11289				b[0].x2 = b[0].x1 + rr.width + offset2;
11290				b[0].y1 = rr.y - offset1;
11291				b[0].y2 = b[0].y1 + offset2;
11292
11293				b[1].x1 = rr.x - offset1;
11294				b[1].x2 = b[1].x1 + offset2;
11295				b[1].y1 = rr.y + offset3;
11296				b[1].y2 = rr.y + rr.height - offset1;
11297
11298				b[2] = b[1];
11299				b[2].x1 += rr.width;
11300				b[2].x2 += rr.width;
11301
11302				b[3] = b[0];
11303				b[3].y1 += rr.height;
11304				b[3].y2 += rr.height;
11305				b += 4;
11306			}
11307		} while (--n);
11308	}
11309	goto done;
11310
11311done:
11312	if (b != boxes) {
11313		fill.boxes(sna, &fill, boxes, b-boxes);
11314		if (damage)
11315			sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
11316	}
11317	fill.done(sna, &fill);
11318	assert_pixmap_damage(pixmap);
11319	return true;
11320}
11321
11322static void
11323sna_poly_rectangle(DrawablePtr drawable, GCPtr gc, int n, xRectangle *r)
11324{
11325	PixmapPtr pixmap = get_drawable_pixmap(drawable);
11326	struct sna *sna = to_sna_from_pixmap(pixmap);
11327	struct sna_damage **damage;
11328	struct kgem_bo *bo;
11329	RegionRec region;
11330	unsigned flags;
11331
11332	DBG(("%s(n=%d, first=((%d, %d)x(%d, %d)), lineWidth=%d\n",
11333	     __FUNCTION__,
11334	     n, r->x, r->y, r->width, r->height,
11335	     gc->lineWidth));
11336
11337	flags = sna_poly_rectangle_extents(drawable, gc, n, r, &region.extents);
11338	if (flags == 0)
11339		return;
11340
11341	DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
11342	     region.extents.x1, region.extents.y1,
11343	     region.extents.x2, region.extents.y2,
11344	     flags));
11345
11346	if (FORCE_FALLBACK)
11347		goto fallback;
11348
11349	if (!ACCEL_POLY_RECTANGLE)
11350		goto fallback;
11351
11352	if (wedged(sna)) {
11353		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
11354		goto fallback;
11355	}
11356
11357	DBG(("%s: fill=%d [%d], line=%d [%d], join=%d [%d], mask=%lu [%d]\n",
11358	     __FUNCTION__,
11359	     gc->fillStyle, gc->fillStyle == FillSolid,
11360	     gc->lineStyle, gc->lineStyle == LineSolid,
11361	     gc->joinStyle, gc->joinStyle == JoinMiter,
11362	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask)));
11363
11364	if (!PM_IS_SOLID(drawable, gc->planemask))
11365		goto fallback;
11366
11367	if (flags & 4 && gc->fillStyle == FillSolid && gc->lineStyle == LineSolid && gc->joinStyle == JoinMiter) {
11368		DBG(("%s: trying blt solid fill [%08lx] paths\n",
11369		     __FUNCTION__, gc->fgPixel));
11370		if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU,
11371					      &region.extents, &damage)) &&
11372		    sna_poly_rectangle_blt(drawable, bo, damage,
11373					   gc, n, r, &region.extents, flags&2))
11374			return;
11375	} else {
11376		/* Not a trivial outline, but we still maybe able to break it
11377		 * down into simpler operations that we can accelerate.
11378		 */
11379		if (sna_drawable_use_bo(drawable, PREFER_GPU,
11380					&region.extents, &damage)) {
11381			miPolyRectangle(drawable, gc, n, r);
11382			return;
11383		}
11384	}
11385
11386fallback:
11387	DBG(("%s: fallback, clip=%dx[(%d, %d), (%d, %d)]\n", __FUNCTION__,
11388	     region_num_rects(gc->pCompositeClip),
11389	     gc->pCompositeClip->extents.x1, gc->pCompositeClip->extents.y1,
11390	     gc->pCompositeClip->extents.x2, gc->pCompositeClip->extents.y2));
11391
11392	region.data = NULL;
11393	if (!region_maybe_clip(&region, gc->pCompositeClip))
11394		return;
11395
11396	DBG(("%s: CPU region=%dx[(%d, %d), (%d, %d)]\n", __FUNCTION__,
11397	     region_num_rects(&region),
11398	     region.extents.x1, region.extents.y1,
11399	     region.extents.x2, region.extents.y2));
11400	if (!sna_gc_move_to_cpu(gc, drawable, &region))
11401		goto out;
11402	if (!sna_drawable_move_region_to_cpu(drawable, &region,
11403					     drawable_gc_flags(drawable, gc, true)))
11404		goto out;
11405
11406	if (sigtrap_get() == 0) {
11407		DBG(("%s: miPolyRectangle\n", __FUNCTION__));
11408		miPolyRectangle(drawable, gc, n, r);
11409		FALLBACK_FLUSH(drawable);
11410		sigtrap_put();
11411	}
11412out:
11413	sna_gc_move_to_gpu(gc);
11414	RegionUninit(&region);
11415}
11416
11417static unsigned
11418sna_poly_arc_extents(DrawablePtr drawable, GCPtr gc,
11419		     int n, xArc *arc,
11420		     BoxPtr out)
11421{
11422	BoxRec box;
11423	bool clipped;
11424	int v;
11425
11426	if (n == 0)
11427		return 0;
11428
11429	box.x1 = arc->x;
11430	box.x2 = bound(box.x1, arc->width);
11431	box.y1 = arc->y;
11432	box.y2 = bound(box.y1, arc->height);
11433
11434	while (--n) {
11435		arc++;
11436		if (box.x1 > arc->x)
11437			box.x1 = arc->x;
11438		v = bound(arc->x, arc->width);
11439		if (box.x2 < v)
11440			box.x2 = v;
11441		if (box.y1 > arc->y)
11442			box.y1 = arc->y;
11443		v = bound(arc->y, arc->height);
11444		if (box.y2 < v)
11445			box.y2 = v;
11446	}
11447
11448	v = gc->lineWidth >> 1;
11449	if (v) {
11450		box.x1 -= v;
11451		box.x2 += v;
11452		box.y1 -= v;
11453		box.y2 += v;
11454	}
11455
11456	box.x2++;
11457	box.y2++;
11458
11459	clipped = trim_and_translate_box(&box, drawable, gc);
11460	if (box_empty(&box))
11461		return 0;
11462
11463	*out = box;
11464	return 1 | clipped << 1;
11465}
11466
11467static void
11468sna_poly_arc(DrawablePtr drawable, GCPtr gc, int n, xArc *arc)
11469{
11470	struct sna_fill_spans data;
11471	struct sna_pixmap *priv;
11472
11473	DBG(("%s(n=%d, lineWidth=%d\n", __FUNCTION__, n, gc->lineWidth));
11474
11475	data.flags = sna_poly_arc_extents(drawable, gc, n, arc,
11476					  &data.region.extents);
11477	if (data.flags == 0)
11478		return;
11479
11480	DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
11481	     data.region.extents.x1, data.region.extents.y1,
11482	     data.region.extents.x2, data.region.extents.y2,
11483	     data.flags));
11484
11485	data.region.data = NULL;
11486
11487	if (FORCE_FALLBACK)
11488		goto fallback;
11489
11490	if (!ACCEL_POLY_ARC)
11491		goto fallback;
11492
11493	data.pixmap = get_drawable_pixmap(drawable);
11494	data.sna = to_sna_from_pixmap(data.pixmap);
11495	priv = sna_pixmap(data.pixmap);
11496	if (priv == NULL) {
11497		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
11498		goto fallback;
11499	}
11500
11501	if (wedged(data.sna)) {
11502		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
11503		goto fallback;
11504	}
11505
11506	if (!PM_IS_SOLID(drawable, gc->planemask))
11507		goto fallback;
11508
11509	if ((data.bo = sna_drawable_use_bo(drawable,
11510					   use_wide_spans(drawable, gc, &data.region.extents),
11511					   &data.region.extents, &data.damage))) {
11512		uint32_t color;
11513
11514		DBG(("%s: converting arcs into spans\n", __FUNCTION__));
11515		get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy);
11516
11517		if (gc_is_solid(gc, &color)) {
11518			sna_gc(gc)->priv = &data;
11519
11520			assert(gc->miTranslate);
11521			if (gc->lineStyle == LineSolid) {
11522				struct sna_fill_op fill;
11523
11524				if (!sna_fill_init_blt(&fill,
11525						       data.sna, data.pixmap,
11526						       data.bo, gc->alu, color,
11527						       FILL_POINTS | FILL_SPANS))
11528					goto fallback;
11529
11530				if ((data.flags & 2) == 0) {
11531					if (data.dx | data.dy)
11532						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
11533					else
11534						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
11535					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill;
11536				} else {
11537					if (!region_maybe_clip(&data.region,
11538							       gc->pCompositeClip))
11539						return;
11540
11541					if (region_is_singular(&data.region)) {
11542						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
11543						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents;
11544					} else {
11545						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
11546						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes;
11547					}
11548				}
11549
11550				data.op = &fill;
11551				gc->ops = &sna_gc_ops__tmp;
11552				if (gc->lineWidth == 0)
11553					miZeroPolyArc(drawable, gc, n, arc);
11554				else
11555					miPolyArc(drawable, gc, n, arc);
11556				gc->ops = (GCOps *)&sna_gc_ops;
11557
11558				fill.done(data.sna, &fill);
11559			} else {
11560				if (!region_maybe_clip(&data.region,
11561						       gc->pCompositeClip))
11562					return;
11563
11564				sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
11565				sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu;
11566
11567				gc->ops = &sna_gc_ops__tmp;
11568				if (gc->lineWidth == 0)
11569					miZeroPolyArc(drawable, gc, n, arc);
11570				else
11571					miPolyArc(drawable, gc, n, arc);
11572				gc->ops = (GCOps *)&sna_gc_ops;
11573			}
11574
11575			if (data.damage) {
11576				if (data.dx | data.dy)
11577					pixman_region_translate(&data.region, data.dx, data.dy);
11578				assert_pixmap_contains_box(data.pixmap, &data.region.extents);
11579				sna_damage_add(data.damage, &data.region);
11580			}
11581			assert_pixmap_damage(data.pixmap);
11582			RegionUninit(&data.region);
11583			return;
11584		}
11585
11586		/* XXX still around 10x slower for x11perf -ellipse */
11587		if (gc->lineWidth == 0)
11588			miZeroPolyArc(drawable, gc, n, arc);
11589		else
11590			miPolyArc(drawable, gc, n, arc);
11591		return;
11592	}
11593
11594fallback:
11595	DBG(("%s -- fallback\n", __FUNCTION__));
11596	if (!region_maybe_clip(&data.region, gc->pCompositeClip))
11597		return;
11598
11599	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
11600		goto out;
11601	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
11602					     drawable_gc_flags(drawable, gc, true)))
11603		goto out;
11604
11605	if (sigtrap_get() == 0) {
11606		DBG(("%s -- fbPolyArc\n", __FUNCTION__));
11607		fbPolyArc(drawable, gc, n, arc);
11608		FALLBACK_FLUSH(drawable);
11609		sigtrap_put();
11610	}
11611out:
11612	sna_gc_move_to_gpu(gc);
11613	RegionUninit(&data.region);
11614}
11615
11616static bool
11617sna_poly_fill_rect_blt(DrawablePtr drawable,
11618		       struct kgem_bo *bo,
11619		       struct sna_damage **damage,
11620		       GCPtr gc, uint32_t pixel,
11621		       int n, const xRectangle *rect,
11622		       const BoxRec *extents,
11623		       bool clipped)
11624{
11625	PixmapPtr pixmap = get_drawable_pixmap(drawable);
11626	struct sna *sna = to_sna_from_pixmap(pixmap);
11627	struct sna_fill_op fill;
11628	BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes);
11629	int16_t dx, dy;
11630
11631	DBG(("%s pixmap=%ld x %d [(%d, %d)x(%d, %d)...]+(%d,%d), clipped?=%d\n",
11632	     __FUNCTION__, pixmap->drawable.serialNumber, n,
11633	     rect->x, rect->y, rect->width, rect->height,
11634	     drawable->x, drawable->y,
11635	     clipped));
11636
11637	if (n == 1 && region_is_singular(gc->pCompositeClip)) {
11638		BoxRec r;
11639		bool success = true;
11640
11641		r.x1 = rect->x + drawable->x;
11642		r.y1 = rect->y + drawable->y;
11643		r.x2 = bound(r.x1, rect->width);
11644		r.y2 = bound(r.y1, rect->height);
11645		if (box_intersect(&r, &gc->pCompositeClip->extents)) {
11646			if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
11647				r.x1 += dx; r.y1 += dy;
11648				r.x2 += dx; r.y2 += dy;
11649			}
11650			DBG(("%s: using fill_one() fast path: (%d, %d), (%d, %d). alu=%d, pixel=%08x\n",
11651			     __FUNCTION__, r.x1, r.y1, r.x2, r.y2, gc->alu, pixel));
11652
11653			if (sna->render.fill_one(sna, pixmap, bo, pixel,
11654						 r.x1, r.y1, r.x2, r.y2,
11655						 gc->alu)) {
11656				if (damage) {
11657					assert_pixmap_contains_box(pixmap, &r);
11658					if (r.x2 - r.x1 == pixmap->drawable.width &&
11659					    r.y2 - r.y1 == pixmap->drawable.height)
11660						sna_damage_all(damage, pixmap);
11661					else
11662						sna_damage_add_box(damage, &r);
11663				}
11664				assert_pixmap_damage(pixmap);
11665
11666				if (alu_overwrites(gc->alu) &&
11667				    r.x2 - r.x1 == pixmap->drawable.width &&
11668				    r.y2 - r.y1 == pixmap->drawable.height) {
11669					struct sna_pixmap *priv = sna_pixmap(pixmap);
11670					if (bo == priv->gpu_bo) {
11671						assert(priv->gpu_bo->proxy == NULL);
11672						sna_damage_all(&priv->gpu_damage, pixmap);
11673						sna_damage_destroy(&priv->cpu_damage);
11674						list_del(&priv->flush_list);
11675						priv->clear = true;
11676						priv->clear_color = gc->alu == GXcopyInverted ? ~pixel & ((1 << gc->depth) - 1) : pixel;
11677
11678						DBG(("%s: pixmap=%ld, marking clear [%08x]\n",
11679						     __FUNCTION__, pixmap->drawable.serialNumber, priv->clear_color));
11680					}
11681				}
11682			} else
11683				success = false;
11684		}
11685
11686		return success;
11687	}
11688
11689	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_BOXES)) {
11690		DBG(("%s: unsupported blt\n", __FUNCTION__));
11691		return false;
11692	}
11693
11694	get_drawable_deltas(drawable, pixmap, &dx, &dy);
11695	if (!clipped) {
11696		dx += drawable->x;
11697		dy += drawable->y;
11698
11699		sna_damage_add_rectangles(damage, rect, n, dx, dy);
11700		if (dx|dy) {
11701			do {
11702				unsigned nbox = n;
11703				if (nbox > ARRAY_SIZE(boxes))
11704					nbox = ARRAY_SIZE(boxes);
11705				n -= nbox;
11706				do {
11707					b->x1 = rect->x + dx;
11708					b->y1 = rect->y + dy;
11709					b->x2 = b->x1 + rect->width;
11710					b->y2 = b->y1 + rect->height;
11711					b++;
11712					rect++;
11713				} while (--nbox);
11714				fill.boxes(sna, &fill, boxes, b-boxes);
11715				b = boxes;
11716			} while (n);
11717		} else {
11718			do {
11719				unsigned nbox = n;
11720				if (nbox > ARRAY_SIZE(boxes))
11721					nbox = ARRAY_SIZE(boxes);
11722				n -= nbox;
11723				do {
11724					b->x1 = rect->x;
11725					b->y1 = rect->y;
11726					b->x2 = b->x1 + rect->width;
11727					b->y2 = b->y1 + rect->height;
11728					b++;
11729					rect++;
11730				} while (--nbox);
11731				fill.boxes(sna, &fill, boxes, b-boxes);
11732				b = boxes;
11733			} while (n);
11734		}
11735	} else {
11736		RegionRec clip;
11737
11738		region_set(&clip, extents);
11739		if (!region_maybe_clip(&clip, gc->pCompositeClip))
11740			goto done;
11741
11742		if (clip.data == NULL) {
11743			do {
11744				b->x1 = rect->x + drawable->x;
11745				b->y1 = rect->y + drawable->y;
11746				b->x2 = bound(b->x1, rect->width);
11747				b->y2 = bound(b->y1, rect->height);
11748				rect++;
11749
11750				if (box_intersect(b, &clip.extents)) {
11751					b->x1 += dx;
11752					b->x2 += dx;
11753					b->y1 += dy;
11754					b->y2 += dy;
11755					if (++b == last_box) {
11756						fill.boxes(sna, &fill, boxes, last_box-boxes);
11757						if (damage)
11758							sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11759						b = boxes;
11760					}
11761				}
11762			} while (--n);
11763		} else {
11764			const BoxRec * const clip_start = RegionBoxptr(&clip);
11765			const BoxRec * const clip_end = clip_start + clip.data->numRects;
11766			const BoxRec *c;
11767
11768			do {
11769				BoxRec box;
11770
11771				box.x1 = rect->x + drawable->x;
11772				box.y1 = rect->y + drawable->y;
11773				box.x2 = bound(box.x1, rect->width);
11774				box.y2 = bound(box.y1, rect->height);
11775				rect++;
11776
11777				c = find_clip_box_for_y(clip_start,
11778							clip_end,
11779							box.y1);
11780				while (c != clip_end) {
11781					if (box.y2 <= c->y1)
11782						break;
11783
11784					*b = box;
11785					if (box_intersect(b, c++)) {
11786						b->x1 += dx;
11787						b->x2 += dx;
11788						b->y1 += dy;
11789						b->y2 += dy;
11790						if (++b == last_box) {
11791							fill.boxes(sna, &fill, boxes, last_box-boxes);
11792							if (damage)
11793								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
11794							b = boxes;
11795						}
11796					}
11797
11798				}
11799			} while (--n);
11800		}
11801
11802		RegionUninit(&clip);
11803		if (b != boxes) {
11804			fill.boxes(sna, &fill, boxes, b-boxes);
11805			if (damage)
11806				sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
11807		}
11808	}
11809done:
11810	fill.done(sna, &fill);
11811	assert_pixmap_damage(pixmap);
11812	return true;
11813}
11814
11815static uint32_t
11816get_pixel(PixmapPtr pixmap)
11817{
11818	DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber));
11819	if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
11820		return 0;
11821
11822	switch (pixmap->drawable.bitsPerPixel) {
11823	case 32: return *(uint32_t *)pixmap->devPrivate.ptr;
11824	case 16: return *(uint16_t *)pixmap->devPrivate.ptr;
11825	default: return *(uint8_t *)pixmap->devPrivate.ptr;
11826	}
11827}
11828
11829static void
11830sna_poly_fill_polygon(DrawablePtr draw, GCPtr gc,
11831		      int shape, int mode,
11832		      int n, DDXPointPtr pt)
11833{
11834	struct sna_fill_spans data;
11835	struct sna_pixmap *priv;
11836
11837	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
11838	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
11839	     (gc->fillStyle == FillSolid ||
11840	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
11841	     gc->fillStyle, gc->tileIsPixel,
11842	     gc->alu));
11843	DBG(("%s: draw=%ld, offset=(%d, %d), size=%dx%d\n",
11844	     __FUNCTION__, draw->serialNumber,
11845	     draw->x, draw->y, draw->width, draw->height));
11846
11847	data.flags = sna_poly_point_extents(draw, gc, mode, n, pt,
11848					    &data.region.extents);
11849	if (data.flags == 0) {
11850		DBG(("%s, nothing to do\n", __FUNCTION__));
11851		return;
11852	}
11853
11854	DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
11855	     data.region.extents.x1, data.region.extents.y1,
11856	     data.region.extents.x2, data.region.extents.y2,
11857	     data.flags));
11858
11859	data.region.data = NULL;
11860
11861	if (FORCE_FALLBACK)
11862		goto fallback;
11863
11864	if (!ACCEL_POLY_FILL_POLYGON)
11865		goto fallback;
11866
11867	data.pixmap = get_drawable_pixmap(draw);
11868	data.sna = to_sna_from_pixmap(data.pixmap);
11869	priv = sna_pixmap(data.pixmap);
11870	if (priv == NULL) {
11871		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
11872		goto fallback;
11873	}
11874
11875	if (wedged(data.sna)) {
11876		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
11877		goto fallback;
11878	}
11879
11880	if (!PM_IS_SOLID(draw, gc->planemask))
11881		goto fallback;
11882
11883	if ((data.bo = sna_drawable_use_bo(draw,
11884					   (shape == Convex ? use_zero_spans : use_wide_spans)(draw, gc, &data.region.extents),
11885					   &data.region.extents,
11886					   &data.damage))) {
11887		uint32_t color;
11888
11889		sna_gc(gc)->priv = &data;
11890		get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy);
11891
11892		if (gc_is_solid(gc, &color)) {
11893			struct sna_fill_op fill;
11894
11895			if (!sna_fill_init_blt(&fill,
11896					       data.sna, data.pixmap,
11897					       data.bo, gc->alu, color,
11898					       FILL_SPANS))
11899				goto fallback;
11900
11901			data.op = &fill;
11902
11903			if ((data.flags & 2) == 0) {
11904				if (data.dx | data.dy)
11905					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
11906				else
11907					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
11908			} else {
11909				if (!region_maybe_clip(&data.region,
11910						       gc->pCompositeClip))
11911					return;
11912
11913				if (region_is_singular(&data.region))
11914					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
11915				else
11916					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
11917			}
11918			assert(gc->miTranslate);
11919			gc->ops = &sna_gc_ops__tmp;
11920
11921			miFillPolygon(draw, gc, shape, mode, n, pt);
11922			fill.done(data.sna, &fill);
11923		} else {
11924			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
11925			gc->ops = &sna_gc_ops__tmp;
11926
11927			miFillPolygon(draw, gc, shape, mode, n, pt);
11928		}
11929
11930		gc->ops = (GCOps *)&sna_gc_ops;
11931		if (data.damage) {
11932			if (data.dx | data.dy)
11933				pixman_region_translate(&data.region, data.dx, data.dy);
11934			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
11935			sna_damage_add(data.damage, &data.region);
11936		}
11937		assert_pixmap_damage(data.pixmap);
11938		RegionUninit(&data.region);
11939		return;
11940	}
11941
11942fallback:
11943	DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__,
11944	     data.region.extents.x1, data.region.extents.y1,
11945	     data.region.extents.x2, data.region.extents.y2));
11946	if (!region_maybe_clip(&data.region, gc->pCompositeClip)) {
11947		DBG(("%s: nothing to do, all clipped\n", __FUNCTION__));
11948		return;
11949	}
11950
11951	if (!sna_gc_move_to_cpu(gc, draw, &data.region))
11952		goto out;
11953	if (!sna_drawable_move_region_to_cpu(draw, &data.region,
11954					     drawable_gc_flags(draw, gc, true)))
11955		goto out;
11956
11957	if (sigtrap_get() == 0) {
11958		DBG(("%s: fallback -- miFillPolygon -> sna_fill_spans__cpu\n",
11959		     __FUNCTION__));
11960		miFillPolygon(draw, gc, shape, mode, n, pt);
11961		sigtrap_put();
11962	}
11963out:
11964	sna_gc_move_to_gpu(gc);
11965	RegionUninit(&data.region);
11966}
11967
11968static struct kgem_bo *
11969sna_pixmap_get_source_bo(PixmapPtr pixmap)
11970{
11971	struct sna_pixmap *priv = sna_pixmap(pixmap);
11972	unsigned flags;
11973	BoxRec box;
11974
11975	box.x1 = box.y1 = 0;
11976	box.x2 = pixmap->drawable.width;
11977	box.y2 = pixmap->drawable.height;
11978
11979	DBG(("%s(pixmap=%ld, size=%dx%d)\n", __FUNCTION__,
11980	     pixmap->drawable.serialNumber, pixmap->drawable.width, pixmap->drawable.height));
11981
11982	if (priv == NULL) {
11983		DBG(("%s: unattached, uploading data into temporary\n", __FUNCTION__));
11984		return kgem_upload_source_image(&to_sna_from_pixmap(pixmap)->kgem,
11985						pixmap->devPrivate.ptr, &box,
11986						pixmap->devKind,
11987						pixmap->drawable.bitsPerPixel);
11988	}
11989
11990	if (priv->gpu_damage) {
11991		if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT))
11992			return kgem_bo_reference(priv->gpu_bo);
11993	} else if (priv->cpu_damage) {
11994		if (priv->cpu_bo)
11995			return kgem_bo_reference(priv->cpu_bo);
11996	} else {
11997		if (priv->gpu_bo)
11998			return kgem_bo_reference(priv->gpu_bo);
11999		if (priv->cpu_bo)
12000			return kgem_bo_reference(priv->cpu_bo);
12001	}
12002
12003	flags = MOVE_READ | MOVE_ASYNC_HINT;
12004	if (priv->gpu_bo && priv->gpu_bo->proxy) {
12005		struct kgem_bo *bo = priv->gpu_bo;
12006		if (bo->rq == NULL && (bo->snoop || bo->pitch >= 4096))
12007			flags |= __MOVE_FORCE;
12008	}
12009	if (priv->gpu_bo == NULL) {
12010		if (++priv->source_count > SOURCE_BIAS)
12011			flags |= __MOVE_FORCE;
12012	}
12013
12014	if (!sna_pixmap_move_to_gpu(pixmap, flags)) {
12015		struct kgem_bo *upload;
12016
12017		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
12018			return NULL;
12019
12020		upload = kgem_upload_source_image(&to_sna_from_pixmap(pixmap)->kgem,
12021						  pixmap->devPrivate.ptr, &box,
12022						  pixmap->devKind,
12023						  pixmap->drawable.bitsPerPixel);
12024		if (upload == NULL)
12025			return NULL;
12026
12027		if (priv->gpu_bo == NULL) {
12028			DBG(("%s: adding upload cache to pixmap=%ld\n",
12029			     __FUNCTION__, pixmap->drawable.serialNumber));
12030			assert(upload->proxy != NULL);
12031			kgem_proxy_bo_attach(upload, &priv->gpu_bo);
12032		}
12033
12034		return upload;
12035	}
12036
12037	return kgem_bo_reference(priv->gpu_bo);
12038}
12039
12040/*
12041static bool
12042tile(DrawablePtr drawable,
12043	struct kgem_bo *bo, struct sna_damage **damage,
12044	PixmapPtr tile, const DDXPointRec * const origin, int alu,
12045	int n, xRectangle *rect,
12046	const BoxRec *extents, unsigned clipped)
12047	*/
12048
12049static bool
12050sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
12051				 struct kgem_bo *bo, struct sna_damage **damage,
12052				 struct kgem_bo *tile_bo, GCPtr gc,
12053				 int n, const xRectangle *r,
12054				 const BoxRec *extents, unsigned clipped)
12055{
12056	PixmapPtr pixmap = get_drawable_pixmap(drawable);
12057	struct sna *sna = to_sna_from_pixmap(pixmap);
12058	const DDXPointRec * const origin = &gc->patOrg;
12059	uint32_t br00, br13;
12060	int tx, ty;
12061	int16_t dx, dy;
12062	uint32_t *b;
12063
12064	if (NO_TILE_8x8)
12065		return false;
12066
12067	DBG(("%s x %d [(%d, %d)x(%d, %d)...], clipped=%x, origin=(%d, %d)\n",
12068	     __FUNCTION__, n, r->x, r->y, r->width, r->height, clipped, origin->x, origin->y));
12069
12070	DBG(("%s: tile_bo tiling=%d, pitch=%d\n", __FUNCTION__, tile_bo->tiling, tile_bo->pitch));
12071	if (tile_bo->tiling)
12072		return false;
12073
12074	assert(tile_bo->pitch == 8 * drawable->bitsPerPixel >> 3);
12075
12076	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
12077	if (!kgem_check_batch(&sna->kgem, 10+2*3) ||
12078	    !kgem_check_reloc(&sna->kgem, 2) ||
12079	    !kgem_check_many_bo_fenced(&sna->kgem, bo, tile_bo, NULL)) {
12080		kgem_submit(&sna->kgem);
12081		if (!kgem_check_many_bo_fenced(&sna->kgem, bo, tile_bo, NULL))
12082			return false;
12083		_kgem_set_mode(&sna->kgem, KGEM_BLT);
12084	}
12085
12086	get_drawable_deltas(drawable, pixmap, &dx, &dy);
12087	assert(extents->x1 + dx >= 0);
12088	assert(extents->y1 + dy >= 0);
12089	assert(extents->x2 + dx <= pixmap->drawable.width);
12090	assert(extents->y2 + dy <= pixmap->drawable.height);
12091
12092	br00 = XY_SCANLINE_BLT;
12093	tx = (-drawable->x - dx - origin->x) % 8;
12094	if (tx < 0)
12095		tx += 8;
12096	ty = (-drawable->y - dy - origin->y) % 8;
12097	if (ty < 0)
12098		ty += 8;
12099	br00 |= tx << 12 | ty << 8;
12100
12101	br13 = bo->pitch;
12102	if (sna->kgem.gen >= 040 && bo->tiling) {
12103		br00 |= BLT_DST_TILED;
12104		br13 >>= 2;
12105	}
12106	br13 |= blt_depth(drawable->depth) << 24;
12107	br13 |= fill_ROP[gc->alu] << 16;
12108
12109	if (!clipped) {
12110		dx += drawable->x;
12111		dy += drawable->y;
12112
12113		sna_damage_add_rectangles(damage, r, n, dx, dy);
12114		if (n == 1) {
12115			DBG(("%s: rect=(%d, %d)x(%d, %d) + (%d, %d), tile=(%d, %d)\n",
12116			     __FUNCTION__, r->x, r->y, r->width, r->height, dx, dy, tx, ty));
12117
12118			assert(r->x + dx >= 0);
12119			assert(r->y + dy >= 0);
12120			assert(r->x + dx + r->width  <= pixmap->drawable.width);
12121			assert(r->y + dy + r->height <= pixmap->drawable.height);
12122
12123			assert(sna->kgem.mode == KGEM_BLT);
12124			b = sna->kgem.batch + sna->kgem.nbatch;
12125			if (sna->kgem.gen >= 0100) {
12126				b[0] = XY_PAT_BLT | 3 << 20 | (br00 & 0x7f00) | 6;
12127				b[1] = br13;
12128				b[2] = (r->y + dy) << 16 | (r->x + dx);
12129				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
12130				*(uint64_t *)(b+4) =
12131					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12132							 I915_GEM_DOMAIN_RENDER << 16 |
12133							 I915_GEM_DOMAIN_RENDER |
12134							 KGEM_RELOC_FENCED,
12135							 0);
12136				*(uint64_t *)(b+6) =
12137					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, tile_bo,
12138							 I915_GEM_DOMAIN_RENDER << 16 |
12139							 KGEM_RELOC_FENCED,
12140							 0);
12141				sna->kgem.nbatch += 8;
12142			} else {
12143				b[0] = XY_PAT_BLT | 3 << 20 | (br00 & 0x7f00) | 4;
12144				b[1] = br13;
12145				b[2] = (r->y + dy) << 16 | (r->x + dx);
12146				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
12147				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12148						      I915_GEM_DOMAIN_RENDER << 16 |
12149						      I915_GEM_DOMAIN_RENDER |
12150						      KGEM_RELOC_FENCED,
12151						      0);
12152				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, tile_bo,
12153						      I915_GEM_DOMAIN_RENDER << 16 |
12154						      KGEM_RELOC_FENCED,
12155						      0);
12156				sna->kgem.nbatch += 6;
12157			}
12158		} else do {
12159			int n_this_time;
12160
12161			assert(sna->kgem.mode == KGEM_BLT);
12162			b = sna->kgem.batch + sna->kgem.nbatch;
12163			if (sna->kgem.gen >= 0100) {
12164				b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
12165				b[1] = br13;
12166				b[2] = 0;
12167				b[3] = 0;
12168				*(uint64_t *)(b+4) =
12169					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12170							 I915_GEM_DOMAIN_RENDER << 16 |
12171							 I915_GEM_DOMAIN_RENDER |
12172							 KGEM_RELOC_FENCED,
12173							 0);
12174				b[6] = gc->bgPixel;
12175				b[7] = gc->fgPixel;
12176				*(uint64_t *)(b+8) =
12177					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo,
12178							 I915_GEM_DOMAIN_RENDER << 16 |
12179							 KGEM_RELOC_FENCED,
12180							 0);
12181				sna->kgem.nbatch += 10;
12182			} else {
12183				b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6;
12184				b[1] = br13;
12185				b[2] = 0;
12186				b[3] = 0;
12187				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12188						      I915_GEM_DOMAIN_RENDER << 16 |
12189						      I915_GEM_DOMAIN_RENDER |
12190						      KGEM_RELOC_FENCED,
12191						      0);
12192				b[5] = gc->bgPixel;
12193				b[6] = gc->fgPixel;
12194				b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
12195						      I915_GEM_DOMAIN_RENDER << 16 |
12196						      KGEM_RELOC_FENCED,
12197						      0);
12198				sna->kgem.nbatch += 8;
12199			}
12200
12201			n_this_time = n;
12202			if (3*n_this_time > sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED)
12203				n_this_time = (sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED) / 3;
12204			assert(n_this_time);
12205			n -= n_this_time;
12206
12207			assert(sna->kgem.mode == KGEM_BLT);
12208			b = sna->kgem.batch + sna->kgem.nbatch;
12209			sna->kgem.nbatch += 3*n_this_time;
12210			do {
12211				assert(r->x + dx >= 0);
12212				assert(r->y + dy >= 0);
12213				assert(r->x + dx + r->width  <= pixmap->drawable.width);
12214				assert(r->y + dy + r->height <= pixmap->drawable.height);
12215
12216				b[0] = br00;
12217				b[1] = (r->y + dy) << 16 | (r->x + dx);
12218				b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
12219				b += 3; r++;
12220			} while (--n_this_time);
12221
12222			if (!n)
12223				break;
12224
12225			_kgem_submit(&sna->kgem);
12226			_kgem_set_mode(&sna->kgem, KGEM_BLT);
12227		} while (1);
12228	} else {
12229		RegionRec clip;
12230		uint16_t unwind_batch, unwind_reloc;
12231
12232		region_set(&clip, extents);
12233		if (!region_maybe_clip(&clip, gc->pCompositeClip))
12234			goto done;
12235
12236		unwind_batch = sna->kgem.nbatch;
12237		unwind_reloc = sna->kgem.nreloc;
12238
12239		assert(sna->kgem.mode == KGEM_BLT);
12240		b = sna->kgem.batch + sna->kgem.nbatch;
12241		if (sna->kgem.gen >= 0100) {
12242			b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
12243			b[1] = br13;
12244			b[2] = 0;
12245			b[3] = 0;
12246			*(uint64_t *)(b+4) =
12247				kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12248						 I915_GEM_DOMAIN_RENDER << 16 |
12249						 I915_GEM_DOMAIN_RENDER |
12250						 KGEM_RELOC_FENCED,
12251						 0);
12252			b[6] = gc->bgPixel;
12253			b[7] = gc->fgPixel;
12254			*(uint64_t *)(b+8) =
12255				kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo,
12256						 I915_GEM_DOMAIN_RENDER << 16 |
12257						 KGEM_RELOC_FENCED,
12258						 0);
12259			sna->kgem.nbatch += 10;
12260		} else {
12261			b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6;
12262			b[1] = br13;
12263			b[2] = 0;
12264			b[3] = 0;
12265			b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12266					      I915_GEM_DOMAIN_RENDER << 16 |
12267					      I915_GEM_DOMAIN_RENDER |
12268					      KGEM_RELOC_FENCED,
12269					      0);
12270			b[5] = gc->bgPixel;
12271			b[6] = gc->fgPixel;
12272			b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
12273					      I915_GEM_DOMAIN_RENDER << 16 |
12274					      KGEM_RELOC_FENCED,
12275					      0);
12276			sna->kgem.nbatch += 8;
12277		}
12278
12279		if (clip.data == NULL) {
12280			const BoxRec *c = &clip.extents;
12281			DBG(("%s: simple clip, %d boxes\n", __FUNCTION__, n));
12282			while (n--) {
12283				BoxRec box;
12284
12285				box.x1 = r->x + drawable->x;
12286				box.y1 = r->y + drawable->y;
12287				box.x2 = bound(box.x1, r->width);
12288				box.y2 = bound(box.y1, r->height);
12289				r++;
12290
12291				if (box_intersect(&box, c)) {
12292					if (!kgem_check_batch(&sna->kgem, 3)) {
12293						_kgem_submit(&sna->kgem);
12294						_kgem_set_mode(&sna->kgem, KGEM_BLT);
12295
12296						unwind_batch = sna->kgem.nbatch;
12297						unwind_reloc = sna->kgem.nreloc;
12298
12299						assert(sna->kgem.mode == KGEM_BLT);
12300						b = sna->kgem.batch + sna->kgem.nbatch;
12301						if (sna->kgem.gen >= 0100) {
12302							b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
12303							b[1] = br13;
12304							b[2] = 0;
12305							b[3] = 0;
12306							*(uint64_t *)(b+4) =
12307								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12308										 I915_GEM_DOMAIN_RENDER << 16 |
12309										 I915_GEM_DOMAIN_RENDER |
12310										 KGEM_RELOC_FENCED,
12311										 0);
12312							b[6] = gc->bgPixel;
12313							b[7] = gc->fgPixel;
12314							*(uint64_t *)(b+8) =
12315								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo,
12316										 I915_GEM_DOMAIN_RENDER << 16 |
12317										 KGEM_RELOC_FENCED,
12318										 0);
12319							sna->kgem.nbatch += 10;
12320						} else {
12321							b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6;
12322							b[1] = br13;
12323							b[2] = 0;
12324							b[3] = 0;
12325							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12326									      I915_GEM_DOMAIN_RENDER << 16 |
12327									      I915_GEM_DOMAIN_RENDER |
12328									      KGEM_RELOC_FENCED,
12329									      0);
12330							b[5] = gc->bgPixel;
12331							b[6] = gc->fgPixel;
12332							b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
12333									      I915_GEM_DOMAIN_RENDER << 16 |
12334									      KGEM_RELOC_FENCED,
12335									      0);
12336							sna->kgem.nbatch += 8;
12337						}
12338					}
12339
12340					assert(box.x1 + dx >= 0);
12341					assert(box.y1 + dy >= 0);
12342					assert(box.x2 + dx <= pixmap->drawable.width);
12343					assert(box.y2 + dy <= pixmap->drawable.height);
12344
12345					DBG(("%s: box=(%d, %d),(%d, %d) + (%d, %d), tile=(%d, %d)\n",
12346					     __FUNCTION__, box.x1, box.y1, box.x2, box.y2, dx, dy, tx, ty));
12347
12348					assert(sna->kgem.mode == KGEM_BLT);
12349					b = sna->kgem.batch + sna->kgem.nbatch;
12350					b[0] = br00;
12351					b[1] = (box.y1 + dy) << 16 | (box.x1 + dx);
12352					b[2] = (box.y2 + dy) << 16 | (box.x2 + dx);
12353					sna->kgem.nbatch += 3;
12354				}
12355			}
12356		} else {
12357			const BoxRec * const clip_start = RegionBoxptr(&clip);
12358			const BoxRec * const clip_end = clip_start + clip.data->numRects;
12359			const BoxRec *c;
12360
12361			DBG(("%s: complex clip (%ld cliprects), %d boxes\n", __FUNCTION__, (long)clip.data->numRects, n));
12362			do {
12363				BoxRec box;
12364
12365				box.x1 = r->x + drawable->x;
12366				box.y1 = r->y + drawable->y;
12367				box.x2 = bound(box.x1, r->width);
12368				box.y2 = bound(box.y1, r->height);
12369				DBG(("%s: rect=(%d, %d), (%d, %d), box=(%d, %d), (%d, %d)\n", __FUNCTION__,
12370				     r->x, r->y, r->width, r->height,
12371				     box.x1, box.y1, box.x2, box.y2));
12372				r++;
12373
12374				c = find_clip_box_for_y(clip_start,
12375							clip_end,
12376							box.y1);
12377				while (c != clip_end) {
12378					BoxRec bb;
12379
12380					DBG(("%s: clip=(%d, %d), (%d, %d)\n", __FUNCTION__, c->x1, c->y1, c->x2, c->y2));
12381
12382					if (box.y2 <= c->y1)
12383						break;
12384
12385					bb = box;
12386					if (box_intersect(&bb, c++)) {
12387						if (!kgem_check_batch(&sna->kgem, 3)) {
12388							DBG(("%s: emitting split batch\n", __FUNCTION__));
12389							_kgem_submit(&sna->kgem);
12390							_kgem_set_mode(&sna->kgem, KGEM_BLT);
12391
12392							unwind_batch = sna->kgem.nbatch;
12393							unwind_reloc = sna->kgem.nreloc;
12394
12395							assert(sna->kgem.mode == KGEM_BLT);
12396							b = sna->kgem.batch + sna->kgem.nbatch;
12397							if (sna->kgem.gen >= 0100) {
12398								b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
12399								b[1] = br13;
12400								b[2] = 0;
12401								b[3] = 0;
12402								*(uint64_t *)(b+4) =
12403									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
12404											 I915_GEM_DOMAIN_RENDER << 16 |
12405											 I915_GEM_DOMAIN_RENDER |
12406											 KGEM_RELOC_FENCED,
12407											 0);
12408								b[6] = gc->bgPixel;
12409								b[7] = gc->fgPixel;
12410								*(uint64_t *)(b+8) =
12411									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo,
12412											 I915_GEM_DOMAIN_RENDER << 16 |
12413											 KGEM_RELOC_FENCED,
12414											 0);
12415								sna->kgem.nbatch += 10;
12416							} else {
12417								b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6;
12418								b[1] = br13;
12419								b[2] = 0;
12420								b[3] = 0;
12421								b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
12422										      I915_GEM_DOMAIN_RENDER << 16 |
12423										      I915_GEM_DOMAIN_RENDER |
12424										      KGEM_RELOC_FENCED,
12425										      0);
12426								b[5] = gc->bgPixel;
12427								b[6] = gc->fgPixel;
12428								b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
12429										      I915_GEM_DOMAIN_RENDER << 16 |
12430										      KGEM_RELOC_FENCED,
12431										      0);
12432								sna->kgem.nbatch += 8;
12433							}
12434						}
12435
12436						assert(bb.x1 + dx >= 0);
12437						assert(bb.y1 + dy >= 0);
12438						assert(bb.x2 + dx <= pixmap->drawable.width);
12439						assert(bb.y2 + dy <= pixmap->drawable.height);
12440
12441						DBG(("%s: emit box=(%d, %d),(%d, %d) + (%d, %d), tile=(%d, %d) [relative to drawable: (%d, %d)]\n",
12442						     __FUNCTION__, bb.x1, bb.y1, bb.x2, bb.y2, dx, dy, tx, ty, bb.x1 - drawable->x, bb.y1 - drawable->y));
12443
12444						assert(sna->kgem.mode == KGEM_BLT);
12445						b = sna->kgem.batch + sna->kgem.nbatch;
12446						b[0] = br00;
12447						b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx);
12448						b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx);
12449						sna->kgem.nbatch += 3;
12450					}
12451				}
12452			} while (--n);
12453		}
12454
12455		if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) {
12456			sna->kgem.nbatch = unwind_batch;
12457			sna->kgem.nreloc = unwind_reloc;
12458			if (sna->kgem.nbatch == 0)
12459				kgem_bo_pair_undo(&sna->kgem, bo, tile_bo);
12460		}
12461	}
12462done:
12463	assert_pixmap_damage(pixmap);
12464	sna->blt_state.fill_bo = 0;
12465	return true;
12466}
12467
12468static bool tile8(int x)
12469{
12470	switch(x) {
12471	case 1:
12472	case 2:
12473	case 4:
12474	case 8:
12475		return true;
12476	default:
12477		return false;
12478	}
12479}
12480
12481static int next8(int x, int max)
12482{
12483	if (x > 2 && x <= 4)
12484		x = 4;
12485	else if (x < 8)
12486		x = 8;
12487	return MIN(x, max);
12488}
12489
12490static bool
12491sna_poly_fill_rect_tiled_nxm_blt(DrawablePtr drawable,
12492				 struct kgem_bo *bo,
12493				 struct sna_damage **damage,
12494				 GCPtr gc, int n, const xRectangle *rect,
12495				 const BoxRec *extents, unsigned clipped)
12496{
12497	PixmapPtr pixmap = get_drawable_pixmap(drawable);
12498	struct sna *sna = to_sna_from_pixmap(pixmap);
12499	PixmapPtr tile = gc->tile.pixmap;
12500	int w, h, tx, ty, tw, th, bpp = tile->drawable.bitsPerPixel;
12501	const DDXPointRec origin = gc->patOrg;
12502	struct kgem_bo *upload;
12503	bool ret = false;
12504	uint8_t *src;
12505	void *ptr;
12506
12507	tx = 0, tw = tile->drawable.width;
12508	if (!tile8(tw) && tw > extents->x2 - extents->x1) {
12509		tx = (extents->x1 - gc->patOrg.x - drawable->x) % tw;
12510		if (tx < 0)
12511			tx += tw;
12512		tw = next8(extents->x2 - extents->x1, tw);
12513		gc->patOrg.x = extents->x1 - drawable->x;
12514	}
12515
12516	ty = 0, th = tile->drawable.height;
12517	if (!tile8(th) && th > extents->y2 - extents->y1) {
12518		ty = (extents->y1 - gc->patOrg.y - drawable->y) % th;
12519		if (ty < 0)
12520			ty += th;
12521		th = next8(extents->y2 - extents->y1, th);
12522		gc->patOrg.y = extents->y1 - drawable->y;
12523	}
12524
12525	DBG(("%s: %dx%d+%d+%d (full tile size %dx%d)\n", __FUNCTION__,
12526	     tw, th, tx, ty, tile->drawable.width, tile->drawable.height));
12527	assert(tx < tile->drawable.width && tx >= 0);
12528	assert(ty < tile->drawable.height && ty >= 0);
12529	assert(tw && tw <= 8 && tw <= tile->drawable.width);
12530	assert(is_power_of_two(tw));
12531	assert(th && th <= 8 && th <= tile->drawable.height);
12532	assert(is_power_of_two(th));
12533
12534	if (!sna_pixmap_move_to_cpu(tile, MOVE_READ))
12535		goto out_gc;
12536
12537	assert(tile->devKind);
12538	assert(has_coherent_ptr(sna, sna_pixmap(tile), MOVE_READ));
12539
12540	src = tile->devPrivate.ptr;
12541	src += tile->devKind * ty;
12542	src += tx * bpp/8;
12543
12544	if ((tw | th) == 1) {
12545		uint32_t pixel;
12546		switch (bpp) {
12547			case 32: pixel = *(uint32_t *)src; break;
12548			case 16: pixel = *(uint16_t *)src; break;
12549			default: pixel = *(uint8_t *)src; break;
12550		}
12551		return sna_poly_fill_rect_blt(drawable, bo, damage,
12552					      gc, pixel, n, rect,
12553					      extents, clipped);
12554	}
12555
12556	upload = kgem_create_buffer(&sna->kgem, 8*bpp, KGEM_BUFFER_WRITE, &ptr);
12557	if (upload == NULL)
12558		goto out_gc;
12559
12560	upload->pitch = bpp; /* for sanity checks */
12561
12562	if (sigtrap_get() == 0) {
12563		uint8_t *dst = ptr;
12564		if (tx + tw > tile->drawable.width ||
12565		    ty + th > tile->drawable.height) {
12566			int sy = ty;
12567			src = tile->devPrivate.ptr;
12568			for (h = 0; h < th; h++) {
12569				int sx = tx;
12570				for (w = 0; w < tw; w++) {
12571					memcpy(dst + w*bpp/8, src + sy * tile->devKind + sx*bpp/8, bpp/8);
12572					if (++sx == tile->drawable.width)
12573						sx = 0;
12574				}
12575				w *= bpp/8;
12576				while (w < bpp) {
12577					memcpy(dst+w, dst, w);
12578					w *= 2;
12579				}
12580				if (++sy == tile->drawable.height)
12581					sy = 0;
12582				dst += bpp;
12583			}
12584			while (h < 8) {
12585				memcpy(dst, ptr, bpp*h);
12586				dst += bpp * h;
12587				h *= 2;
12588			}
12589		} else {
12590			for (h = 0; h < th; h++) {
12591				w = tw*bpp/8;
12592				memcpy(dst, src, w);
12593				while (w < bpp) {
12594					memcpy(dst+w, dst, w);
12595					w *= 2;
12596				}
12597				assert(w == bpp);
12598
12599				src += tile->devKind;
12600				dst += bpp;
12601			}
12602			while (h < 8) {
12603				memcpy(dst, ptr, bpp*h);
12604				dst += bpp * h;
12605				h *= 2;
12606			}
12607			assert(h == 8);
12608		}
12609
12610		ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage,
12611						       upload, gc, n, rect,
12612						       extents, clipped);
12613		sigtrap_put();
12614	}
12615
12616	kgem_bo_destroy(&sna->kgem, upload);
12617out_gc:
12618	gc->patOrg = origin;
12619	return ret;
12620}
12621
12622inline static bool tile_is_solid(GCPtr gc, uint32_t *pixel)
12623{
12624	PixmapPtr tile = gc->tile.pixmap;
12625	struct sna_pixmap *priv;
12626
12627	if ((tile->drawable.width | tile->drawable.height) == 1) {
12628		DBG(("%s: single pixel tile pixmap, converting to solid fill\n", __FUNCTION__));
12629		*pixel = get_pixel(tile);
12630		return true;
12631	}
12632
12633	priv = sna_pixmap(tile);
12634	if (priv == NULL || !priv->clear)
12635		return false;
12636
12637	DBG(("%s: tile is clear, converting to solid fill\n", __FUNCTION__));
12638	*pixel = priv->clear_color;
12639	return true;
12640}
12641
12642static bool
12643sna_poly_fill_rect_tiled_blt(DrawablePtr drawable,
12644			     struct kgem_bo *bo,
12645			     struct sna_damage **damage,
12646			     GCPtr gc, int n, xRectangle *rect,
12647			     const BoxRec *extents, unsigned clipped)
12648{
12649	PixmapPtr pixmap = get_drawable_pixmap(drawable);
12650	struct sna *sna = to_sna_from_pixmap(pixmap);
12651	PixmapPtr tile = gc->tile.pixmap;
12652	struct kgem_bo *tile_bo;
12653	const DDXPointRec * const origin = &gc->patOrg;
12654	struct sna_copy_op copy;
12655	CARD32 alu = gc->alu;
12656	int tile_width, tile_height;
12657	int16_t dx, dy;
12658	uint32_t pixel;
12659
12660	DBG(("%s pixmap=%ld, x %d [(%d, %d)x(%d, %d)...], clipped? %d\n",
12661	     __FUNCTION__, pixmap->drawable.serialNumber,
12662	     n, rect->x, rect->y, rect->width, rect->height,
12663	     clipped));
12664
12665	assert(tile->drawable.depth == drawable->depth);
12666	assert(bo);
12667
12668	if (tile_is_solid(gc, &pixel))
12669		return sna_poly_fill_rect_blt(drawable, bo, damage,
12670					      gc, pixel,
12671					      n, rect,
12672					      extents, clipped);
12673
12674	/* XXX [248]x[238] tiling can be reduced to a pattern fill.
12675	 * Also we can do the lg2 reduction for BLT and use repeat modes for
12676	 * RENDER.
12677	 */
12678
12679	tile_width = tile->drawable.width;
12680	tile_height = tile->drawable.height;
12681	if ((tile_width | tile_height) == 8) {
12682		bool ret;
12683
12684		DBG(("%s: have 8x8 tile, using BLT fast path\n", __FUNCTION__));
12685
12686		tile_bo = sna_pixmap_get_source_bo(tile);
12687		if (tile_bo == NULL) {
12688			DBG(("%s: unable to move tile go GPU, fallback\n",
12689			     __FUNCTION__));
12690			return false;
12691		}
12692
12693		ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage,
12694						       tile_bo, gc, n, rect,
12695						       extents, clipped);
12696		if (ret) {
12697			kgem_bo_destroy(&sna->kgem, tile_bo);
12698			return true;
12699		}
12700	} else {
12701		int w = tile_width, h = tile_height;
12702		struct sna_pixmap *priv = sna_pixmap(tile);
12703
12704		if (priv == NULL || priv->gpu_damage == NULL) {
12705			w = next8(extents->x2 - extents->x1, w);
12706			h = next8(extents->y2 - extents->y1, h);
12707		}
12708
12709		DBG(("%s: not 8x8, triming size for tile: %dx%d from %dx%d (area %dx%d)\n",
12710		     __FUNCTION__, w, h, tile_width, tile_height, extents->x2-extents->x1, extents->y2-extents->y1));
12711
12712		if ((w|h) < 0x10 && is_power_of_two(w) && is_power_of_two(h) &&
12713		    sna_poly_fill_rect_tiled_nxm_blt(drawable, bo, damage,
12714						     gc, n, rect,
12715						     extents, clipped))
12716			return true;
12717
12718		tile_bo = sna_pixmap_get_source_bo(tile);
12719		if (tile_bo == NULL) {
12720			DBG(("%s: unable to move tile go GPU, fallback\n",
12721						__FUNCTION__));
12722			return false;
12723		}
12724	}
12725
12726	if (!sna_copy_init_blt(&copy, sna, tile, tile_bo, pixmap, bo, alu)) {
12727		DBG(("%s: unsupported blt\n", __FUNCTION__));
12728		kgem_bo_destroy(&sna->kgem, tile_bo);
12729		return false;
12730	}
12731
12732	get_drawable_deltas(drawable, pixmap, &dx, &dy);
12733	DBG(("%s: drawable offset into pixmap(%ld) = (%d, %d)\n",
12734	     __FUNCTION__, pixmap->drawable.serialNumber, dx, dy));
12735	if (!clipped) {
12736		dx += drawable->x;
12737		dy += drawable->y;
12738
12739		sna_damage_add_rectangles(damage, rect, n, dx, dy);
12740		do {
12741			xRectangle r = *rect++;
12742			int16_t tile_y = (r.y - origin->y) % tile_height;
12743			if (tile_y < 0)
12744				tile_y += tile_height;
12745
12746			assert(r.x + dx >= 0);
12747			assert(r.y + dy >= 0);
12748			assert(r.x + dx + r.width  <= pixmap->drawable.width);
12749			assert(r.y + dy + r.height <= pixmap->drawable.height);
12750
12751			r.y += dy;
12752			do {
12753				int16_t width = r.width;
12754				int16_t x = r.x + dx, tile_x;
12755				int16_t h = tile_height - tile_y;
12756				if (h > r.height)
12757					h = r.height;
12758				r.height -= h;
12759
12760				tile_x = (r.x - origin->x) % tile_width;
12761				if (tile_x < 0)
12762					tile_x += tile_width;
12763
12764				do {
12765					int16_t w = tile_width - tile_x;
12766					if (w > width)
12767						w = width;
12768					width -= w;
12769
12770					copy.blt(sna, &copy,
12771						 tile_x, tile_y,
12772						 w, h,
12773						 x, r.y);
12774
12775					x += w;
12776					tile_x = 0;
12777				} while (width);
12778				r.y += h;
12779				tile_y = 0;
12780			} while (r.height);
12781		} while (--n);
12782	} else {
12783		RegionRec clip;
12784
12785		region_set(&clip, extents);
12786		if (!region_maybe_clip(&clip, gc->pCompositeClip))
12787			goto done;
12788
12789		if (clip.data == NULL) {
12790			const BoxRec *box = &clip.extents;
12791			DBG(("%s: single clip box [(%d, %d), (%d, %d)]\n",
12792			     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
12793			while (n--) {
12794				BoxRec r;
12795
12796				r.x1 = rect->x + drawable->x;
12797				r.y1 = rect->y + drawable->y;
12798				r.x2 = bound(r.x1, rect->width);
12799				r.y2 = bound(r.y1, rect->height);
12800				rect++;
12801
12802				DBG(("%s: rectangle [(%d, %d), (%d, %d)]\n",
12803				     __FUNCTION__, r.x1, r.y1, r.x2, r.y2));
12804
12805				if (box_intersect(&r, box)) {
12806					int height = r.y2 - r.y1;
12807					int dst_y = r.y1;
12808					int tile_y = (r.y1 - drawable->y - origin->y) % tile_height;
12809					if (tile_y < 0)
12810						tile_y += tile_height;
12811
12812					assert(r.x1 + dx >= 0);
12813					assert(r.y1 + dy >= 0);
12814					assert(r.x2 + dx <= pixmap->drawable.width);
12815					assert(r.y2 + dy <= pixmap->drawable.height);
12816
12817					while (height) {
12818						int width = r.x2 - r.x1;
12819						int dst_x = r.x1, tile_x;
12820						int h = tile_height - tile_y;
12821						if (h > height)
12822							h = height;
12823						height -= h;
12824
12825						tile_x = (r.x1 - drawable->x - origin->x) % tile_width;
12826						if (tile_x < 0)
12827							tile_x += tile_width;
12828
12829						while (width > 0) {
12830							int w = tile_width - tile_x;
12831							if (w > width)
12832								w = width;
12833							width -= w;
12834
12835							copy.blt(sna, &copy,
12836								 tile_x, tile_y,
12837								 w, h,
12838								 dst_x + dx, dst_y + dy);
12839							if (damage) {
12840								BoxRec b;
12841
12842								b.x1 = dst_x + dx;
12843								b.y1 = dst_y + dy;
12844								b.x2 = b.x1 + w;
12845								b.y2 = b.y1 + h;
12846
12847								assert_pixmap_contains_box(pixmap, &b);
12848								sna_damage_add_box(damage, &b);
12849							}
12850
12851							dst_x += w;
12852							tile_x = 0;
12853						}
12854						dst_y += h;
12855						tile_y = 0;
12856					}
12857				}
12858			}
12859		} else {
12860			while (n--) {
12861				RegionRec region;
12862				const BoxRec *box;
12863				int nbox;
12864
12865				region.extents.x1 = rect->x + drawable->x;
12866				region.extents.y1 = rect->y + drawable->y;
12867				region.extents.x2 = bound(region.extents.x1, rect->width);
12868				region.extents.y2 = bound(region.extents.y1, rect->height);
12869				rect++;
12870
12871				DBG(("%s: rectangle [(%d, %d), (%d, %d)]\n",
12872				     __FUNCTION__,
12873				     region.extents.x1,
12874				     region.extents.y1,
12875				     region.extents.x2,
12876				     region.extents.y2));
12877
12878				region.data = NULL;
12879				RegionIntersect(&region, &region, &clip);
12880
12881				assert(region.extents.x1 + dx >= 0);
12882				assert(region.extents.y1 + dy >= 0);
12883				assert(region.extents.x2 + dx <= pixmap->drawable.width);
12884				assert(region.extents.y2 + dy <= pixmap->drawable.height);
12885
12886				nbox = region_num_rects(&region);
12887				box = region_rects(&region);
12888				DBG(("%s: split into %d boxes after clipping\n", __FUNCTION__, nbox));
12889				while (nbox--) {
12890					int height = box->y2 - box->y1;
12891					int dst_y = box->y1;
12892					int tile_y = (box->y1 - drawable->y - origin->y) % tile_height;
12893					if (tile_y < 0)
12894						tile_y += tile_height;
12895
12896					while (height) {
12897						int width = box->x2 - box->x1;
12898						int dst_x = box->x1, tile_x;
12899						int h = tile_height - tile_y;
12900						if (h > height)
12901							h = height;
12902						height -= h;
12903
12904						tile_x = (box->x1 - drawable->x - origin->x) % tile_width;
12905						if (tile_x < 0)
12906							tile_x += tile_width;
12907
12908						while (width > 0) {
12909							int w = tile_width - tile_x;
12910							if (w > width)
12911								w = width;
12912							width -= w;
12913
12914							copy.blt(sna, &copy,
12915								 tile_x, tile_y,
12916								 w, h,
12917								 dst_x + dx, dst_y + dy);
12918							if (damage) {
12919								BoxRec b;
12920
12921								b.x1 = dst_x + dx;
12922								b.y1 = dst_y + dy;
12923								b.x2 = b.x1 + w;
12924								b.y2 = b.y1 + h;
12925
12926								assert_pixmap_contains_box(pixmap, &b);
12927								sna_damage_add_box(damage, &b);
12928							}
12929
12930							dst_x += w;
12931							tile_x = 0;
12932						}
12933						dst_y += h;
12934						tile_y = 0;
12935					}
12936					box++;
12937				}
12938
12939				RegionUninit(&region);
12940			}
12941		}
12942
12943		RegionUninit(&clip);
12944	}
12945done:
12946	copy.done(sna, &copy);
12947	assert_pixmap_damage(pixmap);
12948	kgem_bo_destroy(&sna->kgem, tile_bo);
12949	return true;
12950}
12951
12952static bool
12953sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
12954				    struct kgem_bo *bo,
12955				    struct sna_damage **damage,
12956				    GCPtr gc, int n, xRectangle *r,
12957				    const BoxRec *extents, unsigned clipped)
12958{
12959	PixmapPtr pixmap = get_drawable_pixmap(drawable);
12960	struct sna *sna = to_sna_from_pixmap(pixmap);
12961	uint32_t pat[2] = {0, 0}, br00, br13;
12962	int16_t dx, dy;
12963	uint32_t *b;
12964
12965	if (NO_STIPPLE_8x8)
12966		return false;
12967
12968	DBG(("%s: alu=%d, upload (%d, %d), (%d, %d), origin (%d, %d)\n",
12969	     __FUNCTION__, gc->alu,
12970	     extents->x1, extents->y1,
12971	     extents->x2, extents->y2,
12972	     gc->patOrg.x, gc->patOrg.y));
12973
12974	get_drawable_deltas(drawable, pixmap, &dx, &dy);
12975	{
12976		int px, py;
12977
12978		px = (0 - gc->patOrg.x - drawable->x - dx) % 8;
12979		if (px < 0)
12980			px += 8;
12981
12982		py = (0 - gc->patOrg.y - drawable->y - dy) % 8;
12983		if (py < 0)
12984			py += 8;
12985		DBG(("%s: pat offset (%d, %d)\n", __FUNCTION__ ,px, py));
12986
12987		br00 = XY_SCANLINE_BLT | px << 12 | py << 8 | 3 << 20;
12988		br13 = bo->pitch;
12989		if (sna->kgem.gen >= 040 && bo->tiling) {
12990			br00 |= BLT_DST_TILED;
12991			br13 >>= 2;
12992		}
12993		br13 |= (gc->fillStyle == FillStippled) << 28;
12994		br13 |= blt_depth(drawable->depth) << 24;
12995		br13 |= fill_ROP[gc->alu] << 16;
12996	}
12997
12998	assert(gc->stipple->devKind);
12999	{
13000		uint8_t *dst = (uint8_t *)pat;
13001		const uint8_t *src = gc->stipple->devPrivate.ptr;
13002		int stride = gc->stipple->devKind;
13003		int j = gc->stipple->drawable.height;
13004		do {
13005			*dst++ = byte_reverse(*src);
13006			src += stride;
13007		} while (--j);
13008	}
13009
13010	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
13011	if (!kgem_check_batch(&sna->kgem, 10 + 2*3) ||
13012	    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13013	    !kgem_check_reloc(&sna->kgem, 1)) {
13014		kgem_submit(&sna->kgem);
13015		if (!kgem_check_bo_fenced(&sna->kgem, bo))
13016			return false;
13017		_kgem_set_mode(&sna->kgem, KGEM_BLT);
13018	}
13019
13020	if (!clipped) {
13021		dx += drawable->x;
13022		dy += drawable->y;
13023
13024		sna_damage_add_rectangles(damage, r, n, dx, dy);
13025		if (n == 1) {
13026			DBG(("%s: single unclipped rect (%d, %d)x(%d, %d)\n",
13027			     __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height));
13028
13029			assert(sna->kgem.mode == KGEM_BLT);
13030			b = sna->kgem.batch + sna->kgem.nbatch;
13031			if (sna->kgem.gen >= 0100) {
13032				b[0] = XY_MONO_PAT | (br00 & 0x7f00) | 3<<20 | 8;
13033				b[1] = br13;
13034				b[2] = (r->y + dy) << 16 | (r->x + dx);
13035				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13036				*(uint64_t *)(b+4) =
13037					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13038							 I915_GEM_DOMAIN_RENDER << 16 |
13039							 I915_GEM_DOMAIN_RENDER |
13040							 KGEM_RELOC_FENCED,
13041							 0);
13042				b[6] = gc->bgPixel;
13043				b[7] = gc->fgPixel;
13044				b[8] = pat[0];
13045				b[9] = pat[1];
13046				sna->kgem.nbatch += 10;
13047			} else {
13048				b[0] = XY_MONO_PAT | (br00 & 0x7f00) | 3<<20 | 7;
13049				b[1] = br13;
13050				b[2] = (r->y + dy) << 16 | (r->x + dx);
13051				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13052				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13053						      I915_GEM_DOMAIN_RENDER << 16 |
13054						      I915_GEM_DOMAIN_RENDER |
13055						      KGEM_RELOC_FENCED,
13056						      0);
13057				b[5] = gc->bgPixel;
13058				b[6] = gc->fgPixel;
13059				b[7] = pat[0];
13060				b[8] = pat[1];
13061				sna->kgem.nbatch += 9;
13062			}
13063		} else do {
13064			int n_this_time;
13065
13066			assert(sna->kgem.mode == KGEM_BLT);
13067			b = sna->kgem.batch + sna->kgem.nbatch;
13068			if (sna->kgem.gen >= 0100) {
13069				b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
13070				b[1] = br13;
13071				b[2] = 0;
13072				b[3] = 0;
13073				*(uint64_t *)(b+4) =
13074					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13075							 I915_GEM_DOMAIN_RENDER << 16 |
13076							 I915_GEM_DOMAIN_RENDER |
13077							 KGEM_RELOC_FENCED,
13078							 0);
13079				b[6] = gc->bgPixel;
13080				b[7] = gc->fgPixel;
13081				b[8] = pat[0];
13082				b[9] = pat[1];
13083				sna->kgem.nbatch += 10;
13084			} else {
13085				b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7;
13086				b[1] = br13;
13087				b[2] = 0;
13088				b[3] = 0;
13089				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13090						      I915_GEM_DOMAIN_RENDER << 16 |
13091						      I915_GEM_DOMAIN_RENDER |
13092						      KGEM_RELOC_FENCED,
13093						      0);
13094				b[5] = gc->bgPixel;
13095				b[6] = gc->fgPixel;
13096				b[7] = pat[0];
13097				b[8] = pat[1];
13098				sna->kgem.nbatch += 9;
13099			}
13100
13101			n_this_time = n;
13102			if (3*n_this_time > sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED)
13103				n_this_time = (sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED) / 3;
13104			assert(n_this_time);
13105			n -= n_this_time;
13106
13107			assert(sna->kgem.mode == KGEM_BLT);
13108			b = sna->kgem.batch + sna->kgem.nbatch;
13109			sna->kgem.nbatch += 3 * n_this_time;
13110			do {
13111				DBG(("%s: rect (%d, %d)x(%d, %d)\n",
13112				     __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height));
13113				assert(r->x + dx >= 0);
13114				assert(r->y + dy >= 0);
13115				assert(r->x + dx + r->width  <= pixmap->drawable.width);
13116				assert(r->y + dy + r->height <= pixmap->drawable.height);
13117
13118				b[0] = br00;
13119				b[1] = (r->y + dy) << 16 | (r->x + dx);
13120				b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13121
13122				b += 3; r++;
13123			} while(--n_this_time);
13124
13125			if (!n)
13126				break;
13127
13128			_kgem_submit(&sna->kgem);
13129			_kgem_set_mode(&sna->kgem, KGEM_BLT);
13130		} while (1);
13131	} else {
13132		RegionRec clip;
13133
13134		region_set(&clip, extents);
13135		if (!region_maybe_clip(&clip, gc->pCompositeClip))
13136			return true;
13137
13138		assert(sna->kgem.mode == KGEM_BLT);
13139		b = sna->kgem.batch + sna->kgem.nbatch;
13140		if (sna->kgem.gen >= 0100) {
13141			b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
13142			b[1] = br13;
13143			b[2] = 0;
13144			b[3] = 0;
13145			*(uint64_t *)(b+4) =
13146				kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13147						 I915_GEM_DOMAIN_RENDER << 16 |
13148						 I915_GEM_DOMAIN_RENDER |
13149						 KGEM_RELOC_FENCED,
13150						 0);
13151			b[6] = gc->bgPixel;
13152			b[7] = gc->fgPixel;
13153			b[8] = pat[0];
13154			b[9] = pat[1];
13155			sna->kgem.nbatch += 10;
13156		} else {
13157			b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7;
13158			b[1] = br13;
13159			b[2] = 0;
13160			b[3] = 0;
13161			b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13162					      I915_GEM_DOMAIN_RENDER << 16 |
13163					      I915_GEM_DOMAIN_RENDER |
13164					      KGEM_RELOC_FENCED,
13165					      0);
13166			b[5] = gc->bgPixel;
13167			b[6] = gc->fgPixel;
13168			b[7] = pat[0];
13169			b[8] = pat[1];
13170			sna->kgem.nbatch += 9;
13171		}
13172
13173		if (clip.data == NULL) {
13174			do {
13175				BoxRec box;
13176
13177				box.x1 = r->x + drawable->x;
13178				box.y1 = r->y + drawable->y;
13179				box.x2 = bound(box.x1, r->width);
13180				box.y2 = bound(box.y1, r->height);
13181				r++;
13182
13183				if (box_intersect(&box, &clip.extents)) {
13184					if (!kgem_check_batch(&sna->kgem, 3)) {
13185						_kgem_submit(&sna->kgem);
13186						_kgem_set_mode(&sna->kgem, KGEM_BLT);
13187
13188						assert(sna->kgem.mode == KGEM_BLT);
13189						b = sna->kgem.batch + sna->kgem.nbatch;
13190						if (sna->kgem.gen >= 0100) {
13191							b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
13192							b[1] = br13;
13193							b[2] = 0;
13194							b[3] = 0;
13195							*(uint64_t *)(b+4) =
13196								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13197										 I915_GEM_DOMAIN_RENDER << 16 |
13198										 I915_GEM_DOMAIN_RENDER |
13199										 KGEM_RELOC_FENCED,
13200										 0);
13201							b[6] = gc->bgPixel;
13202							b[7] = gc->fgPixel;
13203							b[8] = pat[0];
13204							b[9] = pat[1];
13205							sna->kgem.nbatch += 10;
13206						} else {
13207							b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7;
13208							b[1] = br13;
13209							b[2] = 0;
13210							b[3] = 0;
13211							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13212									      I915_GEM_DOMAIN_RENDER << 16 |
13213									      I915_GEM_DOMAIN_RENDER |
13214									      KGEM_RELOC_FENCED,
13215									      0);
13216							b[5] = gc->bgPixel;
13217							b[6] = gc->fgPixel;
13218							b[7] = pat[0];
13219							b[8] = pat[1];
13220							sna->kgem.nbatch += 9;
13221						}
13222					}
13223
13224					assert(sna->kgem.mode == KGEM_BLT);
13225					b = sna->kgem.batch + sna->kgem.nbatch;
13226					sna->kgem.nbatch += 3;
13227					b[0] = br00;
13228					b[1] = (box.y1 + dy) << 16 | (box.x1 + dx);
13229					b[2] = (box.y2 + dy) << 16 | (box.x2 + dx);
13230				}
13231			} while (--n);
13232		} else {
13233			const BoxRec * const clip_start = RegionBoxptr(&clip);
13234			const BoxRec * const clip_end = clip_start + clip.data->numRects;
13235			const BoxRec *c;
13236
13237			do {
13238				BoxRec box;
13239
13240				box.x1 = r->x + drawable->x;
13241				box.y1 = r->y + drawable->y;
13242				box.x2 = bound(box.x1, r->width);
13243				box.y2 = bound(box.y1, r->height);
13244				r++;
13245
13246				c = find_clip_box_for_y(clip_start,
13247							clip_end,
13248							box.y1);
13249				while (c != clip_end) {
13250					BoxRec bb;
13251					if (box.y2 <= c->y1)
13252						break;
13253
13254					bb = box;
13255					if (box_intersect(&bb, c++)) {
13256						if (!kgem_check_batch(&sna->kgem, 3)) {
13257							_kgem_submit(&sna->kgem);
13258							_kgem_set_mode(&sna->kgem, KGEM_BLT);
13259
13260							assert(sna->kgem.mode == KGEM_BLT);
13261							b = sna->kgem.batch + sna->kgem.nbatch;
13262							if (sna->kgem.gen >= 0100) {
13263								b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8;
13264								b[1] = br13;
13265								b[2] = 0;
13266								b[3] = 0;
13267								*(uint64_t *)(b+4) =
13268									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13269											 I915_GEM_DOMAIN_RENDER << 16 |
13270											 I915_GEM_DOMAIN_RENDER |
13271											 KGEM_RELOC_FENCED,
13272											 0);
13273								b[6] = gc->bgPixel;
13274								b[7] = gc->fgPixel;
13275								b[8] = pat[0];
13276								b[9] = pat[1];
13277								sna->kgem.nbatch += 10;
13278							} else {
13279								b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7;
13280								b[1] = br13;
13281								b[2] = 0;
13282								b[3] = 0;
13283								b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13284										      I915_GEM_DOMAIN_RENDER << 16 |
13285										      I915_GEM_DOMAIN_RENDER |
13286										      KGEM_RELOC_FENCED,
13287										      0);
13288								b[5] = gc->bgPixel;
13289								b[6] = gc->fgPixel;
13290								b[7] = pat[0];
13291								b[8] = pat[1];
13292								sna->kgem.nbatch += 9;
13293							}
13294						}
13295
13296						assert(sna->kgem.mode == KGEM_BLT);
13297						b = sna->kgem.batch + sna->kgem.nbatch;
13298						sna->kgem.nbatch += 3;
13299						b[0] = br00;
13300						b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx);
13301						b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx);
13302					}
13303				}
13304			} while (--n);
13305		}
13306	}
13307
13308	assert_pixmap_damage(pixmap);
13309	sna->blt_state.fill_bo = 0;
13310	return true;
13311}
13312
13313static bool
13314sna_poly_fill_rect_stippled_nxm_blt(DrawablePtr drawable,
13315				    struct kgem_bo *bo,
13316				    struct sna_damage **damage,
13317				    GCPtr gc, int n, xRectangle *r,
13318				    const BoxRec *extents, unsigned clipped)
13319{
13320	PixmapPtr scratch, stipple;
13321	uint8_t bytes[8], *dst = bytes;
13322	const uint8_t *src, *end;
13323	int j, stride;
13324	bool ret;
13325
13326	DBG(("%s: expanding %dx%d stipple to 8x8\n",
13327	     __FUNCTION__,
13328	     gc->stipple->drawable.width,
13329	     gc->stipple->drawable.height));
13330
13331	scratch = GetScratchPixmapHeader(drawable->pScreen,
13332					 8, 8, 1, 1, 1, bytes);
13333	if (scratch == NullPixmap)
13334		return false;
13335
13336	stipple = gc->stipple;
13337	gc->stipple = scratch;
13338
13339	assert(stipple->devKind);
13340	stride = stipple->devKind;
13341	src = stipple->devPrivate.ptr;
13342	end = src + stride * stipple->drawable.height;
13343	for(j = 0; j < 8; j++) {
13344		switch (stipple->drawable.width) {
13345		case 1: *dst = (*src & 1) * 0xff; break;
13346		case 2: *dst = (*src & 3) * 0x55; break;
13347		case 4: *dst = (*src & 15) * 0x11; break;
13348		case 8: *dst = *src; break;
13349		default: assert(0); break;
13350		}
13351		dst++;
13352		src += stride;
13353		if (src == end)
13354			src = stipple->devPrivate.ptr;
13355	}
13356
13357	ret = sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage,
13358						  gc, n, r, extents, clipped);
13359
13360	gc->stipple = stipple;
13361	FreeScratchPixmapHeader(scratch);
13362
13363	return ret;
13364}
13365
13366static bool
13367sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
13368				  struct kgem_bo *bo,
13369				  struct sna_damage **damage,
13370				  GCPtr gc, int n, xRectangle *r,
13371				  const BoxRec *extents, unsigned clipped)
13372{
13373	PixmapPtr pixmap = get_drawable_pixmap(drawable);
13374	struct sna *sna = to_sna_from_pixmap(pixmap);
13375	PixmapPtr stipple = gc->stipple;
13376	const DDXPointRec *origin = &gc->patOrg;
13377	int16_t dx, dy;
13378	uint32_t br00, br13;
13379
13380	DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%x\n", __FUNCTION__,
13381	     extents->x1, extents->y1,
13382	     extents->x2, extents->y2,
13383	     origin->x, origin->y,
13384	     clipped));
13385
13386	get_drawable_deltas(drawable, pixmap, &dx, &dy);
13387	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
13388
13389	br00 = 3 << 20;
13390	br13 = bo->pitch;
13391	if (sna->kgem.gen >= 040 && bo->tiling) {
13392		br00 |= BLT_DST_TILED;
13393		br13 >>= 2;
13394	}
13395	br13 |= (gc->fillStyle == FillStippled) << 29;
13396	br13 |= blt_depth(drawable->depth) << 24;
13397	br13 |= copy_ROP[gc->alu] << 16;
13398
13399	if (!clipped) {
13400		dx += drawable->x;
13401		dy += drawable->y;
13402
13403		sna_damage_add_rectangles(damage, r, n, dx, dy);
13404		do {
13405			int bx1 = (r->x - origin->x) & ~7;
13406			int bx2 = (r->x + r->width - origin->x + 7) & ~7;
13407			int bw = (bx2 - bx1)/8;
13408			int bh = r->height;
13409			int bstride = ALIGN(bw, 2);
13410			int src_stride;
13411			uint8_t *dst, *src;
13412			uint32_t *b;
13413
13414			DBG(("%s: rect (%d, %d)x(%d, %d) stipple [%d,%d]\n",
13415			     __FUNCTION__,
13416			     r->x, r->y, r->width, r->height,
13417			     bx1, bx2));
13418
13419			src_stride = bstride*bh;
13420			assert(src_stride > 0);
13421			if (src_stride <= 128) {
13422				src_stride = ALIGN(src_stride, 8) / 4;
13423				assert(src_stride <= 32);
13424				if (!kgem_check_batch(&sna->kgem, 8+src_stride) ||
13425				    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13426				    !kgem_check_reloc(&sna->kgem, 1)) {
13427					kgem_submit(&sna->kgem);
13428					if (!kgem_check_bo_fenced(&sna->kgem, bo))
13429						return false;
13430					_kgem_set_mode(&sna->kgem, KGEM_BLT);
13431				}
13432
13433				assert(sna->kgem.mode == KGEM_BLT);
13434				b = sna->kgem.batch + sna->kgem.nbatch;
13435				if (sna->kgem.gen >= 0100) {
13436					b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00;
13437					b[0] |= ((r->x - origin->x) & 7) << 17;
13438					b[1] = br13;
13439					b[2] = (r->y + dy) << 16 | (r->x + dx);
13440					b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13441					*(uint64_t *)(b+4) =
13442						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13443								 I915_GEM_DOMAIN_RENDER << 16 |
13444								 I915_GEM_DOMAIN_RENDER |
13445								 KGEM_RELOC_FENCED,
13446								 0);
13447					b[6] = gc->bgPixel;
13448					b[7] = gc->fgPixel;
13449
13450					dst = (uint8_t *)&b[8];
13451					sna->kgem.nbatch += 8 + src_stride;
13452				} else {
13453					b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
13454					b[0] |= ((r->x - origin->x) & 7) << 17;
13455					b[1] = br13;
13456					b[2] = (r->y + dy) << 16 | (r->x + dx);
13457					b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13458					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13459							      I915_GEM_DOMAIN_RENDER << 16 |
13460							      I915_GEM_DOMAIN_RENDER |
13461							      KGEM_RELOC_FENCED,
13462							      0);
13463					b[5] = gc->bgPixel;
13464					b[6] = gc->fgPixel;
13465
13466					dst = (uint8_t *)&b[7];
13467					sna->kgem.nbatch += 7 + src_stride;
13468				}
13469				assert(stipple->devKind);
13470				src_stride = stipple->devKind;
13471				src = stipple->devPrivate.ptr;
13472				src += (r->y - origin->y) * src_stride + bx1/8;
13473				src_stride -= bstride;
13474				do {
13475					int i = bstride;
13476					do {
13477						*dst++ = byte_reverse(*src++);
13478						*dst++ = byte_reverse(*src++);
13479						i -= 2;
13480					} while (i);
13481					src += src_stride;
13482				} while (--bh);
13483			} else {
13484				struct kgem_bo *upload;
13485				void *ptr;
13486
13487				if (!kgem_check_batch(&sna->kgem, 10) ||
13488				    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13489				    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
13490					kgem_submit(&sna->kgem);
13491					if (!kgem_check_bo_fenced(&sna->kgem, bo))
13492						return false;
13493					_kgem_set_mode(&sna->kgem, KGEM_BLT);
13494				}
13495
13496				upload = kgem_create_buffer(&sna->kgem,
13497							    bstride*bh,
13498							    KGEM_BUFFER_WRITE_INPLACE,
13499							    &ptr);
13500				if (!upload)
13501					break;
13502
13503				if (sigtrap_get() == 0) {
13504					dst = ptr;
13505					assert(stipple->devKind);
13506					src_stride = stipple->devKind;
13507					src = stipple->devPrivate.ptr;
13508					src += (r->y - origin->y) * src_stride + bx1/8;
13509					src_stride -= bstride;
13510					do {
13511						int i = bstride;
13512						do {
13513							*dst++ = byte_reverse(*src++);
13514							*dst++ = byte_reverse(*src++);
13515							i -= 2;
13516						} while (i);
13517						src += src_stride;
13518					} while (--bh);
13519
13520					assert(sna->kgem.mode == KGEM_BLT);
13521					b = sna->kgem.batch + sna->kgem.nbatch;
13522					if (sna->kgem.gen >= 0100) {
13523						b[0] = XY_MONO_SRC_COPY | br00 | 8;
13524						b[0] |= ((r->x - origin->x) & 7) << 17;
13525						b[1] = br13;
13526						b[2] = (r->y + dy) << 16 | (r->x + dx);
13527						b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13528						*(uint64_t *)(b+4) =
13529							kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13530									I915_GEM_DOMAIN_RENDER << 16 |
13531									I915_GEM_DOMAIN_RENDER |
13532									KGEM_RELOC_FENCED,
13533									0);
13534						*(uint64_t *)(b+6) =
13535							kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
13536									I915_GEM_DOMAIN_RENDER << 16 |
13537									KGEM_RELOC_FENCED,
13538									0);
13539						b[8] = gc->bgPixel;
13540						b[9] = gc->fgPixel;
13541						sna->kgem.nbatch += 10;
13542					} else {
13543						b[0] = XY_MONO_SRC_COPY | br00 | 6;
13544						b[0] |= ((r->x - origin->x) & 7) << 17;
13545						b[1] = br13;
13546						b[2] = (r->y + dy) << 16 | (r->x + dx);
13547						b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
13548						b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13549								I915_GEM_DOMAIN_RENDER << 16 |
13550								I915_GEM_DOMAIN_RENDER |
13551								KGEM_RELOC_FENCED,
13552								0);
13553						b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
13554								I915_GEM_DOMAIN_RENDER << 16 |
13555								KGEM_RELOC_FENCED,
13556								0);
13557						b[6] = gc->bgPixel;
13558						b[7] = gc->fgPixel;
13559
13560						sna->kgem.nbatch += 8;
13561					}
13562					sigtrap_put();
13563				}
13564
13565				kgem_bo_destroy(&sna->kgem, upload);
13566			}
13567
13568			r++;
13569		} while (--n);
13570	} else {
13571		RegionRec clip;
13572		DDXPointRec pat;
13573
13574		region_set(&clip, extents);
13575		if (!region_maybe_clip(&clip, gc->pCompositeClip))
13576			return true;
13577
13578		pat.x = origin->x + drawable->x;
13579		pat.y = origin->y + drawable->y;
13580
13581		if (clip.data == NULL) {
13582			do {
13583				BoxRec box;
13584				int bx1, bx2, bw, bh, bstride;
13585				int src_stride;
13586				uint8_t *dst, *src;
13587				uint32_t *b;
13588				struct kgem_bo *upload;
13589				void *ptr;
13590
13591				box.x1 = r->x + drawable->x;
13592				box.x2 = bound(box.x1, r->width);
13593				box.y1 = r->y + drawable->y;
13594				box.y2 = bound(box.y1, r->height);
13595				r++;
13596
13597				if (!box_intersect(&box, &clip.extents))
13598					continue;
13599
13600				bx1 = (box.x1 - pat.x) & ~7;
13601				bx2 = (box.x2 - pat.x + 7) & ~7;
13602				bw = (bx2 - bx1)/8;
13603				bh = box.y2 - box.y1;
13604				bstride = ALIGN(bw, 2);
13605
13606				DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d], pitch=%d, stride=%d\n",
13607				     __FUNCTION__,
13608				     r->x, r->y, r->width, r->height,
13609				     box.x1, box.y1, box.x2, box.y2,
13610				     bx1, bx2, bw, bstride));
13611
13612				src_stride = bstride*bh;
13613				assert(src_stride > 0);
13614				if (src_stride <= 128) {
13615					src_stride = ALIGN(src_stride, 8) / 4;
13616					assert(src_stride <= 32);
13617					if (!kgem_check_batch(&sna->kgem, 8+src_stride) ||
13618					    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13619					    !kgem_check_reloc(&sna->kgem, 1)) {
13620						kgem_submit(&sna->kgem);
13621						if (!kgem_check_bo_fenced(&sna->kgem, bo))
13622							return false;
13623						_kgem_set_mode(&sna->kgem, KGEM_BLT);
13624					}
13625
13626					assert(sna->kgem.mode == KGEM_BLT);
13627					b = sna->kgem.batch + sna->kgem.nbatch;
13628					if (sna->kgem.gen >= 0100) {
13629						b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00;
13630						b[0] |= ((box.x1 - pat.x) & 7) << 17;
13631						b[1] = br13;
13632						b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13633						b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13634						*(uint64_t *)(b+4) =
13635							kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13636									 I915_GEM_DOMAIN_RENDER << 16 |
13637									 I915_GEM_DOMAIN_RENDER |
13638									 KGEM_RELOC_FENCED,
13639									 0);
13640						b[6] = gc->bgPixel;
13641						b[7] = gc->fgPixel;
13642
13643						dst = (uint8_t *)&b[8];
13644						sna->kgem.nbatch += 8 + src_stride;
13645					} else {
13646						b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
13647						b[0] |= ((box.x1 - pat.x) & 7) << 17;
13648						b[1] = br13;
13649						b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13650						b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13651						b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13652								      I915_GEM_DOMAIN_RENDER << 16 |
13653								      I915_GEM_DOMAIN_RENDER |
13654								      KGEM_RELOC_FENCED,
13655								      0);
13656						b[5] = gc->bgPixel;
13657						b[6] = gc->fgPixel;
13658
13659						dst = (uint8_t *)&b[7];
13660						sna->kgem.nbatch += 7 + src_stride;
13661					}
13662
13663					assert(stipple->devKind);
13664					src_stride = stipple->devKind;
13665					src = stipple->devPrivate.ptr;
13666					src += (box.y1 - pat.y) * src_stride + bx1/8;
13667					src_stride -= bstride;
13668					do {
13669						int i = bstride;
13670						do {
13671							*dst++ = byte_reverse(*src++);
13672							*dst++ = byte_reverse(*src++);
13673							i -= 2;
13674						} while (i);
13675						src += src_stride;
13676					} while (--bh);
13677				} else {
13678					if (!kgem_check_batch(&sna->kgem, 10) ||
13679					    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13680					    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
13681						kgem_submit(&sna->kgem);
13682						if (!kgem_check_bo_fenced(&sna->kgem, bo))
13683							return false;
13684						_kgem_set_mode(&sna->kgem, KGEM_BLT);
13685					}
13686
13687					upload = kgem_create_buffer(&sna->kgem,
13688								    bstride*bh,
13689								    KGEM_BUFFER_WRITE_INPLACE,
13690								    &ptr);
13691					if (!upload)
13692						break;
13693
13694					if (sigtrap_get() == 0) {
13695						dst = ptr;
13696						assert(stipple->devKind);
13697						src_stride = stipple->devKind;
13698						src = stipple->devPrivate.ptr;
13699						src += (box.y1 - pat.y) * src_stride + bx1/8;
13700						src_stride -= bstride;
13701						do {
13702							int i = bstride;
13703							do {
13704								*dst++ = byte_reverse(*src++);
13705								*dst++ = byte_reverse(*src++);
13706								i -= 2;
13707							} while (i);
13708							src += src_stride;
13709						} while (--bh);
13710
13711						assert(sna->kgem.mode == KGEM_BLT);
13712						b = sna->kgem.batch + sna->kgem.nbatch;
13713						if (sna->kgem.gen >= 0100) {
13714							b[0] = XY_MONO_SRC_COPY | br00 | 8;
13715							b[0] |= ((box.x1 - pat.x) & 7) << 17;
13716							b[1] = br13;
13717							b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13718							b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13719							*(uint64_t *)(b+4) =
13720								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13721										I915_GEM_DOMAIN_RENDER << 16 |
13722										I915_GEM_DOMAIN_RENDER |
13723										KGEM_RELOC_FENCED,
13724										0);
13725							*(uint64_t *)(b+5) =
13726								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
13727										I915_GEM_DOMAIN_RENDER << 16 |
13728										KGEM_RELOC_FENCED,
13729										0);
13730							b[8] = gc->bgPixel;
13731							b[9] = gc->fgPixel;
13732							sna->kgem.nbatch += 10;
13733						} else {
13734							b[0] = XY_MONO_SRC_COPY | br00 | 6;
13735							b[0] |= ((box.x1 - pat.x) & 7) << 17;
13736							b[1] = br13;
13737							b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13738							b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13739							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13740									I915_GEM_DOMAIN_RENDER << 16 |
13741									I915_GEM_DOMAIN_RENDER |
13742									KGEM_RELOC_FENCED,
13743									0);
13744							b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
13745									I915_GEM_DOMAIN_RENDER << 16 |
13746									KGEM_RELOC_FENCED,
13747									0);
13748							b[6] = gc->bgPixel;
13749							b[7] = gc->fgPixel;
13750
13751							sna->kgem.nbatch += 8;
13752						}
13753						sigtrap_put();
13754					}
13755					kgem_bo_destroy(&sna->kgem, upload);
13756				}
13757			} while (--n);
13758		} else {
13759			const BoxRec * const clip_start = RegionBoxptr(&clip);
13760			const BoxRec * const clip_end = clip_start + clip.data->numRects;
13761			const BoxRec *c;
13762
13763			do {
13764				BoxRec unclipped;
13765				int bx1, bx2, bw, bh, bstride;
13766				int src_stride;
13767				uint8_t *dst, *src;
13768				uint32_t *b;
13769				struct kgem_bo *upload;
13770				void *ptr;
13771
13772				unclipped.x1 = r->x + drawable->x;
13773				unclipped.x2 = bound(unclipped.x1, r->width);
13774				unclipped.y1 = r->y + drawable->y;
13775				unclipped.y2 = bound(unclipped.y1, r->height);
13776				r++;
13777
13778				c = find_clip_box_for_y(clip_start,
13779							clip_end,
13780							unclipped.y1);
13781				while (c != clip_end) {
13782					BoxRec box;
13783
13784					if (unclipped.y2 <= c->y1)
13785						break;
13786
13787					box = unclipped;
13788					if (!box_intersect(&box, c++))
13789						continue;
13790
13791					bx1 = (box.x1 - pat.x) & ~7;
13792					bx2 = (box.x2 - pat.x + 7) & ~7;
13793					bw = (bx2 - bx1)/8;
13794					bh = box.y2 - box.y1;
13795					bstride = ALIGN(bw, 2);
13796
13797					DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d]\n",
13798					     __FUNCTION__,
13799					     r->x, r->y, r->width, r->height,
13800					     box.x1, box.y1, box.x2, box.y2,
13801					     bx1, bx2));
13802
13803					src_stride = bstride*bh;
13804					assert(src_stride > 0);
13805					if (src_stride <= 128) {
13806						src_stride = ALIGN(src_stride, 8) / 4;
13807						assert(src_stride <= 32);
13808						if (!kgem_check_batch(&sna->kgem, 8+src_stride) ||
13809						    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13810						    !kgem_check_reloc(&sna->kgem, 1)) {
13811							kgem_submit(&sna->kgem);
13812							if (!kgem_check_bo_fenced(&sna->kgem, bo))
13813								return false;
13814							_kgem_set_mode(&sna->kgem, KGEM_BLT);
13815						}
13816
13817						assert(sna->kgem.mode == KGEM_BLT);
13818						b = sna->kgem.batch + sna->kgem.nbatch;
13819						if (sna->kgem.gen >= 0100) {
13820							b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00;
13821							b[0] |= ((box.x1 - pat.x) & 7) << 17;
13822							b[1] = br13;
13823							b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13824							b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13825							*(uint64_t *)(b+4) =
13826								kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13827										 I915_GEM_DOMAIN_RENDER << 16 |
13828										 I915_GEM_DOMAIN_RENDER |
13829										 KGEM_RELOC_FENCED,
13830										 0);
13831							b[6] = gc->bgPixel;
13832							b[7] = gc->fgPixel;
13833
13834							dst = (uint8_t *)&b[8];
13835							sna->kgem.nbatch += 8 + src_stride;
13836						} else {
13837							b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
13838							b[0] |= ((box.x1 - pat.x) & 7) << 17;
13839							b[1] = br13;
13840							b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13841							b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13842							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13843									      I915_GEM_DOMAIN_RENDER << 16 |
13844									      I915_GEM_DOMAIN_RENDER |
13845									      KGEM_RELOC_FENCED,
13846									      0);
13847							b[5] = gc->bgPixel;
13848							b[6] = gc->fgPixel;
13849
13850							dst = (uint8_t *)&b[7];
13851							sna->kgem.nbatch += 7 + src_stride;
13852						}
13853						assert(stipple->devKind);
13854						src_stride = stipple->devKind;
13855						src = stipple->devPrivate.ptr;
13856						src += (box.y1 - pat.y) * src_stride + bx1/8;
13857						src_stride -= bstride;
13858						do {
13859							int i = bstride;
13860							do {
13861								*dst++ = byte_reverse(*src++);
13862								*dst++ = byte_reverse(*src++);
13863								i -= 2;
13864							} while (i);
13865							src += src_stride;
13866						} while (--bh);
13867					} else {
13868						if (!kgem_check_batch(&sna->kgem, 10) ||
13869						    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13870						    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
13871							kgem_submit(&sna->kgem);
13872							if (!kgem_check_bo_fenced(&sna->kgem, bo))
13873								return false;
13874							_kgem_set_mode(&sna->kgem, KGEM_BLT);
13875						}
13876
13877						upload = kgem_create_buffer(&sna->kgem,
13878									    bstride*bh,
13879									    KGEM_BUFFER_WRITE_INPLACE,
13880									    &ptr);
13881						if (!upload)
13882							break;
13883
13884						if (sigtrap_get() == 0) {
13885							dst = ptr;
13886							assert(stipple->devKind);
13887							src_stride = stipple->devKind;
13888							src = stipple->devPrivate.ptr;
13889							src += (box.y1 - pat.y) * src_stride + bx1/8;
13890							src_stride -= bstride;
13891							do {
13892								int i = bstride;
13893								do {
13894									*dst++ = byte_reverse(*src++);
13895									*dst++ = byte_reverse(*src++);
13896									i -= 2;
13897								} while (i);
13898								src += src_stride;
13899							} while (--bh);
13900
13901							assert(sna->kgem.mode == KGEM_BLT);
13902							b = sna->kgem.batch + sna->kgem.nbatch;
13903							if (sna->kgem.gen >= 0100) {
13904								b[0] = XY_MONO_SRC_COPY | br00 | 8;
13905								b[0] |= ((box.x1 - pat.x) & 7) << 17;
13906								b[1] = br13;
13907								b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13908								b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13909								*(uint64_t *)(b+4) =
13910									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
13911											I915_GEM_DOMAIN_RENDER << 16 |
13912											I915_GEM_DOMAIN_RENDER |
13913											KGEM_RELOC_FENCED,
13914											0);
13915								*(uint64_t *)(b+6) =
13916									kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
13917											I915_GEM_DOMAIN_RENDER << 16 |
13918											KGEM_RELOC_FENCED,
13919											0);
13920								b[8] = gc->bgPixel;
13921								b[9] = gc->fgPixel;
13922								sna->kgem.nbatch += 10;
13923							} else {
13924								b[0] = XY_MONO_SRC_COPY | br00 | 6;
13925								b[0] |= ((box.x1 - pat.x) & 7) << 17;
13926								b[1] = br13;
13927								b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
13928								b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
13929								b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13930										I915_GEM_DOMAIN_RENDER << 16 |
13931										I915_GEM_DOMAIN_RENDER |
13932										KGEM_RELOC_FENCED,
13933										0);
13934								b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
13935										I915_GEM_DOMAIN_RENDER << 16 |
13936										KGEM_RELOC_FENCED,
13937										0);
13938								b[6] = gc->bgPixel;
13939								b[7] = gc->fgPixel;
13940
13941								sna->kgem.nbatch += 8;
13942							}
13943							sigtrap_put();
13944						}
13945						kgem_bo_destroy(&sna->kgem, upload);
13946					}
13947				}
13948			} while (--n);
13949
13950		}
13951	}
13952
13953	sna->blt_state.fill_bo = 0;
13954	return true;
13955}
13956
13957static void
13958sna_poly_fill_rect_stippled_n_box__imm(struct sna *sna,
13959				       struct kgem_bo *bo,
13960				       uint32_t br00, uint32_t br13,
13961				       const GC *gc,
13962				       const BoxRec *box,
13963				       const DDXPointRec *origin)
13964{
13965	int x1, x2, y1, y2;
13966	uint32_t *b;
13967
13968	for (y1 = box->y1; y1 < box->y2; y1 = y2) {
13969		int oy = (y1 - origin->y) % gc->stipple->drawable.height;
13970		if (oy < 0)
13971			oy += gc->stipple->drawable.height;
13972
13973		y2 = box->y2;
13974		if (y2 - y1 > gc->stipple->drawable.height - oy)
13975			y2 = y1 + gc->stipple->drawable.height - oy;
13976
13977		for (x1 = box->x1; x1 < box->x2; x1 = x2) {
13978			int bx1, bx2, bw, bh, len, ox;
13979			uint8_t *dst, *src;
13980
13981			x2 = box->x2;
13982			ox = (x1 - origin->x) % gc->stipple->drawable.width;
13983			if (ox < 0)
13984				ox += gc->stipple->drawable.width;
13985			bx1 = ox & ~7;
13986			bx2 = ox + (x2 - x1);
13987			if (bx2 > gc->stipple->drawable.width) {
13988				bx2 = gc->stipple->drawable.width;
13989				x2 = x1 + bx2-ox;
13990			}
13991			bw = (bx2 - bx1 + 7)/8;
13992			bw = ALIGN(bw, 2);
13993			bh = y2 - y1;
13994
13995			DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d\n",
13996			     __FUNCTION__,
13997			     x1, y1, x2-x1, y2-y1,
13998			     origin->x, origin->y,
13999			     ox, oy, bx1, bx2,
14000			     gc->stipple->drawable.width,
14001			     gc->stipple->drawable.height));
14002
14003			len = bw*bh;
14004			len = ALIGN(len, 8) / 4;
14005			assert(len > 0);
14006			assert(len <= 32);
14007			if (!kgem_check_batch(&sna->kgem, 8+len) ||
14008			    !kgem_check_bo_fenced(&sna->kgem, bo) ||
14009			    !kgem_check_reloc(&sna->kgem, 1)) {
14010				kgem_submit(&sna->kgem);
14011				if (!kgem_check_bo_fenced(&sna->kgem, bo))
14012					return; /* XXX fallback? */
14013				_kgem_set_mode(&sna->kgem, KGEM_BLT);
14014			}
14015
14016			assert(sna->kgem.mode == KGEM_BLT);
14017			b = sna->kgem.batch + sna->kgem.nbatch;
14018			if (sna->kgem.gen >= 0100) {
14019				b[0] = br00 | (6 + len) | (ox & 7) << 17;
14020				b[1] = br13;
14021				b[2] = y1 << 16 | x1;
14022				b[3] = y2 << 16 | x2;
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				b[6] = gc->bgPixel;
14030				b[7] = gc->fgPixel;
14031				dst = (uint8_t *)&b[8];
14032				sna->kgem.nbatch += 8 + len;
14033			} else {
14034				b[0] = br00 | (5 + len) | (ox & 7) << 17;
14035				b[1] = br13;
14036				b[2] = y1 << 16 | x1;
14037				b[3] = y2 << 16 | x2;
14038				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14039						      I915_GEM_DOMAIN_RENDER << 16 |
14040						      I915_GEM_DOMAIN_RENDER |
14041						      KGEM_RELOC_FENCED,
14042						      0);
14043				b[5] = gc->bgPixel;
14044				b[6] = gc->fgPixel;
14045				dst = (uint8_t *)&b[7];
14046				sna->kgem.nbatch += 7 + len;
14047			}
14048
14049			assert(gc->stipple->devKind);
14050			len = gc->stipple->devKind;
14051			src = gc->stipple->devPrivate.ptr;
14052			src += oy*len + ox/8;
14053			len -= bw;
14054			do {
14055				int i = bw;
14056				do {
14057					*dst++ = byte_reverse(*src++);
14058					*dst++ = byte_reverse(*src++);
14059					i -= 2;
14060				} while (i);
14061				src += len;
14062			} while (--bh);
14063		}
14064	}
14065}
14066
14067static void
14068sna_poly_fill_rect_stippled_n_box(struct sna *sna,
14069				  struct kgem_bo *bo,
14070				  struct kgem_bo **tile,
14071				  uint32_t br00, uint32_t br13,
14072				  const GC *gc,
14073				  const BoxRec *box,
14074				  const DDXPointRec *origin)
14075{
14076	int x1, x2, y1, y2;
14077	int w = gc->stipple->drawable.width;
14078	int h = gc->stipple->drawable.height;
14079	int stride = gc->stipple->devKind;
14080	uint32_t *b;
14081
14082	assert(stride);
14083	if ((((box->y2-box->y1) | (box->x2-box->x1)) & ~31) == 0) {
14084		br00 = XY_MONO_SRC_COPY_IMM |(br00 & (BLT_DST_TILED | 3 << 20));
14085		sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
14086						       br00, br13, gc,
14087						       box, origin);
14088		return;
14089	}
14090
14091	for (y1 = box->y1; y1 < box->y2; y1 = y2) {
14092		int row, oy = (y1 - origin->y) % gc->stipple->drawable.height;
14093		if (oy < 0)
14094			oy += h;
14095
14096		y2 = box->y2;
14097		if (y2 - y1 > h - oy)
14098			y2 = y1 + h - oy;
14099
14100		row = oy * stride;
14101		for (x1 = box->x1; x1 < box->x2; x1 = x2) {
14102			int bx1, bx2, bw, bh, len, ox;
14103			bool use_tile;
14104
14105			x2 = box->x2;
14106			ox = (x1 - origin->x) % w;
14107			if (ox < 0)
14108				ox += w;
14109			bx1 = ox & ~7;
14110			bx2 = ox + (x2 - x1);
14111			if (bx2 > w) {
14112				bx2 = w;
14113				x2 = x1 + bx2-ox;
14114			}
14115
14116			use_tile = y2-y1 == h && x2-x1 == w;
14117
14118			DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d, full tile?=%d\n",
14119			     __FUNCTION__,
14120			     x1, y1, x2-x1, y2-y1,
14121			     origin->x, origin->y,
14122			     ox, oy, bx1, bx2, w, h,
14123			     use_tile));
14124
14125			bw = (bx2 - bx1 + 7)/8;
14126			bw = ALIGN(bw, 2);
14127			bh = y2 - y1;
14128
14129			len = bw*bh;
14130			len = ALIGN(len, 8) / 4;
14131			assert(len > 0);
14132			if (!kgem_check_batch(&sna->kgem, 8+len) ||
14133			    !kgem_check_bo_fenced(&sna->kgem, bo) ||
14134			    !kgem_check_reloc(&sna->kgem, 2)) {
14135				kgem_submit(&sna->kgem);
14136				if (!kgem_check_bo_fenced(&sna->kgem, bo))
14137					return; /* XXX fallback? */
14138				_kgem_set_mode(&sna->kgem, KGEM_BLT);
14139			}
14140
14141			assert(sna->kgem.mode == KGEM_BLT);
14142			b = sna->kgem.batch + sna->kgem.nbatch;
14143
14144			if (!use_tile && len <= 32) {
14145				uint8_t *dst, *src;
14146
14147				if (sna->kgem.gen >= 0100) {
14148					b[0] = XY_MONO_SRC_COPY_IMM;
14149					b[0] |= (br00 & (BLT_DST_TILED | 3 << 20));
14150					b[0] |= (ox & 7) << 17;
14151					b[0] |= (6 + len);
14152					b[1] = br13;
14153					b[2] = y1 << 16 | x1;
14154					b[3] = y2 << 16 | x2;
14155					*(uint64_t *)(b+4) =
14156						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14157								 I915_GEM_DOMAIN_RENDER << 16 |
14158								 I915_GEM_DOMAIN_RENDER |
14159								 KGEM_RELOC_FENCED,
14160								 0);
14161					b[6] = gc->bgPixel;
14162					b[7] = gc->fgPixel;
14163
14164					dst = (uint8_t *)&b[8];
14165					sna->kgem.nbatch += 8 + len;
14166				} else {
14167					b[0] = XY_MONO_SRC_COPY_IMM;
14168					b[0] |= (br00 & (BLT_DST_TILED | 3 << 20));
14169					b[0] |= (ox & 7) << 17;
14170					b[0] |= (5 + len);
14171					b[1] = br13;
14172					b[2] = y1 << 16 | x1;
14173					b[3] = y2 << 16 | x2;
14174					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14175							      I915_GEM_DOMAIN_RENDER << 16 |
14176							      I915_GEM_DOMAIN_RENDER |
14177							      KGEM_RELOC_FENCED,
14178							      0);
14179					b[5] = gc->bgPixel;
14180					b[6] = gc->fgPixel;
14181
14182					dst = (uint8_t *)&b[7];
14183					sna->kgem.nbatch += 7 + len;
14184				}
14185
14186				assert(gc->stipple->devKind);
14187				len = gc->stipple->devKind;
14188				src = gc->stipple->devPrivate.ptr;
14189				src += oy*len + ox/8;
14190				len -= bw;
14191				do {
14192					int i = bw;
14193					do {
14194						*dst++ = byte_reverse(*src++);
14195						*dst++ = byte_reverse(*src++);
14196						i -= 2;
14197					} while (i);
14198					src += len;
14199				} while (--bh);
14200			} else {
14201				bool has_tile = use_tile && *tile;
14202				struct kgem_bo *upload;
14203				uint8_t *dst, *src;
14204				void *ptr;
14205
14206				if (has_tile) {
14207					upload = kgem_bo_reference(*tile);
14208				} else {
14209					upload = kgem_create_buffer(&sna->kgem, bw*bh,
14210								    KGEM_BUFFER_WRITE_INPLACE,
14211								    &ptr);
14212					if (!upload)
14213						return;
14214				}
14215
14216				assert(sna->kgem.mode == KGEM_BLT);
14217				b = sna->kgem.batch + sna->kgem.nbatch;
14218				if (sna->kgem.gen >= 0100) {
14219					b[0] = br00 | (ox & 7) << 17 | 8;
14220					b[1] = br13;
14221					b[2] = y1 << 16 | x1;
14222					b[3] = y2 << 16 | x2;
14223					*(uint64_t *)(b+4) =
14224						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
14225								 I915_GEM_DOMAIN_RENDER << 16 |
14226								 I915_GEM_DOMAIN_RENDER |
14227								 KGEM_RELOC_FENCED,
14228								 0);
14229					*(uint64_t *)(b+6) =
14230						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
14231							       I915_GEM_DOMAIN_RENDER << 16 |
14232							       KGEM_RELOC_FENCED,
14233							       0);
14234					b[8] = gc->bgPixel;
14235					b[9] = gc->fgPixel;
14236					sna->kgem.nbatch += 10;
14237				} else {
14238					b[0] = br00 | (ox & 7) << 17 | 6;
14239					b[1] = br13;
14240					b[2] = y1 << 16 | x1;
14241					b[3] = y2 << 16 | x2;
14242					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14243							      I915_GEM_DOMAIN_RENDER << 16 |
14244							      I915_GEM_DOMAIN_RENDER |
14245							      KGEM_RELOC_FENCED,
14246							      0);
14247					b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
14248							      I915_GEM_DOMAIN_RENDER << 16 |
14249							      KGEM_RELOC_FENCED,
14250							      0);
14251					b[6] = gc->bgPixel;
14252					b[7] = gc->fgPixel;
14253					sna->kgem.nbatch += 8;
14254				}
14255
14256				if (!has_tile) {
14257					dst = ptr;
14258					len = stride;
14259					src = gc->stipple->devPrivate.ptr;
14260					src += row + (ox >> 3);
14261					len -= bw;
14262					do {
14263						int i = bw;
14264						do {
14265							*dst++ = byte_reverse(*src++);
14266							*dst++ = byte_reverse(*src++);
14267							i -= 2;
14268						} while (i);
14269						src += len;
14270					} while (--bh);
14271					if (use_tile)
14272						*tile = kgem_bo_reference(upload);
14273				}
14274
14275				kgem_bo_destroy(&sna->kgem, upload);
14276			}
14277		}
14278	}
14279}
14280
14281static bool
14282sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable,
14283				       struct kgem_bo *bo,
14284				       struct sna_damage **damage,
14285				       GCPtr gc, int n, xRectangle *r,
14286				       const BoxRec *extents, unsigned clipped)
14287{
14288	PixmapPtr pixmap = get_drawable_pixmap(drawable);
14289	struct sna *sna = to_sna_from_pixmap(pixmap);
14290	DDXPointRec origin = gc->patOrg;
14291	int16_t dx, dy;
14292	uint32_t br00, br13;
14293
14294	DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__,
14295	     extents->x1, extents->y1,
14296	     extents->x2, extents->y2,
14297	     origin.x, origin.y,
14298	     clipped, gc->alu, gc->fillStyle == FillOpaqueStippled));
14299
14300	get_drawable_deltas(drawable, pixmap, &dx, &dy);
14301	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
14302
14303	br00 = XY_MONO_SRC_COPY_IMM | 3 << 20;
14304	br13 = bo->pitch;
14305	if (sna->kgem.gen >= 040 && bo->tiling) {
14306		br00 |= BLT_DST_TILED;
14307		br13 >>= 2;
14308	}
14309	br13 |= (gc->fillStyle == FillStippled) << 29;
14310	br13 |= blt_depth(drawable->depth) << 24;
14311	br13 |= copy_ROP[gc->alu] << 16;
14312
14313	origin.x += dx + drawable->x;
14314	origin.y += dy + drawable->y;
14315
14316	if (!clipped) {
14317		dx += drawable->x;
14318		dy += drawable->y;
14319
14320		sna_damage_add_rectangles(damage, r, n, dx, dy);
14321		do {
14322			BoxRec box;
14323
14324			box.x1 = r->x + dx;
14325			box.y1 = r->y + dy;
14326			box.x2 = box.x1 + r->width;
14327			box.y2 = box.y1 + r->height;
14328
14329			sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
14330							       br00, br13, gc,
14331							       &box, &origin);
14332			r++;
14333		} while (--n);
14334	} else {
14335		RegionRec clip;
14336
14337		region_set(&clip, extents);
14338		if (!region_maybe_clip(&clip, gc->pCompositeClip)) {
14339			DBG(("%s: all clipped\n", __FUNCTION__));
14340			return true;
14341		}
14342
14343		if (clip.data == NULL) {
14344			DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n",
14345			     __FUNCTION__,
14346			     clip.extents.x1, clip.extents.y1,
14347			     clip.extents.x2, clip.extents.y2));
14348			do {
14349				BoxRec box;
14350
14351				box.x1 = r->x + drawable->x;
14352				box.x2 = bound(box.x1, r->width);
14353				box.y1 = r->y + drawable->y;
14354				box.y2 = bound(box.y1, r->height);
14355				r++;
14356
14357				DBG(("%s: box (%d, %d), (%d, %d)\n",
14358				     __FUNCTION__,
14359				     box.x1, box.y1, box.x2, box.y2));
14360				if (!box_intersect(&box, &clip.extents))
14361					continue;
14362
14363				box.x1 += dx; box.x2 += dx;
14364				box.y1 += dy; box.y2 += dy;
14365
14366				sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
14367								       br00, br13, gc,
14368								       &box, &origin);
14369			} while (--n);
14370		} else {
14371			const BoxRec * const clip_start = RegionBoxptr(&clip);
14372			const BoxRec * const clip_end = clip_start + clip.data->numRects;
14373			const BoxRec *c;
14374
14375			DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__,
14376			     clip_start->x1, clip_start->y1,
14377			     clip_start->x2, clip_start->y2,
14378			     clip_end->x1, clip_end->y1,
14379			     clip_end->x2, clip_end->y2));
14380			do {
14381				BoxRec unclipped;
14382
14383				unclipped.x1 = r->x + drawable->x;
14384				unclipped.x2 = bound(unclipped.x1, r->width);
14385				unclipped.y1 = r->y + drawable->y;
14386				unclipped.y2 = bound(unclipped.y1, r->height);
14387				r++;
14388
14389				c = find_clip_box_for_y(clip_start,
14390							clip_end,
14391							unclipped.y1);
14392				while (c != clip_end) {
14393					BoxRec box;
14394
14395					if (unclipped.y2 <= c->y1)
14396						break;
14397
14398					box = unclipped;
14399					if (!box_intersect(&box, c++))
14400						continue;
14401
14402					box.x1 += dx; box.x2 += dx;
14403					box.y1 += dy; box.y2 += dy;
14404
14405					sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
14406									       br00, br13, gc,
14407									       &box, &origin);
14408				}
14409			} while (--n);
14410		}
14411	}
14412
14413	assert_pixmap_damage(pixmap);
14414	sna->blt_state.fill_bo = 0;
14415	return true;
14416}
14417
14418static bool
14419sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable,
14420				  struct kgem_bo *bo,
14421				  struct sna_damage **damage,
14422				  GCPtr gc, int n, xRectangle *r,
14423				  const BoxRec *extents, unsigned clipped)
14424{
14425	PixmapPtr pixmap = get_drawable_pixmap(drawable);
14426	struct sna *sna = to_sna_from_pixmap(pixmap);
14427	DDXPointRec origin = gc->patOrg;
14428	struct kgem_bo *tile = NULL;
14429	int16_t dx, dy;
14430	uint32_t br00, br13;
14431
14432	DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__,
14433	     extents->x1, extents->y1,
14434	     extents->x2, extents->y2,
14435	     origin.x, origin.y,
14436	     clipped, gc->alu, gc->fillStyle == FillOpaqueStippled));
14437
14438	if (((gc->stipple->drawable.width | gc->stipple->drawable.height) & ~31) == 0)
14439		return sna_poly_fill_rect_stippled_n_blt__imm(drawable,
14440							      bo, damage,
14441							      gc, n, r,
14442							      extents, clipped);
14443
14444	get_drawable_deltas(drawable, pixmap, &dx, &dy);
14445	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
14446
14447	br00 = XY_MONO_SRC_COPY | 3 << 20;
14448	br13 = bo->pitch;
14449	if (sna->kgem.gen >= 040 && bo->tiling) {
14450		br00 |= BLT_DST_TILED;
14451		br13 >>= 2;
14452	}
14453	br13 |= (gc->fillStyle == FillStippled) << 29;
14454	br13 |= blt_depth(drawable->depth) << 24;
14455	br13 |= copy_ROP[gc->alu] << 16;
14456
14457	origin.x += dx + drawable->x;
14458	origin.y += dy + drawable->y;
14459
14460	if (!clipped) {
14461		dx += drawable->x;
14462		dy += drawable->y;
14463
14464		sna_damage_add_rectangles(damage, r, n, dx, dy);
14465		do {
14466			BoxRec box;
14467
14468			box.x1 = r->x + dx;
14469			box.y1 = r->y + dy;
14470			box.x2 = box.x1 + r->width;
14471			box.y2 = box.y1 + r->height;
14472
14473			sna_poly_fill_rect_stippled_n_box(sna, bo, &tile,
14474							  br00, br13, gc,
14475							  &box, &origin);
14476			r++;
14477		} while (--n);
14478	} else {
14479		RegionRec clip;
14480
14481		region_set(&clip, extents);
14482		if (!region_maybe_clip(&clip, gc->pCompositeClip)) {
14483			DBG(("%s: all clipped\n", __FUNCTION__));
14484			return true;
14485		}
14486
14487		if (clip.data == NULL) {
14488			DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n",
14489			     __FUNCTION__,
14490			     clip.extents.x1, clip.extents.y1,
14491			     clip.extents.x2, clip.extents.y2));
14492			do {
14493				BoxRec box;
14494
14495				box.x1 = r->x + drawable->x;
14496				box.x2 = bound(box.x1, r->width);
14497				box.y1 = r->y + drawable->y;
14498				box.y2 = bound(box.y1, r->height);
14499				r++;
14500
14501				DBG(("%s: box (%d, %d), (%d, %d)\n",
14502				     __FUNCTION__,
14503				     box.x1, box.y1, box.x2, box.y2));
14504				if (!box_intersect(&box, &clip.extents))
14505					continue;
14506
14507				box.x1 += dx; box.x2 += dx;
14508				box.y1 += dy; box.y2 += dy;
14509
14510				sna_poly_fill_rect_stippled_n_box(sna, bo, &tile,
14511								  br00, br13, gc,
14512								  &box, &origin);
14513			} while (--n);
14514		} else {
14515			const BoxRec * const clip_start = RegionBoxptr(&clip);
14516			const BoxRec * const clip_end = clip_start + clip.data->numRects;
14517			const BoxRec *c;
14518
14519			DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__,
14520			     clip_start->x1, clip_start->y1,
14521			     clip_start->x2, clip_start->y2,
14522			     clip_end->x1, clip_end->y1,
14523			     clip_end->x2, clip_end->y2));
14524			do {
14525				BoxRec unclipped;
14526
14527				unclipped.x1 = r->x + drawable->x;
14528				unclipped.x2 = bound(unclipped.x1, r->width);
14529				unclipped.y1 = r->y + drawable->y;
14530				unclipped.y2 = bound(unclipped.y1, r->height);
14531				r++;
14532
14533				c = find_clip_box_for_y(clip_start,
14534							clip_end,
14535							unclipped.y1);
14536				while (c != clip_end) {
14537					BoxRec box;
14538
14539					if (unclipped.y2 <= c->y1)
14540						break;
14541
14542					box = unclipped;
14543					if (!box_intersect(&box, c++))
14544						continue;
14545
14546					box.x1 += dx; box.x2 += dx;
14547					box.y1 += dy; box.y2 += dy;
14548
14549					sna_poly_fill_rect_stippled_n_box(sna, bo, &tile,
14550									  br00, br13, gc,
14551									  &box, &origin);
14552				}
14553			} while (--n);
14554		}
14555	}
14556
14557	assert_pixmap_damage(pixmap);
14558	if (tile)
14559		kgem_bo_destroy(&sna->kgem, tile);
14560	sna->blt_state.fill_bo = 0;
14561	return true;
14562}
14563
14564static bool
14565sna_poly_fill_rect_stippled_blt(DrawablePtr drawable,
14566				struct kgem_bo *bo,
14567				struct sna_damage **damage,
14568				GCPtr gc, int n, xRectangle *rect,
14569				const BoxRec *extents, unsigned clipped)
14570{
14571
14572	PixmapPtr stipple = gc->stipple;
14573
14574	if (bo->tiling == I915_TILING_Y) {
14575		PixmapPtr pixmap = get_drawable_pixmap(drawable);
14576
14577		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
14578		/* This is cheating, but only the gpu_bo can be tiled */
14579		assert(bo == __sna_pixmap_get_bo(pixmap));
14580		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
14581		if (bo == NULL) {
14582			DBG(("%s: fallback -- unable to change tiling\n",
14583			     __FUNCTION__));
14584			return false;
14585		}
14586	}
14587
14588	if (!sna_drawable_move_to_cpu(&stipple->drawable, MOVE_READ))
14589		return false;
14590
14591	DBG(("%s: origin (%d, %d), extents (stipple): (%d, %d), stipple size %dx%d\n",
14592	     __FUNCTION__, gc->patOrg.x, gc->patOrg.y,
14593	     extents->x2 - gc->patOrg.x - drawable->x,
14594	     extents->y2 - gc->patOrg.y - drawable->y,
14595	     stipple->drawable.width, stipple->drawable.height));
14596
14597	if ((stipple->drawable.width | stipple->drawable.height) == 8)
14598		return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage,
14599							   gc, n, rect,
14600							   extents, clipped);
14601
14602	if ((stipple->drawable.width | stipple->drawable.height) <= 0xc &&
14603	    is_power_of_two(stipple->drawable.width) &&
14604	    is_power_of_two(stipple->drawable.height))
14605		return sna_poly_fill_rect_stippled_nxm_blt(drawable, bo, damage,
14606							   gc, n, rect,
14607							   extents, clipped);
14608
14609	if (extents->x1 - gc->patOrg.x - drawable->x >= 0 &&
14610	    extents->x2 - gc->patOrg.x - drawable->x <= stipple->drawable.width &&
14611	    extents->y1 - gc->patOrg.y - drawable->y >= 0 &&
14612	    extents->y2 - gc->patOrg.y - drawable->y <= stipple->drawable.height) {
14613		if (stipple->drawable.width <= 8 && stipple->drawable.height <= 8)
14614			return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage,
14615								   gc, n, rect,
14616								   extents, clipped);
14617		else
14618			return sna_poly_fill_rect_stippled_1_blt(drawable, bo, damage,
14619								 gc, n, rect,
14620								 extents, clipped);
14621	} else {
14622		return sna_poly_fill_rect_stippled_n_blt(drawable, bo, damage,
14623							 gc, n, rect,
14624							 extents, clipped);
14625	}
14626}
14627
14628static unsigned
14629sna_poly_fill_rect_extents(DrawablePtr drawable, GCPtr gc,
14630			   int *_n, xRectangle **_r,
14631			   BoxPtr out)
14632{
14633	int n;
14634	xRectangle *r;
14635	Box32Rec box;
14636	bool clipped;
14637
14638	if (*_n == 0)
14639		return 0;
14640
14641	DBG(("%s: [0] = (%d, %d)x(%d, %d)\n",
14642	     __FUNCTION__, (*_r)->x, (*_r)->y, (*_r)->width, (*_r)->height));
14643
14644	/* Remove any zero-size rectangles from the array */
14645	while (*_n && ((*_r)->width == 0 || (*_r)->height == 0))
14646		--*_n, ++*_r;
14647
14648	if (*_n == 0)
14649		return 0;
14650
14651	n = *_n;
14652	r = *_r;
14653
14654	box.x1 = r->x;
14655	box.x2 = box.x1 + r->width;
14656	box.y1 = r->y;
14657	box.y2 = box.y1 + r->height;
14658	r++;
14659
14660	while (--n) {
14661		if (r->width == 0 || r->height == 0)
14662			goto slow;
14663
14664		box32_add_rect(&box, r++);
14665	}
14666	goto done;
14667slow:
14668	{
14669		xRectangle *rr = r;
14670		do {
14671			do {
14672				--*_n, r++;
14673			} while (--n && (r->width == 0 || r->height == 0));
14674			while (n && r->width && r->height) {
14675				box32_add_rect(&box, r);
14676				*rr++ = *r++;
14677				n--;
14678			}
14679		} while (n);
14680	}
14681done:
14682
14683	clipped = box32_trim_and_translate(&box, drawable, gc);
14684	if (!box32_to_box16(&box, out))
14685		return 0;
14686
14687	return 1 | clipped << 1;
14688}
14689
14690static void
14691sna_poly_fill_rect(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect)
14692{
14693	PixmapPtr pixmap = get_drawable_pixmap(draw);
14694	struct sna *sna = to_sna_from_pixmap(pixmap);
14695	struct sna_pixmap *priv = sna_pixmap(pixmap);
14696	struct sna_damage **damage;
14697	struct kgem_bo *bo;
14698	RegionRec region;
14699	unsigned flags, hint;
14700	uint32_t color;
14701
14702	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
14703	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
14704	     (gc->fillStyle == FillSolid ||
14705	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
14706	     gc->fillStyle, gc->tileIsPixel,
14707	     gc->alu));
14708
14709	flags = sna_poly_fill_rect_extents(draw, gc, &n, &rect, &region.extents);
14710	if (flags == 0) {
14711		DBG(("%s, nothing to do\n", __FUNCTION__));
14712		return;
14713	}
14714
14715	DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
14716	     region.extents.x1, region.extents.y1,
14717	     region.extents.x2, region.extents.y2,
14718	     flags));
14719
14720	if (FORCE_FALLBACK || !ACCEL_POLY_FILL_RECT) {
14721		DBG(("%s: fallback forced\n", __FUNCTION__));
14722		goto fallback;
14723	}
14724
14725	if (priv == NULL) {
14726		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
14727		goto fallback;
14728	}
14729
14730	if (wedged(sna)) {
14731		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
14732		goto fallback;
14733	}
14734
14735	if (!PM_IS_SOLID(draw, gc->planemask)) {
14736		DBG(("%s: fallback -- planemask=0x%lx (not-solid)\n",
14737		     __FUNCTION__, gc->planemask));
14738		goto fallback;
14739	}
14740
14741	/* Clear the cpu damage so that we refresh the GPU status of the
14742	 * pixmap upon a redraw after a period of inactivity.
14743	 */
14744	hint = PREFER_GPU;
14745	if (n == 1 && gc->fillStyle != FillStippled && alu_overwrites(gc->alu)) {
14746		int16_t dx, dy;
14747
14748		region.data = NULL;
14749
14750		if (get_drawable_deltas(draw, pixmap, &dx, &dy)) {
14751			DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy));
14752			RegionTranslate(&region, dx, dy);
14753		}
14754
14755		if ((flags & 2) == 0) {
14756			hint |= IGNORE_DAMAGE;
14757			if (region_subsumes_drawable(&region, &pixmap->drawable)) {
14758				discard_cpu_damage(sna, priv);
14759				hint |= REPLACES;
14760			} else {
14761				if (priv->cpu_damage &&
14762				    region_subsumes_damage(&region, priv->cpu_damage))
14763					discard_cpu_damage(sna, priv);
14764			}
14765		}
14766		if (priv->cpu_damage == NULL) {
14767			if (priv->gpu_bo &&
14768			    (hint & REPLACES ||
14769			     box_covers_pixmap(pixmap, &region.extents) ||
14770			     box_inplace(pixmap, &region.extents))) {
14771				DBG(("%s: promoting to full GPU\n",
14772				     __FUNCTION__));
14773				assert(priv->gpu_bo->proxy == NULL);
14774				sna_damage_all(&priv->gpu_damage, pixmap);
14775			}
14776			DBG(("%s: dropping last-cpu hint\n", __FUNCTION__));
14777			priv->cpu = false;
14778		}
14779
14780		if (dx | dy)
14781			RegionTranslate(&region, -dx, -dy);
14782	}
14783
14784	/* If the source is already on the GPU, keep the operation on the GPU */
14785	if (gc->fillStyle == FillTiled && !gc->tileIsPixel &&
14786	    sna_pixmap_is_gpu(gc->tile.pixmap)) {
14787		DBG(("%s: source is already on the gpu\n", __FUNCTION__));
14788		hint |= FORCE_GPU;
14789	}
14790
14791	bo = sna_drawable_use_bo(draw, hint, &region.extents, &damage);
14792	if (bo == NULL) {
14793		DBG(("%s: not using GPU, hint=%x\n", __FUNCTION__, hint));
14794		goto fallback;
14795	}
14796	if (hint & REPLACES && UNDO)
14797		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
14798
14799	if (gc_is_solid(gc, &color)) {
14800		DBG(("%s: solid fill [%08x], testing for blt\n",
14801		     __FUNCTION__, color));
14802
14803		if (sna_poly_fill_rect_blt(draw,
14804					   bo, damage,
14805					   gc, color, n, rect,
14806					   &region.extents, flags & 2))
14807			return;
14808	} else if (gc->fillStyle == FillTiled) {
14809		DBG(("%s: tiled fill, testing for blt\n", __FUNCTION__));
14810
14811		if (sna_poly_fill_rect_tiled_blt(draw, bo, damage,
14812						 gc, n, rect,
14813						 &region.extents, flags & 2))
14814			return;
14815	} else {
14816		DBG(("%s: stippled fill, testing for blt\n", __FUNCTION__));
14817
14818		if (sna_poly_fill_rect_stippled_blt(draw, bo, damage,
14819						    gc, n, rect,
14820						    &region.extents, flags & 2))
14821			return;
14822	}
14823
14824fallback:
14825	DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__,
14826	     region.extents.x1, region.extents.y1,
14827	     region.extents.x2, region.extents.y2));
14828	region.data = NULL;
14829	if (!region_maybe_clip(&region, gc->pCompositeClip)) {
14830		DBG(("%s: nothing to do, all clipped\n", __FUNCTION__));
14831		return;
14832	}
14833
14834	if (!sna_gc_move_to_cpu(gc, draw, &region))
14835		goto out;
14836	if (!sna_drawable_move_region_to_cpu(draw, &region,
14837					     drawable_gc_flags(draw, gc, n > 1)))
14838		goto out;
14839
14840	if (sigtrap_get() == 0) {
14841		DBG(("%s: fallback - fbPolyFillRect\n", __FUNCTION__));
14842		fbPolyFillRect(draw, gc, n, rect);
14843		FALLBACK_FLUSH(draw);
14844		sigtrap_put();
14845	}
14846out:
14847	sna_gc_move_to_gpu(gc);
14848	RegionUninit(&region);
14849}
14850
14851static void
14852sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *r)
14853{
14854	struct sna_fill_spans *data = sna_gc(gc)->priv;
14855	uint32_t color;
14856
14857	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
14858	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
14859	     (gc->fillStyle == FillSolid ||
14860	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
14861	     gc->fillStyle, gc->tileIsPixel,
14862	     gc->alu));
14863
14864	assert(PM_IS_SOLID(draw, gc->planemask));
14865	if (n == 0)
14866		return;
14867
14868	/* The mi routines do not attempt to keep the spans it generates
14869	 * within the clip, so we must run them through the clipper.
14870	 */
14871
14872	if (gc_is_solid(gc, &color)) {
14873		(void)sna_poly_fill_rect_blt(draw,
14874					     data->bo, data->damage,
14875					     gc, color, n, r,
14876					     &data->region.extents, true);
14877	} else if (gc->fillStyle == FillTiled) {
14878		(void)sna_poly_fill_rect_tiled_blt(draw,
14879						   data->bo, data->damage,
14880						   gc, n, r,
14881						   &data->region.extents, true);
14882	} else {
14883		(void)sna_poly_fill_rect_stippled_blt(draw,
14884						    data->bo, data->damage,
14885						    gc, n, r,
14886						    &data->region.extents, true);
14887	}
14888}
14889
14890static void
14891sna_poly_fill_arc(DrawablePtr draw, GCPtr gc, int n, xArc *arc)
14892{
14893	struct sna_fill_spans data;
14894	struct sna_pixmap *priv;
14895
14896	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
14897	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
14898	     (gc->fillStyle == FillSolid ||
14899	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
14900	     gc->fillStyle, gc->tileIsPixel,
14901	     gc->alu));
14902
14903	data.flags = sna_poly_arc_extents(draw, gc, n, arc,
14904					  &data.region.extents);
14905	if (data.flags == 0)
14906		return;
14907
14908	DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
14909	     data.region.extents.x1, data.region.extents.y1,
14910	     data.region.extents.x2, data.region.extents.y2,
14911	     data.flags));
14912
14913	data.region.data = NULL;
14914
14915	if (FORCE_FALLBACK)
14916		goto fallback;
14917
14918	if (!ACCEL_POLY_FILL_ARC)
14919		goto fallback;
14920
14921	data.pixmap = get_drawable_pixmap(draw);
14922	data.sna = to_sna_from_pixmap(data.pixmap);
14923	priv = sna_pixmap(data.pixmap);
14924	if (priv == NULL) {
14925		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
14926		goto fallback;
14927	}
14928
14929	if (wedged(data.sna)) {
14930		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
14931		goto fallback;
14932	}
14933
14934	if (!PM_IS_SOLID(draw, gc->planemask))
14935		goto fallback;
14936
14937	if ((data.bo = sna_drawable_use_bo(draw, PREFER_GPU,
14938					   &data.region.extents,
14939					   &data.damage))) {
14940		uint32_t color;
14941
14942		get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy);
14943		sna_gc(gc)->priv = &data;
14944
14945		if (gc_is_solid(gc, &color)) {
14946			struct sna_fill_op fill;
14947
14948			if (!sna_fill_init_blt(&fill,
14949					       data.sna, data.pixmap,
14950					       data.bo, gc->alu, color,
14951					       FILL_SPANS))
14952				goto fallback;
14953
14954			data.op = &fill;
14955
14956			if ((data.flags & 2) == 0) {
14957				if (data.dx | data.dy)
14958					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
14959				else
14960					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
14961			} else {
14962				if (!region_maybe_clip(&data.region,
14963						       gc->pCompositeClip))
14964					return;
14965
14966				if (region_is_singular(&data.region))
14967					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
14968				else
14969					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
14970			}
14971			assert(gc->miTranslate);
14972			gc->ops = &sna_gc_ops__tmp;
14973
14974			miPolyFillArc(draw, gc, n, arc);
14975			fill.done(data.sna, &fill);
14976		} else {
14977			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
14978			gc->ops = &sna_gc_ops__tmp;
14979
14980			miPolyFillArc(draw, gc, n, arc);
14981		}
14982
14983		gc->ops = (GCOps *)&sna_gc_ops;
14984		if (data.damage) {
14985			if (data.dx | data.dy)
14986				pixman_region_translate(&data.region, data.dx, data.dy);
14987			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
14988			sna_damage_add(data.damage, &data.region);
14989		}
14990		assert_pixmap_damage(data.pixmap);
14991		RegionUninit(&data.region);
14992		return;
14993	}
14994
14995fallback:
14996	DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__,
14997	     data.region.extents.x1, data.region.extents.y1,
14998	     data.region.extents.x2, data.region.extents.y2));
14999	if (!region_maybe_clip(&data.region, gc->pCompositeClip)) {
15000		DBG(("%s: nothing to do, all clipped\n", __FUNCTION__));
15001		return;
15002	}
15003
15004	if (!sna_gc_move_to_cpu(gc, draw, &data.region))
15005		goto out;
15006	if (!sna_drawable_move_region_to_cpu(draw, &data.region,
15007					     drawable_gc_flags(draw, gc, true)))
15008		goto out;
15009
15010	if (sigtrap_get() == 0) {
15011		DBG(("%s: fallback -- miPolyFillArc -> sna_fill_spans__cpu\n",
15012		     __FUNCTION__));
15013		miPolyFillArc(draw, gc, n, arc);
15014		sigtrap_put();
15015	}
15016out:
15017	sna_gc_move_to_gpu(gc);
15018	RegionUninit(&data.region);
15019}
15020
15021struct sna_font {
15022	CharInfoRec glyphs8[256];
15023	CharInfoRec *glyphs16[256];
15024};
15025#define GLYPH_INVALID (void *)1
15026#define GLYPH_EMPTY (void *)2
15027
15028static Bool
15029sna_realize_font(ScreenPtr screen, FontPtr font)
15030{
15031	struct sna_font *priv;
15032
15033	DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key));
15034
15035	priv = calloc(1, sizeof(struct sna_font));
15036	if (priv == NULL)
15037		return FALSE;
15038
15039	if (!FontSetPrivate(font, sna_font_key, priv)) {
15040		free(priv);
15041		return FALSE;
15042	}
15043
15044	return TRUE;
15045}
15046
15047static Bool
15048sna_unrealize_font(ScreenPtr screen, FontPtr font)
15049{
15050	struct sna_font *priv = FontGetPrivate(font, sna_font_key);
15051	int i, j;
15052
15053	DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key));
15054
15055	if (priv == NULL)
15056		return TRUE;
15057
15058	for (i = 0; i < 256; i++) {
15059		if ((uintptr_t)priv->glyphs8[i].bits & ~3)
15060			free(priv->glyphs8[i].bits);
15061	}
15062	for (j = 0; j < 256; j++) {
15063		if (priv->glyphs16[j] == NULL)
15064			continue;
15065
15066		for (i = 0; i < 256; i++) {
15067			if ((uintptr_t)priv->glyphs16[j][i].bits & ~3)
15068				free(priv->glyphs16[j][i].bits);
15069		}
15070		free(priv->glyphs16[j]);
15071	}
15072	free(priv);
15073
15074	FontSetPrivate(font, sna_font_key, NULL);
15075	return TRUE;
15076}
15077
15078static bool
15079sna_glyph_blt(DrawablePtr drawable, GCPtr gc,
15080	      int _x, int _y, unsigned int _n,
15081	      CharInfoPtr *_info,
15082	      RegionRec *clip,
15083	      uint32_t fg, uint32_t bg,
15084	      bool transparent)
15085{
15086	PixmapPtr pixmap = get_drawable_pixmap(drawable);
15087	struct sna *sna = to_sna_from_pixmap(pixmap);
15088	struct kgem_bo *bo;
15089	struct sna_damage **damage;
15090	const BoxRec *extents, *last_extents;
15091	uint32_t *b;
15092	int16_t dx, dy;
15093	uint32_t br00;
15094	uint16_t unwind_batch, unwind_reloc;
15095	unsigned hint;
15096
15097	uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S;
15098
15099	DBG(("%s (%d, %d) x %d, fg=%08x, bg=%08x alu=%02x\n",
15100	     __FUNCTION__, _x, _y, _n, fg, bg, rop));
15101
15102	if (wedged(sna)) {
15103		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
15104		return false;
15105	}
15106
15107	if (!transparent && clip->data == NULL)
15108		hint = PREFER_GPU | IGNORE_DAMAGE;
15109	else
15110		hint = PREFER_GPU;
15111
15112	bo = sna_drawable_use_bo(drawable, hint, &clip->extents, &damage);
15113	if (bo == NULL)
15114		return false;
15115
15116	if (bo->tiling == I915_TILING_Y) {
15117		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
15118		assert(bo == __sna_pixmap_get_bo(pixmap));
15119		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
15120		if (bo == NULL) {
15121			DBG(("%s: fallback -- unable to change tiling\n",
15122			     __FUNCTION__));
15123			return false;
15124		}
15125	}
15126
15127	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
15128		RegionTranslate(clip, dx, dy);
15129	_x += drawable->x + dx;
15130	_y += drawable->y + dy;
15131
15132	extents = region_rects(clip);
15133	last_extents = extents + region_num_rects(clip);
15134
15135	if (!transparent) { /* emulate miImageGlyphBlt */
15136		if (!sna_blt_fill_boxes(sna, GXcopy,
15137					bo, drawable->bitsPerPixel,
15138					bg, extents, last_extents - extents)) {
15139			RegionTranslate(clip, -dx, -dy);
15140			return false;
15141		}
15142	}
15143
15144	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
15145	if (!kgem_check_batch(&sna->kgem, 20) ||
15146	    !kgem_check_bo_fenced(&sna->kgem, bo) ||
15147	    !kgem_check_reloc(&sna->kgem, 1)) {
15148		kgem_submit(&sna->kgem);
15149		if (!kgem_check_bo_fenced(&sna->kgem, bo)) {
15150			RegionTranslate(clip, -dx, -dy);
15151			return false;
15152		}
15153		_kgem_set_mode(&sna->kgem, KGEM_BLT);
15154	}
15155
15156	DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
15157	     __FUNCTION__,
15158	     extents->x1, extents->y1,
15159	     extents->x2, extents->y2));
15160
15161	unwind_batch = sna->kgem.nbatch;
15162	unwind_reloc = sna->kgem.nreloc;
15163
15164	assert(sna->kgem.mode == KGEM_BLT);
15165	b = sna->kgem.batch + sna->kgem.nbatch;
15166	if (sna->kgem.gen >= 0100) {
15167		b[0] = XY_SETUP_BLT | 3 << 20 | 8;
15168		b[1] = bo->pitch;
15169		if (sna->kgem.gen >= 040 && bo->tiling) {
15170			b[0] |= BLT_DST_TILED;
15171			b[1] >>= 2;
15172		}
15173		b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15174		b[2] = extents->y1 << 16 | extents->x1;
15175		b[3] = extents->y2 << 16 | extents->x2;
15176		*(uint64_t *)(b+4) =
15177			kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
15178					 I915_GEM_DOMAIN_RENDER << 16 |
15179					 I915_GEM_DOMAIN_RENDER |
15180					 KGEM_RELOC_FENCED,
15181					 0);
15182		b[6] = bg;
15183		b[7] = fg;
15184		b[8] = 0;
15185		b[9] = 0;
15186		sna->kgem.nbatch += 10;
15187	} else {
15188		b[0] = XY_SETUP_BLT | 3 << 20 | 6;
15189		b[1] = bo->pitch;
15190		if (sna->kgem.gen >= 040 && bo->tiling) {
15191			b[0] |= BLT_DST_TILED;
15192			b[1] >>= 2;
15193		}
15194		b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15195		b[2] = extents->y1 << 16 | extents->x1;
15196		b[3] = extents->y2 << 16 | extents->x2;
15197		b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
15198				      I915_GEM_DOMAIN_RENDER << 16 |
15199				      I915_GEM_DOMAIN_RENDER |
15200				      KGEM_RELOC_FENCED,
15201				      0);
15202		b[5] = bg;
15203		b[6] = fg;
15204		b[7] = 0;
15205		sna->kgem.nbatch += 8;
15206	}
15207
15208	br00 = XY_TEXT_IMMEDIATE_BLT;
15209	if (bo->tiling && sna->kgem.gen >= 040)
15210		br00 |= BLT_DST_TILED;
15211
15212	do {
15213		CharInfoPtr *info = _info;
15214		int x = _x, y = _y, n = _n;
15215
15216		do {
15217			CharInfoPtr c = *info++;
15218			int w = GLYPHWIDTHPIXELS(c);
15219			int h = GLYPHHEIGHTPIXELS(c);
15220			int w8 = (w + 7) >> 3;
15221			int x1, y1, len;
15222
15223			if (c->bits == GLYPH_EMPTY)
15224				goto skip;
15225
15226			len = (w8 * h + 7) >> 3 << 1;
15227			x1 = x + c->metrics.leftSideBearing;
15228			y1 = y - c->metrics.ascent;
15229
15230			DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__,
15231			     x,y, x1, y1, w, w8, h, len));
15232
15233			if (x1 >= extents->x2 || y1 >= extents->y2)
15234				goto skip;
15235			if (x1 + w <= extents->x1 || y1 + h <= extents->y1)
15236				goto skip;
15237
15238			assert(len > 0);
15239			if (!kgem_check_batch(&sna->kgem, 3+len)) {
15240				_kgem_submit(&sna->kgem);
15241				_kgem_set_mode(&sna->kgem, KGEM_BLT);
15242
15243				DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n",
15244				     __FUNCTION__,
15245				     extents->x1, extents->y1,
15246				     extents->x2, extents->y2));
15247
15248				unwind_batch = sna->kgem.nbatch;
15249				unwind_reloc = sna->kgem.nreloc;
15250
15251				assert(sna->kgem.mode == KGEM_BLT);
15252				b = sna->kgem.batch + sna->kgem.nbatch;
15253				if (sna->kgem.gen >= 0100) {
15254					b[0] = XY_SETUP_BLT | 3 << 20 | 8;
15255					b[1] = bo->pitch;
15256					if (bo->tiling) {
15257						b[0] |= BLT_DST_TILED;
15258						b[1] >>= 2;
15259					}
15260					b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15261					b[2] = extents->y1 << 16 | extents->x1;
15262					b[3] = extents->y2 << 16 | extents->x2;
15263					*(uint64_t *)(b+4) =
15264						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
15265								 I915_GEM_DOMAIN_RENDER << 16 |
15266								 I915_GEM_DOMAIN_RENDER |
15267								 KGEM_RELOC_FENCED,
15268								 0);
15269					b[6] = bg;
15270					b[7] = fg;
15271					b[8] = 0;
15272					b[9] = 0;
15273					sna->kgem.nbatch += 10;
15274				} else {
15275					b[0] = XY_SETUP_BLT | 3 << 20 | 6;
15276					b[1] = bo->pitch;
15277					if (sna->kgem.gen >= 040 && bo->tiling) {
15278						b[0] |= BLT_DST_TILED;
15279						b[1] >>= 2;
15280					}
15281					b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15282					b[2] = extents->y1 << 16 | extents->x1;
15283					b[3] = extents->y2 << 16 | extents->x2;
15284					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
15285							      I915_GEM_DOMAIN_RENDER << 16 |
15286							      I915_GEM_DOMAIN_RENDER |
15287							      KGEM_RELOC_FENCED,
15288							      0);
15289					b[5] = bg;
15290					b[6] = fg;
15291					b[7] = 0;
15292					sna->kgem.nbatch += 8;
15293				}
15294			}
15295
15296			assert(sna->kgem.mode == KGEM_BLT);
15297			b = sna->kgem.batch + sna->kgem.nbatch;
15298			sna->kgem.nbatch += 3 + len;
15299
15300			b[0] = br00 | (1 + len);
15301			b[1] = (uint16_t)y1 << 16 | (uint16_t)x1;
15302			b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w);
15303			{
15304				uint64_t *src = (uint64_t *)c->bits;
15305				uint64_t *dst = (uint64_t *)(b + 3);
15306				do  {
15307					*dst++ = *src++;
15308					len -= 2;
15309				} while (len);
15310			}
15311
15312			if (damage) {
15313				BoxRec r;
15314
15315				r.x1 = x1;
15316				r.y1 = y1;
15317				r.x2 = x1 + w;
15318				r.y2 = y1 + h;
15319				if (box_intersect(&r, extents))
15320					sna_damage_add_box(damage, &r);
15321			}
15322skip:
15323			x += c->metrics.characterWidth;
15324		} while (--n);
15325
15326		if (++extents == last_extents)
15327			break;
15328
15329		if (kgem_check_batch(&sna->kgem, 3)) {
15330			assert(sna->kgem.mode == KGEM_BLT);
15331			b = sna->kgem.batch + sna->kgem.nbatch;
15332			sna->kgem.nbatch += 3;
15333
15334			DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
15335			     __FUNCTION__,
15336			     extents->x1, extents->y1,
15337			     extents->x2, extents->y2));
15338
15339			b[0] = XY_SETUP_CLIP;
15340			b[1] = extents->y1 << 16 | extents->x1;
15341			b[2] = extents->y2 << 16 | extents->x2;
15342		}
15343	} while (1);
15344
15345	if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) {
15346		sna->kgem.nbatch = unwind_batch;
15347		sna->kgem.nreloc = unwind_reloc;
15348		if (sna->kgem.nbatch == 0)
15349			kgem_bo_undo(&sna->kgem, bo);
15350	}
15351
15352	assert_pixmap_damage(pixmap);
15353	sna->blt_state.fill_bo = 0;
15354	return true;
15355}
15356
15357static void
15358sna_glyph_extents(FontPtr font,
15359		  CharInfoPtr *info,
15360		  unsigned long count,
15361		  ExtentInfoRec *extents)
15362{
15363	extents->drawDirection = font->info.drawDirection;
15364	extents->fontAscent = font->info.fontAscent;
15365	extents->fontDescent = font->info.fontDescent;
15366
15367	extents->overallAscent = info[0]->metrics.ascent;
15368	extents->overallDescent = info[0]->metrics.descent;
15369	extents->overallLeft = info[0]->metrics.leftSideBearing;
15370	extents->overallRight = info[0]->metrics.rightSideBearing;
15371	extents->overallWidth = info[0]->metrics.characterWidth;
15372
15373	while (--count) {
15374		CharInfoPtr p =*++info;
15375		int v;
15376
15377		if (p->metrics.ascent > extents->overallAscent)
15378			extents->overallAscent = p->metrics.ascent;
15379		if (p->metrics.descent > extents->overallDescent)
15380			extents->overallDescent = p->metrics.descent;
15381
15382		v = extents->overallWidth + p->metrics.leftSideBearing;
15383		if (v < extents->overallLeft)
15384			extents->overallLeft = v;
15385
15386		v = extents->overallWidth + p->metrics.rightSideBearing;
15387		if (v > extents->overallRight)
15388			extents->overallRight = v;
15389
15390		extents->overallWidth += p->metrics.characterWidth;
15391	}
15392}
15393
15394static bool sna_set_glyph(CharInfoPtr in, CharInfoPtr out)
15395{
15396	int w = GLYPHWIDTHPIXELS(in);
15397	int h = GLYPHHEIGHTPIXELS(in);
15398	int stride = GLYPHWIDTHBYTESPADDED(in);
15399	uint8_t *dst, *src;
15400	int clear = 1;
15401
15402	out->metrics = in->metrics;
15403
15404	/* Skip empty glyphs */
15405	if (w == 0 || h == 0 || ((w|h) == 1 && (in->bits[0] & 1) == 0)) {
15406		out->bits = GLYPH_EMPTY;
15407		return true;
15408	}
15409
15410	w = (w + 7) >> 3;
15411
15412	out->bits = malloc((w*h + 7) & ~7);
15413	if (out->bits == NULL)
15414		return false;
15415
15416	VG(memset(out->bits, 0, (w*h + 7) & ~7));
15417	src = (uint8_t *)in->bits;
15418	dst = (uint8_t *)out->bits;
15419	stride -= w;
15420	do {
15421		int i = w;
15422		do {
15423			clear &= *src == 0;
15424			*dst++ = byte_reverse(*src++);
15425		} while (--i);
15426		src += stride;
15427	} while (--h);
15428
15429	if (clear) {
15430		free(out->bits);
15431		out->bits = GLYPH_EMPTY;
15432	}
15433
15434	return true;
15435}
15436
15437inline static bool sna_get_glyph8(FontPtr font, struct sna_font *priv,
15438				  uint8_t g, CharInfoPtr *out)
15439{
15440	unsigned long n;
15441	CharInfoPtr p, ret;
15442
15443	p = &priv->glyphs8[g];
15444	if (p->bits) {
15445		*out = p;
15446		return p->bits != GLYPH_INVALID;
15447	}
15448
15449	font->get_glyphs(font, 1, &g, Linear8Bit, &n, &ret);
15450	if (n == 0) {
15451		p->bits = GLYPH_INVALID;
15452		return false;
15453	}
15454
15455	return sna_set_glyph(ret, *out = p);
15456}
15457
15458inline static bool sna_get_glyph16(FontPtr font, struct sna_font *priv,
15459				   uint16_t g, CharInfoPtr *out)
15460{
15461	unsigned long n;
15462	CharInfoPtr page, p, ret;
15463
15464	page = priv->glyphs16[g>>8];
15465	if (page == NULL)
15466		page = priv->glyphs16[g>>8] = calloc(256, sizeof(CharInfoRec));
15467
15468	p = &page[g&0xff];
15469	if (p->bits) {
15470		*out = p;
15471		return p->bits != GLYPH_INVALID;
15472	}
15473
15474	font->get_glyphs(font, 1, (unsigned char *)&g,
15475			 FONTLASTROW(font) ? TwoD16Bit : Linear16Bit,
15476			 &n, &ret);
15477	if (n == 0) {
15478		p->bits = GLYPH_INVALID;
15479		return false;
15480	}
15481
15482	return sna_set_glyph(ret, *out = p);
15483}
15484
15485static inline bool sna_font_too_large(FontPtr font)
15486{
15487	int top = max(FONTMAXBOUNDS(font, ascent), FONTASCENT(font));
15488	int bot = max(FONTMAXBOUNDS(font, descent), FONTDESCENT(font));
15489	int width = max(FONTMAXBOUNDS(font, characterWidth), -FONTMINBOUNDS(font, characterWidth));
15490	DBG(("%s? (%d + %d) x %d: %d > 124\n", __FUNCTION__,
15491	     top, bot, width, (top + bot) * (width + 7)/8));
15492	return (top + bot) * (width + 7)/8 > 124;
15493}
15494
15495static int
15496sna_poly_text8(DrawablePtr drawable, GCPtr gc,
15497	       int x, int y,
15498	       int count, char *chars)
15499{
15500	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
15501	CharInfoPtr info[255];
15502	ExtentInfoRec extents;
15503	RegionRec region;
15504	long unsigned i, n;
15505	uint32_t fg;
15506
15507	for (i = n = 0; i < count; i++) {
15508		if (sna_get_glyph8(gc->font, priv, chars[i], &info[n]))
15509			n++;
15510	}
15511	if (n == 0)
15512		return x;
15513
15514	sna_glyph_extents(gc->font, info, n, &extents);
15515	region.extents.x1 = x + extents.overallLeft;
15516	region.extents.y1 = y - extents.overallAscent;
15517	region.extents.x2 = x + extents.overallRight;
15518	region.extents.y2 = y + extents.overallDescent;
15519
15520	translate_box(&region.extents, drawable);
15521	clip_box(&region.extents, gc);
15522	if (box_empty(&region.extents))
15523		return x + extents.overallRight;
15524
15525	region.data = NULL;
15526	if (!region_maybe_clip(&region, gc->pCompositeClip))
15527		return x + extents.overallRight;
15528
15529	if (FORCE_FALLBACK)
15530		goto fallback;
15531
15532	if (!ACCEL_POLY_TEXT8)
15533		goto fallback;
15534
15535	if (sna_font_too_large(gc->font))
15536		goto fallback;
15537
15538	if (!PM_IS_SOLID(drawable, gc->planemask))
15539		goto fallback;
15540
15541	if (!gc_is_solid(gc, &fg))
15542		goto fallback;
15543
15544	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region, fg, -1, true)) {
15545fallback:
15546		DBG(("%s: fallback\n", __FUNCTION__));
15547		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
15548				     Linear8Bit, &n, info);
15549
15550		if (!sna_gc_move_to_cpu(gc, drawable, &region))
15551			goto out;
15552		if (!sna_drawable_move_region_to_cpu(drawable, &region,
15553						     MOVE_READ | MOVE_WRITE))
15554			goto out;
15555
15556		if (sigtrap_get() == 0) {
15557			DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
15558			fbPolyGlyphBlt(drawable, gc, x, y, n,
15559				       info, FONTGLYPHS(gc->font));
15560			FALLBACK_FLUSH(drawable);
15561			sigtrap_put();
15562		}
15563out:
15564		sna_gc_move_to_gpu(gc);
15565	}
15566	RegionUninit(&region);
15567	return x + extents.overallRight;
15568}
15569
15570static int
15571sna_poly_text16(DrawablePtr drawable, GCPtr gc,
15572		int x, int y,
15573		int count, unsigned short *chars)
15574{
15575	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
15576	CharInfoPtr info[255];
15577	ExtentInfoRec extents;
15578	RegionRec region;
15579	long unsigned i, n;
15580	uint32_t fg;
15581
15582	for (i = n = 0; i < count; i++) {
15583		if (sna_get_glyph16(gc->font, priv, chars[i], &info[n]))
15584			n++;
15585	}
15586	if (n == 0)
15587		return x;
15588
15589	sna_glyph_extents(gc->font, info, n, &extents);
15590	region.extents.x1 = x + extents.overallLeft;
15591	region.extents.y1 = y - extents.overallAscent;
15592	region.extents.x2 = x + extents.overallRight;
15593	region.extents.y2 = y + extents.overallDescent;
15594
15595	translate_box(&region.extents, drawable);
15596	clip_box(&region.extents, gc);
15597	if (box_empty(&region.extents))
15598		return x + extents.overallRight;
15599
15600	region.data = NULL;
15601	if (!region_maybe_clip(&region, gc->pCompositeClip))
15602		return x + extents.overallRight;
15603
15604	if (FORCE_FALLBACK)
15605		goto fallback;
15606
15607	if (!ACCEL_POLY_TEXT16)
15608		goto fallback;
15609
15610	if (sna_font_too_large(gc->font))
15611		goto fallback;
15612
15613	if (!PM_IS_SOLID(drawable, gc->planemask))
15614		goto fallback;
15615
15616	if (!gc_is_solid(gc, &fg))
15617		goto fallback;
15618
15619	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region, fg, -1, true)) {
15620fallback:
15621		DBG(("%s: fallback\n", __FUNCTION__));
15622		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
15623				     FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit,
15624				     &n, info);
15625
15626		if (!sna_gc_move_to_cpu(gc, drawable, &region))
15627			goto out;
15628		if (!sna_drawable_move_region_to_cpu(drawable, &region,
15629						     MOVE_READ | MOVE_WRITE))
15630			goto out;
15631
15632		if (sigtrap_get() == 0) {
15633			DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
15634			fbPolyGlyphBlt(drawable, gc, x, y, n,
15635				       info, FONTGLYPHS(gc->font));
15636			FALLBACK_FLUSH(drawable);
15637			sigtrap_put();
15638		}
15639out:
15640		sna_gc_move_to_gpu(gc);
15641	}
15642	RegionUninit(&region);
15643	return x + extents.overallRight;
15644}
15645
15646static void
15647sna_image_text8(DrawablePtr drawable, GCPtr gc,
15648		int x, int y,
15649		int count, char *chars)
15650{
15651	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
15652	CharInfoPtr info[255];
15653	ExtentInfoRec extents;
15654	RegionRec region;
15655	long unsigned i, n;
15656
15657	for (i = n = 0; i < count; i++) {
15658		if (sna_get_glyph8(gc->font, priv, chars[i], &info[n]))
15659			n++;
15660	}
15661	if (n == 0)
15662		return;
15663
15664	sna_glyph_extents(gc->font, info, n, &extents);
15665	region.extents.x1 = x + MIN(0, extents.overallLeft);
15666	region.extents.y1 = y - extents.fontAscent;
15667	region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight);
15668	region.extents.y2 = y + extents.fontDescent;
15669
15670	DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n",
15671	     __FUNCTION__, n, count,
15672	     extents.overallLeft, extents.overallRight, extents.overallWidth,
15673	     extents.fontAscent, extents.fontDescent,
15674	     region.extents.x1, region.extents.y1,
15675	     region.extents.x2, region.extents.y2));
15676
15677	translate_box(&region.extents, drawable);
15678	clip_box(&region.extents, gc);
15679	if (box_empty(&region.extents))
15680		return;
15681
15682	region.data = NULL;
15683	if (!region_maybe_clip(&region, gc->pCompositeClip))
15684		return;
15685
15686	DBG(("%s: clipped extents (%d, %d), (%d, %d)\n",
15687	     __FUNCTION__,
15688	     region.extents.x1, region.extents.y1,
15689	     region.extents.x2, region.extents.y2));
15690
15691	if (FORCE_FALLBACK)
15692		goto fallback;
15693
15694	if (!ACCEL_IMAGE_TEXT8)
15695		goto fallback;
15696
15697	if (sna_font_too_large(gc->font))
15698		goto fallback;
15699
15700	if (!PM_IS_SOLID(drawable, gc->planemask))
15701		goto fallback;
15702
15703	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region,
15704			   gc->fgPixel, gc->bgPixel, false)) {
15705fallback:
15706		DBG(("%s: fallback\n", __FUNCTION__));
15707		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
15708				     Linear8Bit, &n, info);
15709
15710		if (!sna_gc_move_to_cpu(gc, drawable, &region))
15711			goto out;
15712		if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_WRITE))
15713			goto out;
15714
15715		if (sigtrap_get() == 0) {
15716			DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
15717			fbImageGlyphBlt(drawable, gc, x, y, n,
15718					info, FONTGLYPHS(gc->font));
15719			FALLBACK_FLUSH(drawable);
15720			sigtrap_put();
15721		}
15722out:
15723		sna_gc_move_to_gpu(gc);
15724	}
15725	RegionUninit(&region);
15726}
15727
15728static void
15729sna_image_text16(DrawablePtr drawable, GCPtr gc,
15730		int x, int y,
15731		int count, unsigned short *chars)
15732{
15733	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
15734	CharInfoPtr info[255];
15735	ExtentInfoRec extents;
15736	RegionRec region;
15737	long unsigned i, n;
15738
15739	for (i = n = 0; i < count; i++) {
15740		if (sna_get_glyph16(gc->font, priv, chars[i], &info[n]))
15741			n++;
15742	}
15743	if (n == 0)
15744		return;
15745
15746	sna_glyph_extents(gc->font, info, n, &extents);
15747	region.extents.x1 = x + MIN(0, extents.overallLeft);
15748	region.extents.y1 = y - extents.fontAscent;
15749	region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight);
15750	region.extents.y2 = y + extents.fontDescent;
15751
15752	DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n",
15753	     __FUNCTION__, n, count,
15754	     extents.overallLeft, extents.overallRight, extents.overallWidth,
15755	     extents.fontAscent, extents.fontDescent,
15756	     region.extents.x1, region.extents.y1,
15757	     region.extents.x2, region.extents.y2));
15758
15759	translate_box(&region.extents, drawable);
15760	clip_box(&region.extents, gc);
15761	if (box_empty(&region.extents))
15762		return;
15763
15764	region.data = NULL;
15765	if (!region_maybe_clip(&region, gc->pCompositeClip))
15766		return;
15767
15768	DBG(("%s: clipped extents (%d, %d), (%d, %d)\n",
15769	     __FUNCTION__,
15770	     region.extents.x1, region.extents.y1,
15771	     region.extents.x2, region.extents.y2));
15772
15773	if (FORCE_FALLBACK)
15774		goto fallback;
15775
15776	if (!ACCEL_IMAGE_TEXT16)
15777		goto fallback;
15778
15779	if (sna_font_too_large(gc->font))
15780		goto fallback;
15781
15782	if (!PM_IS_SOLID(drawable, gc->planemask))
15783		goto fallback;
15784
15785	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region,
15786			   gc->fgPixel, gc->bgPixel, false)) {
15787fallback:
15788		DBG(("%s: fallback\n", __FUNCTION__));
15789		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
15790				     FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit,
15791				     &n, info);
15792
15793		if (!sna_gc_move_to_cpu(gc, drawable, &region))
15794			goto out;
15795		if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_WRITE))
15796			goto out;
15797
15798		if (sigtrap_get() == 0) {
15799			DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
15800			fbImageGlyphBlt(drawable, gc, x, y, n,
15801					info, FONTGLYPHS(gc->font));
15802			FALLBACK_FLUSH(drawable);
15803			sigtrap_put();
15804		}
15805out:
15806		sna_gc_move_to_gpu(gc);
15807	}
15808	RegionUninit(&region);
15809}
15810
15811/* XXX Damage bypasses the Text interface and so we lose our custom gluphs */
15812static bool
15813sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc,
15814		       int _x, int _y, unsigned int _n,
15815		       CharInfoPtr *_info, pointer _base,
15816		       struct kgem_bo *bo,
15817		       struct sna_damage **damage,
15818		       RegionPtr clip,
15819		       uint32_t fg, uint32_t bg,
15820		       bool transparent)
15821{
15822	PixmapPtr pixmap = get_drawable_pixmap(drawable);
15823	struct sna *sna = to_sna_from_pixmap(pixmap);
15824	const BoxRec *extents, *last_extents;
15825	uint32_t *b;
15826	int16_t dx, dy;
15827	uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S;
15828	uint16_t unwind_batch, unwind_reloc;
15829
15830	DBG(("%s: pixmap=%ld, bo=%d, damage=%p, fg=%08x, bg=%08x\n",
15831	     __FUNCTION__, pixmap->drawable.serialNumber, bo->handle, damage, fg, bg));
15832
15833	if (bo->tiling == I915_TILING_Y) {
15834		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
15835		assert(bo == __sna_pixmap_get_bo(pixmap));
15836		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
15837		if (bo == NULL) {
15838			DBG(("%s: fallback -- unable to change tiling\n",
15839			     __FUNCTION__));
15840			return false;
15841		}
15842	}
15843
15844	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
15845		RegionTranslate(clip, dx, dy);
15846	_x += drawable->x + dx;
15847	_y += drawable->y + dy;
15848
15849	extents = region_rects(clip);
15850	last_extents = extents + region_num_rects(clip);
15851
15852	if (!transparent) { /* emulate miImageGlyphBlt */
15853		if (!sna_blt_fill_boxes(sna, GXcopy,
15854					bo, drawable->bitsPerPixel,
15855					bg, extents, last_extents - extents)) {
15856			RegionTranslate(clip, -dx, -dy);
15857			return false;
15858		}
15859	}
15860
15861	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
15862	if (!kgem_check_batch(&sna->kgem, 20) ||
15863	    !kgem_check_bo_fenced(&sna->kgem, bo) ||
15864	    !kgem_check_reloc(&sna->kgem, 1)) {
15865		kgem_submit(&sna->kgem);
15866		if (!kgem_check_bo_fenced(&sna->kgem, bo)) {
15867			RegionTranslate(clip, -dx, -dy);
15868			return false;
15869		}
15870		_kgem_set_mode(&sna->kgem, KGEM_BLT);
15871	}
15872
15873	unwind_batch = sna->kgem.nbatch;
15874	unwind_reloc = sna->kgem.nreloc;
15875
15876	DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
15877	     __FUNCTION__,
15878	     extents->x1, extents->y1,
15879	     extents->x2, extents->y2));
15880
15881	assert(sna->kgem.mode == KGEM_BLT);
15882	b = sna->kgem.batch + sna->kgem.nbatch;
15883	if (sna->kgem.gen >= 0100) {
15884		b[0] = XY_SETUP_BLT | 1 << 20 | 8;
15885		b[1] = bo->pitch;
15886		if (sna->kgem.gen >= 040 && bo->tiling) {
15887			b[0] |= BLT_DST_TILED;
15888			b[1] >>= 2;
15889		}
15890		b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15891		b[2] = extents->y1 << 16 | extents->x1;
15892		b[3] = extents->y2 << 16 | extents->x2;
15893		*(uint64_t *)(b+4) =
15894			kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
15895					 I915_GEM_DOMAIN_RENDER << 16 |
15896					 I915_GEM_DOMAIN_RENDER |
15897					 KGEM_RELOC_FENCED,
15898					 0);
15899		b[6] = bg;
15900		b[7] = fg;
15901		b[8] = 0;
15902		b[9] = 0;
15903		sna->kgem.nbatch += 10;
15904	} else {
15905		b[0] = XY_SETUP_BLT | 1 << 20 | 6;
15906		b[1] = bo->pitch;
15907		if (sna->kgem.gen >= 040 && bo->tiling) {
15908			b[0] |= BLT_DST_TILED;
15909			b[1] >>= 2;
15910		}
15911		b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
15912		b[2] = extents->y1 << 16 | extents->x1;
15913		b[3] = extents->y2 << 16 | extents->x2;
15914		b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
15915				      I915_GEM_DOMAIN_RENDER << 16 |
15916				      I915_GEM_DOMAIN_RENDER |
15917				      KGEM_RELOC_FENCED,
15918				      0);
15919		b[5] = bg;
15920		b[6] = fg;
15921		b[7] = 0;
15922		sna->kgem.nbatch += 8;
15923	}
15924
15925	do {
15926		CharInfoPtr *info = _info;
15927		int x = _x, y = _y, n = _n;
15928
15929		do {
15930			CharInfoPtr c = *info++;
15931			uint8_t *glyph = FONTGLYPHBITS(base, c);
15932			int w = GLYPHWIDTHPIXELS(c);
15933			int h = GLYPHHEIGHTPIXELS(c);
15934			int stride = GLYPHWIDTHBYTESPADDED(c);
15935			int w8 = (w + 7) >> 3;
15936			int x1, y1, len, i;
15937			uint8_t *byte;
15938
15939			if (w == 0 || h == 0)
15940				goto skip;
15941
15942			len = (w8 * h + 7) >> 3 << 1;
15943			x1 = x + c->metrics.leftSideBearing;
15944			y1 = y - c->metrics.ascent;
15945
15946			DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__,
15947			     x,y, x1, y1, w, w8, h, len));
15948
15949			if (x1 >= extents->x2 || y1 >= extents->y2 ||
15950			    x1 + w <= extents->x1 || y1 + h <= extents->y1) {
15951				DBG(("%s: glyph is clipped (%d, %d)x(%d,%d) against extents (%d, %d), (%d, %d)\n",
15952				     __FUNCTION__,
15953				     x1, y1, w, h,
15954				     extents->x1, extents->y1,
15955				     extents->x2, extents->y2));
15956				goto skip;
15957			}
15958
15959			{
15960				int clear = 1, j = h;
15961				uint8_t *g = glyph;
15962
15963				do {
15964					i = w8;
15965					do {
15966						clear = *g++ == 0;
15967					} while (clear && --i);
15968					g += stride - w8;
15969				} while (clear && --j);
15970				if (clear) {
15971					DBG(("%s: skipping clear glyph for ImageGlyph\n",
15972					     __FUNCTION__));
15973					goto skip;
15974				}
15975			}
15976
15977			assert(len > 0);
15978			if (!kgem_check_batch(&sna->kgem, 3+len)) {
15979				_kgem_submit(&sna->kgem);
15980				_kgem_set_mode(&sna->kgem, KGEM_BLT);
15981
15982				unwind_batch = sna->kgem.nbatch;
15983				unwind_reloc = sna->kgem.nreloc;
15984
15985				DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n",
15986				     __FUNCTION__,
15987				     extents->x1, extents->y1,
15988				     extents->x2, extents->y2));
15989
15990				assert(sna->kgem.mode == KGEM_BLT);
15991				b = sna->kgem.batch + sna->kgem.nbatch;
15992				if (sna->kgem.gen >= 0100) {
15993					b[0] = XY_SETUP_BLT | 1 << 20 | 8;
15994					b[1] = bo->pitch;
15995					if (bo->tiling) {
15996						b[0] |= BLT_DST_TILED;
15997						b[1] >>= 2;
15998					}
15999					b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
16000					b[2] = extents->y1 << 16 | extents->x1;
16001					b[3] = extents->y2 << 16 | extents->x2;
16002					*(uint64_t *)(b+4) =
16003						kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
16004								 I915_GEM_DOMAIN_RENDER << 16 |
16005								 I915_GEM_DOMAIN_RENDER |
16006								 KGEM_RELOC_FENCED,
16007								 0);
16008					b[6] = bg;
16009					b[7] = fg;
16010					b[8] = 0;
16011					b[9] = 0;
16012					sna->kgem.nbatch += 10;
16013				} else {
16014					b[0] = XY_SETUP_BLT | 1 << 20 | 6;
16015					b[1] = bo->pitch;
16016					if (sna->kgem.gen >= 040 && bo->tiling) {
16017						b[0] |= BLT_DST_TILED;
16018						b[1] >>= 2;
16019					}
16020					b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
16021					b[2] = extents->y1 << 16 | extents->x1;
16022					b[3] = extents->y2 << 16 | extents->x2;
16023					b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
16024							      I915_GEM_DOMAIN_RENDER << 16 |
16025							      I915_GEM_DOMAIN_RENDER |
16026							      KGEM_RELOC_FENCED,
16027							      0);
16028					b[5] = bg;
16029					b[6] = fg;
16030					b[7] = 0;
16031					sna->kgem.nbatch += 8;
16032				}
16033			}
16034
16035			assert(sna->kgem.mode == KGEM_BLT);
16036			b = sna->kgem.batch + sna->kgem.nbatch;
16037			sna->kgem.nbatch += 3 + len;
16038
16039			b[0] = XY_TEXT_IMMEDIATE_BLT | (1 + len);
16040			if (bo->tiling && sna->kgem.gen >= 040)
16041				b[0] |= BLT_DST_TILED;
16042			b[1] = (uint16_t)y1 << 16 | (uint16_t)x1;
16043			b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w);
16044
16045			byte = (uint8_t *)&b[3];
16046			stride -= w8;
16047			do {
16048				i = w8;
16049				do {
16050					*byte++ = byte_reverse(*glyph++);
16051				} while (--i);
16052				glyph += stride;
16053			} while (--h);
16054			while ((byte - (uint8_t *)&b[3]) & 7)
16055				*byte++ = 0;
16056			assert((uint32_t *)byte == sna->kgem.batch + sna->kgem.nbatch);
16057
16058			if (damage) {
16059				BoxRec r;
16060
16061				r.x1 = x1;
16062				r.y1 = y1;
16063				r.x2 = x1 + w;
16064				r.y2 = y1 + h;
16065				if (box_intersect(&r, extents))
16066					sna_damage_add_box(damage, &r);
16067			}
16068skip:
16069			x += c->metrics.characterWidth;
16070		} while (--n);
16071
16072		if (++extents == last_extents)
16073			break;
16074
16075		if (kgem_check_batch(&sna->kgem, 3 + 5)) {
16076			assert(sna->kgem.mode == KGEM_BLT);
16077			b = sna->kgem.batch + sna->kgem.nbatch;
16078			sna->kgem.nbatch += 3;
16079
16080			DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
16081			     __FUNCTION__,
16082			     extents->x1, extents->y1,
16083			     extents->x2, extents->y2));
16084
16085			b[0] = XY_SETUP_CLIP;
16086			b[1] = extents->y1 << 16 | extents->x1;
16087			b[2] = extents->y2 << 16 | extents->x2;
16088		}
16089	} while (1);
16090
16091	if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) {
16092		sna->kgem.nbatch = unwind_batch;
16093		sna->kgem.nreloc = unwind_reloc;
16094		if (sna->kgem.nbatch == 0)
16095			kgem_bo_undo(&sna->kgem, bo);
16096	}
16097
16098	assert_pixmap_damage(pixmap);
16099	sna->blt_state.fill_bo = 0;
16100	return true;
16101}
16102
16103static void
16104sna_image_glyph(DrawablePtr drawable, GCPtr gc,
16105		int x, int y, unsigned int n,
16106		CharInfoPtr *info, pointer base)
16107{
16108	PixmapPtr pixmap = get_drawable_pixmap(drawable);
16109	struct sna *sna = to_sna_from_pixmap(pixmap);
16110	ExtentInfoRec extents;
16111	RegionRec region;
16112	struct sna_damage **damage;
16113	struct kgem_bo *bo;
16114	unsigned hint;
16115
16116	if (n == 0)
16117		return;
16118
16119	sna_glyph_extents(gc->font, info, n, &extents);
16120	region.extents.x1 = x + MIN(0, extents.overallLeft);
16121	region.extents.y1 = y - extents.fontAscent;
16122	region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight);
16123	region.extents.y2 = y + extents.fontDescent;
16124
16125	DBG(("%s: count=%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n",
16126	     __FUNCTION__, n,
16127	     extents.overallLeft, extents.overallRight, extents.overallWidth,
16128	     extents.fontAscent, extents.fontDescent,
16129	     region.extents.x1, region.extents.y1,
16130	     region.extents.x2, region.extents.y2));
16131
16132	translate_box(&region.extents, drawable);
16133	clip_box(&region.extents, gc);
16134	if (box_empty(&region.extents))
16135		return;
16136
16137	DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__,
16138	     region.extents.x1, region.extents.y1,
16139	     region.extents.x2, region.extents.y2));
16140
16141	region.data = NULL;
16142	if (!region_maybe_clip(&region, gc->pCompositeClip))
16143		return;
16144
16145	if (FORCE_FALLBACK)
16146		goto fallback;
16147
16148	if (!ACCEL_IMAGE_GLYPH)
16149		goto fallback;
16150
16151	if (wedged(sna)) {
16152		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
16153		goto fallback;
16154	}
16155
16156	if (!PM_IS_SOLID(drawable, gc->planemask))
16157		goto fallback;
16158
16159	if (sna_font_too_large(gc->font))
16160		goto fallback;
16161
16162	if (region.data == NULL)
16163		hint = IGNORE_DAMAGE | PREFER_GPU;
16164	else
16165		hint = PREFER_GPU;
16166	if ((bo = sna_drawable_use_bo(drawable, hint,
16167				      &region.extents, &damage)) &&
16168	    sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base,
16169				   bo, damage, &region,
16170				   gc->fgPixel, gc->bgPixel, false))
16171		goto out;
16172
16173fallback:
16174	DBG(("%s: fallback\n", __FUNCTION__));
16175	if (!sna_gc_move_to_cpu(gc, drawable, &region))
16176		goto out_gc;
16177	if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_WRITE))
16178		goto out_gc;
16179
16180	if (sigtrap_get() == 0) {
16181		DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
16182		fbImageGlyphBlt(drawable, gc, x, y, n, info, base);
16183		FALLBACK_FLUSH(drawable);
16184		sigtrap_put();
16185	}
16186out_gc:
16187	sna_gc_move_to_gpu(gc);
16188out:
16189	RegionUninit(&region);
16190}
16191
16192static void
16193sna_poly_glyph(DrawablePtr drawable, GCPtr gc,
16194	       int x, int y, unsigned int n,
16195	       CharInfoPtr *info, pointer base)
16196{
16197	PixmapPtr pixmap = get_drawable_pixmap(drawable);
16198	struct sna *sna = to_sna_from_pixmap(pixmap);
16199	ExtentInfoRec extents;
16200	RegionRec region;
16201	struct sna_damage **damage;
16202	struct kgem_bo *bo;
16203	uint32_t fg;
16204
16205	if (n == 0)
16206		return;
16207
16208	sna_glyph_extents(gc->font, info, n, &extents);
16209	region.extents.x1 = x + extents.overallLeft;
16210	region.extents.y1 = y - extents.overallAscent;
16211	region.extents.x2 = x + extents.overallRight;
16212	region.extents.y2 = y + extents.overallDescent;
16213
16214	translate_box(&region.extents, drawable);
16215	clip_box(&region.extents, gc);
16216	if (box_empty(&region.extents))
16217		return;
16218
16219	DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__,
16220	     region.extents.x1, region.extents.y1,
16221	     region.extents.x2, region.extents.y2));
16222
16223	region.data = NULL;
16224	if (!region_maybe_clip(&region, gc->pCompositeClip))
16225		return;
16226
16227	if (FORCE_FALLBACK)
16228		goto fallback;
16229
16230	if (!ACCEL_POLY_GLYPH)
16231		goto fallback;
16232
16233	if (wedged(sna)) {
16234		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
16235		goto fallback;
16236	}
16237
16238	if (!PM_IS_SOLID(drawable, gc->planemask))
16239		goto fallback;
16240
16241	if (!gc_is_solid(gc, &fg))
16242		goto fallback;
16243
16244	if (sna_font_too_large(gc->font))
16245		goto fallback;
16246
16247	if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU,
16248				      &region.extents, &damage)) &&
16249	    sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base,
16250				   bo, damage, &region, fg, -1, true))
16251		goto out;
16252
16253fallback:
16254	DBG(("%s: fallback\n", __FUNCTION__));
16255	if (!sna_gc_move_to_cpu(gc, drawable, &region))
16256		goto out_gc;
16257	if (!sna_drawable_move_region_to_cpu(drawable, &region,
16258					     MOVE_READ | MOVE_WRITE))
16259		goto out_gc;
16260
16261	if (sigtrap_get() == 0) {
16262		DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
16263		fbPolyGlyphBlt(drawable, gc, x, y, n, info, base);
16264		FALLBACK_FLUSH(drawable);
16265		sigtrap_put();
16266	}
16267out_gc:
16268	sna_gc_move_to_gpu(gc);
16269out:
16270	RegionUninit(&region);
16271}
16272
16273static bool
16274sna_push_pixels_solid_blt(GCPtr gc,
16275			  PixmapPtr bitmap,
16276			  DrawablePtr drawable,
16277			  RegionPtr region)
16278{
16279	PixmapPtr pixmap = get_drawable_pixmap(drawable);
16280	struct sna *sna = to_sna_from_pixmap(pixmap);
16281	struct sna_damage **damage;
16282	struct kgem_bo *bo;
16283	const BoxRec *box;
16284	int16_t dx, dy;
16285	int n;
16286	uint8_t rop = copy_ROP[gc->alu];
16287
16288	bo = sna_drawable_use_bo(drawable, PREFER_GPU, &region->extents, &damage);
16289	if (bo == NULL)
16290		return false;
16291
16292	if (bo->tiling == I915_TILING_Y) {
16293		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
16294		assert(bo == __sna_pixmap_get_bo(pixmap));
16295		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
16296		if (bo == NULL) {
16297			DBG(("%s: fallback -- unable to change tiling\n",
16298			     __FUNCTION__));
16299			return false;
16300		}
16301	}
16302
16303	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
16304		RegionTranslate(region, dx, dy);
16305
16306	assert_pixmap_contains_box(pixmap, RegionExtents(region));
16307	if (damage)
16308		sna_damage_add(damage, region);
16309	assert_pixmap_damage(pixmap);
16310
16311	DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__,
16312	     region->extents.x1, region->extents.y1,
16313	     region->extents.x2, region->extents.y2));
16314
16315	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
16316
16317	/* Region is pre-clipped and translated into pixmap space */
16318	box = region_rects(region);
16319	n = region_num_rects(region);
16320	do {
16321		int bx1 = (box->x1 - region->extents.x1) & ~7;
16322		int bx2 = (box->x2 - region->extents.x1 + 7) & ~7;
16323		int bw = (bx2 - bx1)/8;
16324		int bh = box->y2 - box->y1;
16325		int bstride = ALIGN(bw, 2);
16326		struct kgem_bo *upload;
16327		void *ptr;
16328
16329		if (!kgem_check_batch(&sna->kgem, 10) ||
16330		    !kgem_check_bo_fenced(&sna->kgem, bo) ||
16331		    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
16332			kgem_submit(&sna->kgem);
16333			if (!kgem_check_bo_fenced(&sna->kgem, bo))
16334				return false;
16335			_kgem_set_mode(&sna->kgem, KGEM_BLT);
16336		}
16337
16338		upload = kgem_create_buffer(&sna->kgem,
16339					    bstride*bh,
16340					    KGEM_BUFFER_WRITE_INPLACE,
16341					    &ptr);
16342		if (!upload)
16343			break;
16344
16345		if (sigtrap_get() == 0) {
16346			uint8_t *dst = ptr;
16347
16348			int src_stride = bitmap->devKind;
16349			uint8_t *src;
16350			uint32_t *b;
16351
16352			assert(src_stride);
16353			src = (uint8_t*)bitmap->devPrivate.ptr;
16354			src += (box->y1 - region->extents.y1) * src_stride + bx1/8;
16355			src_stride -= bstride;
16356			do {
16357				int i = bstride;
16358				do {
16359					*dst++ = byte_reverse(*src++);
16360					*dst++ = byte_reverse(*src++);
16361					i -= 2;
16362				} while (i);
16363				src += src_stride;
16364			} while (--bh);
16365
16366			assert(sna->kgem.mode == KGEM_BLT);
16367			b = sna->kgem.batch + sna->kgem.nbatch;
16368			if (sna->kgem.gen >= 0100) {
16369				b[0] = XY_MONO_SRC_COPY | 3 << 20 | 8;
16370				b[0] |= ((box->x1 - region->extents.x1) & 7) << 17;
16371				b[1] = bo->pitch;
16372				if (sna->kgem.gen >= 040 && bo->tiling) {
16373					b[0] |= BLT_DST_TILED;
16374					b[1] >>= 2;
16375				}
16376				b[1] |= 1 << 29;
16377				b[1] |= blt_depth(drawable->depth) << 24;
16378				b[1] |= rop << 16;
16379				b[2] = box->y1 << 16 | box->x1;
16380				b[3] = box->y2 << 16 | box->x2;
16381				*(uint64_t *)(b+4) =
16382					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo,
16383							I915_GEM_DOMAIN_RENDER << 16 |
16384							I915_GEM_DOMAIN_RENDER |
16385							KGEM_RELOC_FENCED,
16386							0);
16387				*(uint64_t *)(b+6) =
16388					kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload,
16389							I915_GEM_DOMAIN_RENDER << 16 |
16390							KGEM_RELOC_FENCED,
16391							0);
16392				b[8] = gc->bgPixel;
16393				b[9] = gc->fgPixel;
16394				sna->kgem.nbatch += 10;
16395			} else {
16396				b[0] = XY_MONO_SRC_COPY | 3 << 20 | 6;
16397				b[0] |= ((box->x1 - region->extents.x1) & 7) << 17;
16398				b[1] = bo->pitch;
16399				if (sna->kgem.gen >= 040 && bo->tiling) {
16400					b[0] |= BLT_DST_TILED;
16401					b[1] >>= 2;
16402				}
16403				b[1] |= 1 << 29;
16404				b[1] |= blt_depth(drawable->depth) << 24;
16405				b[1] |= rop << 16;
16406				b[2] = box->y1 << 16 | box->x1;
16407				b[3] = box->y2 << 16 | box->x2;
16408				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
16409						I915_GEM_DOMAIN_RENDER << 16 |
16410						I915_GEM_DOMAIN_RENDER |
16411						KGEM_RELOC_FENCED,
16412						0);
16413				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload,
16414						I915_GEM_DOMAIN_RENDER << 16 |
16415						KGEM_RELOC_FENCED,
16416						0);
16417				b[6] = gc->bgPixel;
16418				b[7] = gc->fgPixel;
16419
16420				sna->kgem.nbatch += 8;
16421			}
16422			sigtrap_put();
16423		}
16424
16425		kgem_bo_destroy(&sna->kgem, upload);
16426
16427		box++;
16428	} while (--n);
16429
16430	sna->blt_state.fill_bo = 0;
16431	return true;
16432}
16433
16434static void
16435sna_push_pixels(GCPtr gc, PixmapPtr bitmap, DrawablePtr drawable,
16436		int w, int h,
16437		int x, int y)
16438{
16439	RegionRec region;
16440
16441	if (w == 0 || h == 0)
16442		return;
16443
16444	DBG(("%s (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
16445
16446	region.extents.x1 = x;
16447	region.extents.y1 = y;
16448	region.extents.x2 = region.extents.x1 + w;
16449	region.extents.y2 = region.extents.y1 + h;
16450
16451	clip_box(&region.extents, gc);
16452	if (box_empty(&region.extents))
16453		return;
16454
16455	DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__,
16456	     region.extents.x1, region.extents.y1,
16457	     region.extents.x2, region.extents.y2));
16458
16459	region.data = NULL;
16460	if (!region_maybe_clip(&region, gc->pCompositeClip))
16461		return;
16462
16463	switch (gc->fillStyle) {
16464	case FillSolid:
16465		if (sna_push_pixels_solid_blt(gc, bitmap, drawable, &region))
16466			return;
16467		break;
16468	default:
16469		break;
16470	}
16471
16472	DBG(("%s: fallback\n", __FUNCTION__));
16473	if (!sna_gc_move_to_cpu(gc, drawable, &region))
16474		goto out;
16475	if (!sna_pixmap_move_to_cpu(bitmap, MOVE_READ))
16476		goto out;
16477	if (!sna_drawable_move_region_to_cpu(drawable, &region,
16478					     drawable_gc_flags(drawable, gc, false)))
16479		goto out;
16480
16481	if (sigtrap_get() == 0) {
16482		DBG(("%s: fallback, fbPushPixels(%d, %d, %d %d)\n",
16483		     __FUNCTION__, w, h, x, y));
16484		fbPushPixels(gc, bitmap, drawable, w, h, x, y);
16485		FALLBACK_FLUSH(drawable);
16486		sigtrap_put();
16487	}
16488out:
16489	sna_gc_move_to_gpu(gc);
16490	RegionUninit(&region);
16491}
16492
16493static const GCOps sna_gc_ops = {
16494	sna_fill_spans,
16495	sna_set_spans,
16496	sna_put_image,
16497	sna_copy_area,
16498	sna_copy_plane,
16499	sna_poly_point,
16500	sna_poly_line,
16501	sna_poly_segment,
16502	sna_poly_rectangle,
16503	sna_poly_arc,
16504	sna_poly_fill_polygon,
16505	sna_poly_fill_rect,
16506	sna_poly_fill_arc,
16507	sna_poly_text8,
16508	sna_poly_text16,
16509	sna_image_text8,
16510	sna_image_text16,
16511	sna_image_glyph,
16512	sna_poly_glyph,
16513	sna_push_pixels,
16514};
16515
16516static const GCOps sna_gc_ops__cpu = {
16517	fbFillSpans,
16518	fbSetSpans,
16519	fbPutImage,
16520	fbCopyArea,
16521	fbCopyPlane,
16522	sna_poly_point__cpu,
16523	fbPolyLine,
16524	fbPolySegment,
16525	miPolyRectangle,
16526	fbPolyArc,
16527	miFillPolygon,
16528	fbPolyFillRect,
16529	miPolyFillArc,
16530	miPolyText8,
16531	miPolyText16,
16532	miImageText8,
16533	miImageText16,
16534	fbImageGlyphBlt,
16535	fbPolyGlyphBlt,
16536	fbPushPixels
16537};
16538
16539static GCOps sna_gc_ops__tmp = {
16540	sna_fill_spans,
16541	sna_set_spans,
16542	sna_put_image,
16543	sna_copy_area,
16544	sna_copy_plane,
16545	sna_poly_point,
16546	sna_poly_line,
16547	sna_poly_segment,
16548	sna_poly_rectangle,
16549	sna_poly_arc,
16550	sna_poly_fill_polygon,
16551	sna_poly_fill_rect,
16552	sna_poly_fill_arc,
16553	sna_poly_text8,
16554	sna_poly_text16,
16555	sna_image_text8,
16556	sna_image_text16,
16557	sna_image_glyph,
16558	sna_poly_glyph,
16559	sna_push_pixels,
16560};
16561
16562static void
16563sna_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable)
16564{
16565	DBG(("%s(%p) changes=%lx, previous serial=%lx, drawable=%lx\n", __FUNCTION__, gc,
16566	     changes, gc->serialNumber, drawable->serialNumber));
16567
16568	if (changes & (GCClipMask|GCSubwindowMode) ||
16569	    drawable->serialNumber != (gc->serialNumber & DRAWABLE_SERIAL_BITS) ||
16570	    (gc->clientClipType != CT_NONE && (changes & (GCClipXOrigin | GCClipYOrigin)))) {
16571		DBG(("%s: recomputing clip\n", __FUNCTION__));
16572		miComputeCompositeClip(gc, drawable);
16573		DBG(("%s: composite clip=%dx[(%d, %d), (%d, %d)] [%p]\n",
16574		     __FUNCTION__,
16575		     region_num_rects(gc->pCompositeClip),
16576		     gc->pCompositeClip->extents.x1,
16577		     gc->pCompositeClip->extents.y1,
16578		     gc->pCompositeClip->extents.x2,
16579		     gc->pCompositeClip->extents.y2,
16580		     gc->pCompositeClip));
16581	}
16582
16583	assert(gc->pCompositeClip);
16584	assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.x1 >= drawable->x);
16585	assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.y1 >= drawable->y);
16586	assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.x2 - drawable->x <= drawable->width);
16587	assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.y2 - drawable->y <= drawable->height);
16588
16589	sna_gc(gc)->changes |= changes;
16590	sna_gc(gc)->serial = gc->serialNumber;
16591}
16592
16593static const GCFuncs sna_gc_funcs = {
16594	sna_validate_gc,
16595	miChangeGC,
16596	miCopyGC,
16597	miDestroyGC,
16598	miChangeClip,
16599	miDestroyClip,
16600	miCopyClip
16601};
16602
16603static const GCFuncs sna_gc_funcs__cpu = {
16604	fbValidateGC,
16605	miChangeGC,
16606	miCopyGC,
16607	miDestroyGC,
16608	miChangeClip,
16609	miDestroyClip,
16610	miCopyClip
16611};
16612
16613static int sna_create_gc(GCPtr gc)
16614{
16615	gc->miTranslate = 1;
16616	gc->fExpose = 1;
16617
16618	gc->freeCompClip = 0;
16619	gc->pCompositeClip = 0;
16620	gc->pRotatedPixmap = 0;
16621
16622	fb_gc(gc)->bpp = bits_per_pixel(gc->depth);
16623
16624	gc->funcs = (GCFuncs *)&sna_gc_funcs;
16625	gc->ops = (GCOps *)&sna_gc_ops;
16626	return true;
16627}
16628
16629static bool
16630sna_get_image__inplace(PixmapPtr pixmap,
16631		       RegionPtr region,
16632		       char *dst,
16633		       unsigned flags,
16634		       bool idle)
16635{
16636	struct sna_pixmap *priv = sna_pixmap(pixmap);
16637	struct sna *sna = to_sna_from_pixmap(pixmap);
16638	char *src;
16639
16640	if (!USE_INPLACE)
16641		return false;
16642
16643	assert(priv && priv->gpu_bo);
16644
16645	switch (priv->gpu_bo->tiling) {
16646	case I915_TILING_Y:
16647		return false;
16648	case I915_TILING_X:
16649		if (!sna->kgem.memcpy_from_tiled_x)
16650			return false;
16651	default:
16652		break;
16653	}
16654
16655	if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC))
16656		return false;
16657
16658	if (idle && __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
16659		return false;
16660
16661	if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ))
16662		return false;
16663
16664	assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
16665	assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
16666
16667	src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
16668	if (src == NULL)
16669		return false;
16670
16671	kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC);
16672
16673	if (sigtrap_get())
16674		return false;
16675
16676	if (priv->gpu_bo->tiling) {
16677		DBG(("%s: download through a tiled CPU map\n", __FUNCTION__));
16678		memcpy_from_tiled_x(&sna->kgem, src, dst,
16679				    pixmap->drawable.bitsPerPixel,
16680				    priv->gpu_bo->pitch,
16681				    PixmapBytePad(region->extents.x2 - region->extents.x1,
16682						  pixmap->drawable.depth),
16683				    region->extents.x1, region->extents.y1,
16684				    0, 0,
16685				    region->extents.x2 - region->extents.x1,
16686				    region->extents.y2 - region->extents.y1);
16687	} else {
16688		DBG(("%s: download through a linear CPU map\n", __FUNCTION__));
16689		memcpy_blt(src, dst,
16690			   pixmap->drawable.bitsPerPixel,
16691			   priv->gpu_bo->pitch,
16692			   PixmapBytePad(region->extents.x2 - region->extents.x1,
16693					 pixmap->drawable.depth),
16694			   region->extents.x1, region->extents.y1,
16695			   0, 0,
16696			   region->extents.x2 - region->extents.x1,
16697			   region->extents.y2 - region->extents.y1);
16698		if (!priv->shm) {
16699			assert(src == MAP(priv->gpu_bo->map__cpu));
16700			pixmap->devPrivate.ptr = src;
16701			pixmap->devKind = priv->gpu_bo->pitch;
16702			priv->mapped = MAPPED_CPU;
16703			assert_pixmap_map(pixmap, priv);
16704			priv->cpu = true;
16705		}
16706	}
16707
16708	sigtrap_put();
16709	return true;
16710}
16711
16712static bool
16713sna_get_image__blt(PixmapPtr pixmap,
16714		   RegionPtr region,
16715		   char *dst,
16716		   unsigned flags)
16717{
16718	struct sna_pixmap *priv = sna_pixmap(pixmap);
16719	struct sna *sna = to_sna_from_pixmap(pixmap);
16720	struct kgem_bo *dst_bo;
16721	bool ok = false;
16722	int pitch;
16723
16724	assert(priv && priv->gpu_bo);
16725
16726	if (!sna->kgem.has_userptr || !USE_USERPTR_DOWNLOADS)
16727		return false;
16728
16729	if (!sna->kgem.can_blt_cpu)
16730		return false;
16731
16732	if ((priv->create & (KGEM_CAN_CREATE_GTT | KGEM_CAN_CREATE_LARGE)) == KGEM_CAN_CREATE_GTT &&
16733	    kgem_bo_can_map(&sna->kgem, priv->gpu_bo)) {
16734		if (flags & (MOVE_WHOLE_HINT | MOVE_INPLACE_HINT))
16735			return false;
16736
16737		if (priv->gpu_damage == NULL)
16738			return false;
16739
16740		assert(priv->gpu_bo);
16741		if (!__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
16742			return false;
16743	} else {
16744		if (priv->gpu_damage == NULL)
16745			return false;
16746
16747		assert(priv->gpu_bo);
16748	}
16749
16750	if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ))
16751		return false;
16752
16753	DBG(("%s: download through a temporary map\n", __FUNCTION__));
16754
16755	assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
16756	assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
16757
16758	pitch = PixmapBytePad(region->extents.x2 - region->extents.x1,
16759			      pixmap->drawable.depth);
16760	dst_bo = kgem_create_map(&sna->kgem, dst,
16761				 pitch * (region->extents.y2 - region->extents.y1),
16762				 false);
16763	if (dst_bo) {
16764		dst_bo->pitch = pitch;
16765		kgem_bo_mark_unreusable(dst_bo);
16766
16767		ok = sna->render.copy_boxes(sna, GXcopy,
16768					    &pixmap->drawable, priv->gpu_bo, 0, 0,
16769					    &pixmap->drawable, dst_bo,
16770					    -region->extents.x1,
16771					    -region->extents.y1,
16772					    &region->extents, 1,
16773					    COPY_LAST);
16774
16775		kgem_bo_sync__cpu(&sna->kgem, dst_bo);
16776		assert(dst_bo->rq == NULL);
16777		kgem_bo_destroy(&sna->kgem, dst_bo);
16778	}
16779
16780	return ok;
16781}
16782
16783static bool
16784sna_get_image__fast(PixmapPtr pixmap,
16785		   RegionPtr region,
16786		   char *dst,
16787		   unsigned flags)
16788{
16789	struct sna_pixmap *priv = sna_pixmap(pixmap);
16790
16791	DBG(("%s: attached?=%d, has gpu damage?=%d\n",
16792	     __FUNCTION__, priv != NULL,  priv && priv->gpu_damage));
16793	if (priv == NULL || priv->gpu_damage == NULL)
16794		return false;
16795
16796	if (priv->clear) {
16797		int w = region->extents.x2 - region->extents.x1;
16798		int h = region->extents.y2 - region->extents.y1;
16799		int pitch = PixmapBytePad(w, pixmap->drawable.depth);
16800
16801		DBG(("%s: applying clear [%08x]\n",
16802		     __FUNCTION__, priv->clear_color));
16803		assert(DAMAGE_IS_ALL(priv->gpu_damage));
16804		assert(priv->cpu_damage == NULL);
16805
16806		if (priv->clear_color == 0 ||
16807		    pixmap->drawable.bitsPerPixel == 8 ||
16808		    priv->clear_color == (1U << pixmap->drawable.depth) - 1) {
16809			DBG(("%s: memset clear [%02x]\n",
16810			     __FUNCTION__, priv->clear_color & 0xff));
16811			memset(dst, priv->clear_color, pitch * h);
16812		} else {
16813			pixman_fill((uint32_t *)dst,
16814				    pitch/sizeof(uint32_t),
16815				    pixmap->drawable.bitsPerPixel,
16816				    0, 0,
16817				    w, h,
16818				    priv->clear_color);
16819		}
16820
16821		return true;
16822	}
16823
16824	if (!DAMAGE_IS_ALL(priv->gpu_damage) &&
16825	    !sna_damage_contains_box__no_reduce(priv->gpu_damage,
16826						&region->extents))
16827		return false;
16828
16829	if (sna_get_image__inplace(pixmap, region, dst, flags, true))
16830		return true;
16831
16832	if (sna_get_image__blt(pixmap, region, dst, flags))
16833		return true;
16834
16835	if (sna_get_image__inplace(pixmap, region, dst, flags, false))
16836		return true;
16837
16838	return false;
16839}
16840
16841static void
16842sna_get_image(DrawablePtr drawable,
16843	      int x, int y, int w, int h,
16844	      unsigned int format, unsigned long mask,
16845	      char *dst)
16846{
16847	RegionRec region;
16848	unsigned int flags;
16849
16850	if (!fbDrawableEnabled(drawable))
16851		return;
16852
16853	DBG(("%s: pixmap=%ld (%d, %d)x(%d, %d), format=%d, mask=%lx, depth=%d\n",
16854	     __FUNCTION__,
16855	     (long)get_drawable_pixmap(drawable)->drawable.serialNumber,
16856	     x, y, w, h, format, mask, drawable->depth));
16857
16858	flags = MOVE_READ;
16859	if ((w | h) == 1)
16860		flags |= MOVE_INPLACE_HINT;
16861	if (w == drawable->width)
16862		flags |= MOVE_WHOLE_HINT;
16863
16864	if (ACCEL_GET_IMAGE &&
16865	    !FORCE_FALLBACK &&
16866	    format == ZPixmap &&
16867	    drawable->bitsPerPixel >= 8 &&
16868	    PM_IS_SOLID(drawable, mask)) {
16869		PixmapPtr pixmap = get_drawable_pixmap(drawable);
16870		int16_t dx, dy;
16871
16872		get_drawable_deltas(drawable, pixmap, &dx, &dy);
16873		region.extents.x1 = x + drawable->x + dx;
16874		region.extents.y1 = y + drawable->y + dy;
16875		region.extents.x2 = region.extents.x1 + w;
16876		region.extents.y2 = region.extents.y1 + h;
16877		region.data = NULL;
16878
16879		if (sna_get_image__fast(pixmap, &region, dst, flags))
16880			return;
16881
16882		if (!sna_drawable_move_region_to_cpu(&pixmap->drawable,
16883						     &region, flags))
16884			return;
16885
16886		DBG(("%s: copy box (%d, %d), (%d, %d)\n",
16887		     __FUNCTION__,
16888		     region.extents.x1, region.extents.y1,
16889		     region.extents.x2, region.extents.y2));
16890		assert(has_coherent_ptr(to_sna_from_pixmap(pixmap), sna_pixmap(pixmap), MOVE_READ));
16891		if (sigtrap_get() == 0) {
16892			assert(pixmap->devKind);
16893			memcpy_blt(pixmap->devPrivate.ptr, dst, drawable->bitsPerPixel,
16894				   pixmap->devKind, PixmapBytePad(w, drawable->depth),
16895				   region.extents.x1, region.extents.y1, 0, 0, w, h);
16896			sigtrap_put();
16897		}
16898	} else {
16899		region.extents.x1 = x + drawable->x;
16900		region.extents.y1 = y + drawable->y;
16901		region.extents.x2 = region.extents.x1 + w;
16902		region.extents.y2 = region.extents.y1 + h;
16903		region.data = NULL;
16904
16905		if (sna_drawable_move_region_to_cpu(drawable, &region, flags))
16906			fbGetImage(drawable, x, y, w, h, format, mask, dst);
16907	}
16908}
16909
16910static void
16911sna_get_spans(DrawablePtr drawable, int wMax,
16912	      DDXPointPtr pt, int *width, int n, char *start)
16913{
16914	RegionRec region;
16915
16916	if (!fbDrawableEnabled(drawable))
16917		return;
16918
16919	if (sna_spans_extents(drawable, NULL, n, pt, width, &region.extents) == 0)
16920		return;
16921
16922	region.data = NULL;
16923	if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_READ))
16924		return;
16925
16926	fbGetSpans(drawable, wMax, pt, width, n, start);
16927}
16928
16929static void
16930sna_copy_window(WindowPtr win, DDXPointRec origin, RegionPtr src)
16931{
16932	PixmapPtr pixmap = get_window_pixmap(win);
16933	struct sna *sna = to_sna_from_pixmap(pixmap);
16934	RegionRec dst;
16935	int dx, dy;
16936
16937	DBG(("%s origin=(%d, %d)\n", __FUNCTION__, origin.x, origin.y));
16938	if (!fbWindowEnabled(win))
16939		return;
16940
16941	dx = origin.x - win->drawable.x;
16942	dy = origin.y - win->drawable.y;
16943	RegionTranslate(src, -dx, -dy);
16944
16945	RegionNull(&dst);
16946	RegionIntersect(&dst, &win->borderClip, src);
16947	if (box_empty(&dst.extents))
16948		return;
16949
16950#ifdef COMPOSITE
16951	if (pixmap->screen_x | pixmap->screen_y)
16952		RegionTranslate(&dst, -pixmap->screen_x, -pixmap->screen_y);
16953#endif
16954
16955	if (wedged(sna) || FORCE_FALLBACK || !ACCEL_COPY_WINDOW) {
16956		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
16957		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE))
16958			return;
16959
16960		if (sigtrap_get() == 0) {
16961			miCopyRegion(&pixmap->drawable, &pixmap->drawable,
16962				     0, &dst, dx, dy, fbCopyNtoN, 0, NULL);
16963			sigtrap_put();
16964		}
16965	} else {
16966		sna_self_copy_boxes(&pixmap->drawable, &pixmap->drawable, NULL,
16967				    &dst, dx, dy, 0, NULL);
16968	}
16969
16970	RegionUninit(&dst);
16971}
16972
16973static Bool sna_change_window_attributes(WindowPtr win, unsigned long mask)
16974{
16975	bool ret = true;
16976
16977	DBG(("%s\n", __FUNCTION__));
16978
16979	/* Check if the fb layer wishes to modify the attached pixmaps,
16980	 * to fix up mismatches between the window and pixmap depths.
16981	 */
16982	if (mask & CWBackPixmap && win->backgroundState == BackgroundPixmap) {
16983		DBG(("%s: flushing background pixmap\n", __FUNCTION__));
16984		ret &= sna_validate_pixmap(&win->drawable, win->background.pixmap);
16985	}
16986
16987	if (mask & CWBorderPixmap && win->borderIsPixel == false) {
16988		DBG(("%s: flushing border pixmap\n", __FUNCTION__));
16989		ret &= sna_validate_pixmap(&win->drawable, win->border.pixmap);
16990	}
16991
16992	return ret;
16993}
16994
16995void sna_accel_flush(struct sna *sna)
16996{
16997	struct sna_pixmap *priv;
16998
16999	/* XXX we should be able to reduce the frequency of flushes further
17000	 * by checking for outgoing damage events or sync replies. Tricky,
17001	 * and doesn't appear to mitigate the performance loss.
17002	 */
17003	DBG(("%s: flush?=%d, dirty?=%d\n", __FUNCTION__,
17004	     sna->kgem.flush, !list_is_empty(&sna->flush_pixmaps)));
17005
17006	/* flush any pending damage from shadow copies to tfp clients */
17007	while (!list_is_empty(&sna->flush_pixmaps)) {
17008		bool ret;
17009
17010		priv = list_first_entry(&sna->flush_pixmaps,
17011					struct sna_pixmap, flush_list);
17012
17013		list_del(&priv->flush_list);
17014		if (priv->shm) {
17015			DBG(("%s: syncing SHM pixmap=%ld (refcnt=%d)\n",
17016			     __FUNCTION__,
17017			     priv->pixmap->drawable.serialNumber,
17018			     priv->pixmap->refcnt));
17019			assert(!priv->flush);
17020			ret = sna_pixmap_move_to_cpu(priv->pixmap,
17021						     MOVE_READ | MOVE_WRITE);
17022			assert(!ret || priv->gpu_bo == NULL);
17023			if (priv->pixmap->refcnt == 0) {
17024				sna_damage_destroy(&priv->cpu_damage);
17025				__sna_free_pixmap(sna, priv->pixmap, priv);
17026			}
17027		} else {
17028			DBG(("%s: flushing DRI pixmap=%ld\n", __FUNCTION__,
17029			     priv->pixmap->drawable.serialNumber));
17030			assert(priv->flush);
17031			if (sna_pixmap_move_to_gpu(priv->pixmap,
17032						   MOVE_READ | __MOVE_FORCE)) {
17033				if (priv->flush & 2) {
17034					kgem_bo_unclean(&sna->kgem, priv->gpu_bo);
17035					sna_damage_all(&priv->gpu_damage, priv->pixmap);
17036					assert(priv->cpu_damage == NULL);
17037					priv->clear = false;
17038					priv->cpu = false;
17039				}
17040			}
17041		}
17042		(void)ret;
17043	}
17044
17045	if (sna->kgem.flush)
17046		kgem_submit(&sna->kgem);
17047}
17048
17049static void
17050sna_accel_flush_callback(CallbackListPtr *list,
17051			 pointer user_data, pointer call_data)
17052{
17053	sna_accel_flush(user_data);
17054}
17055
17056static struct sna_pixmap *sna_accel_scanout(struct sna *sna)
17057{
17058	struct sna_pixmap *priv;
17059
17060	if (sna->mode.front_active == 0)
17061		return NULL;
17062
17063	assert(sna->vblank_interval);
17064	assert(sna->front);
17065
17066	priv = sna_pixmap(sna->front);
17067	if (priv->gpu_bo == NULL)
17068		return NULL;
17069
17070	return priv;
17071}
17072
17073#define TIME currentTime.milliseconds
17074static void sna_accel_disarm_timer(struct sna *sna, int id)
17075{
17076	DBG(("%s[%d] (time=%ld)\n", __FUNCTION__, id, (long)TIME));
17077	sna->timer_active &= ~(1<<id);
17078}
17079
17080static bool has_offload_slaves(struct sna *sna)
17081{
17082#if HAS_PIXMAP_SHARING
17083	ScreenPtr screen = sna->scrn->pScreen;
17084	PixmapDirtyUpdatePtr dirty;
17085
17086	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
17087		assert(dirty->src == sna->front);
17088		if (RegionNotEmpty(DamageRegion(dirty->damage)))
17089			return true;
17090	}
17091#endif
17092	return false;
17093}
17094
17095static bool has_shadow(struct sna *sna)
17096{
17097	DamagePtr damage = sna->mode.shadow_damage;
17098
17099	if (damage == NULL)
17100		return false;
17101
17102	DBG(("%s: has pending damage? %d, outstanding flips: %d\n",
17103	     __FUNCTION__,
17104	     RegionNotEmpty(DamageRegion(damage)),
17105	     sna->mode.flip_active));
17106
17107	return RegionNotEmpty(DamageRegion(damage));
17108}
17109
17110static bool start_flush(struct sna *sna)
17111{
17112	struct sna_pixmap *scanout;
17113
17114	if (has_offload_slaves(sna)) {
17115		DBG(("%s: has offload slaves\n", __FUNCTION__));
17116		return true;
17117	}
17118
17119	if (has_shadow(sna)) {
17120		DBG(("%s: has dirty shadow\n", __FUNCTION__));
17121		return true;
17122	}
17123
17124	scanout = sna_accel_scanout(sna);
17125	if (!scanout)
17126		return false;
17127
17128	if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) {
17129		scanout->gpu_bo->needs_flush = true;
17130		return true;
17131	}
17132
17133	if (scanout->cpu_damage || scanout->gpu_bo->needs_flush)
17134		return true;
17135
17136	kgem_scanout_flush(&sna->kgem, scanout->gpu_bo);
17137	return false;
17138}
17139
17140static bool stop_flush(struct sna *sna, struct sna_pixmap *scanout)
17141{
17142	DBG(("%s: scanout=%d shadow?=%d, slaves?=%d, (cpu?=%d || gpu?=%d))\n",
17143	     __FUNCTION__,
17144	     scanout && scanout->gpu_bo ? scanout->gpu_bo->handle : 0,
17145	     has_shadow(sna), has_offload_slaves(sna),
17146	     scanout && scanout->cpu_damage != NULL,
17147	     scanout && scanout->gpu_bo && scanout->gpu_bo->rq != NULL));
17148
17149	if (has_offload_slaves(sna))
17150		return true;
17151
17152	if (has_shadow(sna))
17153		return true;
17154
17155	if (!scanout)
17156		return false;
17157
17158	if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) {
17159		scanout->gpu_bo->needs_flush = true;
17160		return true;
17161	}
17162
17163	return scanout->cpu_damage || scanout->gpu_bo->needs_flush;
17164}
17165
17166static void timer_enable(struct sna *sna, int whom, int interval)
17167{
17168	if (!sna->timer_active)
17169		UpdateCurrentTimeIf();
17170	sna->timer_active |= 1 << whom;
17171	sna->timer_expire[whom] = TIME + interval;
17172	DBG(("%s (time=%ld), starting timer %d\n", __FUNCTION__, (long)TIME, whom));
17173}
17174
17175static bool sna_scanout_do_flush(struct sna *sna)
17176{
17177	int interval = sna->vblank_interval ?: 50;
17178	if (sna->timer_active & (1<<(FLUSH_TIMER))) {
17179		int32_t delta = sna->timer_expire[FLUSH_TIMER] - TIME;
17180		DBG(("%s: flush timer active: delta=%d\n",
17181		     __FUNCTION__, delta));
17182		if (delta <= 3) {
17183			DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME));
17184			sna->timer_expire[FLUSH_TIMER] = TIME + interval;
17185			return true;
17186		}
17187	} else {
17188		if (start_flush(sna))
17189			timer_enable(sna, FLUSH_TIMER, interval/2);
17190	}
17191
17192	return false;
17193}
17194
17195static bool sna_accel_do_throttle(struct sna *sna)
17196{
17197	if (sna->timer_active & (1<<(THROTTLE_TIMER))) {
17198		int32_t delta = sna->timer_expire[THROTTLE_TIMER] - TIME;
17199		if (delta <= 3) {
17200			DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME));
17201			sna->timer_expire[THROTTLE_TIMER] = TIME + 20;
17202			return true;
17203		}
17204	} else if (!sna->kgem.need_retire) {
17205		DBG(("%s -- no pending activity\n", __FUNCTION__));
17206	} else
17207		timer_enable(sna, THROTTLE_TIMER, 20);
17208
17209	return false;
17210}
17211
17212static bool sna_accel_do_expire(struct sna *sna)
17213{
17214	if (sna->timer_active & (1<<(EXPIRE_TIMER))) {
17215		int32_t delta = sna->timer_expire[EXPIRE_TIMER] - TIME;
17216		if (delta <= 3) {
17217			DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME));
17218			sna->timer_expire[EXPIRE_TIMER] =
17219				TIME + MAX_INACTIVE_TIME * 1000;
17220			return true;
17221		}
17222	} else if (sna->kgem.need_expire)
17223		timer_enable(sna, EXPIRE_TIMER, MAX_INACTIVE_TIME * 1000);
17224
17225	return false;
17226}
17227
17228static void sna_accel_post_damage(struct sna *sna)
17229{
17230#if HAS_PIXMAP_SHARING
17231	ScreenPtr screen = sna->scrn->pScreen;
17232	PixmapDirtyUpdatePtr dirty;
17233	bool flush = false;
17234
17235	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
17236		RegionRec region, *damage;
17237		PixmapPtr src, dst;
17238		const BoxRec *box;
17239		int16_t dx, dy;
17240		int n;
17241
17242		assert(dirty->src == sna->front);
17243
17244		damage = DamageRegion(dirty->damage);
17245		if (RegionNil(damage))
17246			continue;
17247
17248		src = dirty->src;
17249		dst = dirty->slave_dst->master_pixmap;
17250
17251		region.extents.x1 = dirty->x;
17252		region.extents.x2 = dirty->x + dst->drawable.width;
17253		region.extents.y1 = dirty->y;
17254		region.extents.y2 = dirty->y + dst->drawable.height;
17255		region.data = NULL;
17256
17257		DBG(("%s: pushing damage ((%d, %d), (%d, %d))x%d to slave pixmap=%d, ((%d, %d), (%d, %d))\n", __FUNCTION__,
17258		     damage->extents.x1, damage->extents.y1,
17259		     damage->extents.x2, damage->extents.y2,
17260		     region_num_rects(damage),
17261		     dst->drawable.serialNumber,
17262		     region.extents.x1, region.extents.y1,
17263		     region.extents.x2, region.extents.y2));
17264
17265		RegionIntersect(&region, &region, damage);
17266		if (RegionNil(&region))
17267			goto skip;
17268
17269		dx = -dirty->x;
17270		dy = -dirty->y;
17271#if HAS_DIRTYTRACKING2
17272		dx += dirty->dst_x;
17273		dy += dirty->dst_y;
17274#endif
17275		RegionTranslate(&region, dx, dy);
17276		DamageRegionAppend(&dirty->slave_dst->drawable, &region);
17277
17278		DBG(("%s: slave:  ((%d, %d), (%d, %d))x%d\n", __FUNCTION__,
17279		     region.extents.x1, region.extents.y1,
17280		     region.extents.x2, region.extents.y2,
17281		     region_num_rects(&region)));
17282
17283		box = region_rects(&region);
17284		n = region_num_rects(&region);
17285		if (wedged(sna)) {
17286fallback:
17287			if (!sna_pixmap_move_to_cpu(src, MOVE_READ))
17288				goto skip;
17289
17290			if (!sna_pixmap_move_to_cpu(dst, MOVE_READ | MOVE_WRITE | MOVE_INPLACE_HINT))
17291				goto skip;
17292
17293			if (sigtrap_get() == 0) {
17294				assert(src->drawable.bitsPerPixel == dst->drawable.bitsPerPixel);
17295				do {
17296					DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n",
17297					     __FUNCTION__,
17298					     box->x1 - dx, box->y1 - dy,
17299					     box->x1, box->y1,
17300					     box->x2 - box->x1, box->y2 - box->y1));
17301
17302					assert(box->x2 > box->x1);
17303					assert(box->y2 > box->y1);
17304
17305					assert(box->x1 - dx >= 0);
17306					assert(box->y1 - dy >= 0);
17307					assert(box->x2 - dx <= src->drawable.width);
17308					assert(box->y2 - dy <= src->drawable.height);
17309
17310					assert(box->x1 >= 0);
17311					assert(box->y1 >= 0);
17312					assert(box->x2 <= src->drawable.width);
17313					assert(box->y2 <= src->drawable.height);
17314
17315					assert(has_coherent_ptr(sna, sna_pixmap(src), MOVE_READ));
17316					assert(has_coherent_ptr(sna, sna_pixmap(dst), MOVE_WRITE));
17317					assert(src->devKind);
17318					assert(dst->devKind);
17319					memcpy_blt(src->devPrivate.ptr,
17320						   dst->devPrivate.ptr,
17321						   src->drawable.bitsPerPixel,
17322						   src->devKind, dst->devKind,
17323						   box->x1 - dx,      box->y1 - dy,
17324						   box->x1,           box->y1,
17325						   box->x2 - box->x1, box->y2 - box->y1);
17326					box++;
17327				} while (--n);
17328				sigtrap_put();
17329			}
17330		} else {
17331			if (!sna_pixmap_move_to_gpu(src, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE))
17332				goto fallback;
17333
17334			if (!sna_pixmap_move_to_gpu(dst, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE))
17335				goto fallback;
17336
17337			if (!sna->render.copy_boxes(sna, GXcopy,
17338						    &src->drawable, __sna_pixmap_get_bo(src), -dx, -dy,
17339						    &dst->drawable, __sna_pixmap_get_bo(dst),   0,   0,
17340						    box, n, COPY_LAST))
17341				goto fallback;
17342
17343			flush = true;
17344		}
17345
17346		DamageRegionProcessPending(&dirty->slave_dst->drawable);
17347skip:
17348		RegionUninit(&region);
17349		DamageEmpty(dirty->damage);
17350	}
17351	if (flush)
17352		kgem_submit(&sna->kgem);
17353#endif
17354}
17355
17356static void sna_scanout_flush(struct sna *sna)
17357{
17358	struct sna_pixmap *priv = sna_accel_scanout(sna);
17359	bool busy;
17360
17361	DBG(("%s (time=%ld), cpu damage? %d, exec? %d nbatch=%d, busy? %d\n",
17362	     __FUNCTION__, (long)TIME,
17363	     priv && priv->cpu_damage,
17364	     priv && priv->gpu_bo->exec != NULL,
17365	     sna->kgem.nbatch,
17366	     sna->kgem.busy));
17367
17368	busy = stop_flush(sna, priv);
17369	if (!sna->kgem.busy && !busy)
17370		sna_accel_disarm_timer(sna, FLUSH_TIMER);
17371	sna->kgem.busy = busy;
17372
17373	if (priv &&
17374	    sna_pixmap_force_to_gpu(priv->pixmap,
17375				    MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT))
17376		kgem_scanout_flush(&sna->kgem, priv->gpu_bo);
17377
17378	sna_mode_redisplay(sna);
17379	sna_accel_post_damage(sna);
17380}
17381
17382static void sna_accel_throttle(struct sna *sna)
17383{
17384	DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME));
17385
17386	if (sna->kgem.need_throttle) {
17387		kgem_submit(&sna->kgem);
17388		kgem_throttle(&sna->kgem);
17389	}
17390
17391	if (!sna->kgem.need_retire)
17392		sna_accel_disarm_timer(sna, THROTTLE_TIMER);
17393}
17394
17395static void sna_pixmap_expire(struct sna *sna)
17396{
17397	while (sna->freed_pixmap) {
17398		PixmapPtr pixmap = __pop_freed_pixmap(sna);
17399		free(sna_pixmap(pixmap));
17400		FreePixmap(pixmap);
17401	}
17402}
17403
17404static void sna_accel_expire(struct sna *sna)
17405{
17406	DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME));
17407
17408	kgem_expire_cache(&sna->kgem);
17409	sna_pixmap_expire(sna);
17410
17411	if (!sna->kgem.need_expire)
17412		sna_accel_disarm_timer(sna, EXPIRE_TIMER);
17413}
17414
17415#ifdef DEBUG_MEMORY
17416static bool sna_accel_do_debug_memory(struct sna *sna)
17417{
17418	int32_t delta = sna->timer_expire[DEBUG_MEMORY_TIMER] - TIME;
17419
17420	if (delta <= 3) {
17421		sna->timer_expire[DEBUG_MEMORY_TIMER] = TIME + 10 * 1000;
17422		return true;
17423	} else
17424		return false;
17425}
17426
17427static void sna_accel_debug_memory(struct sna *sna)
17428{
17429	ErrorF("Allocated pixmaps: %d (cached: %d), bo: %d, %lu bytes (CPU bo: %d, %lu bytes)\n",
17430	       sna->debug_memory.pixmap_allocs,
17431	       sna->debug_memory.pixmap_cached,
17432	       sna->kgem.debug_memory.bo_allocs,
17433	       (unsigned long)sna->kgem.debug_memory.bo_bytes,
17434	       sna->debug_memory.cpu_bo_allocs,
17435	       (unsigned long)sna->debug_memory.cpu_bo_bytes);
17436
17437#ifdef VALGRIND_DO_ADDED_LEAK_CHECK
17438	VG(VALGRIND_DO_ADDED_LEAK_CHECK);
17439#endif
17440}
17441
17442#else
17443#define sna_accel_do_debug_memory(x) 0
17444static void sna_accel_debug_memory(struct sna *sna) { }
17445#endif
17446
17447static ShmFuncs shm_funcs = { sna_pixmap_create_shm, NULL };
17448
17449static PixmapPtr
17450sna_get_window_pixmap(WindowPtr window)
17451{
17452	return get_window_pixmap(window);
17453}
17454
17455static void
17456sna_set_window_pixmap(WindowPtr window, PixmapPtr pixmap)
17457{
17458	*(PixmapPtr *)__get_private(window, sna_window_key) = pixmap;
17459}
17460
17461struct sna_visit_set_pixmap_window {
17462	PixmapPtr old, new;
17463};
17464
17465static int
17466sna_visit_set_window_pixmap(WindowPtr window, pointer data)
17467{
17468    struct sna_visit_set_pixmap_window *visit = data;
17469
17470    if (sna_get_window_pixmap(window) == visit->old) {
17471	    window->drawable.pScreen->SetWindowPixmap(window, visit->new);
17472	    return WT_WALKCHILDREN;
17473    }
17474
17475    return WT_DONTWALKCHILDREN;
17476}
17477
17478static void
17479migrate_dirty_tracking(PixmapPtr old_front, PixmapPtr new_front)
17480{
17481#if HAS_PIXMAP_SHARING
17482	ScreenPtr screen = old_front->drawable.pScreen;
17483	PixmapDirtyUpdatePtr dirty, safe;
17484
17485	xorg_list_for_each_entry_safe(dirty, safe, &screen->pixmap_dirty_list, ent) {
17486		assert(dirty->src == old_front);
17487		if (dirty->src != old_front)
17488			continue;
17489
17490		DamageUnregister(&dirty->src->drawable, dirty->damage);
17491		DamageDestroy(dirty->damage);
17492
17493		dirty->damage = DamageCreate(NULL, NULL,
17494					     DamageReportNone,
17495					     TRUE, screen, screen);
17496		if (!dirty->damage) {
17497			xorg_list_del(&dirty->ent);
17498			free(dirty);
17499			continue;
17500		}
17501
17502		DamageRegister(&new_front->drawable, dirty->damage);
17503		dirty->src = new_front;
17504	}
17505#endif
17506}
17507
17508static void
17509sna_set_screen_pixmap(PixmapPtr pixmap)
17510{
17511	ScreenPtr screen = pixmap->drawable.pScreen;
17512	PixmapPtr old_front = screen->devPrivate;
17513	WindowPtr root;
17514
17515	DBG(("%s: changing from pixmap=%ld to pixmap=%ld, (sna->front=%ld)\n",
17516	     __FUNCTION__,
17517	     old_front ? (long)old_front->drawable.serialNumber : 0,
17518	     pixmap ? (long)pixmap->drawable.serialNumber : 0,
17519	     to_sna_from_pixmap(pixmap)->front ? (long)to_sna_from_pixmap(pixmap)->front->drawable.serialNumber : 0));
17520
17521	assert(to_sna_from_pixmap(pixmap) == to_sna_from_screen(screen));
17522	assert(to_sna_from_pixmap(pixmap)->front == old_front);
17523
17524	if (old_front) {
17525		assert(to_sna_from_pixmap(old_front)->front == old_front);
17526		migrate_dirty_tracking(old_front, pixmap);
17527	}
17528
17529	root = get_root_window(screen);
17530	if (root) {
17531		struct sna_visit_set_pixmap_window visit = { old_front, pixmap };
17532		TraverseTree(root, sna_visit_set_window_pixmap, &visit);
17533		assert(fbGetWindowPixmap(root) == pixmap);
17534	}
17535
17536	to_sna_from_pixmap(pixmap)->front = pixmap;
17537	screen->devPrivate = pixmap;
17538	pixmap->refcnt++;
17539
17540	if (old_front)
17541		screen->DestroyPixmap(old_front);
17542}
17543
17544static Bool
17545sna_create_window(WindowPtr win)
17546{
17547	sna_set_window_pixmap(win, win->drawable.pScreen->devPrivate);
17548	return TRUE;
17549}
17550
17551static Bool
17552sna_map_window(WindowPtr win)
17553{
17554	return TRUE;
17555}
17556
17557static Bool
17558sna_position_window(WindowPtr win, int x, int y)
17559{
17560	return TRUE;
17561}
17562
17563static Bool
17564sna_unmap_window(WindowPtr win)
17565{
17566	return TRUE;
17567}
17568
17569static Bool
17570sna_destroy_window(WindowPtr win)
17571{
17572	sna_video_destroy_window(win);
17573	sna_dri2_destroy_window(win);
17574	return TRUE;
17575}
17576
17577static void
17578sna_query_best_size(int class,
17579		    unsigned short *width, unsigned short *height,
17580		    ScreenPtr screen)
17581{
17582	unsigned short w;
17583
17584	switch (class) {
17585	case CursorShape:
17586		if (*width > screen->width)
17587			*width = screen->width;
17588		if (*height > screen->height)
17589			*height = screen->height;
17590		break;
17591
17592	case TileShape:
17593	case StippleShape:
17594		w = *width;
17595		if ((w & (w - 1)) && w < FB_UNIT) {
17596			for (w = 1; w < *width; w <<= 1)
17597				;
17598			*width = w;
17599		}
17600		break;
17601	}
17602}
17603
17604static void sna_store_colors(ColormapPtr cmap, int n, xColorItem *def)
17605{
17606}
17607
17608static bool sna_picture_init(ScreenPtr screen)
17609{
17610	PictureScreenPtr ps;
17611
17612	DBG(("%s\n", __FUNCTION__));
17613
17614	if (!miPictureInit(screen, NULL, 0))
17615		return false;
17616
17617	ps = GetPictureScreen(screen);
17618	assert(ps != NULL);
17619	assert(ps->CreatePicture != NULL);
17620	assert(ps->DestroyPicture != NULL);
17621
17622	ps->Composite = sna_composite;
17623	ps->CompositeRects = sna_composite_rectangles;
17624	ps->Glyphs = sna_glyphs;
17625	if (xf86IsEntityShared(xf86ScreenToScrn(screen)->entityList[0]))
17626		ps->Glyphs = sna_glyphs__shared;
17627	ps->UnrealizeGlyph = sna_glyph_unrealize;
17628	ps->AddTraps = sna_add_traps;
17629	ps->Trapezoids = sna_composite_trapezoids;
17630#if HAS_PIXMAN_TRIANGLES
17631	ps->Triangles = sna_composite_triangles;
17632#if PICTURE_SCREEN_VERSION >= 2
17633	ps->TriStrip = sna_composite_tristrip;
17634	ps->TriFan = sna_composite_trifan;
17635#endif
17636#endif
17637
17638	return true;
17639}
17640
17641static bool sna_option_accel_none(struct sna *sna)
17642{
17643	const char *s;
17644
17645	if (xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_DISABLE, FALSE))
17646		return true;
17647
17648	s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD);
17649	if (s == NULL)
17650		return IS_DEFAULT_ACCEL_METHOD(NOACCEL);
17651
17652	return strcasecmp(s, "none") == 0;
17653}
17654
17655static bool sna_option_accel_blt(struct sna *sna)
17656{
17657	const char *s;
17658
17659	s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD);
17660	if (s == NULL)
17661		return false;
17662
17663	return strcasecmp(s, "blt") == 0;
17664}
17665
17666bool sna_accel_init(ScreenPtr screen, struct sna *sna)
17667{
17668	const char *backend;
17669
17670	DBG(("%s\n", __FUNCTION__));
17671
17672	sna_font_key = AllocateFontPrivateIndex();
17673
17674	list_init(&sna->flush_pixmaps);
17675	list_init(&sna->active_pixmaps);
17676
17677	AddGeneralSocket(sna->kgem.fd);
17678
17679#ifdef DEBUG_MEMORY
17680	sna->timer_expire[DEBUG_MEMORY_TIMER] = GetTimeInMillis()+ 10 * 1000;
17681#endif
17682
17683	screen->defColormap = FakeClientID(0);
17684	/* let CreateDefColormap do whatever it wants for pixels */
17685	screen->blackPixel = screen->whitePixel = (Pixel) 0;
17686	screen->QueryBestSize = sna_query_best_size;
17687	assert(screen->GetImage == NULL);
17688	screen->GetImage = sna_get_image;
17689	assert(screen->GetSpans == NULL);
17690	screen->GetSpans = sna_get_spans;
17691	assert(screen->CreateWindow == NULL);
17692	screen->CreateWindow = sna_create_window;
17693	assert(screen->DestroyWindow == NULL);
17694	screen->DestroyWindow = sna_destroy_window;
17695	screen->PositionWindow = sna_position_window;
17696	screen->ChangeWindowAttributes = sna_change_window_attributes;
17697	screen->RealizeWindow = sna_map_window;
17698	screen->UnrealizeWindow = sna_unmap_window;
17699	screen->CopyWindow = sna_copy_window;
17700	assert(screen->CreatePixmap == NULL);
17701	screen->CreatePixmap = sna_create_pixmap;
17702	assert(screen->DestroyPixmap == NULL);
17703	screen->DestroyPixmap = sna_destroy_pixmap;
17704#ifdef CREATE_PIXMAP_USAGE_SHARED
17705	screen->SharePixmapBacking = sna_share_pixmap_backing;
17706	screen->SetSharedPixmapBacking = sna_set_shared_pixmap_backing;
17707#endif
17708	screen->RealizeFont = sna_realize_font;
17709	screen->UnrealizeFont = sna_unrealize_font;
17710	assert(screen->CreateGC == NULL);
17711	screen->CreateGC = sna_create_gc;
17712	screen->CreateColormap = miInitializeColormap;
17713	screen->DestroyColormap = (void (*)(ColormapPtr)) NoopDDA;
17714	screen->InstallColormap = miInstallColormap;
17715	screen->UninstallColormap = miUninstallColormap;
17716	screen->ListInstalledColormaps = miListInstalledColormaps;
17717	screen->ResolveColor = miResolveColor;
17718	assert(screen->StoreColors == NULL);
17719	screen->StoreColors = sna_store_colors;
17720	screen->BitmapToRegion = fbBitmapToRegion;
17721
17722#if HAS_PIXMAP_SHARING
17723	screen->StartPixmapTracking = PixmapStartDirtyTracking;
17724	screen->StopPixmapTracking = PixmapStopDirtyTracking;
17725#endif
17726
17727	assert(screen->GetWindowPixmap == NULL);
17728	screen->GetWindowPixmap = sna_get_window_pixmap;
17729	assert(screen->SetWindowPixmap == NULL);
17730	screen->SetWindowPixmap = sna_set_window_pixmap;
17731
17732	screen->SetScreenPixmap = sna_set_screen_pixmap;
17733
17734	if (sna->kgem.has_userptr)
17735		ShmRegisterFuncs(screen, &shm_funcs);
17736	else
17737		ShmRegisterFbFuncs(screen);
17738
17739	if (!sna_picture_init(screen))
17740		return false;
17741
17742	backend = no_render_init(sna);
17743	if (sna_option_accel_none(sna)) {
17744		backend = "disabled";
17745		sna->kgem.wedged = true;
17746	} else if (sna_option_accel_blt(sna) || sna->info->gen >= 0110)
17747		(void)backend;
17748	else if (sna->info->gen >= 0100)
17749		backend = gen8_render_init(sna, backend);
17750	else if (sna->info->gen >= 070)
17751		backend = gen7_render_init(sna, backend);
17752	else if (sna->info->gen >= 060)
17753		backend = gen6_render_init(sna, backend);
17754	else if (sna->info->gen >= 050)
17755		backend = gen5_render_init(sna, backend);
17756	else if (sna->info->gen >= 040)
17757		backend = gen4_render_init(sna, backend);
17758	else if (sna->info->gen >= 030)
17759		backend = gen3_render_init(sna, backend);
17760	else if (sna->info->gen >= 020)
17761		backend = gen2_render_init(sna, backend);
17762
17763	DBG(("%s(backend=%s, prefer_gpu=%x)\n",
17764	     __FUNCTION__, backend, sna->render.prefer_gpu));
17765
17766	kgem_reset(&sna->kgem);
17767	sigtrap_init();
17768
17769	xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
17770		   "SNA initialized with %s backend\n",
17771		   backend);
17772
17773	return true;
17774}
17775
17776void sna_accel_create(struct sna *sna)
17777{
17778	DBG(("%s\n", __FUNCTION__));
17779
17780	if (!sna_glyphs_create(sna))
17781		goto fail;
17782
17783	if (!sna_gradients_create(sna))
17784		goto fail;
17785
17786	if (!sna_composite_create(sna))
17787		goto fail;
17788
17789	return;
17790
17791fail:
17792	xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
17793		   "Failed to allocate caches, disabling RENDER acceleration\n");
17794	no_render_init(sna);
17795}
17796
17797void sna_accel_watch_flush(struct sna *sna, int enable)
17798{
17799	DBG(("%s: enable=%d\n", __FUNCTION__, enable));
17800	assert(enable);
17801
17802	if (sna->watch_flush == 0) {
17803		DBG(("%s: installing watchers\n", __FUNCTION__));
17804		assert(enable > 0);
17805		if (!AddCallback(&FlushCallback, sna_accel_flush_callback, sna)) {
17806			xf86DrvMsg(sna->scrn->scrnIndex, X_Error,
17807				   "Failed to attach ourselves to the flush callbacks, expect missing synchronisation with DRI clients (e.g a compositor)\n");
17808		}
17809		sna->watch_flush++;
17810	}
17811
17812	sna->watch_flush += enable;
17813}
17814
17815void sna_accel_leave(struct sna *sna)
17816{
17817	DBG(("%s\n", __FUNCTION__));
17818
17819	/* as root we always have permission to render */
17820	if (geteuid() == 0)
17821		return;
17822
17823	/* as a user, we can only render now if we have a rendernode */
17824	if (intel_has_render_node(sna->scrn))
17825		return;
17826
17827	/* no longer authorized to use our fd */
17828	DBG(("%s: dropping render privileges\n", __FUNCTION__));
17829
17830	kgem_submit(&sna->kgem);
17831	sna->kgem.wedged |= 2;
17832}
17833
17834void sna_accel_enter(struct sna *sna)
17835{
17836	DBG(("%s\n", __FUNCTION__));
17837	sna->kgem.wedged &= kgem_is_wedged(&sna->kgem);
17838	kgem_throttle(&sna->kgem);
17839}
17840
17841void sna_accel_close(struct sna *sna)
17842{
17843	DBG(("%s\n", __FUNCTION__));
17844
17845	sna_composite_close(sna);
17846	sna_gradients_close(sna);
17847	sna_glyphs_close(sna);
17848
17849	sna_pixmap_expire(sna);
17850
17851	DeleteCallback(&FlushCallback, sna_accel_flush_callback, sna);
17852	RemoveGeneralSocket(sna->kgem.fd);
17853
17854	kgem_cleanup_cache(&sna->kgem);
17855}
17856
17857void sna_accel_block_handler(struct sna *sna, struct timeval **tv)
17858{
17859	sigtrap_assert_inactive();
17860
17861	if (sna->kgem.need_retire)
17862		kgem_retire(&sna->kgem);
17863	kgem_retire__buffers(&sna->kgem);
17864
17865	if (sna->timer_active)
17866		UpdateCurrentTimeIf();
17867
17868	if (sna->kgem.nbatch &&
17869	    (sna->kgem.scanout_busy ||
17870	     kgem_ring_is_idle(&sna->kgem, sna->kgem.ring))) {
17871		DBG(("%s: GPU idle, flushing\n", __FUNCTION__));
17872		_kgem_submit(&sna->kgem);
17873	}
17874
17875restart:
17876	if (sna_scanout_do_flush(sna))
17877		sna_scanout_flush(sna);
17878	assert(sna_accel_scanout(sna) == NULL ||
17879	       !sna_accel_scanout(sna)->gpu_bo->needs_flush ||
17880	       sna->timer_active & (1<<(FLUSH_TIMER)));
17881
17882	if (sna_accel_do_throttle(sna))
17883		sna_accel_throttle(sna);
17884	assert(!sna->kgem.need_retire ||
17885	       sna->timer_active & (1<<(THROTTLE_TIMER)));
17886
17887	if (sna_accel_do_expire(sna))
17888		sna_accel_expire(sna);
17889	assert(!sna->kgem.need_expire ||
17890	       sna->timer_active & (1<<(EXPIRE_TIMER)));
17891
17892	if (sna_accel_do_debug_memory(sna))
17893		sna_accel_debug_memory(sna);
17894
17895	if (sna->watch_flush == 1) {
17896		DBG(("%s: removing watchers\n", __FUNCTION__));
17897		DeleteCallback(&FlushCallback, sna_accel_flush_callback, sna);
17898		sna->watch_flush = 0;
17899	}
17900
17901	if (sna->timer_active & 1) {
17902		int32_t timeout;
17903
17904		DBG(("%s: evaluating timers, active=%x\n",
17905		     __FUNCTION__, sna->timer_active));
17906
17907		timeout = sna->timer_expire[FLUSH_TIMER] - TIME;
17908		DBG(("%s: flush timer expires in %d [%d]\n",
17909		     __FUNCTION__, timeout, sna->timer_expire[FLUSH_TIMER]));
17910		if (timeout < 3)
17911			goto restart;
17912
17913		if (*tv == NULL) {
17914			*tv = &sna->timer_tv;
17915			goto set_tv;
17916		}
17917		if ((*tv)->tv_sec * 1000 + (*tv)->tv_usec / 1000 > timeout) {
17918set_tv:
17919			(*tv)->tv_sec = timeout / 1000;
17920			(*tv)->tv_usec = timeout % 1000 * 1000;
17921		}
17922	}
17923
17924	sna->kgem.scanout_busy = false;
17925
17926	if (FAULT_INJECTION && (rand() % FAULT_INJECTION) == 0) {
17927		DBG(("%s hardware acceleration\n",
17928		     sna->kgem.wedged ? "Re-enabling" : "Disabling"));
17929		kgem_submit(&sna->kgem);
17930		sna->kgem.wedged = !sna->kgem.wedged;
17931	}
17932}
17933
17934void sna_accel_wakeup_handler(struct sna *sna)
17935{
17936	DBG(("%s: nbatch=%d, need_retire=%d, need_purge=%d\n", __FUNCTION__,
17937	     sna->kgem.nbatch, sna->kgem.need_retire, sna->kgem.need_purge));
17938
17939	if (!sna->kgem.nbatch)
17940		return;
17941
17942	if (kgem_is_idle(&sna->kgem)) {
17943		DBG(("%s: GPU idle, flushing\n", __FUNCTION__));
17944		_kgem_submit(&sna->kgem);
17945	}
17946
17947	sigtrap_assert_inactive();
17948}
17949
17950void sna_accel_free(struct sna *sna)
17951{
17952	DBG(("%s\n", __FUNCTION__));
17953	sigtrap_assert_inactive();
17954}
17955