sna_accel.c revision 03b705cf
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 "intel_options.h"
33#include "sna.h"
34#include "sna_reg.h"
35#include "sna_video.h"
36#include "rop.h"
37
38#include <X11/fonts/font.h>
39#include <X11/fonts/fontstruct.h>
40
41#include <dixfontstr.h>
42
43#include <mi.h>
44#include <migc.h>
45#include <miline.h>
46#include <micmap.h>
47#ifdef RENDER
48#include <mipict.h>
49#endif
50#include <shmint.h>
51
52#include <sys/time.h>
53#include <sys/mman.h>
54#include <unistd.h>
55
56#define FAULT_INJECTION 0
57
58#define FORCE_INPLACE 0
59#define FORCE_FALLBACK 0
60#define FORCE_FLUSH 0
61#define FORCE_FULL_SYNC 0 /* https://bugs.freedesktop.org/show_bug.cgi?id=61628 */
62
63#define DEFAULT_TILING I915_TILING_X
64
65#define USE_INPLACE 1
66#define USE_WIDE_SPANS 0 /* -1 force CPU, 1 force GPU */
67#define USE_ZERO_SPANS 1 /* -1 force CPU, 1 force GPU */
68#define USE_CPU_BO 1
69#define USE_USERPTR_UPLOADS 1
70#define USE_USERPTR_DOWNLOADS 1
71#define USE_COW 1
72#define UNDO 1
73
74#define MIGRATE_ALL 0
75#define DBG_NO_CPU_UPLOAD 0
76#define DBG_NO_CPU_DOWNLOAD 0
77
78#define ACCEL_FILL_SPANS 1
79#define ACCEL_SET_SPANS 1
80#define ACCEL_PUT_IMAGE 1
81#define ACCEL_GET_IMAGE 1
82#define ACCEL_COPY_AREA 1
83#define ACCEL_COPY_PLANE 1
84#define ACCEL_COPY_WINDOW 1
85#define ACCEL_POLY_POINT 1
86#define ACCEL_POLY_LINE 1
87#define ACCEL_POLY_SEGMENT 1
88#define ACCEL_POLY_RECTANGLE 1
89#define ACCEL_POLY_ARC 1
90#define ACCEL_POLY_FILL_POLYGON 1
91#define ACCEL_POLY_FILL_RECT 1
92#define ACCEL_POLY_FILL_ARC 1
93#define ACCEL_POLY_TEXT8 1
94#define ACCEL_POLY_TEXT16 1
95#define ACCEL_POLY_GLYPH 1
96#define ACCEL_IMAGE_TEXT8 1
97#define ACCEL_IMAGE_TEXT16 1
98#define ACCEL_IMAGE_GLYPH 1
99#define ACCEL_PUSH_PIXELS 1
100
101#define NO_TILE_8x8 0
102#define NO_STIPPLE_8x8 0
103
104#define IS_STATIC_PTR(ptr) ((uintptr_t)(ptr) & 1)
105#define MAKE_STATIC_PTR(ptr) ((void*)((uintptr_t)(ptr) | 1))
106
107#define IS_COW_OWNER(ptr) ((uintptr_t)(ptr) & 1)
108#define MAKE_COW_OWNER(ptr) ((void*)((uintptr_t)(ptr) | 1))
109#define COW(ptr) (void *)((uintptr_t)(ptr) & ~1)
110
111#if 0
112static void __sna_fallback_flush(DrawablePtr d)
113{
114	PixmapPtr pixmap = get_drawable_pixmap(d);
115	struct sna *sna = to_sna_from_pixmap(pixmap);
116	struct sna_pixmap *priv;
117	BoxRec box;
118	PixmapPtr tmp;
119	int i, j;
120	char *src, *dst;
121
122	DBG(("%s: uploading CPU damage...\n", __FUNCTION__));
123	priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ);
124	if (priv == NULL)
125		return;
126
127	DBG(("%s: downloading GPU damage...\n", __FUNCTION__));
128	if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
129		return;
130
131	box.x1 = box.y1 = 0;
132	box.x2 = pixmap->drawable.width;
133	box.y2 = pixmap->drawable.height;
134
135	tmp = sna_pixmap_create_unattached(pixmap->drawable.pScreen,
136					   pixmap->drawable.width,
137					   pixmap->drawable.height,
138					   pixmap->drawable.depth,
139					   0);
140
141	DBG(("%s: comparing with direct read...\n", __FUNCTION__));
142	sna_read_boxes(sna, tmp, priv->gpu_bo, &box, 1);
143
144	src = pixmap->devPrivate.ptr;
145	dst = tmp->devPrivate.ptr;
146	for (i = 0; i < tmp->drawable.height; i++) {
147		if (memcmp(src, dst, tmp->drawable.width * tmp->drawable.bitsPerPixel >> 3)) {
148			for (j = 0; src[j] == dst[j]; j++)
149				;
150			ErrorF("mismatch at (%d, %d)\n",
151			       8*j / tmp->drawable.bitsPerPixel, i);
152			abort();
153		}
154		src += pixmap->devKind;
155		dst += tmp->devKind;
156	}
157	tmp->drawable.pScreen->DestroyPixmap(tmp);
158}
159#define FALLBACK_FLUSH(d) __sna_fallback_flush(d)
160#else
161#define FALLBACK_FLUSH(d)
162#endif
163
164static int sna_font_key;
165
166static const uint8_t copy_ROP[] = {
167	ROP_0,		/* GXclear */
168	ROP_DSa,	/* GXand */
169	ROP_SDna,	/* GXandReverse */
170	ROP_S,		/* GXcopy */
171	ROP_DSna,	/* GXandInverted */
172	ROP_D,		/* GXnoop */
173	ROP_DSx,	/* GXxor */
174	ROP_DSo,	/* GXor */
175	ROP_DSon,	/* GXnor */
176	ROP_DSxn,	/* GXequiv */
177	ROP_Dn,		/* GXinvert */
178	ROP_SDno,	/* GXorReverse */
179	ROP_Sn,		/* GXcopyInverted */
180	ROP_DSno,	/* GXorInverted */
181	ROP_DSan,	/* GXnand */
182	ROP_1		/* GXset */
183};
184static const uint8_t fill_ROP[] = {
185	ROP_0,
186	ROP_DPa,
187	ROP_PDna,
188	ROP_P,
189	ROP_DPna,
190	ROP_D,
191	ROP_DPx,
192	ROP_DPo,
193	ROP_DPon,
194	ROP_PDxn,
195	ROP_Dn,
196	ROP_PDno,
197	ROP_Pn,
198	ROP_DPno,
199	ROP_DPan,
200	ROP_1
201};
202
203static const GCOps sna_gc_ops;
204static const GCOps sna_gc_ops__cpu;
205static GCOps sna_gc_ops__tmp;
206static const GCFuncs sna_gc_funcs;
207static const GCFuncs sna_gc_funcs__cpu;
208
209static void
210sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect);
211
212static inline void region_set(RegionRec *r, const BoxRec *b)
213{
214	r->extents = *b;
215	r->data = NULL;
216}
217
218static inline void region_maybe_clip(RegionRec *r, RegionRec *clip)
219{
220	if (clip->data)
221		RegionIntersect(r, r, clip);
222}
223
224static inline bool region_is_singular(const RegionRec *r)
225{
226	return r->data == NULL;
227}
228
229typedef struct box32 {
230	int32_t x1, y1, x2, y2;
231} Box32Rec;
232
233#define PM_IS_SOLID(_draw, _pm) \
234	(((_pm) & FbFullMask((_draw)->depth)) == FbFullMask((_draw)->depth))
235
236#ifdef DEBUG_PIXMAP
237static void _assert_pixmap_contains_box(PixmapPtr pixmap, const BoxRec *box, const char *function)
238{
239	if (box->x1 < 0 || box->y1 < 0 ||
240	    box->x2 > pixmap->drawable.width ||
241	    box->y2 > pixmap->drawable.height)
242	{
243		ErrorF("%s: damage box is beyond the pixmap: box=(%d, %d), (%d, %d), pixmap=(%d, %d)\n",
244		       __FUNCTION__,
245		       box->x1, box->y1, box->x2, box->y2,
246		       pixmap->drawable.width,
247		       pixmap->drawable.height);
248		assert(0);
249	}
250}
251
252static void _assert_pixmap_contains_box_with_offset(PixmapPtr pixmap, const BoxRec *box, int dx, int dy, const char *function)
253{
254	BoxRec b = *box;
255	b.x1 += dx; b.x2 += dx;
256	b.y1 += dy; b.y2 += dy;
257	_assert_pixmap_contains_box(pixmap, &b, function);
258}
259
260static void _assert_pixmap_contains_boxes(PixmapPtr pixmap, const BoxRec *box, int n, int dx, int dy, const char *function)
261{
262	BoxRec extents;
263
264	extents = *box;
265	while (--n) {
266		++box;
267
268		if (box->x1 < extents.x1)
269			extents.x1 = box->x1;
270		if (box->x2 > extents.x2)
271			extents.x2 = box->x2;
272
273		if (box->y1 < extents.y1)
274			extents.y1 = box->y1;
275		if (box->y2 > extents.y2)
276			extents.y2 = box->y2;
277	}
278	extents.x1 += dx;
279	extents.x2 += dx;
280	extents.y1 += dy;
281	extents.y2 += dy;
282	_assert_pixmap_contains_box(pixmap, &extents, function);
283}
284
285
286static void _assert_pixmap_contains_points(PixmapPtr pixmap, const DDXPointRec *pt, int n, int dx, int dy, const char *function)
287{
288	BoxRec extents;
289
290	extents.x2 = extents.x1 = pt->x;
291	extents.y2 = extents.y1 = pt->y;
292	while (--n) {
293		++pt;
294
295		if (pt->x < extents.x1)
296			extents.x1 = pt->x;
297		else if (pt->x > extents.x2)
298			extents.x2 = pt->x;
299
300		if (pt->y < extents.y1)
301			extents.y1 = pt->y;
302		else if (pt->y > extents.y2)
303			extents.y2 = pt->y;
304	}
305	extents.x1 += dx;
306	extents.x2 += dx + 1;
307	extents.y1 += dy;
308	extents.y2 += dy + 1;
309	_assert_pixmap_contains_box(pixmap, &extents, function);
310}
311
312static void _assert_drawable_contains_box(DrawablePtr drawable, const BoxRec *box, const char *function)
313{
314	if (box->x1 < drawable->x ||
315	    box->y1 < drawable->y ||
316	    box->x2 > drawable->x + drawable->width ||
317	    box->y2 > drawable->y + drawable->height)
318	{
319		ErrorF("%s: damage box is beyond the drawable: box=(%d, %d), (%d, %d), drawable=(%d, %d)x(%d, %d)\n",
320		       __FUNCTION__,
321		       box->x1, box->y1, box->x2, box->y2,
322		       drawable->x, drawable->y,
323		       drawable->width, drawable->height);
324		assert(0);
325	}
326}
327
328static void assert_pixmap_damage(PixmapPtr p)
329{
330	struct sna_pixmap *priv;
331	RegionRec reg, cpu, gpu;
332
333	priv = sna_pixmap(p);
334	if (priv == NULL)
335		return;
336
337	assert(priv->gpu_damage == NULL || priv->gpu_bo);
338
339	if (priv->clear) {
340		assert(DAMAGE_IS_ALL(priv->gpu_damage));
341		assert(priv->cpu_damage == NULL);
342	}
343
344	if (DAMAGE_IS_ALL(priv->gpu_damage) && DAMAGE_IS_ALL(priv->cpu_damage)) {
345		/* special upload buffer */
346		assert(priv->gpu_bo && priv->gpu_bo->proxy);
347		assert(priv->cpu_bo == NULL);
348		return;
349	}
350
351	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
352		assert(priv->cpu == false || (priv->mapped && IS_CPU_MAP(priv->gpu_bo->map)));
353	}
354
355	assert(!DAMAGE_IS_ALL(priv->gpu_damage) || priv->cpu_damage == NULL);
356	assert(!DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL);
357
358	/* Avoid reducing damage to minimise interferrence */
359	RegionNull(&reg);
360	RegionNull(&gpu);
361	RegionNull(&cpu);
362
363	if (priv->gpu_damage)
364		_sna_damage_debug_get_region(DAMAGE_PTR(priv->gpu_damage), &gpu);
365
366	if (priv->cpu_damage)
367		_sna_damage_debug_get_region(DAMAGE_PTR(priv->cpu_damage), &cpu);
368
369	RegionIntersect(&reg, &cpu, &gpu);
370	assert(RegionNil(&reg));
371
372	RegionUninit(&reg);
373	RegionUninit(&gpu);
374	RegionUninit(&cpu);
375}
376
377#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__)
378#define assert_pixmap_contains_box_with_offset(p, b, dx, dy) _assert_pixmap_contains_box_with_offset(p, b, dx, dy, __FUNCTION__)
379#define assert_drawable_contains_box(d, b) _assert_drawable_contains_box(d, b, __FUNCTION__)
380#define assert_pixmap_contains_boxes(p, b, n, x, y) _assert_pixmap_contains_boxes(p, b, n, x, y, __FUNCTION__)
381#define assert_pixmap_contains_points(p, pt, n, x, y) _assert_pixmap_contains_points(p, pt, n, x, y, __FUNCTION__)
382
383#else
384#define assert_pixmap_contains_box(p, b)
385#define assert_pixmap_contains_box_with_offset(p, b, dx, dy)
386#define assert_pixmap_contains_boxes(p, b, n, x, y)
387#define assert_pixmap_contains_points(p, pt, n, x, y)
388#define assert_drawable_contains_box(d, b)
389#ifndef NDEBUG
390#define assert_pixmap_damage(p) do { \
391	struct sna_pixmap *priv__ = sna_pixmap(p); \
392	assert(priv__ == NULL || priv__->gpu_damage == NULL || priv__->gpu_bo); \
393} while (0)
394#else
395#define assert_pixmap_damage(p)
396#endif
397#endif
398
399inline static bool
400sna_fill_init_blt(struct sna_fill_op *fill,
401		  struct sna *sna,
402		  PixmapPtr pixmap,
403		  struct kgem_bo *bo,
404		  uint8_t alu,
405		  uint32_t pixel)
406{
407	return sna->render.fill(sna, alu, pixmap, bo, pixel, fill);
408}
409
410static bool
411sna_copy_init_blt(struct sna_copy_op *copy,
412		  struct sna *sna,
413		  PixmapPtr src, struct kgem_bo *src_bo,
414		  PixmapPtr dst, struct kgem_bo *dst_bo,
415		  uint8_t alu)
416{
417	memset(copy, 0, sizeof(*copy));
418	return sna->render.copy(sna, alu, src, src_bo, dst, dst_bo, copy);
419}
420
421static void sna_pixmap_free_gpu(struct sna *sna, struct sna_pixmap *priv)
422{
423	assert(priv->gpu_damage == NULL || priv->gpu_bo);
424
425	if (priv->cow)
426		sna_pixmap_undo_cow(sna, priv, 0);
427	assert(priv->cow == NULL);
428
429	sna_damage_destroy(&priv->gpu_damage);
430	priv->clear = false;
431
432	if (priv->gpu_bo && !priv->pinned) {
433		assert(!priv->flush);
434		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
435		priv->gpu_bo = NULL;
436	}
437
438	if (priv->mapped) {
439		assert(!priv->shm);
440		priv->pixmap->devPrivate.ptr = NULL;
441		priv->mapped = false;
442	}
443
444	/* and reset the upload counter */
445	priv->source_count = SOURCE_BIAS;
446}
447
448static bool must_check
449sna_pixmap_alloc_cpu(struct sna *sna,
450		     PixmapPtr pixmap,
451		     struct sna_pixmap *priv,
452		     bool from_gpu)
453{
454	/* Restore after a GTT mapping? */
455	assert(priv->gpu_damage == NULL || priv->gpu_bo);
456	assert(!priv->shm);
457	if (priv->ptr)
458		goto done;
459
460	DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
461	assert(priv->stride);
462
463	if (priv->create & KGEM_CAN_CREATE_CPU) {
464		DBG(("%s: allocating CPU buffer (%dx%d)\n", __FUNCTION__,
465		     pixmap->drawable.width, pixmap->drawable.height));
466
467		priv->cpu_bo = kgem_create_cpu_2d(&sna->kgem,
468						  pixmap->drawable.width,
469						  pixmap->drawable.height,
470						  pixmap->drawable.bitsPerPixel,
471						  from_gpu ? 0 : CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE);
472		if (priv->cpu_bo) {
473			priv->ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo);
474			if (priv->ptr) {
475				DBG(("%s: allocated CPU handle=%d (snooped? %d)\n", __FUNCTION__,
476				     priv->cpu_bo->handle, priv->cpu_bo->snoop));
477				priv->stride = priv->cpu_bo->pitch;
478#ifdef DEBUG_MEMORY
479				sna->debug_memory.cpu_bo_allocs++;
480				sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo);
481#endif
482			} else {
483				kgem_bo_destroy(&sna->kgem, priv->cpu_bo);
484				priv->cpu_bo = NULL;
485			}
486		}
487	}
488
489	if (priv->ptr == NULL) {
490		DBG(("%s: allocating ordinary memory for shadow pixels [%d bytes]\n",
491		     __FUNCTION__, priv->stride * pixmap->drawable.height));
492		priv->ptr = malloc(priv->stride * pixmap->drawable.height);
493	}
494
495	assert(priv->ptr);
496done:
497	assert(priv->stride);
498	assert(!priv->mapped);
499	pixmap->devPrivate.ptr = PTR(priv->ptr);
500	pixmap->devKind = priv->stride;
501	return priv->ptr != NULL;
502}
503
504static void __sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv)
505{
506	if (priv->cpu_bo) {
507		DBG(("%s: discarding CPU buffer, handle=%d, size=%d\n",
508		     __FUNCTION__, priv->cpu_bo->handle, kgem_bo_size(priv->cpu_bo)));
509#ifdef DEBUG_MEMORY
510		sna->debug_memory.cpu_bo_allocs--;
511		sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo);
512#endif
513		if (!priv->cpu_bo->reusable) {
514			assert(priv->cpu_bo->flush == true);
515			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
516			sna_accel_watch_flush(sna, -1);
517		}
518		kgem_bo_destroy(&sna->kgem, priv->cpu_bo);
519	} else if (!IS_STATIC_PTR(priv->ptr))
520		free(priv->ptr);
521}
522
523static void sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv)
524{
525	assert(priv->cpu_damage == NULL);
526	assert(list_is_empty(&priv->flush_list));
527
528	if (IS_STATIC_PTR(priv->ptr))
529		return;
530
531	__sna_pixmap_free_cpu(sna, priv);
532
533	priv->cpu_bo = NULL;
534	priv->ptr = NULL;
535
536	if (!priv->mapped)
537		priv->pixmap->devPrivate.ptr = NULL;
538}
539
540static inline uint32_t default_tiling(PixmapPtr pixmap,
541				      uint32_t tiling)
542{
543	struct sna_pixmap *priv = sna_pixmap(pixmap);
544	struct sna *sna = to_sna_from_pixmap(pixmap);
545
546	/* Try to avoid hitting the Y-tiling GTT mapping bug on 855GM */
547	if (sna->kgem.gen == 021)
548		return I915_TILING_X;
549
550	/* Only on later generations was the render pipeline
551	 * more flexible than the BLT. So on gen2/3, prefer to
552	 * keep large objects accessible through the BLT.
553	 */
554	if (sna->kgem.gen < 040 &&
555	    (pixmap->drawable.width  > sna->render.max_3d_size ||
556	     pixmap->drawable.height > sna->render.max_3d_size))
557		return I915_TILING_X;
558
559	if (tiling == I915_TILING_Y &&
560	    sna_damage_is_all(&priv->cpu_damage,
561			      pixmap->drawable.width,
562			      pixmap->drawable.height)) {
563		DBG(("%s: entire source is damaged, using Y-tiling\n",
564		     __FUNCTION__));
565		sna_damage_destroy(&priv->gpu_damage);
566
567		return I915_TILING_Y;
568	}
569
570	return tiling;
571}
572
573pure static uint32_t sna_pixmap_choose_tiling(PixmapPtr pixmap,
574					      uint32_t tiling)
575{
576	struct sna *sna = to_sna_from_pixmap(pixmap);
577	uint32_t bit;
578
579	/* Use tiling by default, but disable per user request */
580	if (pixmap->usage_hint == SNA_CREATE_FB) {
581		tiling = -I915_TILING_X;
582		bit = SNA_TILING_FB;
583	} else {
584		tiling = default_tiling(pixmap, tiling);
585		bit = SNA_TILING_2D;
586	}
587	if ((sna->tiling & bit) == 0)
588		tiling = I915_TILING_NONE;
589
590	/* Also adjust tiling if it is not supported or likely to
591	 * slow us down,
592	 */
593	return kgem_choose_tiling(&sna->kgem, tiling,
594				  pixmap->drawable.width,
595				  pixmap->drawable.height,
596				  pixmap->drawable.bitsPerPixel);
597}
598
599struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling)
600{
601	struct sna_pixmap *priv = sna_pixmap(pixmap);
602	struct sna *sna = to_sna_from_pixmap(pixmap);
603	struct kgem_bo *bo;
604	BoxRec box;
605
606	DBG(("%s: changing tiling %d -> %d for %dx%d pixmap\n",
607	     __FUNCTION__, priv->gpu_bo->tiling, tiling,
608	     pixmap->drawable.width, pixmap->drawable.height));
609	assert(priv->gpu_damage == NULL || priv->gpu_bo);
610
611	if (priv->pinned) {
612		DBG(("%s: can't convert pinned bo\n", __FUNCTION__));
613		return NULL;
614	}
615
616	if (wedged(sna)) {
617		DBG(("%s: can't convert bo, wedged\n", __FUNCTION__));
618		return NULL;
619	}
620
621	assert_pixmap_damage(pixmap);
622
623	bo = kgem_create_2d(&sna->kgem,
624			    pixmap->drawable.width,
625			    pixmap->drawable.height,
626			    pixmap->drawable.bitsPerPixel,
627			    tiling, 0);
628	if (bo == NULL) {
629		DBG(("%s: allocation failed\n", __FUNCTION__));
630		return NULL;
631	}
632
633	box.x1 = box.y1 = 0;
634	box.x2 = pixmap->drawable.width;
635	box.y2 = pixmap->drawable.height;
636
637	if (!sna->render.copy_boxes(sna, GXcopy,
638				    pixmap, priv->gpu_bo, 0, 0,
639				    pixmap, bo, 0, 0,
640				    &box, 1, 0)) {
641		DBG(("%s: copy failed\n", __FUNCTION__));
642		kgem_bo_destroy(&sna->kgem, bo);
643		return NULL;
644	}
645
646	kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
647
648	if (priv->mapped) {
649		assert(!priv->shm);
650		pixmap->devPrivate.ptr = NULL;
651		priv->mapped = false;
652	}
653
654	return priv->gpu_bo = bo;
655}
656
657static inline void sna_set_pixmap(PixmapPtr pixmap, struct sna_pixmap *sna)
658{
659	((void **)__get_private(pixmap, sna_pixmap_key))[1] = sna;
660	assert(sna_pixmap(pixmap) == sna);
661}
662
663static struct sna_pixmap *
664_sna_pixmap_init(struct sna_pixmap *priv, PixmapPtr pixmap)
665{
666	list_init(&priv->flush_list);
667	priv->source_count = SOURCE_BIAS;
668	priv->pixmap = pixmap;
669
670	return priv;
671}
672
673static struct sna_pixmap *
674_sna_pixmap_reset(PixmapPtr pixmap)
675{
676	struct sna_pixmap *priv;
677
678	assert(pixmap->drawable.type == DRAWABLE_PIXMAP);
679	assert(pixmap->drawable.class == 0);
680	assert(pixmap->drawable.x == 0);
681	assert(pixmap->drawable.y == 0);
682
683	priv = sna_pixmap(pixmap);
684	assert(priv != NULL);
685
686	memset(priv, 0, sizeof(*priv));
687	return _sna_pixmap_init(priv, pixmap);
688}
689
690static struct sna_pixmap *sna_pixmap_attach(PixmapPtr pixmap)
691{
692	struct sna_pixmap *priv;
693
694	priv = calloc(1, sizeof(*priv));
695	if (!priv)
696		return NULL;
697
698	sna_set_pixmap(pixmap, priv);
699	return _sna_pixmap_init(priv, pixmap);
700}
701
702bool sna_pixmap_attach_to_bo(PixmapPtr pixmap, struct kgem_bo *bo)
703{
704	struct sna_pixmap *priv;
705
706	assert(bo);
707
708	priv = sna_pixmap_attach(pixmap);
709	if (!priv)
710		return false;
711
712	priv->gpu_bo = kgem_bo_reference(bo);
713	assert(priv->gpu_bo->proxy == NULL);
714	sna_damage_all(&priv->gpu_damage,
715		       pixmap->drawable.width,
716		       pixmap->drawable.height);
717
718	return true;
719}
720
721static int bits_per_pixel(int depth)
722{
723	switch (depth) {
724	case 1: return 1;
725	case 4:
726	case 8: return 8;
727	case 15:
728	case 16: return 16;
729	case 24:
730	case 30:
731	case 32: return 32;
732	default: return 0;
733	}
734}
735static PixmapPtr
736create_pixmap(struct sna *sna, ScreenPtr screen,
737	      int width, int height, int depth,
738	      unsigned usage_hint)
739{
740	PixmapPtr pixmap;
741	size_t datasize;
742	size_t stride;
743	int base, bpp;
744
745	bpp = bits_per_pixel(depth);
746	if (bpp == 0)
747		return NullPixmap;
748
749	stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
750	if (stride / 4 > 32767 || height > 32767)
751		return NullPixmap;
752
753	datasize = height * stride;
754	base = screen->totalPixmapSize;
755	if (datasize && base & 15) {
756		int adjust = 16 - (base & 15);
757		base += adjust;
758		datasize += adjust;
759	}
760
761	DBG(("%s: allocating pixmap %dx%d, depth=%d, size=%ld\n",
762	     __FUNCTION__, width, height, depth, (long)datasize));
763	pixmap = AllocatePixmap(screen, datasize);
764	if (!pixmap)
765		return NullPixmap;
766
767	((void **)__get_private(pixmap, sna_pixmap_key))[0] = sna;
768	assert(to_sna_from_pixmap(pixmap) == sna);
769
770	pixmap->drawable.type = DRAWABLE_PIXMAP;
771	pixmap->drawable.class = 0;
772	pixmap->drawable.pScreen = screen;
773	pixmap->drawable.depth = depth;
774	pixmap->drawable.bitsPerPixel = bpp;
775	pixmap->drawable.id = 0;
776	pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
777	pixmap->drawable.x = 0;
778	pixmap->drawable.y = 0;
779	pixmap->drawable.width = width;
780	pixmap->drawable.height = height;
781	pixmap->devKind = stride;
782	pixmap->refcnt = 1;
783	pixmap->devPrivate.ptr = datasize ? (char *)pixmap + base : NULL;
784
785#ifdef COMPOSITE
786	pixmap->screen_x = 0;
787	pixmap->screen_y = 0;
788#endif
789
790	pixmap->usage_hint = usage_hint;
791#if DEBUG_MEMORY
792	sna->debug_memory.pixmap_allocs++;
793#endif
794
795	DBG(("%s: serial=%ld, usage=%d, %dx%d\n",
796	     __FUNCTION__,
797	     pixmap->drawable.serialNumber,
798	     pixmap->usage_hint,
799	     pixmap->drawable.width,
800	     pixmap->drawable.height));
801
802	return pixmap;
803}
804
805static PixmapPtr
806sna_pixmap_create_shm(ScreenPtr screen,
807		      int width, int height, int depth,
808		      char *addr)
809{
810	struct sna *sna = to_sna_from_screen(screen);
811	int bpp = bits_per_pixel(depth);
812	int pitch = PixmapBytePad(width, depth);
813	struct sna_pixmap *priv;
814	PixmapPtr pixmap;
815
816	DBG(("%s(%dx%d, depth=%d, bpp=%d, pitch=%d)\n",
817	     __FUNCTION__, width, height, depth, bpp, pitch));
818
819	if (wedged(sna) || bpp == 0 || pitch*height < 4096) {
820fallback:
821		pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth);
822		if (pixmap == NULL)
823			return NULL;
824
825		if (!screen->ModifyPixmapHeader(pixmap, width, height, depth,
826						bpp, pitch, addr)) {
827			screen->DestroyPixmap(pixmap);
828			return NULL;
829		}
830
831		return pixmap;
832	}
833
834	if (sna->freed_pixmap) {
835		pixmap = sna->freed_pixmap;
836		sna->freed_pixmap = pixmap->devPrivate.ptr;
837
838		pixmap->usage_hint = 0;
839		pixmap->refcnt = 1;
840
841		pixmap->drawable.width = width;
842		pixmap->drawable.height = height;
843		pixmap->drawable.depth = depth;
844		pixmap->drawable.bitsPerPixel = bpp;
845		pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
846
847		DBG(("%s: serial=%ld, %dx%d\n",
848		     __FUNCTION__,
849		     pixmap->drawable.serialNumber,
850		     pixmap->drawable.width,
851		     pixmap->drawable.height));
852
853		priv = _sna_pixmap_reset(pixmap);
854	} else {
855		pixmap = create_pixmap(sna, screen, 0, 0, depth, 0);
856		if (pixmap == NullPixmap)
857			return NullPixmap;
858
859		pixmap->drawable.width = width;
860		pixmap->drawable.height = height;
861		pixmap->drawable.depth = depth;
862		pixmap->drawable.bitsPerPixel = bpp;
863
864		priv = sna_pixmap_attach(pixmap);
865		if (!priv) {
866			FreePixmap(pixmap);
867			return NullPixmap;
868		}
869	}
870
871	priv->cpu_bo = kgem_create_map(&sna->kgem, addr, pitch*height, false);
872	if (priv->cpu_bo == NULL) {
873		priv->header = true;
874		sna_pixmap_destroy(pixmap);
875		goto fallback;
876	}
877	priv->cpu_bo->pitch = pitch;
878	kgem_bo_mark_unreusable(priv->cpu_bo);
879	sna_accel_watch_flush(sna, 1);
880#ifdef DEBUG_MEMORY
881	sna->debug_memory.cpu_bo_allocs++;
882	sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo);
883#endif
884
885	priv->cpu = true;
886	priv->shm = true;
887	priv->stride = pitch;
888	priv->ptr = MAKE_STATIC_PTR(addr);
889	sna_damage_all(&priv->cpu_damage, width, height);
890
891	pixmap->devKind = pitch;
892	pixmap->devPrivate.ptr = addr;
893	return pixmap;
894}
895
896PixmapPtr
897sna_pixmap_create_unattached(ScreenPtr screen,
898			     int width, int height, int depth)
899{
900	return create_pixmap(to_sna_from_screen(screen),
901			     screen, width, height, depth,
902			     CREATE_PIXMAP_USAGE_SCRATCH);
903}
904
905static PixmapPtr
906sna_pixmap_create_scratch(ScreenPtr screen,
907			  int width, int height, int depth,
908			  uint32_t tiling)
909{
910	struct sna *sna = to_sna_from_screen(screen);
911	struct sna_pixmap *priv;
912	PixmapPtr pixmap;
913	int bpp;
914
915	DBG(("%s(%d, %d, %d, tiling=%d)\n", __FUNCTION__,
916	     width, height, depth, tiling));
917
918	bpp = bits_per_pixel(depth);
919	if (tiling == I915_TILING_Y &&
920	    (sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0)
921		tiling = I915_TILING_X;
922
923	if (tiling == I915_TILING_Y &&
924	    (width > sna->render.max_3d_size ||
925	     height > sna->render.max_3d_size))
926		tiling = I915_TILING_X;
927
928	tiling = kgem_choose_tiling(&sna->kgem, tiling, width, height, bpp);
929
930	/* you promise never to access this via the cpu... */
931	if (sna->freed_pixmap) {
932		pixmap = sna->freed_pixmap;
933		sna->freed_pixmap = pixmap->devPrivate.ptr;
934
935		pixmap->usage_hint = CREATE_PIXMAP_USAGE_SCRATCH;
936		pixmap->refcnt = 1;
937
938		pixmap->drawable.width = width;
939		pixmap->drawable.height = height;
940		pixmap->drawable.depth = depth;
941		pixmap->drawable.bitsPerPixel = bpp;
942		pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
943
944		DBG(("%s: serial=%ld, usage=%d, %dx%d\n",
945		     __FUNCTION__,
946		     pixmap->drawable.serialNumber,
947		     pixmap->usage_hint,
948		     pixmap->drawable.width,
949		     pixmap->drawable.height));
950
951		priv = _sna_pixmap_reset(pixmap);
952	} else {
953		pixmap = create_pixmap(sna, screen, 0, 0, depth,
954				       CREATE_PIXMAP_USAGE_SCRATCH);
955		if (pixmap == NullPixmap)
956			return NullPixmap;
957
958		pixmap->drawable.width = width;
959		pixmap->drawable.height = height;
960		pixmap->drawable.depth = depth;
961		pixmap->drawable.bitsPerPixel = bpp;
962
963		priv = sna_pixmap_attach(pixmap);
964		if (!priv) {
965			FreePixmap(pixmap);
966			return NullPixmap;
967		}
968	}
969
970	priv->stride = PixmapBytePad(width, depth);
971	pixmap->devPrivate.ptr = NULL;
972
973	priv->gpu_bo = kgem_create_2d(&sna->kgem,
974				      width, height, bpp, tiling,
975				      CREATE_TEMPORARY);
976	if (priv->gpu_bo == NULL) {
977		free(priv);
978		FreePixmap(pixmap);
979		return NullPixmap;
980	}
981
982	priv->header = true;
983	sna_damage_all(&priv->gpu_damage, width, height);
984
985	assert(to_sna_from_pixmap(pixmap) == sna);
986	assert(pixmap->drawable.pScreen == screen);
987
988	return pixmap;
989}
990
991#ifdef CREATE_PIXMAP_USAGE_SHARED
992static Bool
993sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle)
994{
995	struct sna *sna = to_sna_from_pixmap(pixmap);
996	struct sna_pixmap *priv;
997	int fd;
998
999	DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
1000
1001	priv = sna_pixmap_move_to_gpu(pixmap,
1002				      MOVE_READ | MOVE_WRITE | __MOVE_DRI | __MOVE_FORCE);
1003	if (priv == NULL)
1004		return FALSE;
1005
1006	assert(!priv->shm);
1007	assert(priv->gpu_bo);
1008	assert(priv->stride);
1009
1010	/* XXX negotiate format and stride restrictions */
1011	if (priv->gpu_bo->tiling != I915_TILING_NONE ||
1012	    priv->gpu_bo->pitch & 255) {
1013		struct kgem_bo *bo;
1014		BoxRec box;
1015
1016		DBG(("%s: removing tiling %d, and aligning pitch  for %dx%d pixmap=%ld\n",
1017		     __FUNCTION__, priv->gpu_bo->tiling,
1018		     pixmap->drawable.width, pixmap->drawable.height,
1019		     pixmap->drawable.serialNumber));
1020
1021		if (priv->pinned & ~(PIN_DRI | PIN_PRIME)) {
1022			DBG(("%s: can't convert pinned bo\n", __FUNCTION__));
1023			return FALSE;
1024		}
1025
1026		assert_pixmap_damage(pixmap);
1027
1028		bo = kgem_create_2d(&sna->kgem,
1029				    pixmap->drawable.width,
1030				    pixmap->drawable.height,
1031				    pixmap->drawable.bitsPerPixel,
1032				    I915_TILING_NONE,
1033				    CREATE_GTT_MAP | CREATE_PRIME);
1034		if (bo == NULL) {
1035			DBG(("%s: allocation failed\n", __FUNCTION__));
1036			return FALSE;
1037		}
1038
1039		box.x1 = box.y1 = 0;
1040		box.x2 = pixmap->drawable.width;
1041		box.y2 = pixmap->drawable.height;
1042
1043		assert(!wedged(sna)); /* XXX */
1044		if (!sna->render.copy_boxes(sna, GXcopy,
1045					    pixmap, priv->gpu_bo, 0, 0,
1046					    pixmap, bo, 0, 0,
1047					    &box, 1, 0)) {
1048			DBG(("%s: copy failed\n", __FUNCTION__));
1049			kgem_bo_destroy(&sna->kgem, bo);
1050			return FALSE;
1051		}
1052
1053		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1054		priv->gpu_bo = bo;
1055
1056		if (priv->mapped) {
1057			pixmap->devPrivate.ptr = NULL;
1058			priv->mapped = false;
1059		}
1060	}
1061	assert(priv->gpu_bo->tiling == I915_TILING_NONE);
1062	assert((priv->gpu_bo->pitch & 255) == 0);
1063
1064	/* And export the bo->pitch via pixmap->devKind */
1065	pixmap->devPrivate.ptr = kgem_bo_map__async(&sna->kgem, priv->gpu_bo);
1066	if (pixmap->devPrivate.ptr == NULL)
1067		return FALSE;
1068
1069	pixmap->devKind = priv->gpu_bo->pitch;
1070	priv->mapped = true;
1071
1072	fd = kgem_bo_export_to_prime(&sna->kgem, priv->gpu_bo);
1073	if (fd == -1)
1074		return FALSE;
1075
1076	priv->pinned |= PIN_PRIME;
1077
1078	*fd_handle = (void *)(intptr_t)fd;
1079	return TRUE;
1080}
1081
1082static Bool
1083sna_set_shared_pixmap_backing(PixmapPtr pixmap, void *fd_handle)
1084{
1085	struct sna *sna = to_sna_from_pixmap(pixmap);
1086	struct sna_pixmap *priv;
1087	struct kgem_bo *bo;
1088
1089	DBG(("%s: pixmap=%ld, size=%dx%d, depth=%d/%d, stride=%d\n",
1090	     __FUNCTION__, pixmap->drawable.serialNumber,
1091	     pixmap->drawable.width, pixmap->drawable.height,
1092	     pixmap->drawable.depth, pixmap->drawable.bitsPerPixel,
1093	     pixmap->devKind));
1094
1095	priv = sna_pixmap(pixmap);
1096	if (priv == NULL)
1097		return FALSE;
1098
1099	assert(!priv->pinned);
1100	assert(priv->gpu_bo == NULL);
1101	assert(priv->cpu_bo == NULL);
1102	assert(priv->cpu_damage == NULL);
1103	assert(priv->gpu_damage == NULL);
1104
1105	bo = kgem_create_for_prime(&sna->kgem,
1106				   (intptr_t)fd_handle,
1107				   pixmap->devKind * pixmap->drawable.height);
1108	if (bo == NULL)
1109		return FALSE;
1110
1111	sna_damage_all(&priv->gpu_damage,
1112		       pixmap->drawable.width,
1113		       pixmap->drawable.height);
1114
1115	bo->pitch = pixmap->devKind;
1116	priv->stride = pixmap->devKind;
1117
1118	priv->gpu_bo = bo;
1119	priv->pinned |= PIN_PRIME;
1120
1121	close((intptr_t)fd_handle);
1122	return TRUE;
1123}
1124
1125static PixmapPtr
1126sna_create_pixmap_shared(struct sna *sna, ScreenPtr screen,
1127			 int width, int height, int depth)
1128{
1129	PixmapPtr pixmap;
1130	struct sna_pixmap *priv;
1131
1132	DBG(("%s: depth=%d\n", __FUNCTION__, depth));
1133
1134	/* Create a stub to be attached later */
1135	pixmap = create_pixmap(sna, screen, 0, 0, depth, 0);
1136	if (pixmap == NullPixmap)
1137		return NullPixmap;
1138
1139	pixmap->devKind = 0;
1140	pixmap->devPrivate.ptr = NULL;
1141
1142	priv = sna_pixmap_attach(pixmap);
1143	if (priv == NULL) {
1144		free(pixmap);
1145		return NullPixmap;
1146	}
1147
1148	priv->stride = 0;
1149	priv->create = 0;
1150
1151	if (width|height) {
1152		int bpp = bits_per_pixel(depth);
1153
1154		priv->gpu_bo = kgem_create_2d(&sna->kgem,
1155					      width, height, bpp,
1156					      I915_TILING_NONE,
1157					      CREATE_GTT_MAP | CREATE_PRIME);
1158		if (priv->gpu_bo == NULL) {
1159			free(priv);
1160			FreePixmap(pixmap);
1161			return NullPixmap;
1162		}
1163
1164		/* minimal interface for sharing is linear, 256 byte pitch */
1165		assert(priv->gpu_bo->tiling == I915_TILING_NONE);
1166		assert((priv->gpu_bo->pitch & 255) == 0);
1167
1168		assert(!priv->mapped);
1169		pixmap->devPrivate.ptr =
1170			kgem_bo_map__async(&sna->kgem, priv->gpu_bo);
1171		if (pixmap->devPrivate.ptr == NULL) {
1172			free(priv);
1173			FreePixmap(pixmap);
1174			return FALSE;
1175		}
1176
1177		pixmap->devKind = priv->gpu_bo->pitch;
1178		pixmap->drawable.width = width;
1179		pixmap->drawable.height = height;
1180
1181		priv->stride = priv->gpu_bo->pitch;
1182		priv->mapped = true;
1183
1184		sna_damage_all(&priv->gpu_damage, width, height);
1185	}
1186
1187	return pixmap;
1188}
1189#endif
1190
1191static PixmapPtr sna_create_pixmap(ScreenPtr screen,
1192				   int width, int height, int depth,
1193				   unsigned int usage)
1194{
1195	struct sna *sna = to_sna_from_screen(screen);
1196	PixmapPtr pixmap;
1197	struct sna_pixmap *priv;
1198	unsigned flags;
1199	int pad;
1200	void *ptr;
1201
1202	DBG(("%s(%d, %d, %d, usage=%x)\n", __FUNCTION__,
1203	     width, height, depth, usage));
1204
1205#ifdef CREATE_PIXMAP_USAGE_SHARED
1206	if (usage == CREATE_PIXMAP_USAGE_SHARED)
1207		return sna_create_pixmap_shared(sna, screen,
1208						width, height, depth);
1209#endif
1210
1211	if ((width|height) == 0) {
1212		usage = -1;
1213		goto fallback;
1214	}
1215	assert(width && height);
1216
1217	flags = kgem_can_create_2d(&sna->kgem, width, height, depth);
1218	if (flags == 0) {
1219		DBG(("%s: can not use GPU, just creating shadow\n",
1220		     __FUNCTION__));
1221		goto fallback;
1222	}
1223
1224	if (unlikely((sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0))
1225		flags &= ~KGEM_CAN_CREATE_GPU;
1226	if (wedged(sna))
1227		flags &= ~KGEM_CAN_CREATE_GTT;
1228
1229	switch (usage) {
1230	case CREATE_PIXMAP_USAGE_SCRATCH:
1231		if (flags & KGEM_CAN_CREATE_GPU)
1232			return sna_pixmap_create_scratch(screen,
1233							 width, height, depth,
1234							 I915_TILING_X);
1235		else
1236			goto fallback;
1237
1238	case SNA_CREATE_GLYPHS:
1239		if (flags & KGEM_CAN_CREATE_GPU)
1240			return sna_pixmap_create_scratch(screen,
1241							 width, height, depth,
1242							 -I915_TILING_Y);
1243		else
1244			goto fallback;
1245
1246	case SNA_CREATE_SCRATCH:
1247		if (flags & KGEM_CAN_CREATE_GPU)
1248			return sna_pixmap_create_scratch(screen,
1249							 width, height, depth,
1250							 I915_TILING_Y);
1251		else
1252			goto fallback;
1253	}
1254
1255	if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE)
1256		flags &= ~KGEM_CAN_CREATE_GPU;
1257	if (usage == CREATE_PIXMAP_USAGE_BACKING_PIXMAP)
1258		usage = 0;
1259
1260	pad = PixmapBytePad(width, depth);
1261	if (pad * height < 4096) {
1262		DBG(("%s: small buffer [%d], attaching to shadow pixmap\n",
1263		     __FUNCTION__, pad * height));
1264		pixmap = create_pixmap(sna, screen,
1265				       width, height, depth, usage);
1266		if (pixmap == NullPixmap)
1267			return NullPixmap;
1268
1269		ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr);
1270		pad = pixmap->devKind;
1271		flags &= ~(KGEM_CAN_CREATE_GPU | KGEM_CAN_CREATE_CPU);
1272	} else {
1273		DBG(("%s: creating GPU pixmap %dx%d, stride=%d, flags=%x\n",
1274		     __FUNCTION__, width, height, pad, flags));
1275
1276		pixmap = create_pixmap(sna, screen, 0, 0, depth, usage);
1277		if (pixmap == NullPixmap)
1278			return NullPixmap;
1279
1280		pixmap->drawable.width = width;
1281		pixmap->drawable.height = height;
1282		pixmap->devKind = pad;
1283		pixmap->devPrivate.ptr = NULL;
1284
1285		ptr = NULL;
1286	}
1287
1288	priv = sna_pixmap_attach(pixmap);
1289	if (priv == NULL) {
1290		free(pixmap);
1291		goto fallback;
1292	}
1293
1294	priv->stride = pad;
1295	priv->create = flags;
1296	priv->ptr = ptr;
1297
1298	assert(to_sna_from_pixmap(pixmap) == sna);
1299	assert(pixmap->drawable.pScreen == screen);
1300
1301	return pixmap;
1302
1303fallback:
1304	return create_pixmap(sna, screen, width, height, depth, usage);
1305}
1306
1307void sna_add_flush_pixmap(struct sna *sna,
1308			  struct sna_pixmap *priv,
1309			  struct kgem_bo *bo)
1310{
1311	DBG(("%s: marking pixmap=%ld for flushing\n",
1312	     __FUNCTION__, priv->pixmap->drawable.serialNumber));
1313	assert(bo);
1314	assert(bo->flush);
1315	assert(priv->gpu_damage == NULL || priv->gpu_bo);
1316	list_move(&priv->flush_list, &sna->flush_pixmaps);
1317
1318	if (bo->exec == NULL && kgem_is_idle(&sna->kgem)) {
1319		DBG(("%s: new flush bo, flushin before\n", __FUNCTION__));
1320		kgem_submit(&sna->kgem);
1321	}
1322}
1323
1324static void __sna_free_pixmap(struct sna *sna,
1325			      PixmapPtr pixmap,
1326			      struct sna_pixmap *priv)
1327{
1328	list_del(&priv->flush_list);
1329
1330	assert(priv->gpu_damage == NULL);
1331	assert(priv->cpu_damage == NULL);
1332
1333	__sna_pixmap_free_cpu(sna, priv);
1334
1335	if (priv->header) {
1336		assert(!priv->shm);
1337		assert(pixmap->drawable.pScreen == sna->scrn->pScreen);
1338		pixmap->devPrivate.ptr = sna->freed_pixmap;
1339		sna->freed_pixmap = pixmap;
1340	} else {
1341		free(priv);
1342		FreePixmap(pixmap);
1343	}
1344}
1345
1346static Bool sna_destroy_pixmap(PixmapPtr pixmap)
1347{
1348	struct sna *sna;
1349	struct sna_pixmap *priv;
1350
1351	if (--pixmap->refcnt)
1352		return TRUE;
1353
1354#if DEBUG_MEMORY
1355	to_sna_from_pixmap(pixmap)->debug_memory.pixmap_allocs--;
1356#endif
1357
1358	priv = sna_pixmap(pixmap);
1359	DBG(("%s: pixmap=%ld, attached?=%d\n",
1360	     __FUNCTION__, pixmap->drawable.serialNumber, priv != NULL));
1361	if (priv == NULL) {
1362		FreePixmap(pixmap);
1363		return TRUE;
1364	}
1365
1366	assert_pixmap_damage(pixmap);
1367	sna = to_sna_from_pixmap(pixmap);
1368
1369	sna_damage_destroy(&priv->gpu_damage);
1370	sna_damage_destroy(&priv->cpu_damage);
1371
1372	if (priv->cow) {
1373		struct sna_cow *cow = COW(priv->cow);
1374		DBG(("%s: pixmap=%ld discarding cow, refcnt=%d\n",
1375		     __FUNCTION__, pixmap->drawable.serialNumber, cow->refcnt));
1376		assert(cow->refcnt);
1377		list_del(&priv->cow_list);
1378		if (!--cow->refcnt)
1379			free(cow);
1380		priv->cow = NULL;
1381	}
1382
1383	/* Always release the gpu bo back to the lower levels of caching */
1384	if (priv->gpu_bo) {
1385		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1386		priv->gpu_bo = NULL;
1387	}
1388
1389	if (priv->shm && kgem_bo_is_busy(priv->cpu_bo)) {
1390		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
1391		kgem_bo_submit(&sna->kgem, priv->cpu_bo); /* XXX ShmDetach */
1392	} else
1393		__sna_free_pixmap(sna, pixmap, priv);
1394	return TRUE;
1395}
1396
1397void sna_pixmap_destroy(PixmapPtr pixmap)
1398{
1399	assert(pixmap->refcnt == 1);
1400	assert(sna_pixmap(pixmap) == NULL || sna_pixmap(pixmap)->header == true);
1401
1402	sna_destroy_pixmap(pixmap);
1403}
1404
1405static inline bool has_coherent_map(struct sna *sna,
1406				    struct kgem_bo *bo,
1407				    unsigned flags)
1408{
1409	assert(bo);
1410	assert(bo->map);
1411
1412	if (!IS_CPU_MAP(bo->map))
1413		return true;
1414
1415	if (bo->tiling == I915_TILING_Y)
1416		return false;
1417
1418	return kgem_bo_can_map__cpu(&sna->kgem, bo, flags & MOVE_WRITE);
1419}
1420
1421static inline bool has_coherent_ptr(struct sna_pixmap *priv)
1422{
1423	if (priv == NULL)
1424		return true;
1425
1426	if (!priv->mapped) {
1427		if (!priv->cpu_bo)
1428			return true;
1429
1430		return priv->pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map);
1431	}
1432
1433	if (priv->cpu && !IS_CPU_MAP(priv->gpu_bo->map))
1434		return false;
1435
1436	return priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map);
1437}
1438
1439static inline bool pixmap_inplace(struct sna *sna,
1440				  PixmapPtr pixmap,
1441				  struct sna_pixmap *priv,
1442				  unsigned flags)
1443{
1444	if (FORCE_INPLACE)
1445		return FORCE_INPLACE > 0;
1446
1447	if (wedged(sna) && !priv->pinned)
1448		return false;
1449
1450	if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) {
1451		if ((flags & (MOVE_WRITE | MOVE_READ)) == (MOVE_WRITE | MOVE_READ))
1452			return false;
1453
1454		if ((flags & MOVE_READ) == 0)
1455			return !priv->pinned;
1456	}
1457
1458	if (priv->mapped)
1459		return has_coherent_map(sna, priv->gpu_bo, flags);
1460
1461	if (flags & MOVE_READ &&
1462	    (priv->cpu || priv->cpu_damage || priv->gpu_damage == NULL))
1463		return false;
1464
1465	return (pixmap->devKind * pixmap->drawable.height >> 12) >
1466		sna->kgem.half_cpu_cache_pages;
1467}
1468
1469static bool
1470sna_pixmap_create_mappable_gpu(PixmapPtr pixmap,
1471			       bool can_replace)
1472{
1473	struct sna *sna = to_sna_from_pixmap(pixmap);
1474	struct sna_pixmap *priv = sna_pixmap(pixmap);
1475	unsigned create;
1476
1477	if (wedged(sna))
1478		goto done;
1479
1480	if ((priv->create & KGEM_CAN_CREATE_GTT) == 0)
1481		goto done;
1482
1483	assert_pixmap_damage(pixmap);
1484
1485	if (can_replace && priv->gpu_bo &&
1486	    (!kgem_bo_is_mappable(&sna->kgem, priv->gpu_bo) ||
1487	     __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) {
1488		if (priv->pinned)
1489			goto done;
1490
1491		DBG(("%s: discard busy GPU bo\n", __FUNCTION__));
1492		sna_pixmap_free_gpu(sna, priv);
1493	}
1494
1495	if (priv->gpu_bo)
1496		return kgem_bo_is_mappable(&sna->kgem, priv->gpu_bo);
1497
1498	assert_pixmap_damage(pixmap);
1499
1500	assert(priv->gpu_damage == NULL);
1501	assert(priv->gpu_bo == NULL);
1502
1503	create = CREATE_GTT_MAP | CREATE_INACTIVE;
1504	if (pixmap->usage_hint == SNA_CREATE_FB)
1505		create |= CREATE_SCANOUT;
1506
1507	priv->gpu_bo =
1508		kgem_create_2d(&sna->kgem,
1509			       pixmap->drawable.width,
1510			       pixmap->drawable.height,
1511			       pixmap->drawable.bitsPerPixel,
1512			       sna_pixmap_choose_tiling(pixmap, DEFAULT_TILING),
1513			       create);
1514
1515done:
1516	return priv->gpu_bo && kgem_bo_is_mappable(&sna->kgem, priv->gpu_bo);
1517}
1518
1519static inline bool use_cpu_bo_for_download(struct sna *sna,
1520					   struct sna_pixmap *priv,
1521					   int nbox, const BoxRec *box)
1522{
1523	if (DBG_NO_CPU_DOWNLOAD)
1524		return false;
1525
1526	if (wedged(sna))
1527		return false;
1528
1529	if (priv->cpu_bo == NULL || !sna->kgem.can_blt_cpu)
1530		return false;
1531
1532	if (kgem_bo_is_busy(priv->gpu_bo) || kgem_bo_is_busy(priv->cpu_bo)) {
1533		DBG(("%s: yes, either bo is busy, so use GPU for readback\n",
1534		     __FUNCTION__));
1535		return true;
1536	}
1537
1538	/* Is it worth detiling? */
1539	assert(box[0].y1 < box[nbox-1].y2);
1540	if (kgem_bo_is_mappable(&sna->kgem, priv->gpu_bo) &&
1541	    (box[nbox-1].y2 - box[0].y1 - 1) * priv->gpu_bo->pitch < 4096) {
1542		DBG(("%s: no, tiny transfer (height=%d, pitch=%d) expect to read inplace\n",
1543		     __FUNCTION__, box[nbox-1].y2-box[0].y1, priv->gpu_bo->pitch));
1544		return false;
1545	}
1546
1547	DBG(("%s: yes, default action\n", __FUNCTION__));
1548	return true;
1549}
1550
1551static inline bool use_cpu_bo_for_upload(struct sna *sna,
1552					 struct sna_pixmap *priv,
1553					 unsigned flags)
1554{
1555	if (DBG_NO_CPU_UPLOAD)
1556		return false;
1557
1558	if (wedged(sna))
1559		return false;
1560
1561	if (priv->cpu_bo == NULL)
1562		return false;
1563
1564	DBG(("%s? flags=%x, gpu busy?=%d, cpu busy?=%d\n", __FUNCTION__,
1565	     flags,
1566	     kgem_bo_is_busy(priv->gpu_bo),
1567	     kgem_bo_is_busy(priv->cpu_bo)));
1568
1569	if (!priv->cpu)
1570		return true;
1571
1572	if (flags & (MOVE_WRITE | MOVE_ASYNC_HINT))
1573		return true;
1574
1575	if (priv->gpu_bo->tiling)
1576		return true;
1577
1578	return kgem_bo_is_busy(priv->gpu_bo) || kgem_bo_is_busy(priv->cpu_bo);
1579}
1580
1581bool
1582sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags)
1583{
1584	struct sna_cow *cow = COW(priv->cow);
1585
1586	DBG(("%s: pixmap=%ld, handle=%d, flags=%x\n",
1587	     __FUNCTION__,
1588	     priv->pixmap->drawable.serialNumber,
1589	     priv->gpu_bo->handle,
1590	     flags));
1591
1592	assert(priv->gpu_bo == cow->bo);
1593	assert(cow->refcnt);
1594
1595	list_del(&priv->cow_list);
1596
1597	if (!--cow->refcnt) {
1598		assert(list_is_empty(&cow->list));
1599		free(cow);
1600	} else if (IS_COW_OWNER(priv->cow) && priv->pinned) {
1601		PixmapPtr pixmap = priv->pixmap;
1602		struct kgem_bo *bo;
1603		BoxRec box;
1604
1605		DBG(("%s: copying the Holy cow\n", __FUNCTION__));
1606
1607		box.x1 = box.y1 = 0;
1608		box.x2 = pixmap->drawable.width;
1609		box.y2 = pixmap->drawable.height;
1610
1611		bo = kgem_create_2d(&sna->kgem,
1612				    box.x2, box.y2,
1613				    pixmap->drawable.bitsPerPixel,
1614				    sna_pixmap_choose_tiling(pixmap, DEFAULT_TILING),
1615				    0);
1616		if (bo == NULL) {
1617			cow->refcnt++;
1618			DBG(("%s: allocation failed\n", __FUNCTION__));
1619			return false;
1620		}
1621
1622		if (!sna->render.copy_boxes(sna, GXcopy,
1623					    pixmap, priv->gpu_bo, 0, 0,
1624					    pixmap, bo, 0, 0,
1625					    &box, 1, 0)) {
1626			DBG(("%s: copy failed\n", __FUNCTION__));
1627			kgem_bo_destroy(&sna->kgem, bo);
1628			cow->refcnt++;
1629			return false;
1630		}
1631
1632		assert(!list_is_empty(&cow->list));
1633		while (!list_is_empty(&cow->list)) {
1634			struct sna_pixmap *clone;
1635
1636			clone = list_first_entry(&cow->list,
1637						 struct sna_pixmap, cow_list);
1638			list_del(&clone->cow_list);
1639
1640			assert(clone->gpu_bo == cow->bo);
1641			kgem_bo_destroy(&sna->kgem, clone->gpu_bo);
1642			clone->gpu_bo = kgem_bo_reference(bo);
1643		}
1644		cow->bo = bo;
1645		kgem_bo_destroy(&sna->kgem, bo);
1646	} else {
1647		struct kgem_bo *bo = NULL;
1648
1649		if (flags & MOVE_READ) {
1650			PixmapPtr pixmap = priv->pixmap;
1651			BoxRec box;
1652
1653			DBG(("%s: copying cow\n", __FUNCTION__));
1654
1655			box.x1 = box.y1 = 0;
1656			box.x2 = pixmap->drawable.width;
1657			box.y2 = pixmap->drawable.height;
1658
1659			bo = kgem_create_2d(&sna->kgem,
1660					    box.x2, box.y2,
1661					    pixmap->drawable.bitsPerPixel,
1662					    sna_pixmap_choose_tiling(pixmap, DEFAULT_TILING),
1663					    0);
1664			if (bo == NULL) {
1665				cow->refcnt++;
1666				DBG(("%s: allocation failed\n", __FUNCTION__));
1667				return false;
1668			}
1669
1670			if (!sna->render.copy_boxes(sna, GXcopy,
1671						    pixmap, priv->gpu_bo, 0, 0,
1672						    pixmap, bo, 0, 0,
1673						    &box, 1, 0)) {
1674				DBG(("%s: copy failed\n", __FUNCTION__));
1675				kgem_bo_destroy(&sna->kgem, bo);
1676				cow->refcnt++;
1677				return false;
1678			}
1679		}
1680
1681		assert(priv->gpu_bo);
1682		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
1683		priv->gpu_bo = bo;
1684		if (priv->gpu_bo == NULL && priv->mapped) {
1685			priv->pixmap->devPrivate.ptr = NULL;
1686			priv->mapped = false;
1687		}
1688	}
1689
1690	priv->cow = NULL;
1691	return true;
1692}
1693
1694static bool
1695sna_pixmap_make_cow(struct sna *sna,
1696		    struct sna_pixmap *src_priv,
1697		    struct sna_pixmap *dst_priv)
1698{
1699	struct sna_cow *cow;
1700
1701	assert(src_priv->gpu_bo);
1702
1703	if (!USE_COW)
1704		return false;
1705
1706	if (src_priv->gpu_bo->proxy)
1707		return false;
1708
1709	DBG(("%s: make cow src=%ld, dst=%ld, handle=%d (already cow? src=%d, dst=%d)\n",
1710	     __FUNCTION__,
1711	     src_priv->pixmap->drawable.serialNumber,
1712	     dst_priv->pixmap->drawable.serialNumber,
1713	     src_priv->gpu_bo->handle,
1714	     src_priv->cow ? IS_COW_OWNER(src_priv->cow) ? 1 : -1 : 0,
1715	     dst_priv->cow ? IS_COW_OWNER(dst_priv->cow) ? 1 : -1 : 0));
1716
1717	if (dst_priv->pinned) {
1718		DBG(("%s: can't cow, dst_pinned=%x\n",
1719		     __FUNCTION__, dst_priv->pinned));
1720		return false;
1721	}
1722
1723	assert(!dst_priv->flush);
1724
1725	cow = COW(src_priv->cow);
1726	if (cow == NULL) {
1727		cow = malloc(sizeof(*cow));
1728		if (cow == NULL)
1729			return false;
1730
1731		list_init(&cow->list);
1732
1733		cow->bo = src_priv->gpu_bo;
1734		cow->refcnt = 1;
1735
1736		DBG(("%s: moo! attaching source cow to pixmap=%ld, handle=%d\n",
1737		     __FUNCTION__,
1738		     src_priv->pixmap->drawable.serialNumber,
1739		     cow->bo->handle));
1740
1741		src_priv->cow = MAKE_COW_OWNER(cow);
1742		list_init(&src_priv->cow_list);
1743	}
1744
1745	if (cow == COW(dst_priv->cow)) {
1746		assert(dst_priv->gpu_bo == cow->bo);
1747		return true;
1748	}
1749
1750	if (dst_priv->cow)
1751		sna_pixmap_undo_cow(sna, dst_priv, 0);
1752
1753	if (dst_priv->gpu_bo)
1754		kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo);
1755	dst_priv->gpu_bo = kgem_bo_reference(cow->bo);
1756	dst_priv->cow = cow;
1757	list_add(&dst_priv->cow_list, &cow->list);
1758	cow->refcnt++;
1759
1760	DBG(("%s: moo! attaching clone to pixmap=%ld (source=%ld, handle=%d)\n",
1761	     __FUNCTION__,
1762	     dst_priv->pixmap->drawable.serialNumber,
1763	     src_priv->pixmap->drawable.serialNumber,
1764	     cow->bo->handle));
1765
1766	if (dst_priv->mapped) {
1767		dst_priv->pixmap->devPrivate.ptr = NULL;
1768		dst_priv->mapped = false;
1769	}
1770
1771	return true;
1772}
1773
1774static inline bool operate_inplace(struct sna_pixmap *priv, unsigned flags)
1775{
1776	if ((flags & MOVE_INPLACE_HINT) == 0) {
1777		DBG(("%s: no, inplace operation not suitable\n", __FUNCTION__));
1778		return false;
1779	}
1780
1781	assert((flags & MOVE_ASYNC_HINT) == 0);
1782
1783	if (priv->cow && flags & MOVE_WRITE) {
1784		DBG(("%s: no, has COW\n", __FUNCTION__));
1785		return false;
1786	}
1787
1788	if ((priv->create & KGEM_CAN_CREATE_GTT) == 0) {
1789		DBG(("%s: no, not accessible via GTT\n", __FUNCTION__));
1790		return false;
1791	}
1792
1793	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) {
1794		DBG(("%s: yes, CPU is busy\n", __FUNCTION__));
1795		return true;
1796	}
1797
1798	if (priv->create & KGEM_CAN_CREATE_LARGE) {
1799		DBG(("%s: large object, has GPU? %d\n",
1800		     __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0));
1801		return priv->gpu_bo != NULL;
1802	}
1803
1804	if (flags & MOVE_WRITE && priv->gpu_bo&&kgem_bo_is_busy(priv->gpu_bo)) {
1805		DBG(("%s: no, GPU is busy, so stage write\n", __FUNCTION__));
1806		return false;
1807	}
1808
1809	return true;
1810}
1811
1812bool
1813_sna_pixmap_move_to_cpu(PixmapPtr pixmap, unsigned int flags)
1814{
1815	struct sna *sna = to_sna_from_pixmap(pixmap);
1816	struct sna_pixmap *priv;
1817
1818	DBG(("%s(pixmap=%ld, %dx%d, flags=%x)\n", __FUNCTION__,
1819	     pixmap->drawable.serialNumber,
1820	     pixmap->drawable.width,
1821	     pixmap->drawable.height,
1822	     flags));
1823
1824	assert(flags & (MOVE_READ | MOVE_WRITE));
1825	assert_pixmap_damage(pixmap);
1826
1827	priv = sna_pixmap(pixmap);
1828	if (priv == NULL) {
1829		DBG(("%s: not attached\n", __FUNCTION__));
1830		return true;
1831	}
1832
1833	DBG(("%s: gpu_bo=%d, gpu_damage=%p, cpu_damage=%p, is-clear?=%d\n",
1834	     __FUNCTION__,
1835	     priv->gpu_bo ? priv->gpu_bo->handle : 0,
1836	     priv->gpu_damage, priv->cpu_damage, priv->clear));
1837
1838	assert(priv->gpu_damage == NULL || priv->gpu_bo);
1839
1840	if ((flags & MOVE_READ) == 0 && UNDO) {
1841		if (priv->gpu_bo)
1842			kgem_bo_undo(&sna->kgem, priv->gpu_bo);
1843		if (priv->cpu_bo)
1844			kgem_bo_undo(&sna->kgem, priv->cpu_bo);
1845	}
1846
1847	if (USE_INPLACE && (flags & MOVE_READ) == 0 && !priv->cow) {
1848		assert(flags & MOVE_WRITE);
1849		DBG(("%s: no readbck, discarding gpu damage [%d], pending clear[%d]\n",
1850		     __FUNCTION__, priv->gpu_damage != NULL, priv->clear));
1851
1852		if ((priv->gpu_bo || priv->create & KGEM_CAN_CREATE_GPU) &&
1853		    pixmap_inplace(sna, pixmap, priv, flags) &&
1854		    sna_pixmap_create_mappable_gpu(pixmap, true)) {
1855			DBG(("%s: write inplace\n", __FUNCTION__));
1856			assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
1857			assert(!priv->shm);
1858			assert(priv->gpu_bo->exec == NULL);
1859			assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL);
1860
1861			pixmap->devPrivate.ptr =
1862				kgem_bo_map(&sna->kgem, priv->gpu_bo);
1863			priv->mapped = pixmap->devPrivate.ptr != NULL;
1864			if (!priv->mapped)
1865				goto skip_inplace_map;
1866
1867			assert(has_coherent_map(sna, priv->gpu_bo, flags));
1868			pixmap->devKind = priv->gpu_bo->pitch;
1869
1870			assert(priv->gpu_bo->proxy == NULL);
1871			sna_damage_all(&priv->gpu_damage,
1872				       pixmap->drawable.width,
1873				       pixmap->drawable.height);
1874			sna_damage_destroy(&priv->cpu_damage);
1875			priv->clear = false;
1876			priv->cpu = false;
1877			list_del(&priv->flush_list);
1878
1879			assert(!priv->shm);
1880			assert(priv->cpu_bo == NULL || !priv->cpu_bo->flush);
1881			sna_pixmap_free_cpu(sna, priv);
1882
1883			assert_pixmap_damage(pixmap);
1884			return true;
1885		}
1886
1887skip_inplace_map:
1888		sna_damage_destroy(&priv->gpu_damage);
1889		priv->clear = false;
1890		if (priv->cpu_bo && !priv->cpu_bo->flush &&
1891		    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
1892			DBG(("%s: discarding busy CPU bo\n", __FUNCTION__));
1893			assert(!priv->shm);
1894			assert(priv->gpu_bo == NULL || priv->gpu_damage == NULL);
1895
1896			sna_damage_destroy(&priv->cpu_damage);
1897			sna_pixmap_free_cpu(sna, priv);
1898
1899			if (!sna_pixmap_alloc_cpu(sna, pixmap, priv, false))
1900				return false;
1901
1902			goto mark_damage;
1903		}
1904	}
1905
1906	if (DAMAGE_IS_ALL(priv->cpu_damage)) {
1907		DBG(("%s: CPU all-damaged\n", __FUNCTION__));
1908		assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage));
1909		goto done;
1910	}
1911
1912	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
1913
1914	if (USE_INPLACE &&
1915	    operate_inplace(priv, flags) &&
1916	    pixmap_inplace(sna, pixmap, priv, flags) &&
1917	    sna_pixmap_create_mappable_gpu(pixmap, (flags & MOVE_READ) == 0)) {
1918		DBG(("%s: try to operate inplace (GTT)\n", __FUNCTION__));
1919		assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
1920		assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL);
1921		/* XXX only sync for writes? */
1922		kgem_bo_submit(&sna->kgem, priv->gpu_bo);
1923		assert(priv->gpu_bo->exec == NULL);
1924
1925		pixmap->devPrivate.ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo);
1926		priv->mapped = pixmap->devPrivate.ptr != NULL;
1927		if (priv->mapped) {
1928			assert(has_coherent_map(sna, priv->gpu_bo, flags));
1929			pixmap->devKind = priv->gpu_bo->pitch;
1930
1931			if (flags & MOVE_WRITE) {
1932				assert(priv->gpu_bo->proxy == NULL);
1933				sna_damage_all(&priv->gpu_damage,
1934					       pixmap->drawable.width,
1935					       pixmap->drawable.height);
1936				sna_damage_destroy(&priv->cpu_damage);
1937				sna_pixmap_free_cpu(sna, priv);
1938				list_del(&priv->flush_list);
1939				priv->clear = false;
1940			}
1941			priv->cpu = false;
1942
1943			assert_pixmap_damage(pixmap);
1944			DBG(("%s: operate inplace (GTT)\n", __FUNCTION__));
1945			return true;
1946		}
1947	}
1948
1949	if (priv->mapped) {
1950		assert(!priv->shm && priv->stride);
1951		pixmap->devPrivate.ptr = PTR(priv->ptr);
1952		pixmap->devKind = priv->stride;
1953		priv->mapped = false;
1954	}
1955
1956	if (USE_INPLACE &&
1957	    priv->gpu_damage && priv->cpu_damage == NULL && !priv->cow &&
1958	    (flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE)) &&
1959	    priv->gpu_bo->tiling == I915_TILING_NONE &&
1960	    ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 ||
1961	     !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) {
1962		DBG(("%s: try to operate inplace (CPU)\n", __FUNCTION__));
1963		assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
1964
1965		assert(!priv->mapped);
1966		pixmap->devPrivate.ptr =
1967			kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
1968		if (pixmap->devPrivate.ptr != NULL) {
1969			priv->cpu = true;
1970			priv->mapped = true;
1971			pixmap->devKind = priv->gpu_bo->pitch;
1972			if (flags & MOVE_WRITE) {
1973				assert(priv->gpu_bo->proxy == NULL);
1974				sna_damage_all(&priv->gpu_damage,
1975					       pixmap->drawable.width,
1976					       pixmap->drawable.height);
1977				sna_damage_destroy(&priv->cpu_damage);
1978				sna_pixmap_free_cpu(sna, priv);
1979				list_del(&priv->flush_list);
1980				priv->clear = false;
1981			}
1982
1983			assert(IS_CPU_MAP(priv->gpu_bo->map));
1984			kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo,
1985					       FORCE_FULL_SYNC || flags & MOVE_WRITE);
1986			assert(pixmap->devPrivate.ptr == (void *)((unsigned long)priv->gpu_bo->map & ~3));
1987			assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo));
1988			assert_pixmap_damage(pixmap);
1989			DBG(("%s: operate inplace (CPU)\n", __FUNCTION__));
1990			return true;
1991		}
1992	}
1993
1994	if (((flags & MOVE_READ) == 0 || priv->clear) &&
1995	    priv->cpu_bo && !priv->cpu_bo->flush &&
1996	    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
1997		assert(!priv->shm);
1998		sna_pixmap_free_cpu(sna, priv);
1999	}
2000
2001	if (pixmap->devPrivate.ptr == NULL &&
2002	    !sna_pixmap_alloc_cpu(sna, pixmap, priv,
2003				  flags & MOVE_READ ? priv->gpu_damage && !priv->clear : 0))
2004		return false;
2005	assert(pixmap->devPrivate.ptr);
2006	assert(!priv->mapped);
2007
2008	if (priv->clear) {
2009		DBG(("%s: applying clear [%08x] size=%dx%d, stride=%d (total=%d)\n",
2010		     __FUNCTION__, priv->clear_color, pixmap->drawable.width, pixmap->drawable.height,
2011		     pixmap->devKind, pixmap->devKind * pixmap->drawable.height));
2012
2013		if (priv->cpu_bo) {
2014			DBG(("%s: syncing CPU bo\n", __FUNCTION__));
2015			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
2016			assert(pixmap->devPrivate.ptr == (void *)((unsigned long)priv->cpu_bo->map & ~3));
2017		}
2018
2019		if (priv->clear_color == 0 ||
2020		    pixmap->drawable.bitsPerPixel == 8 ||
2021		    priv->clear_color == (1 << pixmap->drawable.depth) - 1) {
2022			memset(pixmap->devPrivate.ptr, priv->clear_color,
2023			       pixmap->devKind * pixmap->drawable.height);
2024		} else {
2025			pixman_fill(pixmap->devPrivate.ptr,
2026				    pixmap->devKind/sizeof(uint32_t),
2027				    pixmap->drawable.bitsPerPixel,
2028				    0, 0,
2029				    pixmap->drawable.width,
2030				    pixmap->drawable.height,
2031				    priv->clear_color);
2032		}
2033
2034		sna_damage_all(&priv->cpu_damage,
2035			       pixmap->drawable.width,
2036			       pixmap->drawable.height);
2037		sna_pixmap_free_gpu(sna, priv);
2038		assert(priv->gpu_damage == NULL);
2039		assert(priv->clear == false);
2040	}
2041
2042	if (priv->gpu_damage) {
2043		BoxPtr box;
2044		int n;
2045
2046		DBG(("%s: flushing GPU damage\n", __FUNCTION__));
2047		assert(priv->gpu_bo);
2048
2049		n = sna_damage_get_boxes(priv->gpu_damage, &box);
2050		if (n) {
2051			bool ok = false;
2052
2053			if (use_cpu_bo_for_download(sna, priv, n, box)) {
2054				DBG(("%s: using CPU bo for download from GPU\n", __FUNCTION__));
2055				ok = sna->render.copy_boxes(sna, GXcopy,
2056							    pixmap, priv->gpu_bo, 0, 0,
2057							    pixmap, priv->cpu_bo, 0, 0,
2058							    box, n, COPY_LAST);
2059			}
2060			if (!ok) {
2061				assert(has_coherent_ptr(sna_pixmap(pixmap)));
2062				sna_read_boxes(sna, pixmap, priv->gpu_bo,
2063					       box, n);
2064			}
2065		}
2066
2067		__sna_damage_destroy(DAMAGE_PTR(priv->gpu_damage));
2068		priv->gpu_damage = NULL;
2069	}
2070
2071	if (flags & MOVE_WRITE || priv->create & KGEM_CAN_CREATE_LARGE) {
2072mark_damage:
2073		DBG(("%s: marking as damaged\n", __FUNCTION__));
2074		sna_damage_all(&priv->cpu_damage,
2075			       pixmap->drawable.width,
2076			       pixmap->drawable.height);
2077		assert(priv->gpu_damage == NULL);
2078		sna_pixmap_free_gpu(sna, priv);
2079
2080		if (priv->flush) {
2081			assert(!priv->shm);
2082			sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
2083		}
2084	}
2085
2086done:
2087	if (flags & MOVE_WRITE) {
2088		assert(DAMAGE_IS_ALL(priv->cpu_damage));
2089		assert(priv->gpu_damage == NULL);
2090		assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
2091		if (priv->cow)
2092			sna_pixmap_undo_cow(sna, priv, 0);
2093		if (priv->gpu_bo && priv->gpu_bo->rq == NULL) {
2094			DBG(("%s: discarding idle GPU bo\n", __FUNCTION__));
2095			sna_pixmap_free_gpu(sna, priv);
2096		}
2097		priv->source_count = SOURCE_BIAS;
2098	}
2099
2100	if (priv->cpu_bo) {
2101		if ((flags & MOVE_ASYNC_HINT) == 0) {
2102			DBG(("%s: syncing CPU bo\n", __FUNCTION__));
2103			assert(IS_CPU_MAP(priv->cpu_bo->map));
2104			kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo,
2105					       FORCE_FULL_SYNC || flags & MOVE_WRITE);
2106			assert(pixmap->devPrivate.ptr == (void *)((unsigned long)priv->cpu_bo->map & ~3));
2107			assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo));
2108		}
2109	}
2110	priv->cpu =
2111		(flags & (MOVE_INPLACE_HINT | MOVE_ASYNC_HINT)) == 0 &&
2112		!DAMAGE_IS_ALL(priv->gpu_damage);
2113	assert(pixmap->devPrivate.ptr);
2114	assert(pixmap->devKind);
2115	assert_pixmap_damage(pixmap);
2116	assert(has_coherent_ptr(sna_pixmap(pixmap)));
2117	return true;
2118}
2119
2120static bool
2121region_overlaps_damage(const RegionRec *region,
2122		       struct sna_damage *damage,
2123		       int dx, int dy)
2124{
2125	const BoxRec *re, *de;
2126
2127	DBG(("%s?\n", __FUNCTION__));
2128
2129	if (damage == NULL)
2130		return false;
2131
2132	if (DAMAGE_IS_ALL(damage))
2133		return true;
2134
2135	re = &region->extents;
2136	de = &DAMAGE_PTR(damage)->extents;
2137	DBG(("%s: region (%d, %d), (%d, %d), damage (%d, %d), (%d, %d)\n",
2138	     __FUNCTION__,
2139	     re->x1, re->y1, re->x2, re->y2,
2140	     de->x1, de->y1, de->x2, de->y2));
2141
2142	return (re->x1 + dx < de->x2 && re->x2 + dx > de->x1 &&
2143		re->y1 + dy < de->y2 && re->y2 + dy > de->y1);
2144}
2145
2146#ifndef NDEBUG
2147static bool
2148pixmap_contains_damage(PixmapPtr pixmap, struct sna_damage *damage)
2149{
2150	if (damage == NULL)
2151		return true;
2152
2153	damage = DAMAGE_PTR(damage);
2154	return (damage->extents.x2 <= pixmap->drawable.width &&
2155		damage->extents.y2 <= pixmap->drawable.height &&
2156		damage->extents.x1 >= 0 &&
2157		damage->extents.y1 >= 0);
2158}
2159#endif
2160
2161static inline bool region_inplace(struct sna *sna,
2162				  PixmapPtr pixmap,
2163				  RegionPtr region,
2164				  struct sna_pixmap *priv,
2165				  unsigned flags)
2166{
2167	assert_pixmap_damage(pixmap);
2168
2169	if (FORCE_INPLACE)
2170		return FORCE_INPLACE > 0;
2171
2172	if (wedged(sna) && !priv->pinned)
2173		return false;
2174
2175	if (priv->gpu_damage &&
2176	    (priv->clear || (flags & MOVE_READ) == 0) &&
2177	    kgem_bo_is_busy(priv->gpu_bo))
2178		return false;
2179
2180	if (flags & MOVE_READ &&
2181	    (priv->cpu ||
2182	     priv->gpu_damage == NULL ||
2183	     region_overlaps_damage(region, priv->cpu_damage, 0, 0))) {
2184		DBG(("%s: no, uncovered CPU damage pending\n", __FUNCTION__));
2185		return false;
2186	}
2187
2188	if (priv->mapped) {
2189		DBG(("%s: %s, already mapped, continuing\n", __FUNCTION__,
2190		     has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no"));
2191		return has_coherent_map(sna, priv->gpu_bo, flags);
2192	}
2193
2194	if (priv->flush) {
2195		DBG(("%s: yes, exported via dri, will flush\n", __FUNCTION__));
2196		return true;
2197	}
2198
2199	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
2200		DBG(("%s: yes, already wholly damaged on the GPU\n", __FUNCTION__));
2201		assert(priv->gpu_bo);
2202		assert(priv->cpu == false || (priv->mapped && IS_CPU_MAP(priv->gpu_bo->map)));
2203		return true;
2204	}
2205
2206	DBG(("%s: (%dx%d), inplace? %d\n",
2207	     __FUNCTION__,
2208	     region->extents.x2 - region->extents.x1,
2209	     region->extents.y2 - region->extents.y1,
2210	     ((int)(region->extents.x2 - region->extents.x1) *
2211	      (int)(region->extents.y2 - region->extents.y1) *
2212	      pixmap->drawable.bitsPerPixel >> 12)
2213	     >= sna->kgem.half_cpu_cache_pages));
2214	return ((int)(region->extents.x2 - region->extents.x1) *
2215		(int)(region->extents.y2 - region->extents.y1) *
2216		pixmap->drawable.bitsPerPixel >> 12)
2217		>= sna->kgem.half_cpu_cache_pages;
2218}
2219
2220bool
2221sna_drawable_move_region_to_cpu(DrawablePtr drawable,
2222				RegionPtr region,
2223				unsigned flags)
2224{
2225	PixmapPtr pixmap = get_drawable_pixmap(drawable);
2226	struct sna *sna = to_sna_from_pixmap(pixmap);
2227	struct sna_pixmap *priv;
2228	int16_t dx, dy;
2229
2230	DBG(("%s(pixmap=%ld (%dx%d), [(%d, %d), (%d, %d)], flags=%d)\n",
2231	     __FUNCTION__, pixmap->drawable.serialNumber,
2232	     pixmap->drawable.width, pixmap->drawable.height,
2233	     RegionExtents(region)->x1, RegionExtents(region)->y1,
2234	     RegionExtents(region)->x2, RegionExtents(region)->y2,
2235	     flags));
2236
2237	assert_pixmap_damage(pixmap);
2238	if (flags & MOVE_WRITE) {
2239		assert_drawable_contains_box(drawable, &region->extents);
2240	}
2241	assert(flags & (MOVE_WRITE | MOVE_READ));
2242
2243	if (box_empty(&region->extents))
2244		return true;
2245
2246	priv = sna_pixmap(pixmap);
2247	if (priv == NULL) {
2248		DBG(("%s: not attached to %p\n", __FUNCTION__, pixmap));
2249		return true;
2250	}
2251
2252	assert(priv->gpu_damage == NULL || priv->gpu_bo);
2253
2254	if (sna_damage_is_all(&priv->cpu_damage,
2255			      pixmap->drawable.width,
2256			      pixmap->drawable.height)) {
2257		DBG(("%s: pixmap=%ld all damaged on CPU\n",
2258		     __FUNCTION__, pixmap->drawable.serialNumber));
2259		assert(!priv->clear);
2260
2261		sna_damage_destroy(&priv->gpu_damage);
2262
2263		if (flags & MOVE_WRITE)
2264			sna_pixmap_free_gpu(sna, priv);
2265
2266		if (pixmap->devPrivate.ptr == NULL &&
2267		    !sna_pixmap_alloc_cpu(sna, pixmap, priv, false))
2268			return false;
2269
2270		goto out;
2271	}
2272
2273	if (USE_INPLACE &&
2274	    (priv->create & KGEM_CAN_CREATE_LARGE ||
2275	     ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 &&
2276	      (priv->flush || box_inplace(pixmap, &region->extents))))) {
2277		DBG(("%s: marking for inplace hint (%d, %d)\n",
2278		     __FUNCTION__, priv->flush, box_inplace(pixmap, &region->extents)));
2279		flags |= MOVE_INPLACE_HINT;
2280	}
2281
2282	if (flags & MOVE_WHOLE_HINT)
2283		return _sna_pixmap_move_to_cpu(pixmap, flags);
2284
2285	if (priv->gpu_bo == NULL &&
2286	    (priv->create & KGEM_CAN_CREATE_GPU) == 0 &&
2287	    flags & MOVE_WRITE)
2288		return _sna_pixmap_move_to_cpu(pixmap, flags);
2289
2290	if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
2291		DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy));
2292		RegionTranslate(region, dx, dy);
2293	}
2294
2295	if (region_subsumes_drawable(region, &pixmap->drawable)) {
2296		DBG(("%s: region (%d, %d), (%d, %d) subsumes pixmap (%dx%d)\n",
2297		       __FUNCTION__,
2298		       region->extents.x1,
2299		       region->extents.y1,
2300		       region->extents.x2,
2301		       region->extents.y2,
2302		       pixmap->drawable.width,
2303		       pixmap->drawable.height));
2304		if (dx | dy)
2305			RegionTranslate(region, -dx, -dy);
2306		return _sna_pixmap_move_to_cpu(pixmap, flags);
2307	}
2308
2309	if (USE_INPLACE &&
2310	    operate_inplace(priv, flags) &&
2311	    region_inplace(sna, pixmap, region, priv, flags) &&
2312	    sna_pixmap_create_mappable_gpu(pixmap, false)) {
2313		DBG(("%s: try to operate inplace\n", __FUNCTION__));
2314		assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
2315		/* XXX only sync for writes? */
2316		kgem_bo_submit(&sna->kgem, priv->gpu_bo);
2317		assert(priv->gpu_bo->exec == NULL);
2318
2319		pixmap->devPrivate.ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo);
2320		priv->mapped = pixmap->devPrivate.ptr != NULL;
2321		if (priv->mapped) {
2322			assert(has_coherent_map(sna, priv->gpu_bo, flags));
2323			pixmap->devKind = priv->gpu_bo->pitch;
2324			if (flags & MOVE_WRITE) {
2325				if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
2326					assert(!priv->clear);
2327					sna_damage_add(&priv->gpu_damage, region);
2328					if (sna_damage_is_all(&priv->gpu_damage,
2329							      pixmap->drawable.width,
2330							      pixmap->drawable.height)) {
2331						DBG(("%s: replaced entire pixmap, destroying CPU shadow\n",
2332						     __FUNCTION__));
2333						sna_damage_destroy(&priv->cpu_damage);
2334						list_del(&priv->flush_list);
2335					} else
2336						sna_damage_subtract(&priv->cpu_damage,
2337								    region);
2338				}
2339				priv->clear = false;
2340			}
2341			assert_pixmap_damage(pixmap);
2342			priv->cpu = false;
2343			if (dx | dy)
2344				RegionTranslate(region, -dx, -dy);
2345			DBG(("%s: operate inplace\n", __FUNCTION__));
2346			return true;
2347		}
2348	}
2349
2350	if (priv->clear && flags & MOVE_WRITE) {
2351		DBG(("%s: pending clear, moving whole pixmap for partial write\n", __FUNCTION__));
2352		if (dx | dy)
2353			RegionTranslate(region, -dx, -dy);
2354		return _sna_pixmap_move_to_cpu(pixmap, flags | MOVE_READ);
2355	}
2356
2357	if (priv->mapped) {
2358		assert(!priv->shm);
2359		pixmap->devPrivate.ptr = NULL;
2360		priv->mapped = false;
2361	}
2362
2363	if (USE_INPLACE &&
2364	    priv->gpu_damage &&
2365	    priv->gpu_bo->tiling == I915_TILING_NONE &&
2366	    (DAMAGE_IS_ALL(priv->gpu_damage) ||
2367	     sna_damage_contains_box__no_reduce(priv->gpu_damage,
2368						&region->extents)) &&
2369	    kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE) &&
2370	    ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 ||
2371	     !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) {
2372		DBG(("%s: try to operate inplace (CPU), read? %d, write? %d\n",
2373		     __FUNCTION__, !!(flags & MOVE_READ), !!(flags & MOVE_WRITE)));
2374		assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0);
2375		assert(sna_damage_contains_box(priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
2376		assert(sna_damage_contains_box(priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
2377
2378		assert(!priv->mapped);
2379		pixmap->devPrivate.ptr =
2380			kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
2381		if (pixmap->devPrivate.ptr != NULL) {
2382			assert(has_coherent_map(sna, priv->gpu_bo, flags));
2383			assert(IS_CPU_MAP(priv->gpu_bo->map));
2384			pixmap->devKind = priv->gpu_bo->pitch;
2385			priv->cpu = true;
2386			priv->mapped = true;
2387			if (flags & MOVE_WRITE) {
2388				if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
2389					assert(!priv->clear);
2390					sna_damage_add(&priv->gpu_damage, region);
2391					if (sna_damage_is_all(&priv->gpu_damage,
2392							      pixmap->drawable.width,
2393							      pixmap->drawable.height)) {
2394						DBG(("%s: replaced entire pixmap, destroying CPU shadow\n",
2395						     __FUNCTION__));
2396						sna_damage_destroy(&priv->cpu_damage);
2397						list_del(&priv->flush_list);
2398					} else
2399						sna_damage_subtract(&priv->cpu_damage,
2400								    region);
2401				}
2402				priv->clear = false;
2403			}
2404			assert_pixmap_damage(pixmap);
2405			kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo,
2406					       FORCE_FULL_SYNC || flags & MOVE_WRITE);
2407			assert(pixmap->devPrivate.ptr == (void *)((unsigned long)priv->gpu_bo->map & ~3));
2408			assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo));
2409			assert_pixmap_damage(pixmap);
2410			if (dx | dy)
2411				RegionTranslate(region, -dx, -dy);
2412			DBG(("%s: operate inplace (CPU)\n", __FUNCTION__));
2413			return true;
2414		}
2415	}
2416
2417	if ((priv->clear || (flags & MOVE_READ) == 0) &&
2418	    priv->cpu_bo && !priv->cpu_bo->flush &&
2419	    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
2420		sna_damage_subtract(&priv->cpu_damage, region);
2421		if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) {
2422			assert(priv->gpu_bo);
2423			sna_damage_all(&priv->gpu_damage,
2424				       pixmap->drawable.width,
2425				       pixmap->drawable.height);
2426			sna_pixmap_free_cpu(sna, priv);
2427		}
2428	}
2429
2430	if (pixmap->devPrivate.ptr == NULL &&
2431	    !sna_pixmap_alloc_cpu(sna, pixmap, priv,
2432				  flags & MOVE_READ ? priv->gpu_damage && !priv->clear : 0)) {
2433		if (dx | dy)
2434			RegionTranslate(region, -dx, -dy);
2435		return false;
2436	}
2437	assert(pixmap->devPrivate.ptr);
2438
2439	if (priv->gpu_bo == NULL) {
2440		assert(priv->gpu_damage == NULL);
2441		goto done;
2442	}
2443
2444	assert(priv->gpu_bo->proxy == NULL);
2445	if (priv->clear) {
2446		int n = RegionNumRects(region);
2447		BoxPtr box = RegionRects(region);
2448
2449		assert(DAMAGE_IS_ALL(priv->gpu_damage));
2450
2451		DBG(("%s: pending clear, doing partial fill\n", __FUNCTION__));
2452		if (priv->cpu_bo) {
2453			DBG(("%s: syncing CPU bo\n", __FUNCTION__));
2454			kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
2455			assert(pixmap->devPrivate.ptr == (void *)((unsigned long)priv->cpu_bo->map & ~3));
2456		}
2457
2458		do {
2459			pixman_fill(pixmap->devPrivate.ptr,
2460				    pixmap->devKind/sizeof(uint32_t),
2461				    pixmap->drawable.bitsPerPixel,
2462				    box->x1, box->y1,
2463				    box->x2 - box->x1,
2464				    box->y2 - box->y1,
2465				    priv->clear_color);
2466			box++;
2467		} while (--n);
2468
2469		if (region->extents.x2 - region->extents.x1 > 1 ||
2470		    region->extents.y2 - region->extents.y1 > 1) {
2471			sna_damage_subtract(&priv->gpu_damage, region);
2472			priv->clear = false;
2473		}
2474		goto done;
2475	}
2476
2477	if ((flags & MOVE_READ) == 0) {
2478		assert(flags & MOVE_WRITE);
2479		sna_damage_subtract(&priv->gpu_damage, region);
2480		goto done;
2481	}
2482
2483	if (MIGRATE_ALL && priv->gpu_damage) {
2484		BoxPtr box;
2485		int n = sna_damage_get_boxes(priv->gpu_damage, &box);
2486		if (n) {
2487			bool ok;
2488
2489			DBG(("%s: forced migration\n", __FUNCTION__));
2490
2491			assert(pixmap_contains_damage(pixmap, priv->gpu_damage));
2492			assert(priv->gpu_bo);
2493
2494			ok = false;
2495			if (use_cpu_bo_for_download(sna, priv, n, box)) {
2496				DBG(("%s: using CPU bo for download from GPU\n", __FUNCTION__));
2497				ok = sna->render.copy_boxes(sna, GXcopy,
2498							    pixmap, priv->gpu_bo, 0, 0,
2499							    pixmap, priv->cpu_bo, 0, 0,
2500							    box, n, COPY_LAST);
2501			}
2502			if (!ok) {
2503				assert(has_coherent_ptr(sna_pixmap(pixmap)));
2504				sna_read_boxes(sna, pixmap, priv->gpu_bo,
2505					       box, n);
2506			}
2507		}
2508		sna_damage_destroy(&priv->gpu_damage);
2509	}
2510
2511	if (priv->gpu_damage &&
2512	    (DAMAGE_IS_ALL(priv->gpu_damage) ||
2513	     sna_damage_overlaps_box(priv->gpu_damage, &region->extents))) {
2514		DBG(("%s: region (%dx%d) overlaps gpu damage\n",
2515		     __FUNCTION__,
2516		     region->extents.x2 - region->extents.x1,
2517		     region->extents.y2 - region->extents.y1));
2518		assert(priv->gpu_bo);
2519
2520		if (priv->cpu_damage == NULL) {
2521			if ((flags & MOVE_WRITE) == 0 &&
2522			    region->extents.x2 - region->extents.x1 == 1 &&
2523			    region->extents.y2 - region->extents.y1 == 1) {
2524				/*  Often associated with synchronisation, KISS */
2525				DBG(("%s: single pixel read\n", __FUNCTION__));
2526				sna_read_boxes(sna, pixmap, priv->gpu_bo,
2527					       &region->extents, 1);
2528				goto done;
2529			}
2530		} else {
2531			if (sna_damage_contains_box__no_reduce(priv->cpu_damage,
2532							       &region->extents)) {
2533				assert(sna_damage_contains_box(priv->gpu_damage, &region->extents) == PIXMAN_REGION_OUT);
2534				assert(sna_damage_contains_box(priv->cpu_damage, &region->extents) == PIXMAN_REGION_IN);
2535
2536				DBG(("%s: region already in CPU damage\n",
2537				     __FUNCTION__));
2538				goto done;
2539			}
2540		}
2541
2542		if (sna_damage_contains_box(priv->gpu_damage,
2543					    &region->extents) != PIXMAN_REGION_OUT) {
2544			RegionRec want, *r = region;
2545
2546			DBG(("%s: region (%dx%d) intersects gpu damage\n",
2547			     __FUNCTION__,
2548			     region->extents.x2 - region->extents.x1,
2549			     region->extents.y2 - region->extents.y1));
2550
2551			if ((flags & MOVE_WRITE) == 0 &&
2552			    region->extents.x2 - region->extents.x1 == 1 &&
2553			    region->extents.y2 - region->extents.y1 == 1) {
2554				sna_read_boxes(sna, pixmap, priv->gpu_bo,
2555					       &region->extents, 1);
2556				goto done;
2557			}
2558
2559			/* Expand the region to move 32x32 pixel blocks at a
2560			 * time, as we assume that we will continue writing
2561			 * afterwards and so aim to coallesce subsequent
2562			 * reads.
2563			 */
2564			if (flags & MOVE_WRITE) {
2565				int n = RegionNumRects(region), i;
2566				BoxPtr boxes = RegionRects(region);
2567				BoxPtr blocks;
2568
2569				blocks = NULL;
2570				if (priv->cpu_damage == NULL)
2571					blocks = malloc(sizeof(BoxRec) * RegionNumRects(region));
2572				if (blocks) {
2573					for (i = 0; i < n; i++) {
2574						blocks[i].x1 = boxes[i].x1 & ~31;
2575						if (blocks[i].x1 < 0)
2576							blocks[i].x1 = 0;
2577
2578						blocks[i].x2 = (boxes[i].x2 + 31) & ~31;
2579						if (blocks[i].x2 > pixmap->drawable.width)
2580							blocks[i].x2 = pixmap->drawable.width;
2581
2582						blocks[i].y1 = boxes[i].y1 & ~31;
2583						if (blocks[i].y1 < 0)
2584							blocks[i].y1 = 0;
2585
2586						blocks[i].y2 = (boxes[i].y2 + 31) & ~31;
2587						if (blocks[i].y2 > pixmap->drawable.height)
2588							blocks[i].y2 = pixmap->drawable.height;
2589					}
2590					if (pixman_region_init_rects(&want, blocks, i))
2591						r = &want;
2592					free(blocks);
2593				}
2594			}
2595
2596			if (region_subsumes_damage(r, priv->gpu_damage)) {
2597				BoxPtr box;
2598				int n;
2599
2600				DBG(("%s: region wholly contains damage\n",
2601				     __FUNCTION__));
2602
2603				n = sna_damage_get_boxes(priv->gpu_damage,
2604							 &box);
2605				if (n) {
2606					bool ok = false;
2607
2608					if (use_cpu_bo_for_download(sna, priv, n, box)) {
2609						DBG(("%s: using CPU bo for download from GPU\n", __FUNCTION__));
2610						ok = sna->render.copy_boxes(sna, GXcopy,
2611									    pixmap, priv->gpu_bo, 0, 0,
2612									    pixmap, priv->cpu_bo, 0, 0,
2613									    box, n, COPY_LAST);
2614					}
2615
2616					if (!ok) {
2617						assert(has_coherent_ptr(sna_pixmap(pixmap)));
2618						sna_read_boxes(sna, pixmap, priv->gpu_bo,
2619							       box, n);
2620					}
2621				}
2622
2623				sna_damage_destroy(&priv->gpu_damage);
2624			} else if (DAMAGE_IS_ALL(priv->gpu_damage) ||
2625				   sna_damage_contains_box__no_reduce(priv->gpu_damage,
2626								      &r->extents)) {
2627				BoxPtr box = RegionRects(r);
2628				int n = RegionNumRects(r);
2629				bool ok = false;
2630
2631				DBG(("%s: region wholly inside damage\n",
2632				     __FUNCTION__));
2633
2634				assert(sna_damage_contains_box(priv->gpu_damage, &r->extents) == PIXMAN_REGION_IN);
2635				assert(sna_damage_contains_box(priv->cpu_damage, &r->extents) == PIXMAN_REGION_OUT);
2636
2637				if (use_cpu_bo_for_download(sna, priv, n, box)) {
2638					DBG(("%s: using CPU bo for download from GPU\n", __FUNCTION__));
2639					ok = sna->render.copy_boxes(sna, GXcopy,
2640								    pixmap, priv->gpu_bo, 0, 0,
2641								    pixmap, priv->cpu_bo, 0, 0,
2642								    box, n, COPY_LAST);
2643				}
2644				if (!ok) {
2645					assert(has_coherent_ptr(sna_pixmap(pixmap)));
2646					sna_read_boxes(sna, pixmap, priv->gpu_bo,
2647						       box, n);
2648				}
2649
2650				sna_damage_subtract(&priv->gpu_damage, r);
2651			} else {
2652				RegionRec need;
2653
2654				pixman_region_init(&need);
2655				if (sna_damage_intersect(priv->gpu_damage, r, &need)) {
2656					BoxPtr box = RegionRects(&need);
2657					int n = RegionNumRects(&need);
2658					bool ok = false;
2659
2660					DBG(("%s: region intersects damage\n",
2661					     __FUNCTION__));
2662
2663					if (use_cpu_bo_for_download(sna, priv, n, box)) {
2664						DBG(("%s: using CPU bo for download from GPU\n", __FUNCTION__));
2665						ok = sna->render.copy_boxes(sna, GXcopy,
2666									    pixmap, priv->gpu_bo, 0, 0,
2667									    pixmap, priv->cpu_bo, 0, 0,
2668									    box, n, COPY_LAST);
2669					}
2670					if (!ok) {
2671						assert(has_coherent_ptr(sna_pixmap(pixmap)));
2672						sna_read_boxes(sna, pixmap, priv->gpu_bo,
2673							       box, n);
2674					}
2675
2676					sna_damage_subtract(&priv->gpu_damage, r);
2677					RegionUninit(&need);
2678				}
2679			}
2680			if (r == &want)
2681				pixman_region_fini(&want);
2682		}
2683	}
2684
2685done:
2686	if ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE) {
2687		DBG(("%s: applying cpu damage\n", __FUNCTION__));
2688		assert(!DAMAGE_IS_ALL(priv->cpu_damage));
2689		assert_pixmap_contains_box(pixmap, RegionExtents(region));
2690		sna_damage_add(&priv->cpu_damage, region);
2691		sna_damage_reduce_all(&priv->cpu_damage,
2692				      pixmap->drawable.width,
2693				      pixmap->drawable.height);
2694		if (DAMAGE_IS_ALL(priv->cpu_damage)) {
2695			DBG(("%s: replaced entire pixmap\n", __FUNCTION__));
2696			sna_pixmap_free_gpu(sna, priv);
2697		}
2698		if (priv->flush) {
2699			assert(!priv->shm);
2700			sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
2701		}
2702	}
2703
2704	if (dx | dy)
2705		RegionTranslate(region, -dx, -dy);
2706
2707out:
2708	if (flags & MOVE_WRITE) {
2709		assert(!DAMAGE_IS_ALL(priv->gpu_damage));
2710		priv->source_count = SOURCE_BIAS;
2711		assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
2712		assert(priv->gpu_bo || priv->gpu_damage == NULL);
2713		assert(!priv->flush || !list_is_empty(&priv->flush_list));
2714		assert(!priv->clear);
2715	}
2716	if ((flags & MOVE_ASYNC_HINT) == 0 && priv->cpu_bo) {
2717		DBG(("%s: syncing cpu bo\n", __FUNCTION__));
2718		assert(IS_CPU_MAP(priv->cpu_bo->map));
2719		kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo,
2720				       FORCE_FULL_SYNC || flags & MOVE_WRITE);
2721		assert(pixmap->devPrivate.ptr == (void *)((unsigned long)priv->cpu_bo->map & ~3));
2722		assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo));
2723	}
2724	priv->cpu =
2725		(flags & (MOVE_INPLACE_HINT | MOVE_ASYNC_HINT)) == 0 &&
2726		!DAMAGE_IS_ALL(priv->gpu_damage);
2727	assert(pixmap->devPrivate.ptr);
2728	assert(pixmap->devKind);
2729	assert_pixmap_damage(pixmap);
2730	assert(has_coherent_ptr(sna_pixmap(pixmap)));
2731	return true;
2732}
2733
2734bool
2735sna_drawable_move_to_cpu(DrawablePtr drawable, unsigned flags)
2736{
2737	RegionRec region;
2738	PixmapPtr pixmap;
2739	int16_t dx, dy;
2740
2741	if (drawable->type == DRAWABLE_PIXMAP)
2742		return sna_pixmap_move_to_cpu((PixmapPtr)drawable, flags);
2743
2744	pixmap = get_window_pixmap((WindowPtr)drawable);
2745	get_drawable_deltas(drawable, pixmap, &dx, &dy);
2746
2747	DBG(("%s: (%d, %d)x(%d, %d) + (%d, %d), flags=%x\n",
2748	     __FUNCTION__,
2749	     drawable->x, drawable->y,
2750	     drawable->width, drawable->height,
2751	     dx, dy, flags));
2752
2753	region.extents.x1 = drawable->x + dx;
2754	region.extents.y1 = drawable->y + dy;
2755	region.extents.x2 = region.extents.x1 + drawable->width;
2756	region.extents.y2 = region.extents.y1 + drawable->height;
2757	region.data = NULL;
2758
2759	if (region.extents.x1 < 0)
2760		region.extents.x1 = 0;
2761	if (region.extents.y1 < 0)
2762		region.extents.y1 = 0;
2763	if (region.extents.x2 > pixmap->drawable.width)
2764		region.extents.x2 = pixmap->drawable.width;
2765	if (region.extents.y2 > pixmap->drawable.height)
2766		region.extents.y2 = pixmap->drawable.height;
2767
2768	if (box_empty(&region.extents))
2769		return true;
2770
2771	return sna_drawable_move_region_to_cpu(&pixmap->drawable, &region, flags);
2772}
2773
2774pure static bool alu_overwrites(uint8_t alu)
2775{
2776	switch (alu) {
2777	case GXclear:
2778	case GXcopy:
2779	case GXcopyInverted:
2780	case GXset:
2781		return true;
2782	default:
2783		return false;
2784	}
2785}
2786
2787inline static bool drawable_gc_inplace_hint(DrawablePtr draw, GCPtr gc)
2788{
2789	if (!alu_overwrites(gc->alu))
2790		return false;
2791
2792	if (!PM_IS_SOLID(draw, gc->planemask))
2793		return false;
2794
2795	if (gc->fillStyle == FillStippled)
2796		return false;
2797
2798	return true;
2799}
2800
2801inline static unsigned
2802drawable_gc_flags(DrawablePtr draw, GCPtr gc, bool partial)
2803{
2804	assert(sna_gc(gc)->changes == 0);
2805
2806	if (gc->fillStyle == FillStippled) {
2807		DBG(("%s: read due to fill %d\n",
2808		     __FUNCTION__, gc->fillStyle));
2809		return MOVE_READ | MOVE_WRITE;
2810	}
2811
2812	if (fb_gc(gc)->and | fb_gc(gc)->bgand) {
2813		DBG(("%s: read due to rrop %d:%x\n",
2814		     __FUNCTION__, gc->alu, (unsigned)fb_gc(gc)->and));
2815		return MOVE_READ | MOVE_WRITE;
2816	}
2817
2818	DBG(("%s: try operating on drawable inplace [hint? %d]\n",
2819	     __FUNCTION__, drawable_gc_inplace_hint(draw, gc)));
2820
2821	return (partial ? MOVE_READ : 0) | MOVE_WRITE | MOVE_INPLACE_HINT;
2822}
2823
2824static inline struct sna_pixmap *
2825sna_pixmap_mark_active(struct sna *sna, struct sna_pixmap *priv)
2826{
2827	assert(priv->gpu_bo);
2828	DBG(("%s: pixmap=%ld, handle=%u\n", __FUNCTION__,
2829	     priv->pixmap->drawable.serialNumber,
2830	     priv->gpu_bo->handle));
2831	return priv;
2832}
2833
2834bool
2835sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int flags)
2836{
2837	struct sna *sna = to_sna_from_pixmap(pixmap);
2838	struct sna_pixmap *priv = sna_pixmap(pixmap);
2839	RegionRec i, r;
2840
2841	DBG(("%s: pixmap=%ld box=(%d, %d), (%d, %d), flags=%x\n",
2842	     __FUNCTION__, pixmap->drawable.serialNumber,
2843	     box->x1, box->y1, box->x2, box->y2, flags));
2844
2845	assert(box->x2 > box->x1 && box->y2 > box->y1);
2846	assert_pixmap_damage(pixmap);
2847	assert_pixmap_contains_box(pixmap, box);
2848	assert(!wedged(sna));
2849	assert(priv->gpu_damage == NULL || priv->gpu_bo);
2850
2851	if (priv->cow && (flags & MOVE_WRITE || priv->cpu_damage)) {
2852		unsigned cow = MOVE_READ;
2853
2854		if ((flags & MOVE_READ) == 0) {
2855			if (priv->gpu_damage) {
2856				r.extents = *box;
2857				r.data = NULL;
2858				if (region_subsumes_damage(&r,
2859							   priv->gpu_damage))
2860					cow = 0;
2861			} else
2862				cow = 0;
2863		}
2864
2865		if (!sna_pixmap_undo_cow(sna, priv, cow))
2866			return false;
2867
2868		if (priv->gpu_bo == NULL)
2869			sna_damage_destroy(&priv->gpu_damage);
2870	}
2871
2872	if (sna_damage_is_all(&priv->gpu_damage,
2873			      pixmap->drawable.width,
2874			      pixmap->drawable.height)) {
2875		assert(priv->gpu_bo);
2876		assert(priv->gpu_bo->proxy == NULL);
2877		assert(priv->cpu == false || (priv->mapped && IS_CPU_MAP(priv->gpu_bo->map)));
2878		sna_damage_destroy(&priv->cpu_damage);
2879		list_del(&priv->flush_list);
2880		goto done;
2881	}
2882
2883	if (flags & MOVE_WRITE && priv->gpu_bo && priv->gpu_bo->proxy) {
2884		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
2885		assert(priv->gpu_damage == NULL);
2886		assert(!priv->pinned);
2887		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
2888		priv->gpu_bo = NULL;
2889	}
2890
2891	if ((flags & MOVE_READ) == 0)
2892		sna_damage_subtract_box(&priv->cpu_damage, box);
2893
2894	sna_damage_reduce(&priv->cpu_damage);
2895	assert_pixmap_damage(pixmap);
2896
2897	if (priv->cpu_damage == NULL) {
2898		list_del(&priv->flush_list);
2899		return sna_pixmap_move_to_gpu(pixmap, flags);
2900	}
2901
2902	if (priv->gpu_bo == NULL) {
2903		assert(priv->gpu_damage == NULL);
2904
2905		if (flags & __MOVE_FORCE ||
2906		    priv->create & KGEM_CAN_CREATE_GPU) {
2907			unsigned create, tiling;
2908
2909			create = CREATE_INACTIVE;
2910			if (pixmap->usage_hint == SNA_CREATE_FB)
2911				create |= CREATE_SCANOUT;
2912
2913			tiling = (flags & MOVE_SOURCE_HINT) ? I915_TILING_Y : DEFAULT_TILING;
2914			tiling = sna_pixmap_choose_tiling(pixmap, tiling);
2915
2916			priv->gpu_bo = kgem_create_2d(&sna->kgem,
2917						      pixmap->drawable.width,
2918						      pixmap->drawable.height,
2919						      pixmap->drawable.bitsPerPixel,
2920						      tiling, create);
2921		}
2922
2923		if (priv->gpu_bo == NULL)
2924			return false;
2925
2926		DBG(("%s: created gpu bo\n", __FUNCTION__));
2927	}
2928
2929	if (priv->gpu_bo->proxy) {
2930		DBG(("%s: reusing cached upload\n", __FUNCTION__));
2931		assert((flags & MOVE_WRITE) == 0);
2932		assert(priv->gpu_damage == NULL);
2933		return priv;
2934	}
2935
2936	if (priv->shm) {
2937		assert(!priv->flush);
2938		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
2939	}
2940
2941	assert(priv->cpu_damage);
2942	region_set(&r, box);
2943	if (MIGRATE_ALL || region_subsumes_damage(&r, priv->cpu_damage)) {
2944		int n;
2945
2946		n = sna_damage_get_boxes(priv->cpu_damage, (BoxPtr *)&box);
2947		if (n) {
2948			bool ok = false;
2949
2950			if (use_cpu_bo_for_upload(sna, priv, 0)) {
2951				DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__));
2952				ok = sna->render.copy_boxes(sna, GXcopy,
2953							    pixmap, priv->cpu_bo, 0, 0,
2954							    pixmap, priv->gpu_bo, 0, 0,
2955							    box, n, 0);
2956			}
2957			if (!ok) {
2958				if (priv->mapped || pixmap->devPrivate.ptr == NULL) {
2959					assert(priv->ptr && priv->stride);
2960					pixmap->devPrivate.ptr = PTR(priv->ptr);
2961					pixmap->devKind = priv->stride;
2962					priv->mapped = false;
2963				}
2964				if (n == 1 && !priv->pinned &&
2965				    box->x1 <= 0 && box->y1 <= 0 &&
2966				    box->x2 >= pixmap->drawable.width &&
2967				    box->y2 >= pixmap->drawable.height) {
2968					ok = sna_replace(sna, pixmap,
2969							 &priv->gpu_bo,
2970							 pixmap->devPrivate.ptr,
2971							 pixmap->devKind);
2972				} else {
2973					ok = sna_write_boxes(sna, pixmap,
2974							     priv->gpu_bo, 0, 0,
2975							     pixmap->devPrivate.ptr,
2976							     pixmap->devKind,
2977							     0, 0,
2978							     box, n);
2979				}
2980				if (!ok)
2981					return false;
2982			}
2983		}
2984
2985		sna_damage_destroy(&priv->cpu_damage);
2986	} else if (DAMAGE_IS_ALL(priv->cpu_damage) ||
2987		   sna_damage_contains_box__no_reduce(priv->cpu_damage, box)) {
2988		bool ok = false;
2989
2990		assert(sna_damage_contains_box(priv->gpu_damage, box) == PIXMAN_REGION_OUT);
2991		assert(sna_damage_contains_box(priv->cpu_damage, box) == PIXMAN_REGION_IN);
2992
2993		if (use_cpu_bo_for_upload(sna, priv, 0)) {
2994			DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__));
2995			ok = sna->render.copy_boxes(sna, GXcopy,
2996						    pixmap, priv->cpu_bo, 0, 0,
2997						    pixmap, priv->gpu_bo, 0, 0,
2998						    box, 1, 0);
2999		}
3000		if (!ok) {
3001			if (priv->mapped || pixmap->devPrivate.ptr == NULL) {
3002				assert(priv->ptr && priv->stride);
3003				pixmap->devPrivate.ptr = PTR(priv->ptr);
3004				pixmap->devKind = priv->stride;
3005				priv->mapped = false;
3006			}
3007			ok = sna_write_boxes(sna, pixmap,
3008					     priv->gpu_bo, 0, 0,
3009					     pixmap->devPrivate.ptr,
3010					     pixmap->devKind,
3011					     0, 0,
3012					     box, 1);
3013		}
3014		if (!ok)
3015			return false;
3016
3017		sna_damage_subtract(&priv->cpu_damage, &r);
3018	} else if (sna_damage_intersect(priv->cpu_damage, &r, &i)) {
3019		int n = RegionNumRects(&i);
3020		bool ok;
3021
3022		box = RegionRects(&i);
3023		ok = false;
3024		if (use_cpu_bo_for_upload(sna, priv, 0)) {
3025			DBG(("%s: using CPU bo for upload to GPU, %d boxes\n", __FUNCTION__, n));
3026			ok = sna->render.copy_boxes(sna, GXcopy,
3027						    pixmap, priv->cpu_bo, 0, 0,
3028						    pixmap, priv->gpu_bo, 0, 0,
3029						    box, n, 0);
3030		}
3031		if (!ok) {
3032			if (priv->mapped || pixmap->devPrivate.ptr == NULL) {
3033				assert(priv->ptr && priv->stride);
3034				pixmap->devPrivate.ptr = PTR(priv->ptr);
3035				pixmap->devKind = priv->stride;
3036				priv->mapped = false;
3037			}
3038			ok = sna_write_boxes(sna, pixmap,
3039					     priv->gpu_bo, 0, 0,
3040					     pixmap->devPrivate.ptr,
3041					     pixmap->devKind,
3042					     0, 0,
3043					     box, n);
3044		}
3045		if (!ok)
3046			return false;
3047
3048		sna_damage_subtract(&priv->cpu_damage, &r);
3049		RegionUninit(&i);
3050	}
3051
3052done:
3053	if (priv->cpu_damage == NULL && priv->flush)
3054		list_del(&priv->flush_list);
3055	if (flags & MOVE_WRITE) {
3056		priv->clear = false;
3057		priv->cpu = false;
3058		if (!DAMAGE_IS_ALL(priv->gpu_damage) &&
3059		    priv->cpu_damage == NULL &&
3060		    box_inplace(pixmap, &r.extents)) {
3061			DBG(("%s: large operation on undamaged, promoting to full GPU\n",
3062			     __FUNCTION__));
3063			assert(priv->gpu_bo);
3064			assert(priv->gpu_bo->proxy == NULL);
3065			sna_damage_all(&priv->gpu_damage,
3066				       pixmap->drawable.width,
3067				       pixmap->drawable.height);
3068		}
3069		if (DAMAGE_IS_ALL(priv->gpu_damage))
3070			sna_pixmap_free_cpu(sna, priv);
3071	}
3072
3073	assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0);
3074	return sna_pixmap_mark_active(sna, priv) != NULL;
3075}
3076
3077struct kgem_bo *
3078sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box,
3079		    struct sna_damage ***damage)
3080{
3081	PixmapPtr pixmap = get_drawable_pixmap(drawable);
3082	struct sna_pixmap *priv = sna_pixmap(pixmap);
3083	struct sna *sna;
3084	RegionRec region;
3085	int16_t dx, dy;
3086	int ret;
3087
3088	DBG(("%s pixmap=%ld, box=((%d, %d), (%d, %d)), flags=%x...\n",
3089	     __FUNCTION__,
3090	     pixmap->drawable.serialNumber,
3091	     box->x1, box->y1, box->x2, box->y2,
3092	     flags));
3093
3094	assert(box->x2 > box->x1 && box->y2 > box->y1);
3095	assert(pixmap->refcnt);
3096	assert_pixmap_damage(pixmap);
3097	assert_drawable_contains_box(drawable, box);
3098
3099	if (priv == NULL) {
3100		DBG(("%s: not attached\n", __FUNCTION__));
3101		return NULL;
3102	}
3103
3104	if (priv->cow) {
3105		unsigned cow = MOVE_READ;
3106
3107		if (flags & IGNORE_CPU) {
3108			if (priv->gpu_damage) {
3109				region.extents = *box;
3110				if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3111					region.extents.x1 += dx;
3112					region.extents.x2 += dx;
3113					region.extents.y1 += dy;
3114					region.extents.y2 += dy;
3115				}
3116				region.data = NULL;
3117				if (region_subsumes_damage(&region,
3118							   priv->gpu_damage))
3119					cow = 0;
3120			} else
3121				cow = 0;
3122		}
3123
3124		if (!sna_pixmap_undo_cow(to_sna_from_pixmap(pixmap), priv, cow))
3125			return NULL;
3126
3127		if (priv->gpu_bo == NULL)
3128			sna_damage_destroy(&priv->gpu_damage);
3129	}
3130
3131	if (priv->gpu_bo && priv->gpu_bo->proxy) {
3132		DBG(("%s: cached upload proxy, discard and revert to GPU\n",
3133		     __FUNCTION__));
3134		assert(priv->gpu_damage == NULL);
3135		assert(!priv->pinned);
3136		kgem_bo_destroy(&to_sna_from_pixmap(pixmap)->kgem,
3137				priv->gpu_bo);
3138		priv->gpu_bo = NULL;
3139		goto use_cpu_bo;
3140	}
3141
3142	if (priv->flush)
3143		flags |= PREFER_GPU;
3144	if (priv->shm)
3145		flags &= ~PREFER_GPU;
3146	if (priv->cpu && (flags & (FORCE_GPU | IGNORE_CPU)) == 0)
3147		flags &= ~PREFER_GPU;
3148
3149	DBG(("%s: flush=%d, shm=%d, cpu=%d => flags=%x\n",
3150	     __FUNCTION__, priv->flush, priv->shm, priv->cpu, flags));
3151
3152	if ((flags & PREFER_GPU) == 0 &&
3153	    (flags & REPLACES || !priv->gpu_damage || !kgem_bo_is_busy(priv->gpu_bo))) {
3154		DBG(("%s: try cpu as GPU bo is idle\n", __FUNCTION__));
3155		goto use_cpu_bo;
3156	}
3157
3158	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
3159		DBG(("%s: use GPU fast path (all-damaged)\n", __FUNCTION__));
3160		assert(priv->cpu_damage == NULL);
3161		assert(priv->gpu_bo);
3162		assert(priv->gpu_bo->proxy == NULL);
3163		assert(priv->cpu == false || (priv->mapped && IS_CPU_MAP(priv->gpu_bo->map)));
3164		goto use_gpu_bo;
3165	}
3166
3167	if (DAMAGE_IS_ALL(priv->cpu_damage)) {
3168		assert(priv->gpu_damage == NULL);
3169		if ((flags & FORCE_GPU) == 0 || priv->cpu_bo) {
3170			DBG(("%s: use CPU fast path (all-damaged), and not forced-gpu\n",
3171			     __FUNCTION__));
3172			goto use_cpu_bo;
3173		}
3174	}
3175
3176	DBG(("%s: gpu? %d, damaged? %d; cpu? %d, damaged? %d\n", __FUNCTION__,
3177	     priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->gpu_damage != NULL,
3178	     priv->cpu_bo ? priv->cpu_bo->handle : 0, priv->cpu_damage != NULL));
3179	if (priv->gpu_bo == NULL) {
3180		unsigned int move;
3181
3182		if ((flags & FORCE_GPU) == 0 &&
3183		    (priv->create & KGEM_CAN_CREATE_GPU) == 0) {
3184			DBG(("%s: untiled, will not force allocation\n",
3185			     __FUNCTION__));
3186			goto use_cpu_bo;
3187		}
3188
3189		if ((flags & IGNORE_CPU) == 0) {
3190			if (priv->cpu_bo) {
3191				if (to_sna_from_pixmap(pixmap)->kgem.can_blt_cpu) {
3192					if (kgem_bo_is_busy(priv->cpu_bo)) {
3193						DBG(("%s: already using CPU bo, will not force allocation\n",
3194						     __FUNCTION__));
3195						goto use_cpu_bo;
3196					}
3197
3198					if ((flags & RENDER_GPU) == 0) {
3199						DBG(("%s: prefer cpu", __FUNCTION__));
3200						goto use_cpu_bo;
3201					}
3202				} else {
3203					if (kgem_bo_is_busy(priv->cpu_bo)) {
3204						DBG(("%s: CPU bo active, must force allocation\n",
3205						     __FUNCTION__));
3206						goto create_gpu_bo;
3207					}
3208				}
3209			}
3210
3211			if ((flags & FORCE_GPU) == 0 && priv->cpu_damage) {
3212				if ((flags & PREFER_GPU) == 0) {
3213					DBG(("%s: already damaged and prefer cpu",
3214					     __FUNCTION__));
3215					goto use_cpu_bo;
3216				}
3217
3218				if (!box_inplace(pixmap, box)) {
3219					DBG(("%s: damaged with a small operation, will not force allocation\n",
3220					     __FUNCTION__));
3221					goto use_cpu_bo;
3222				}
3223			}
3224		} else if (priv->cpu_damage) {
3225			region.extents = *box;
3226			if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3227				region.extents.x1 += dx;
3228				region.extents.x2 += dx;
3229				region.extents.y1 += dy;
3230				region.extents.y2 += dy;
3231			}
3232			region.data = NULL;
3233
3234			sna_damage_subtract(&priv->cpu_damage, &region);
3235			if (priv->cpu_damage == NULL) {
3236				list_del(&priv->flush_list);
3237				priv->cpu = false;
3238			}
3239		}
3240
3241create_gpu_bo:
3242		move = MOVE_WRITE | MOVE_READ;
3243		if (flags & FORCE_GPU)
3244			move |= __MOVE_FORCE;
3245		if (!sna_pixmap_move_to_gpu(pixmap, move))
3246			goto use_cpu_bo;
3247
3248		DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__));
3249		goto done;
3250	}
3251
3252
3253	region.extents = *box;
3254	if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3255		region.extents.x1 += dx;
3256		region.extents.x2 += dx;
3257		region.extents.y1 += dy;
3258		region.extents.y2 += dy;
3259	}
3260	region.data = NULL;
3261
3262	DBG(("%s extents (%d, %d), (%d, %d)\n", __FUNCTION__,
3263	     region.extents.x1, region.extents.y1,
3264	     region.extents.x2, region.extents.y2));
3265
3266	if (priv->gpu_damage) {
3267		assert(priv->gpu_bo);
3268		if (!priv->cpu_damage) {
3269			if (sna_damage_contains_box__no_reduce(priv->gpu_damage,
3270							       &region.extents)) {
3271				DBG(("%s: region wholly contained within GPU damage\n",
3272				     __FUNCTION__));
3273				assert(sna_damage_contains_box(priv->gpu_damage, &region.extents) == PIXMAN_REGION_IN);
3274				assert(sna_damage_contains_box(priv->cpu_damage, &region.extents) == PIXMAN_REGION_OUT);
3275				goto use_gpu_bo;
3276			} else {
3277				DBG(("%s: partial GPU damage with no CPU damage, continuing to use GPU\n",
3278				     __FUNCTION__));
3279				priv->cpu = false;
3280				goto done;
3281			}
3282		}
3283
3284		ret = sna_damage_contains_box(priv->gpu_damage, &region.extents);
3285		if (ret == PIXMAN_REGION_IN) {
3286			DBG(("%s: region wholly contained within GPU damage\n",
3287			     __FUNCTION__));
3288			goto use_gpu_bo;
3289		}
3290
3291		if (ret != PIXMAN_REGION_OUT) {
3292			DBG(("%s: region partially contained within GPU damage\n",
3293			     __FUNCTION__));
3294			goto move_to_gpu;
3295		}
3296	}
3297
3298	if ((flags & IGNORE_CPU) == 0 && priv->cpu_damage) {
3299		ret = sna_damage_contains_box(priv->cpu_damage, &region.extents);
3300		if (ret == PIXMAN_REGION_IN) {
3301			DBG(("%s: region wholly contained within CPU damage\n",
3302			     __FUNCTION__));
3303			goto use_cpu_bo;
3304		}
3305
3306		if (box_inplace(pixmap, box)) {
3307			DBG(("%s: forcing inplace\n", __FUNCTION__));
3308			goto move_to_gpu;
3309		}
3310
3311		if (ret != PIXMAN_REGION_OUT) {
3312			DBG(("%s: region partially contained within CPU damage\n",
3313			     __FUNCTION__));
3314			goto use_cpu_bo;
3315		}
3316	}
3317
3318move_to_gpu:
3319	if (!sna_pixmap_move_area_to_gpu(pixmap, &region.extents,
3320					 flags & IGNORE_CPU ? MOVE_WRITE : MOVE_READ | MOVE_WRITE)) {
3321		DBG(("%s: failed to move-to-gpu, fallback\n", __FUNCTION__));
3322		assert(priv->gpu_bo == NULL);
3323		goto use_cpu_bo;
3324	}
3325
3326done:
3327	assert(priv->gpu_bo != NULL);
3328	assert(priv->gpu_bo->refcnt);
3329	if (sna_damage_is_all(&priv->gpu_damage,
3330			      pixmap->drawable.width,
3331			      pixmap->drawable.height)) {
3332		sna_damage_destroy(&priv->cpu_damage);
3333		list_del(&priv->flush_list);
3334		*damage = NULL;
3335	} else
3336		*damage = &priv->gpu_damage;
3337
3338	DBG(("%s: using GPU bo with damage? %d\n",
3339	     __FUNCTION__, *damage != NULL));
3340	assert(*damage == NULL || !DAMAGE_IS_ALL(*damage));
3341	assert(priv->gpu_bo->proxy == NULL);
3342	assert(priv->clear == false);
3343	assert(priv->cpu == false);
3344	return priv->gpu_bo;
3345
3346use_gpu_bo:
3347	DBG(("%s: using whole GPU bo\n", __FUNCTION__));
3348	assert(priv->gpu_bo != NULL);
3349	assert(priv->gpu_bo->refcnt);
3350	assert(priv->gpu_bo->proxy == NULL);
3351	assert(priv->gpu_damage);
3352	priv->clear = false;
3353	priv->cpu = false;
3354	*damage = NULL;
3355	return priv->gpu_bo;
3356
3357use_cpu_bo:
3358	if (!USE_CPU_BO || priv->cpu_bo == NULL) {
3359cpu_fail:
3360		if ((flags & FORCE_GPU) && priv->gpu_bo) {
3361			region.extents = *box;
3362			if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3363				region.extents.x1 += dx;
3364				region.extents.x2 += dx;
3365				region.extents.y1 += dy;
3366				region.extents.y2 += dy;
3367			}
3368			region.data = NULL;
3369
3370			goto move_to_gpu;
3371		}
3372
3373		return NULL;
3374	}
3375
3376	assert(priv->cpu_bo->refcnt);
3377
3378	sna = to_sna_from_pixmap(pixmap);
3379	if ((flags & FORCE_GPU) == 0 &&
3380	    !__kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
3381		DBG(("%s: has CPU bo, but is idle and acceleration not forced\n",
3382		     __FUNCTION__));
3383		return NULL;
3384	}
3385
3386
3387	region.extents = *box;
3388	if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
3389		region.extents.x1 += dx;
3390		region.extents.x2 += dx;
3391		region.extents.y1 += dy;
3392		region.extents.y2 += dy;
3393	}
3394	region.data = NULL;
3395
3396	/* Both CPU and GPU are busy, prefer to use the GPU */
3397	if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo))
3398		goto move_to_gpu;
3399
3400	assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL);
3401
3402	if (flags & RENDER_GPU) {
3403		if (priv->gpu_bo && priv->gpu_bo->tiling)
3404			goto move_to_gpu;
3405
3406		if (priv->cpu_bo->pitch >= 4096)
3407			goto move_to_gpu;
3408
3409		if (!sna->kgem.can_blt_cpu)
3410			goto move_to_gpu;
3411	}
3412
3413	if (!sna->kgem.can_blt_cpu)
3414		goto cpu_fail;
3415
3416	if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, &region,
3417					     (flags & IGNORE_CPU ? MOVE_READ : 0) | MOVE_WRITE | MOVE_ASYNC_HINT)) {
3418		DBG(("%s: failed to move-to-cpu, fallback\n", __FUNCTION__));
3419		goto cpu_fail;
3420	}
3421
3422	if (priv->shm) {
3423		assert(!priv->flush);
3424		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
3425
3426		/* As we may have flushed and retired,, recheck for busy bo */
3427		if ((flags & FORCE_GPU) == 0 && !kgem_bo_is_busy(priv->cpu_bo))
3428			return NULL;
3429	}
3430	if (priv->flush) {
3431		assert(!priv->shm);
3432		sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
3433	}
3434
3435	if (sna_damage_is_all(&priv->cpu_damage,
3436			      pixmap->drawable.width,
3437			      pixmap->drawable.height)) {
3438		sna_damage_destroy(&priv->gpu_damage);
3439		*damage = NULL;
3440	} else {
3441		if (priv->cpu_damage &&
3442		    sna_damage_contains_box__no_reduce(priv->cpu_damage,
3443						       &region.extents)) {
3444			assert(sna_damage_contains_box(priv->gpu_damage, &region.extents) == PIXMAN_REGION_OUT);
3445			assert(sna_damage_contains_box(priv->cpu_damage, &region.extents) == PIXMAN_REGION_IN);
3446			*damage = NULL;
3447		} else
3448			*damage = &priv->cpu_damage;
3449	}
3450
3451	DBG(("%s: using CPU bo with damage? %d\n",
3452	     __FUNCTION__, *damage != NULL));
3453	assert(damage == NULL || !DAMAGE_IS_ALL(*damage));
3454	assert(priv->clear == false);
3455	return priv->cpu_bo;
3456}
3457
3458PixmapPtr
3459sna_pixmap_create_upload(ScreenPtr screen,
3460			 int width, int height, int depth,
3461			 unsigned flags)
3462{
3463	struct sna *sna = to_sna_from_screen(screen);
3464	PixmapPtr pixmap;
3465	struct sna_pixmap *priv;
3466	void *ptr;
3467
3468	DBG(("%s(%d, %d, %d, flags=%x)\n", __FUNCTION__,
3469	     width, height, depth, flags));
3470	assert(width);
3471	assert(height);
3472
3473	if (depth == 1)
3474		return create_pixmap(sna, screen, width, height, depth,
3475				     CREATE_PIXMAP_USAGE_SCRATCH);
3476
3477	if (sna->freed_pixmap) {
3478		pixmap = sna->freed_pixmap;
3479		sna->freed_pixmap = pixmap->devPrivate.ptr;
3480
3481		pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
3482		pixmap->refcnt = 1;
3483	} else {
3484		pixmap = create_pixmap(sna, screen, 0, 0, depth, 0);
3485		if (!pixmap)
3486			return NullPixmap;
3487
3488		priv = malloc(sizeof(*priv));
3489		if (!priv) {
3490			FreePixmap(pixmap);
3491			return NullPixmap;
3492		}
3493
3494		sna_set_pixmap(pixmap, priv);
3495	}
3496
3497	pixmap->drawable.width = width;
3498	pixmap->drawable.height = height;
3499	pixmap->drawable.depth = depth;
3500	pixmap->drawable.bitsPerPixel = bits_per_pixel(depth);
3501
3502	priv = _sna_pixmap_reset(pixmap);
3503	priv->header = true;
3504
3505	priv->gpu_bo = kgem_create_buffer_2d(&sna->kgem,
3506					     width, height,
3507					     pixmap->drawable.bitsPerPixel,
3508					     flags, &ptr);
3509	if (!priv->gpu_bo) {
3510		free(priv);
3511		FreePixmap(pixmap);
3512		return NullPixmap;
3513	}
3514	priv->mapped = true;
3515
3516	/* Marking both the shadow and the GPU bo is a little dubious,
3517	 * but will work so long as we always check before doing the
3518	 * transfer.
3519	 */
3520	sna_damage_all(&priv->gpu_damage, width, height);
3521	sna_damage_all(&priv->cpu_damage, width, height);
3522
3523	pixmap->devKind = priv->gpu_bo->pitch;
3524	pixmap->devPrivate.ptr = ptr;
3525
3526	pixmap->usage_hint = 0;
3527	if (!kgem_buffer_is_inplace(priv->gpu_bo))
3528		pixmap->usage_hint = 1;
3529
3530	DBG(("%s: serial=%ld, usage=%d\n",
3531	     __FUNCTION__,
3532	     pixmap->drawable.serialNumber,
3533	     pixmap->usage_hint));
3534
3535	return pixmap;
3536}
3537
3538struct sna_pixmap *
3539sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
3540{
3541	struct sna *sna = to_sna_from_pixmap(pixmap);
3542	struct sna_pixmap *priv;
3543	BoxPtr box;
3544	int n;
3545
3546	DBG(("%s(pixmap=%ld, usage=%d), flags=%x\n",
3547	     __FUNCTION__,
3548	     pixmap->drawable.serialNumber,
3549	     pixmap->usage_hint,
3550	     flags));
3551
3552	if ((flags & __MOVE_FORCE) == 0 && wedged(sna))
3553		return NULL;
3554
3555	priv = sna_pixmap(pixmap);
3556	if (priv == NULL) {
3557		DBG(("%s: not attached\n", __FUNCTION__));
3558		if ((flags & __MOVE_DRI) == 0)
3559			return NULL;
3560
3561		DBG(("%s: forcing the creation on the GPU\n", __FUNCTION__));
3562
3563		priv = sna_pixmap_attach(pixmap);
3564		if (priv == NULL)
3565			return NULL;
3566
3567		sna_damage_all(&priv->cpu_damage,
3568			       pixmap->drawable.width,
3569			       pixmap->drawable.height);
3570
3571		assert(priv->gpu_bo == NULL);
3572		assert(priv->gpu_damage == NULL);
3573	}
3574
3575	assert(priv->gpu_damage == NULL || priv->gpu_bo);
3576
3577	if ((flags & MOVE_READ) == 0 && UNDO) {
3578		if (priv->gpu_bo)
3579			kgem_bo_undo(&sna->kgem, priv->gpu_bo);
3580		if (priv->cpu_bo)
3581			kgem_bo_undo(&sna->kgem, priv->cpu_bo);
3582	}
3583
3584	if (priv->cow && (flags & MOVE_WRITE || priv->cpu_damage)) {
3585		if (!sna_pixmap_undo_cow(sna, priv, flags & MOVE_READ))
3586			return false;
3587
3588		if (priv->gpu_bo == NULL)
3589			sna_damage_destroy(&priv->gpu_damage);
3590	}
3591
3592	if (sna_damage_is_all(&priv->gpu_damage,
3593			      pixmap->drawable.width,
3594			      pixmap->drawable.height)) {
3595		DBG(("%s: already all-damaged\n", __FUNCTION__));
3596		assert(priv->gpu_bo);
3597		assert(priv->gpu_bo->proxy == NULL);
3598		assert(priv->cpu == false || (priv->mapped && IS_CPU_MAP(priv->gpu_bo->map)));
3599		sna_damage_destroy(&priv->cpu_damage);
3600		list_del(&priv->flush_list);
3601		goto active;
3602	}
3603
3604	if (flags & MOVE_WRITE && priv->gpu_bo && priv->gpu_bo->proxy) {
3605		DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
3606		assert(priv->gpu_damage == NULL);
3607		assert(!priv->pinned);
3608		kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
3609		priv->gpu_bo = NULL;
3610	}
3611
3612	if ((flags & MOVE_READ) == 0)
3613		sna_damage_destroy(&priv->cpu_damage);
3614
3615	sna_damage_reduce(&priv->cpu_damage);
3616	assert_pixmap_damage(pixmap);
3617	DBG(("%s: CPU damage? %d\n", __FUNCTION__, priv->cpu_damage != NULL));
3618	if (priv->gpu_bo == NULL) {
3619		DBG(("%s: creating GPU bo (%dx%d@%d), create=%x\n",
3620		     __FUNCTION__,
3621		     pixmap->drawable.width,
3622		     pixmap->drawable.height,
3623		     pixmap->drawable.bitsPerPixel,
3624		     priv->create));
3625		assert(!priv->mapped);
3626		if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU) {
3627			unsigned create, tiling;
3628
3629			assert(pixmap->drawable.width > 0);
3630			assert(pixmap->drawable.height > 0);
3631			assert(pixmap->drawable.bitsPerPixel >= 8);
3632
3633			tiling = (flags & MOVE_SOURCE_HINT) ? I915_TILING_Y : DEFAULT_TILING;
3634			tiling = sna_pixmap_choose_tiling(pixmap, tiling);
3635
3636			create = 0;
3637			if (flags & MOVE_INPLACE_HINT || (priv->cpu_damage && priv->cpu_bo == NULL))
3638				create = CREATE_GTT_MAP | CREATE_INACTIVE;
3639			if (pixmap->usage_hint == SNA_CREATE_FB)
3640				create |= CREATE_SCANOUT;
3641
3642			priv->gpu_bo =
3643				kgem_create_2d(&sna->kgem,
3644					       pixmap->drawable.width,
3645					       pixmap->drawable.height,
3646					       pixmap->drawable.bitsPerPixel,
3647					       tiling, create);
3648		}
3649		if (priv->gpu_bo == NULL) {
3650			DBG(("%s: not creating GPU bo\n", __FUNCTION__));
3651			assert(priv->gpu_damage == NULL);
3652			return NULL;
3653		}
3654
3655		if (flags & MOVE_WRITE && priv->cpu_damage == NULL) {
3656			/* Presume that we will only ever write to the GPU
3657			 * bo. Readbacks are expensive but fairly constant
3658			 * in cost for all sizes i.e. it is the act of
3659			 * synchronisation that takes the most time. This is
3660			 * mitigated by avoiding fallbacks in the first place.
3661			 */
3662			assert(priv->gpu_bo);
3663			assert(priv->gpu_bo->proxy == NULL);
3664			sna_damage_all(&priv->gpu_damage,
3665				       pixmap->drawable.width,
3666				       pixmap->drawable.height);
3667			DBG(("%s: marking as all-damaged for GPU\n",
3668			     __FUNCTION__));
3669			goto active;
3670		}
3671	}
3672
3673	if (priv->gpu_bo->proxy) {
3674		DBG(("%s: reusing cached upload\n", __FUNCTION__));
3675		assert((flags & MOVE_WRITE) == 0);
3676		assert(priv->gpu_damage == NULL);
3677		return priv;
3678	}
3679
3680	if (priv->cpu_damage == NULL)
3681		goto done;
3682
3683	if (priv->shm) {
3684		assert(!priv->flush);
3685		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
3686	}
3687
3688	n = sna_damage_get_boxes(priv->cpu_damage, &box);
3689	if (n) {
3690		bool ok;
3691
3692		assert(pixmap_contains_damage(pixmap, priv->cpu_damage));
3693		DBG(("%s: uploading %d damage boxes\n", __FUNCTION__, n));
3694
3695		ok = false;
3696		if (use_cpu_bo_for_upload(sna, priv, flags)) {
3697			DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__));
3698			ok = sna->render.copy_boxes(sna, GXcopy,
3699						    pixmap, priv->cpu_bo, 0, 0,
3700						    pixmap, priv->gpu_bo, 0, 0,
3701						    box, n, 0);
3702		}
3703		if (!ok) {
3704			if (priv->mapped) {
3705				assert(priv->stride && priv->stride);
3706				pixmap->devPrivate.ptr = PTR(priv->ptr);
3707				pixmap->devKind = priv->stride;
3708				priv->mapped = false;
3709			}
3710			if (pixmap->devPrivate.ptr == NULL) {
3711				assert(priv->ptr && priv->stride);
3712				pixmap->devPrivate.ptr = PTR(priv->ptr);
3713				pixmap->devKind = priv->stride;
3714			}
3715			if (n == 1 && !priv->pinned &&
3716			    (box->x2 - box->x1) >= pixmap->drawable.width &&
3717			    (box->y2 - box->y1) >= pixmap->drawable.height) {
3718				ok = sna_replace(sna, pixmap,
3719						 &priv->gpu_bo,
3720						 pixmap->devPrivate.ptr,
3721						 pixmap->devKind);
3722			} else {
3723				ok = sna_write_boxes(sna, pixmap,
3724						     priv->gpu_bo, 0, 0,
3725						     pixmap->devPrivate.ptr,
3726						     pixmap->devKind,
3727						     0, 0,
3728						     box, n);
3729			}
3730			if (!ok)
3731				return NULL;
3732		}
3733	}
3734
3735	__sna_damage_destroy(DAMAGE_PTR(priv->cpu_damage));
3736	priv->cpu_damage = NULL;
3737
3738	/* For large bo, try to keep only a single copy around */
3739	if (priv->create & KGEM_CAN_CREATE_LARGE || flags & MOVE_SOURCE_HINT) {
3740		DBG(("%s: disposing of system copy for large/source\n",
3741		     __FUNCTION__));
3742		assert(!priv->shm);
3743		assert(priv->gpu_bo);
3744		assert(priv->gpu_bo->proxy == NULL);
3745		sna_damage_all(&priv->gpu_damage,
3746			       pixmap->drawable.width,
3747			       pixmap->drawable.height);
3748		sna_pixmap_free_cpu(sna, priv);
3749	}
3750done:
3751	list_del(&priv->flush_list);
3752
3753	sna_damage_reduce_all(&priv->gpu_damage,
3754			      pixmap->drawable.width,
3755			      pixmap->drawable.height);
3756	if (DAMAGE_IS_ALL(priv->gpu_damage))
3757		sna_pixmap_free_cpu(sna, priv);
3758
3759active:
3760	if (flags & MOVE_WRITE)
3761		priv->clear = false;
3762	priv->cpu = false;
3763	assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0);
3764	return sna_pixmap_mark_active(sna, priv);
3765}
3766
3767static bool must_check sna_validate_pixmap(DrawablePtr draw, PixmapPtr pixmap)
3768{
3769	if (draw->bitsPerPixel == pixmap->drawable.bitsPerPixel &&
3770	    FbEvenTile(pixmap->drawable.width *
3771		       pixmap->drawable.bitsPerPixel)) {
3772		DBG(("%s: flushing pixmap\n", __FUNCTION__));
3773		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
3774			return false;
3775
3776		fbPadPixmap(pixmap);
3777	}
3778
3779	return true;
3780}
3781
3782static bool must_check sna_gc_move_to_cpu(GCPtr gc,
3783					  DrawablePtr drawable,
3784					  RegionPtr region)
3785{
3786	struct sna_gc *sgc = sna_gc(gc);
3787	long changes = sgc->changes;
3788
3789	DBG(("%s, changes=%lx\n", __FUNCTION__, changes));
3790
3791	assert(gc->ops == (GCOps *)&sna_gc_ops);
3792	gc->ops = (GCOps *)&sna_gc_ops__cpu;
3793
3794	sgc->old_funcs = gc->funcs;
3795	gc->funcs = (GCFuncs *)&sna_gc_funcs__cpu;
3796
3797	sgc->priv = gc->pCompositeClip;
3798	gc->pCompositeClip = region;
3799
3800	if (gc->clientClipType == CT_PIXMAP) {
3801		PixmapPtr clip = gc->clientClip;
3802		gc->clientClip = region_from_bitmap(gc->pScreen, clip);
3803		gc->pScreen->DestroyPixmap(clip);
3804		gc->clientClipType = gc->clientClip ? CT_REGION : CT_NONE;
3805		changes |= GCClipMask;
3806	} else
3807		changes &= ~GCClipMask;
3808
3809	if (changes || drawable->serialNumber != sgc->serial) {
3810		gc->serialNumber = sgc->serial;
3811
3812		if (fb_gc(gc)->bpp != drawable->bitsPerPixel) {
3813			changes |= GCStipple | GCForeground | GCBackground | GCPlaneMask;
3814			fb_gc(gc)->bpp = drawable->bitsPerPixel;
3815		}
3816
3817		if (changes & GCTile && !gc->tileIsPixel) {
3818			DBG(("%s: flushing tile pixmap\n", __FUNCTION__));
3819			if (!sna_validate_pixmap(drawable, gc->tile.pixmap))
3820				return false;
3821		}
3822
3823		if (changes & GCStipple && gc->stipple) {
3824			DBG(("%s: flushing stipple pixmap\n", __FUNCTION__));
3825			if (!sna_validate_pixmap(drawable, gc->stipple))
3826				return false;
3827		}
3828
3829		fbValidateGC(gc, changes, drawable);
3830
3831		gc->serialNumber = drawable->serialNumber;
3832		sgc->serial = drawable->serialNumber;
3833	}
3834	sgc->changes = 0;
3835
3836	switch (gc->fillStyle) {
3837	case FillTiled:
3838		return sna_drawable_move_to_cpu(&gc->tile.pixmap->drawable, MOVE_READ);
3839	case FillStippled:
3840	case FillOpaqueStippled:
3841		return sna_drawable_move_to_cpu(&gc->stipple->drawable, MOVE_READ);
3842	default:
3843		return true;
3844	}
3845}
3846
3847static void sna_gc_move_to_gpu(GCPtr gc)
3848{
3849	assert(gc->ops == (GCOps *)&sna_gc_ops__cpu);
3850	assert(gc->funcs == (GCFuncs *)&sna_gc_funcs__cpu);
3851
3852	gc->ops = (GCOps *)&sna_gc_ops;
3853	gc->funcs = sna_gc(gc)->old_funcs;
3854	gc->pCompositeClip = sna_gc(gc)->priv;
3855}
3856
3857static inline bool clip_box(BoxPtr box, GCPtr gc)
3858{
3859	const BoxRec *clip;
3860	bool clipped;
3861
3862	clip = &gc->pCompositeClip->extents;
3863
3864	clipped = !region_is_singular(gc->pCompositeClip);
3865	if (box->x1 < clip->x1)
3866		box->x1 = clip->x1, clipped = true;
3867	if (box->x2 > clip->x2)
3868		box->x2 = clip->x2, clipped = true;
3869
3870	if (box->y1 < clip->y1)
3871		box->y1 = clip->y1, clipped = true;
3872	if (box->y2 > clip->y2)
3873		box->y2 = clip->y2, clipped = true;
3874
3875	return clipped;
3876}
3877
3878static inline void translate_box(BoxPtr box, DrawablePtr d)
3879{
3880	box->x1 += d->x;
3881	box->x2 += d->x;
3882
3883	box->y1 += d->y;
3884	box->y2 += d->y;
3885}
3886
3887static inline bool trim_and_translate_box(BoxPtr box, DrawablePtr d, GCPtr gc)
3888{
3889	translate_box(box, d);
3890	return clip_box(box, gc);
3891}
3892
3893static inline bool box32_clip(Box32Rec *box, GCPtr gc)
3894{
3895	bool clipped = !region_is_singular(gc->pCompositeClip);
3896	const BoxRec *clip = &gc->pCompositeClip->extents;
3897
3898	if (box->x1 < clip->x1)
3899		box->x1 = clip->x1, clipped = true;
3900	if (box->x2 > clip->x2)
3901		box->x2 = clip->x2, clipped = true;
3902
3903	if (box->y1 < clip->y1)
3904		box->y1 = clip->y1, clipped = true;
3905	if (box->y2 > clip->y2)
3906		box->y2 = clip->y2, clipped = true;
3907
3908	return clipped;
3909}
3910
3911static inline void box32_translate(Box32Rec *box, DrawablePtr d)
3912{
3913	box->x1 += d->x;
3914	box->x2 += d->x;
3915
3916	box->y1 += d->y;
3917	box->y2 += d->y;
3918}
3919
3920static inline bool box32_trim_and_translate(Box32Rec *box, DrawablePtr d, GCPtr gc)
3921{
3922	box32_translate(box, d);
3923	return box32_clip(box, gc);
3924}
3925
3926static inline void box_add_pt(BoxPtr box, int16_t x, int16_t y)
3927{
3928	if (box->x1 > x)
3929		box->x1 = x;
3930	else if (box->x2 < x)
3931		box->x2 = x;
3932
3933	if (box->y1 > y)
3934		box->y1 = y;
3935	else if (box->y2 < y)
3936		box->y2 = y;
3937}
3938
3939static inline bool box32_to_box16(const Box32Rec *b32, BoxRec *b16)
3940{
3941	b16->x1 = b32->x1;
3942	b16->y1 = b32->y1;
3943	b16->x2 = b32->x2;
3944	b16->y2 = b32->y2;
3945
3946	return b16->x2 > b16->x1 && b16->y2 > b16->y1;
3947}
3948
3949static inline void box32_add_rect(Box32Rec *box, const xRectangle *r)
3950{
3951	int32_t v;
3952
3953	v = r->x;
3954	if (box->x1 > v)
3955		box->x1 = v;
3956	v += r->width;
3957	if (box->x2 < v)
3958		box->x2 = v;
3959
3960	v = r->y;
3961	if (box->y1 > v)
3962		box->y1 = v;
3963	v += r->height;
3964	if (box->y2 < v)
3965		box->y2 = v;
3966}
3967
3968static bool
3969create_upload_tiled_x(struct kgem *kgem,
3970		      PixmapPtr pixmap,
3971		      struct sna_pixmap *priv)
3972{
3973	unsigned create, tiling;
3974
3975	if (priv->shm || priv->cpu)
3976		return false;
3977
3978	if ((priv->create & KGEM_CAN_CREATE_GPU) == 0)
3979		return false;
3980
3981	tiling = sna_pixmap_choose_tiling(pixmap, I915_TILING_X);
3982	assert(tiling != I915_TILING_Y && tiling != -I915_TILING_Y);
3983
3984	assert(priv->gpu_bo == NULL);
3985	assert(priv->gpu_damage == NULL);
3986
3987	create = CREATE_CPU_MAP | CREATE_INACTIVE;
3988	if (pixmap->usage_hint == SNA_CREATE_FB)
3989		create |= CREATE_SCANOUT;
3990	if (!kgem->has_llc)
3991		create |= CREATE_CACHED;
3992
3993	priv->gpu_bo =
3994		kgem_create_2d(kgem,
3995			       pixmap->drawable.width,
3996			       pixmap->drawable.height,
3997			       pixmap->drawable.bitsPerPixel,
3998			       tiling, create);
3999	return priv->gpu_bo != NULL;
4000}
4001
4002static bool
4003try_upload_blt(PixmapPtr pixmap, RegionRec *region,
4004		int x, int y, int w, int  h, char *bits, int stride)
4005{
4006	struct sna *sna = to_sna_from_pixmap(pixmap);
4007	struct sna_pixmap *priv;
4008	struct kgem_bo *src_bo;
4009	bool ok;
4010
4011	if (!sna->kgem.has_userptr || !USE_USERPTR_UPLOADS)
4012		return false;
4013
4014	priv = sna_pixmap(pixmap);
4015	if (priv == NULL)
4016		return false;
4017
4018	if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL)
4019		return false;
4020
4021	assert(priv->gpu_bo);
4022	assert(priv->gpu_bo->proxy == NULL);
4023
4024	if (priv->cow || !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
4025		return false;
4026
4027	if (priv->cpu_damage &&
4028	    sna_damage_contains_box__no_reduce(priv->cpu_damage,
4029					       &region->extents) &&
4030	    !box_inplace(pixmap, &region->extents))
4031		return false;
4032
4033	src_bo = kgem_create_map(&sna->kgem, bits, stride * h, true);
4034	if (src_bo == NULL)
4035		return false;
4036
4037	src_bo->pitch = stride;
4038	kgem_bo_mark_unreusable(src_bo);
4039
4040	DBG(("%s: upload(%d, %d, %d, %d) x %d through a temporary map\n",
4041	     __FUNCTION__, x, y, w, h,
4042	     RegionNumRects(region)));
4043
4044	ok = sna->render.copy_boxes(sna, GXcopy,
4045				    pixmap, src_bo, -x, -y,
4046				    pixmap, priv->gpu_bo, 0, 0,
4047				    RegionRects(region),
4048				    RegionNumRects(region),
4049				    COPY_LAST);
4050
4051	kgem_bo_sync__cpu(&sna->kgem, src_bo);
4052	assert(src_bo->rq == NULL);
4053	kgem_bo_destroy(&sna->kgem, src_bo);
4054
4055	if (!ok)
4056		return false;
4057
4058	if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
4059		assert(!priv->clear);
4060		if (region->data == NULL &&
4061		    w >= pixmap->drawable.width &&
4062		    h >= pixmap->drawable.height) {
4063			sna_damage_all(&priv->gpu_damage,
4064				       pixmap->drawable.width,
4065				       pixmap->drawable.height);
4066		} else {
4067			sna_damage_add(&priv->gpu_damage, region);
4068			sna_damage_reduce_all(&priv->gpu_damage,
4069					      pixmap->drawable.width,
4070					      pixmap->drawable.height);
4071		}
4072		if (DAMAGE_IS_ALL(priv->gpu_damage)) {
4073			list_del(&priv->flush_list);
4074			sna_damage_destroy(&priv->cpu_damage);
4075			sna_pixmap_free_cpu(sna, priv);
4076		}
4077	}
4078
4079	return true;
4080}
4081
4082static bool
4083try_upload_tiled_x(PixmapPtr pixmap, RegionRec *region,
4084		   int x, int y, int w, int  h, char *bits, int stride)
4085{
4086	struct sna *sna = to_sna_from_pixmap(pixmap);
4087	struct sna_pixmap *priv = sna_pixmap(pixmap);
4088	bool replaces;
4089	BoxRec *box;
4090	uint8_t *dst;
4091	int n;
4092
4093	if (wedged(sna))
4094		return false;
4095
4096	DBG(("%s: bo? %d, can map? %d\n", __FUNCTION__,
4097	     priv->gpu_bo != NULL,
4098	     priv->gpu_bo ? kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true) : 0));
4099
4100	replaces = region->data == NULL &&
4101		w >= pixmap->drawable.width &&
4102		h >= pixmap->drawable.height;
4103
4104	if (priv->gpu_bo && (replaces || priv->gpu_bo->proxy)) {
4105		DBG(("%s: discarding cached upload proxy\n", __FUNCTION__));
4106		sna_pixmap_free_gpu(sna, priv);
4107	}
4108
4109	if (priv->cow) {
4110		DBG(("%s: no, has COW\n", __FUNCTION__));
4111		return false;
4112	}
4113
4114	if (priv->gpu_bo == NULL &&
4115	    !create_upload_tiled_x(&sna->kgem, pixmap, priv))
4116		return false;
4117
4118	DBG(("%s: tiling=%d\n", __FUNCTION__, priv->gpu_bo->tiling));
4119	switch (priv->gpu_bo->tiling) {
4120	case I915_TILING_Y:
4121		return false;
4122	case I915_TILING_X:
4123		if (!sna->kgem.memcpy_to_tiled_x)
4124			return false;
4125	default:
4126		break;
4127	}
4128
4129	if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo,
4130				  (priv->create & KGEM_CAN_CREATE_LARGE) == 0)) {
4131		DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__));
4132		return false;
4133	}
4134
4135	if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 &&
4136	    __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
4137		return false;
4138
4139	dst = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
4140	if (dst == NULL)
4141		return false;
4142
4143	kgem_bo_sync__cpu(&sna->kgem, priv->gpu_bo);
4144
4145	box = RegionRects(region);
4146	n = RegionNumRects(region);
4147
4148	DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n));
4149
4150	if (priv->gpu_bo->tiling) {
4151		do {
4152			memcpy_to_tiled_x(&sna->kgem, bits, dst,
4153					  pixmap->drawable.bitsPerPixel,
4154					  stride, priv->gpu_bo->pitch,
4155					  box->x1 - x, box->y1 - y,
4156					  box->x1, box->y1,
4157					  box->x2 - box->x1, box->y2 - box->y1);
4158			box++;
4159		} while (--n);
4160	} else {
4161		do {
4162			memcpy_blt(bits, dst,
4163				   pixmap->drawable.bitsPerPixel,
4164				   stride, priv->gpu_bo->pitch,
4165				   box->x1 - x, box->y1 - y,
4166				   box->x1, box->y1,
4167				   box->x2 - box->x1, box->y2 - box->y1);
4168			box++;
4169		} while (--n);
4170	}
4171
4172	if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
4173		assert(!priv->clear);
4174		if (replaces) {
4175			sna_damage_all(&priv->gpu_damage,
4176					pixmap->drawable.width,
4177					pixmap->drawable.height);
4178		} else {
4179			sna_damage_add(&priv->gpu_damage, region);
4180			sna_damage_reduce_all(&priv->gpu_damage,
4181					pixmap->drawable.width,
4182					pixmap->drawable.height);
4183		}
4184		if (DAMAGE_IS_ALL(priv->gpu_damage)) {
4185			list_del(&priv->flush_list);
4186			sna_damage_destroy(&priv->cpu_damage);
4187			sna_pixmap_free_cpu(sna, priv);
4188		}
4189	}
4190	if (priv->cpu_damage)
4191		sna_damage_subtract(&priv->cpu_damage, region);
4192
4193	if (priv->mapped) {
4194		assert(!priv->shm);
4195		priv->pixmap->devPrivate.ptr = NULL;
4196		priv->mapped = false;
4197	}
4198
4199	priv->clear = false;
4200	priv->cpu = false;
4201	return true;
4202}
4203
4204static bool
4205sna_put_zpixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
4206		    int x, int y, int w, int  h, char *bits, int stride)
4207{
4208	PixmapPtr pixmap = get_drawable_pixmap(drawable);
4209	BoxRec *box;
4210	int16_t dx, dy;
4211	int n;
4212
4213	assert_pixmap_contains_box(pixmap, RegionExtents(region));
4214
4215	if (gc->alu != GXcopy)
4216		return false;
4217
4218	if (drawable->depth < 8)
4219		return false;
4220
4221	get_drawable_deltas(drawable, pixmap, &dx, &dy);
4222	x += dx + drawable->x;
4223	y += dy + drawable->y;
4224
4225	if (try_upload_blt(pixmap, region, x, y, w, h, bits, stride))
4226		return true;
4227
4228	if (try_upload_tiled_x(pixmap, region, x, y, w, h, bits, stride))
4229		return true;
4230
4231	if (!sna_drawable_move_region_to_cpu(&pixmap->drawable,
4232					     region, MOVE_WRITE))
4233		return false;
4234
4235	DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h));
4236
4237	/* Region is pre-clipped and translated into pixmap space */
4238	box = RegionRects(region);
4239	n = RegionNumRects(region);
4240	do {
4241		DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n",
4242		     __FUNCTION__,
4243		     box->x1 - x, box->y1 - y,
4244		     box->x1, box->y1,
4245		     box->x2 - box->x1, box->y2 - box->y1));
4246
4247		assert(box->x2 > box->x1);
4248		assert(box->y2 > box->y1);
4249
4250		assert(box->x1 >= 0);
4251		assert(box->y1 >= 0);
4252		assert(box->x2 <= pixmap->drawable.width);
4253		assert(box->y2 <= pixmap->drawable.height);
4254
4255		assert(box->x1 - x >= 0);
4256		assert(box->y1 - y >= 0);
4257		assert(box->x2 - x <= w);
4258		assert(box->y2 - y <= h);
4259
4260		assert(has_coherent_ptr(sna_pixmap(pixmap)));
4261		memcpy_blt(bits, pixmap->devPrivate.ptr,
4262			   pixmap->drawable.bitsPerPixel,
4263			   stride, pixmap->devKind,
4264			   box->x1 - x, box->y1 - y,
4265			   box->x1, box->y1,
4266			   box->x2 - box->x1, box->y2 - box->y1);
4267		box++;
4268	} while (--n);
4269
4270	assert_pixmap_damage(pixmap);
4271	return true;
4272}
4273
4274static inline uint8_t byte_reverse(uint8_t b)
4275{
4276	return ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
4277}
4278
4279static inline uint8_t blt_depth(int depth)
4280{
4281	switch (depth) {
4282	case 8: return 0;
4283	case 15: return 0x2;
4284	case 16: return 0x1;
4285	default: return 0x3;
4286	}
4287}
4288
4289static bool
4290sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
4291		     int x, int y, int w, int  h, char *bits)
4292{
4293	PixmapPtr pixmap = get_drawable_pixmap(drawable);
4294	struct sna *sna = to_sna_from_pixmap(pixmap);
4295	struct sna_damage **damage;
4296	struct kgem_bo *bo;
4297	BoxRec *box;
4298	int16_t dx, dy;
4299	int n;
4300	uint8_t rop = copy_ROP[gc->alu];
4301
4302	bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU,
4303				 &region->extents, &damage);
4304	if (bo == NULL)
4305		return false;
4306
4307	if (bo->tiling == I915_TILING_Y) {
4308		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
4309		assert(bo == __sna_pixmap_get_bo(pixmap));
4310		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
4311		if (bo == NULL) {
4312			DBG(("%s: fallback -- unable to change tiling\n",
4313			     __FUNCTION__));
4314			return false;
4315		}
4316	}
4317
4318	assert_pixmap_contains_box(pixmap, RegionExtents(region));
4319	if (damage)
4320		sna_damage_add(damage, region);
4321	assert_pixmap_damage(pixmap);
4322
4323	DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h));
4324
4325	get_drawable_deltas(drawable, pixmap, &dx, &dy);
4326	x += dx + drawable->x;
4327	y += dy + drawable->y;
4328
4329	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
4330
4331	/* Region is pre-clipped and translated into pixmap space */
4332	box = RegionRects(region);
4333	n = RegionNumRects(region);
4334	do {
4335		int bx1 = (box->x1 - x) & ~7;
4336		int bx2 = (box->x2 - x + 7) & ~7;
4337		int bw = (bx2 - bx1)/8;
4338		int bh = box->y2 - box->y1;
4339		int bstride = ALIGN(bw, 2);
4340		int src_stride;
4341		uint8_t *dst, *src;
4342		uint32_t *b;
4343		struct kgem_bo *upload;
4344		void *ptr;
4345
4346		if (!kgem_check_batch(&sna->kgem, 8) ||
4347		    !kgem_check_bo_fenced(&sna->kgem, bo) ||
4348		    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
4349			kgem_submit(&sna->kgem);
4350			if (!kgem_check_bo_fenced(&sna->kgem, bo))
4351				return false;
4352			_kgem_set_mode(&sna->kgem, KGEM_BLT);
4353		}
4354
4355		upload = kgem_create_buffer(&sna->kgem,
4356					    bstride*bh,
4357					    KGEM_BUFFER_WRITE_INPLACE,
4358					    &ptr);
4359		if (!upload)
4360			break;
4361
4362		dst = ptr;
4363		bstride -= bw;
4364
4365		src_stride = BitmapBytePad(w);
4366		src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8;
4367		src_stride -= bw;
4368		do {
4369			int i = bw;
4370			do {
4371				*dst++ = byte_reverse(*src++);
4372			} while (--i);
4373			dst += bstride;
4374			src += src_stride;
4375		} while (--bh);
4376
4377		b = sna->kgem.batch + sna->kgem.nbatch;
4378		b[0] = XY_MONO_SRC_COPY | 3 << 20;
4379		b[0] |= ((box->x1 - x) & 7) << 17;
4380		b[1] = bo->pitch;
4381		if (sna->kgem.gen >= 040 && bo->tiling) {
4382			b[0] |= BLT_DST_TILED;
4383			b[1] >>= 2;
4384		}
4385		b[1] |= blt_depth(drawable->depth) << 24;
4386		b[1] |= rop << 16;
4387		b[2] = box->y1 << 16 | box->x1;
4388		b[3] = box->y2 << 16 | box->x2;
4389		b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
4390				      I915_GEM_DOMAIN_RENDER << 16 |
4391				      I915_GEM_DOMAIN_RENDER |
4392				      KGEM_RELOC_FENCED,
4393				      0);
4394		b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5,
4395				      upload,
4396				      I915_GEM_DOMAIN_RENDER << 16 |
4397				      KGEM_RELOC_FENCED,
4398				      0);
4399		b[6] = gc->bgPixel;
4400		b[7] = gc->fgPixel;
4401
4402		sna->kgem.nbatch += 8;
4403		kgem_bo_destroy(&sna->kgem, upload);
4404
4405		box++;
4406	} while (--n);
4407
4408	sna->blt_state.fill_bo = 0;
4409	return true;
4410}
4411
4412static bool
4413sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
4414		     int x, int y, int w, int  h, int left,char *bits)
4415{
4416	PixmapPtr pixmap = get_drawable_pixmap(drawable);
4417	struct sna *sna = to_sna_from_pixmap(pixmap);
4418	struct sna_damage **damage;
4419	struct kgem_bo *bo;
4420	int16_t dx, dy;
4421	unsigned i, skip;
4422
4423	if (gc->alu != GXcopy)
4424		return false;
4425
4426	bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU,
4427				 &region->extents, &damage);
4428	if (bo == NULL)
4429		return false;
4430
4431	if (bo->tiling == I915_TILING_Y) {
4432		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
4433		assert(bo == __sna_pixmap_get_bo(pixmap));
4434		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
4435		if (bo == NULL) {
4436			DBG(("%s: fallback -- unable to change tiling\n",
4437			     __FUNCTION__));
4438			return false;
4439		}
4440	}
4441
4442	assert_pixmap_contains_box(pixmap, RegionExtents(region));
4443	if (damage)
4444		sna_damage_add(damage, region);
4445	assert_pixmap_damage(pixmap);
4446
4447	DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h));
4448
4449	get_drawable_deltas(drawable, pixmap, &dx, &dy);
4450	x += dx + drawable->x;
4451	y += dy + drawable->y;
4452
4453	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
4454
4455	skip = h * BitmapBytePad(w + left);
4456	for (i = 1 << (gc->depth-1); i; i >>= 1, bits += skip) {
4457		const BoxRec *box = RegionRects(region);
4458		int n = RegionNumRects(region);
4459
4460		if ((gc->planemask & i) == 0)
4461			continue;
4462
4463		/* Region is pre-clipped and translated into pixmap space */
4464		do {
4465			int bx1 = (box->x1 - x) & ~7;
4466			int bx2 = (box->x2 - x + 7) & ~7;
4467			int bw = (bx2 - bx1)/8;
4468			int bh = box->y2 - box->y1;
4469			int bstride = ALIGN(bw, 2);
4470			int src_stride;
4471			uint8_t *dst, *src;
4472			uint32_t *b;
4473			struct kgem_bo *upload;
4474			void *ptr;
4475
4476			if (!kgem_check_batch(&sna->kgem, 12) ||
4477			    !kgem_check_bo_fenced(&sna->kgem, bo) ||
4478			    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
4479				kgem_submit(&sna->kgem);
4480				if (!kgem_check_bo_fenced(&sna->kgem, bo))
4481					return false;
4482				_kgem_set_mode(&sna->kgem, KGEM_BLT);
4483			}
4484
4485			upload = kgem_create_buffer(&sna->kgem,
4486						    bstride*bh,
4487						    KGEM_BUFFER_WRITE_INPLACE,
4488						    &ptr);
4489			if (!upload)
4490				break;
4491
4492			dst = ptr;
4493			bstride -= bw;
4494
4495			src_stride = BitmapBytePad(w);
4496			src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8;
4497			src_stride -= bw;
4498			do {
4499				int j = bw;
4500				do {
4501					*dst++ = byte_reverse(*src++);
4502				} while (--j);
4503				dst += bstride;
4504				src += src_stride;
4505			} while (--bh);
4506
4507			b = sna->kgem.batch + sna->kgem.nbatch;
4508			b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20;
4509			b[0] |= ((box->x1 - x) & 7) << 17;
4510			b[1] = bo->pitch;
4511			if (sna->kgem.gen >= 040 && bo->tiling) {
4512				b[0] |= BLT_DST_TILED;
4513				b[1] >>= 2;
4514			}
4515			b[1] |= 1 << 31; /* solid pattern */
4516			b[1] |= blt_depth(drawable->depth) << 24;
4517			b[1] |= 0xce << 16; /* S or (D and !P) */
4518			b[2] = box->y1 << 16 | box->x1;
4519			b[3] = box->y2 << 16 | box->x2;
4520			b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4,
4521					      bo,
4522					      I915_GEM_DOMAIN_RENDER << 16 |
4523					      I915_GEM_DOMAIN_RENDER |
4524					      KGEM_RELOC_FENCED,
4525					      0);
4526			b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5,
4527					      upload,
4528					      I915_GEM_DOMAIN_RENDER << 16 |
4529					      KGEM_RELOC_FENCED,
4530					      0);
4531			b[6] = 0;
4532			b[7] = i;
4533			b[8] = i;
4534			b[9] = i;
4535			b[10] = -1;
4536			b[11] = -1;
4537
4538			sna->kgem.nbatch += 12;
4539			kgem_bo_destroy(&sna->kgem, upload);
4540
4541			box++;
4542		} while (--n);
4543	}
4544
4545	sna->blt_state.fill_bo = 0;
4546	return true;
4547}
4548
4549static void
4550sna_put_image(DrawablePtr drawable, GCPtr gc, int depth,
4551	      int x, int y, int w, int h, int left, int format,
4552	      char *bits)
4553{
4554	PixmapPtr pixmap = get_drawable_pixmap(drawable);
4555	struct sna *sna = to_sna_from_pixmap(pixmap);
4556	struct sna_pixmap *priv = sna_pixmap(pixmap);
4557	RegionRec region;
4558	int16_t dx, dy;
4559
4560	DBG(("%s((%d, %d)x(%d, %d), depth=%d, format=%d)\n",
4561	     __FUNCTION__, x, y, w, h, depth, format));
4562
4563	if (w == 0 || h == 0)
4564		return;
4565
4566	region.extents.x1 = x + drawable->x;
4567	region.extents.y1 = y + drawable->y;
4568	region.extents.x2 = region.extents.x1 + w;
4569	region.extents.y2 = region.extents.y1 + h;
4570	region.data = NULL;
4571
4572	if (!region_is_singular(gc->pCompositeClip) ||
4573	    gc->pCompositeClip->extents.x1 > region.extents.x1 ||
4574	    gc->pCompositeClip->extents.y1 > region.extents.y1 ||
4575	    gc->pCompositeClip->extents.x2 < region.extents.x2 ||
4576	    gc->pCompositeClip->extents.y2 < region.extents.y2) {
4577		RegionIntersect(&region, &region, gc->pCompositeClip);
4578		if (RegionNil(&region))
4579			return;
4580	}
4581
4582	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
4583		RegionTranslate(&region, dx, dy);
4584
4585	if (priv == NULL) {
4586		DBG(("%s: fallback -- unattached(%d, %d, %d, %d)\n",
4587		     __FUNCTION__, x, y, w, h));
4588		goto fallback;
4589	}
4590
4591	if (FORCE_FALLBACK)
4592		goto fallback;
4593
4594	if (wedged(sna))
4595		goto fallback;
4596
4597	if (!ACCEL_PUT_IMAGE)
4598		goto fallback;
4599
4600	switch (format) {
4601	case ZPixmap:
4602		if (!PM_IS_SOLID(drawable, gc->planemask))
4603			goto fallback;
4604
4605		if (sna_put_zpixmap_blt(drawable, gc, &region,
4606					x, y, w, h,
4607					bits, PixmapBytePad(w, depth)))
4608			return;
4609		break;
4610
4611	case XYBitmap:
4612		if (!PM_IS_SOLID(drawable, gc->planemask))
4613			goto fallback;
4614
4615		if (sna_put_xybitmap_blt(drawable, gc, &region,
4616					 x, y, w, h,
4617					 bits))
4618			return;
4619		break;
4620
4621	case XYPixmap:
4622		if (sna_put_xypixmap_blt(drawable, gc, &region,
4623					 x, y, w, h, left,
4624					 bits))
4625			return;
4626		break;
4627
4628	default:
4629		return;
4630	}
4631
4632fallback:
4633	DBG(("%s: fallback\n", __FUNCTION__));
4634	RegionTranslate(&region, -dx, -dy);
4635
4636	if (!sna_gc_move_to_cpu(gc, drawable, &region))
4637		goto out;
4638	if (!sna_drawable_move_region_to_cpu(drawable, &region,
4639					      format == XYPixmap ?
4640					      MOVE_READ | MOVE_WRITE :
4641					      drawable_gc_flags(drawable, gc, false)))
4642		goto out_gc;
4643
4644	DBG(("%s: fbPutImage(%d, %d, %d, %d)\n",
4645	     __FUNCTION__, x, y, w, h));
4646	fbPutImage(drawable, gc, depth, x, y, w, h, left, format, bits);
4647	FALLBACK_FLUSH(drawable);
4648out_gc:
4649	sna_gc_move_to_gpu(gc);
4650out:
4651	RegionUninit(&region);
4652}
4653
4654static bool
4655source_contains_region(struct sna_damage *damage,
4656		       const RegionRec *region, int16_t dx, int16_t dy)
4657{
4658	BoxRec box;
4659
4660	if (DAMAGE_IS_ALL(damage))
4661		return true;
4662
4663	box = region->extents;
4664	box.x1 += dx;
4665	box.x2 += dx;
4666	box.y1 += dy;
4667	box.y2 += dy;
4668	return sna_damage_contains_box__no_reduce(damage, &box);
4669}
4670
4671static bool
4672move_to_gpu(PixmapPtr pixmap, struct sna_pixmap *priv,
4673	    RegionRec *region, int16_t dx, int16_t dy,
4674	    uint8_t alu, bool dst_is_gpu)
4675{
4676	int w = region->extents.x2 - region->extents.x1;
4677	int h = region->extents.y2 - region->extents.y1;
4678	int count;
4679
4680	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
4681		assert(priv->gpu_bo);
4682		assert(priv->cpu == false || (priv->mapped && IS_CPU_MAP(priv->gpu_bo->map)));
4683		return true;
4684	}
4685
4686	if (dst_is_gpu && priv->cpu_bo && priv->cpu_damage) {
4687		DBG(("%s: can use CPU bo? cpu_damage=%d, gpu_damage=%d, cpu hint=%d\n",
4688		     __FUNCTION__,
4689		     priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0,
4690		     priv->gpu_damage ? DAMAGE_IS_ALL(priv->gpu_damage) ? -1 : 1 : 0,
4691		     priv->cpu));
4692		if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL)
4693			return false;
4694
4695		if (priv->cpu &&
4696		    source_contains_region(priv->cpu_damage, region, dx, dy))
4697			return false;
4698	}
4699
4700	if (priv->gpu_bo) {
4701		DBG(("%s: has gpu bo (cpu damage?=%d, cpu=%d, gpu tiling=%d)\n",
4702		     __FUNCTION__,
4703		     priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0,
4704		     priv->cpu, priv->gpu_bo->tiling));
4705
4706		if (priv->cpu_damage == NULL)
4707			return true;
4708
4709		if (alu != GXcopy)
4710			return true;
4711
4712		if (!priv->cpu)
4713			return true;
4714
4715		if (priv->gpu_bo->tiling)
4716			return true;
4717
4718		RegionTranslate(region, dx, dy);
4719		count = region_subsumes_damage(region, priv->cpu_damage);
4720		RegionTranslate(region, -dx, -dy);
4721		if (count)
4722			return true;
4723	} else {
4724		if ((priv->create & KGEM_CAN_CREATE_GPU) == 0)
4725			return false;
4726		if (priv->shm)
4727			return false;
4728	}
4729
4730	count = priv->source_count++;
4731	if (priv->cpu_bo) {
4732		if (priv->cpu_bo->flush && count > SOURCE_BIAS)
4733			return true;
4734
4735		if (sna_pixmap_choose_tiling(pixmap,
4736					     DEFAULT_TILING) == I915_TILING_NONE)
4737			return false;
4738
4739		if (priv->cpu)
4740			return false;
4741
4742		return count > SOURCE_BIAS;
4743	} else {
4744		if (w == pixmap->drawable.width && h == pixmap->drawable.height)
4745			return count > SOURCE_BIAS;
4746
4747		return count * w*h >= (SOURCE_BIAS+2) * (int)pixmap->drawable.width * pixmap->drawable.height;
4748	}
4749}
4750
4751static BoxPtr
4752reorder_boxes(BoxPtr box, int n, int dx, int dy)
4753{
4754	BoxPtr new, base, next, tmp;
4755
4756	DBG(("%s x %d dx=%d, dy=%d\n", __FUNCTION__, n, dx, dy));
4757
4758	if (dy <= 0 && dx <= 0) {
4759		new = malloc(sizeof(BoxRec) * n);
4760		if (new == NULL)
4761			return NULL;
4762
4763		tmp = new;
4764		next = box + n;
4765		do {
4766			*tmp++ = *--next;
4767		} while (next != box);
4768	} else if (dy < 0) {
4769		new = malloc(sizeof(BoxRec) * n);
4770		if (new == NULL)
4771			return NULL;
4772
4773		base = next = box + n - 1;
4774		while (base >= box) {
4775			while (next >= box && base->y1 == next->y1)
4776				next--;
4777			tmp = next + 1;
4778			while (tmp <= base)
4779				*new++ = *tmp++;
4780			base = next;
4781		}
4782		new -= n;
4783	} else {
4784		new = malloc(sizeof(BoxRec) * n);
4785		if (!new)
4786			return NULL;
4787
4788		base = next = box;
4789		while (base < box + n) {
4790			while (next < box + n && next->y1 == base->y1)
4791				next++;
4792			tmp = next;
4793			while (tmp != base)
4794				*new++ = *--tmp;
4795			base = next;
4796		}
4797		new -= n;
4798	}
4799
4800	return new;
4801}
4802
4803static void
4804sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
4805		    RegionPtr region,int dx, int dy,
4806		    Pixel bitplane, void *closure)
4807{
4808	PixmapPtr pixmap = get_drawable_pixmap(src);
4809	struct sna *sna = to_sna_from_pixmap(pixmap);
4810	struct sna_pixmap *priv = sna_pixmap(pixmap);
4811	BoxPtr box = RegionRects(region);
4812	int n = RegionNumRects(region);
4813	int alu = gc ? gc->alu : GXcopy;
4814	int16_t tx, ty;
4815
4816	assert(RegionNumRects(region));
4817	if (((dx | dy) == 0 && alu == GXcopy))
4818		return;
4819
4820	if (n > 1 && (dx | dy) < 0) {
4821		box = reorder_boxes(box, n, dx, dy);
4822		if (box == NULL)
4823			return;
4824	}
4825
4826	DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d, pix.size=%dx%d)\n",
4827	     __FUNCTION__, n,
4828	     region->extents.x1, region->extents.y1,
4829	     region->extents.x2, region->extents.y2,
4830	     dx, dy, alu,
4831	     pixmap->drawable.width, pixmap->drawable.height));
4832
4833	if (get_drawable_deltas(src, pixmap, &tx, &ty))
4834		dx += tx, dy += ty;
4835	if (dst != src)
4836		get_drawable_deltas(dst, pixmap, &tx, &ty);
4837
4838	if (priv == NULL || DAMAGE_IS_ALL(priv->cpu_damage) || priv->shm)
4839		goto fallback;
4840
4841	if (priv->gpu_damage || (priv->cpu_damage == NULL && priv->gpu_bo)) {
4842		assert(priv->gpu_bo);
4843
4844		if (alu == GXcopy && priv->clear)
4845			goto out;
4846
4847		assert(priv->gpu_bo->proxy == NULL);
4848		if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT)) {
4849			DBG(("%s: fallback - not a pure copy and failed to move dst to GPU\n",
4850			     __FUNCTION__));
4851			goto fallback;
4852		}
4853
4854		if (!sna->render.copy_boxes(sna, alu,
4855					    pixmap, priv->gpu_bo, dx, dy,
4856					    pixmap, priv->gpu_bo, tx, ty,
4857					    box, n, 0)) {
4858			DBG(("%s: fallback - accelerated copy boxes failed\n",
4859			     __FUNCTION__));
4860			goto fallback;
4861		}
4862
4863		if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
4864			assert(!priv->clear);
4865			RegionTranslate(region, tx, ty);
4866			sna_damage_add(&priv->gpu_damage, region);
4867		}
4868		assert_pixmap_damage(pixmap);
4869	} else {
4870fallback:
4871		DBG(("%s: fallback", __FUNCTION__));
4872		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE))
4873			goto out;
4874
4875		if (alu == GXcopy && pixmap->drawable.bitsPerPixel >= 8) {
4876			FbBits *dst_bits, *src_bits;
4877			int stride = pixmap->devKind;
4878			int bpp = pixmap->drawable.bitsPerPixel;
4879			int i;
4880
4881			dst_bits = (FbBits *)
4882				((char *)pixmap->devPrivate.ptr +
4883				 ty * stride + tx * bpp / 8);
4884			src_bits = (FbBits *)
4885				((char *)pixmap->devPrivate.ptr +
4886				 dy * stride + dx * bpp / 8);
4887
4888			for (i = 0; i < n; i++)
4889				memmove_box(src_bits, dst_bits,
4890					    bpp, stride, box+i,
4891					    dx, dy);
4892		} else {
4893			if (gc && !sna_gc_move_to_cpu(gc, dst, region))
4894				goto out;
4895
4896			get_drawable_deltas(src, pixmap, &tx, &ty);
4897			miCopyRegion(src, dst, gc,
4898				     region, dx - tx, dy - ty,
4899				     fbCopyNtoN, 0, NULL);
4900
4901			if (gc)
4902				sna_gc_move_to_gpu(gc);
4903		}
4904	}
4905
4906out:
4907	if (box != RegionRects(region))
4908		free(box);
4909}
4910
4911static inline bool
4912sna_pixmap_is_gpu(PixmapPtr pixmap)
4913{
4914	struct sna_pixmap *priv = sna_pixmap(pixmap);
4915
4916	if (priv == NULL || priv->clear)
4917		return false;
4918
4919	if (DAMAGE_IS_ALL(priv->gpu_damage) ||
4920	    (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo) && !priv->gpu_bo->proxy))
4921		return true;
4922
4923	return priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo);
4924}
4925
4926static int
4927source_prefer_gpu(struct sna *sna, struct sna_pixmap *priv,
4928		  RegionRec *region, int16_t dx, int16_t dy)
4929{
4930	if (priv == NULL) {
4931		DBG(("%s: source unattached, use cpu\n", __FUNCTION__));
4932		return 0;
4933	}
4934
4935	if (priv->clear) {
4936		DBG(("%s: source is clear, don't force use of GPU\n", __FUNCTION__));
4937		return 0;
4938	}
4939
4940	if (priv->gpu_damage &&
4941	    (priv->cpu_damage == NULL ||
4942	     !source_contains_region(priv->cpu_damage, region, dx, dy))) {
4943		DBG(("%s: source has gpu damage, force gpu? %d\n",
4944		     __FUNCTION__, priv->cpu_damage == NULL));
4945		assert(priv->gpu_bo);
4946		return priv->cpu_damage ? PREFER_GPU : PREFER_GPU | FORCE_GPU;
4947	}
4948
4949	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) {
4950		DBG(("%s: source has busy CPU bo, force gpu\n", __FUNCTION__));
4951		return PREFER_GPU | FORCE_GPU;
4952	}
4953
4954	if (DAMAGE_IS_ALL(priv->cpu_damage))
4955		return priv->cpu_bo && kgem_is_idle(&sna->kgem);
4956
4957	DBG(("%s: source has GPU bo? %d\n",
4958	     __FUNCTION__, priv->gpu_bo != NULL));
4959	return priv->gpu_bo != NULL;
4960}
4961
4962static bool use_shm_bo(struct sna *sna,
4963		       struct kgem_bo *bo,
4964		       struct sna_pixmap *priv,
4965		       int alu, bool replaces)
4966{
4967	if (priv == NULL || priv->cpu_bo == NULL) {
4968		DBG(("%s: no, not attached\n", __FUNCTION__));
4969		return false;
4970	}
4971
4972	if (!priv->shm && !priv->cpu) {
4973		DBG(("%s: yes, ordinary CPU bo\n", __FUNCTION__));
4974		return true;
4975	}
4976
4977	if (alu != GXcopy) {
4978		DBG(("%s: yes, complex alu=%d\n", __FUNCTION__, alu));
4979		return true;
4980	}
4981
4982	if (!replaces && __kgem_bo_is_busy(&sna->kgem, bo)) {
4983		DBG(("%s: yes, dst is busy\n", __FUNCTION__));
4984		return true;
4985	}
4986
4987	if (priv->cpu_bo->needs_flush &&
4988	    __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) {
4989		DBG(("%s: yes, src is busy\n", __FUNCTION__));
4990		return true;
4991	}
4992
4993	return false;
4994}
4995
4996static void
4997sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
4998	       RegionPtr region, int dx, int dy,
4999	       Pixel bitplane, void *closure)
5000{
5001	PixmapPtr src_pixmap = get_drawable_pixmap(src);
5002	struct sna_pixmap *src_priv = sna_pixmap(src_pixmap);
5003	PixmapPtr dst_pixmap = get_drawable_pixmap(dst);
5004	struct sna_pixmap *dst_priv = sna_pixmap(dst_pixmap);
5005	struct sna *sna = to_sna_from_pixmap(src_pixmap);
5006	struct sna_damage **damage;
5007	struct kgem_bo *bo;
5008	unsigned hint;
5009	int16_t src_dx, src_dy;
5010	int16_t dst_dx, dst_dy;
5011	BoxPtr box = RegionRects(region);
5012	int n = RegionNumRects(region);
5013	int alu = gc->alu;
5014	int stride, bpp;
5015	char *bits;
5016	bool replaces;
5017
5018	assert(RegionNumRects(region));
5019
5020	if (src_pixmap == dst_pixmap)
5021		return sna_self_copy_boxes(src, dst, gc,
5022					   region, dx, dy,
5023					   bitplane, closure);
5024
5025	DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d, src.size=%dx%d, dst.size=%dx%d)\n",
5026	     __FUNCTION__, n,
5027	     box[0].x1, box[0].y1, box[0].x2, box[0].y2,
5028	     dx, dy, alu,
5029	     src_pixmap->drawable.width, src_pixmap->drawable.height,
5030	     dst_pixmap->drawable.width, dst_pixmap->drawable.height));
5031
5032	assert_pixmap_damage(dst_pixmap);
5033	assert_pixmap_damage(src_pixmap);
5034
5035	bpp = dst_pixmap->drawable.bitsPerPixel;
5036
5037	if (get_drawable_deltas(dst, dst_pixmap, &dst_dx, &dst_dy))
5038		RegionTranslate(region, dst_dx, dst_dy);
5039	get_drawable_deltas(src, src_pixmap, &src_dx, &src_dy);
5040	src_dx += dx - dst_dx;
5041	src_dy += dy - dst_dy;
5042
5043	assert_pixmap_contains_box(dst_pixmap, RegionExtents(region));
5044	assert_pixmap_contains_box_with_offset(src_pixmap,
5045					       RegionExtents(region),
5046					       src_dx, src_dy);
5047
5048	replaces = n == 1 &&
5049		alu_overwrites(alu) &&
5050		box->x1 <= 0 &&
5051		box->y1 <= 0 &&
5052		box->x2 >= dst_pixmap->drawable.width &&
5053		box->y2 >= dst_pixmap->drawable.height;
5054
5055	DBG(("%s: dst=(priv=%p, gpu_bo=%d, cpu_bo=%d), src=(priv=%p, gpu_bo=%d, cpu_bo=%d), replaces=%d\n",
5056	     __FUNCTION__,
5057	     dst_priv,
5058	     dst_priv && dst_priv->gpu_bo ? dst_priv->gpu_bo->handle : 0,
5059	     dst_priv && dst_priv->cpu_bo ? dst_priv->cpu_bo->handle : 0,
5060	     src_priv,
5061	     src_priv && src_priv->gpu_bo ? src_priv->gpu_bo->handle : 0,
5062	     src_priv && src_priv->cpu_bo ? src_priv->cpu_bo->handle : 0,
5063	     replaces));
5064
5065	if (dst_priv == NULL)
5066		goto fallback;
5067
5068	hint = source_prefer_gpu(sna, src_priv, region, src_dx, src_dy) ?:
5069		region_inplace(sna, dst_pixmap, region,
5070			       dst_priv, alu_overwrites(alu) ? MOVE_WRITE : MOVE_READ | MOVE_WRITE);
5071	if (dst_priv->cpu_damage && alu_overwrites(alu)) {
5072		DBG(("%s: overwritting CPU damage\n", __FUNCTION__));
5073		if (region_subsumes_damage(region, dst_priv->cpu_damage)) {
5074			DBG(("%s: discarding existing CPU damage\n", __FUNCTION__));
5075			if (dst_priv->gpu_bo && dst_priv->gpu_bo->proxy) {
5076				assert(!dst_priv->pinned);
5077				kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo);
5078				dst_priv->gpu_bo = NULL;
5079			}
5080			sna_damage_destroy(&dst_priv->cpu_damage);
5081			list_del(&dst_priv->flush_list);
5082			dst_priv->cpu = false;
5083		}
5084	}
5085	if (region->data == NULL && alu_overwrites(alu))
5086		hint |= IGNORE_CPU;
5087
5088	/* XXX hack for firefox -- subsequent uses of src will be corrupt! */
5089	if (src_priv &&
5090	    COW(src_priv->cow) == COW(dst_priv->cow) &&
5091	    IS_COW_OWNER(dst_priv->cow)) {
5092		DBG(("%s: ignoring cow reference for cousin copy\n",
5093		     __FUNCTION__));
5094		assert(src_priv->cpu_damage == NULL);
5095		bo = dst_priv->gpu_bo;
5096		damage = NULL;
5097	} else
5098		bo = sna_drawable_use_bo(&dst_pixmap->drawable, hint,
5099					 &region->extents, &damage);
5100	if (bo) {
5101		if (src_priv && src_priv->clear) {
5102			DBG(("%s: applying src clear [%08x] to dst\n",
5103			     __FUNCTION__, src_priv->clear_color));
5104			if (n == 1) {
5105				if (replaces && UNDO)
5106					kgem_bo_undo(&sna->kgem, bo);
5107
5108				if (!sna->render.fill_one(sna,
5109							  dst_pixmap, bo,
5110							  src_priv->clear_color,
5111							  box->x1, box->y1,
5112							  box->x2, box->y2,
5113							  alu)) {
5114					DBG(("%s: unsupported fill\n",
5115					     __FUNCTION__));
5116					goto fallback;
5117				}
5118
5119				if (replaces && bo == dst_priv->gpu_bo) {
5120					DBG(("%s: marking dst handle=%d as all clear [%08x]\n",
5121					     __FUNCTION__,
5122					     dst_priv->gpu_bo->handle,
5123					     src_priv->clear_color));
5124					dst_priv->clear = true;
5125					dst_priv->clear_color = src_priv->clear_color;
5126					sna_damage_all(&dst_priv->gpu_damage,
5127						       dst_pixmap->drawable.width,
5128						       dst_pixmap->drawable.height);
5129					sna_damage_destroy(&dst_priv->cpu_damage);
5130					list_del(&dst_priv->flush_list);
5131					return;
5132				}
5133			} else {
5134				struct sna_fill_op fill;
5135
5136				if (!sna_fill_init_blt(&fill, sna,
5137						       dst_pixmap, bo,
5138						       alu, src_priv->clear_color)) {
5139					DBG(("%s: unsupported fill\n",
5140					     __FUNCTION__));
5141					goto fallback;
5142				}
5143
5144				fill.boxes(sna, &fill, box, n);
5145				fill.done(sna, &fill);
5146			}
5147
5148			if (damage)
5149				sna_damage_add(damage, region);
5150			return;
5151		}
5152
5153		if (src_priv &&
5154		    move_to_gpu(src_pixmap, src_priv, region, src_dx, src_dy, alu, bo == dst_priv->gpu_bo) &&
5155		    sna_pixmap_move_to_gpu(src_pixmap, MOVE_READ | MOVE_ASYNC_HINT)) {
5156			DBG(("%s: move whole src_pixmap to GPU and copy\n",
5157			     __FUNCTION__));
5158			if (replaces && UNDO)
5159				kgem_bo_undo(&sna->kgem, bo);
5160
5161			if (replaces &&
5162			    src_pixmap->drawable.width == dst_pixmap->drawable.width &&
5163			    src_pixmap->drawable.height == dst_pixmap->drawable.height) {
5164				assert(src_pixmap->drawable.depth == dst_pixmap->drawable.depth);
5165				assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel);
5166				if (sna_pixmap_make_cow(sna, src_priv, dst_priv)) {
5167					assert(dst_priv->gpu_bo == src_priv->gpu_bo);
5168					sna_damage_all(&dst_priv->gpu_damage,
5169						       dst_pixmap->drawable.width,
5170						       dst_pixmap->drawable.height);
5171					sna_damage_destroy(&dst_priv->cpu_damage);
5172					list_del(&dst_priv->flush_list);
5173					if (dst_priv->shm)
5174						sna_add_flush_pixmap(sna, dst_priv, dst_priv->cpu_bo);
5175					return;
5176				}
5177			}
5178			if (!sna->render.copy_boxes(sna, alu,
5179						    src_pixmap, src_priv->gpu_bo, src_dx, src_dy,
5180						    dst_pixmap, bo, 0, 0,
5181						    box, n, 0)) {
5182				DBG(("%s: fallback - accelerated copy boxes failed\n",
5183				     __FUNCTION__));
5184				goto fallback;
5185			}
5186
5187			if (damage)
5188				sna_damage_add(damage, region);
5189			return;
5190		}
5191
5192		if (src_priv &&
5193		    region_overlaps_damage(region, src_priv->gpu_damage,
5194					   src_dx, src_dy)) {
5195			BoxRec area;
5196
5197			DBG(("%s: region overlaps GPU damage, upload and copy\n",
5198			     __FUNCTION__));
5199
5200			area = region->extents;
5201			area.x1 += src_dx;
5202			area.x2 += src_dx;
5203			area.y1 += src_dy;
5204			area.y2 += src_dy;
5205
5206			if (!sna_pixmap_move_area_to_gpu(src_pixmap, &area,
5207							 MOVE_READ | MOVE_ASYNC_HINT))
5208				goto fallback;
5209
5210			if (replaces && UNDO)
5211				kgem_bo_undo(&sna->kgem, bo);
5212
5213			if (!sna->render.copy_boxes(sna, alu,
5214						    src_pixmap, src_priv->gpu_bo, src_dx, src_dy,
5215						    dst_pixmap, bo, 0, 0,
5216						    box, n, 0)) {
5217				DBG(("%s: fallback - accelerated copy boxes failed\n",
5218				     __FUNCTION__));
5219				goto fallback;
5220			}
5221
5222			if (damage)
5223				sna_damage_add(damage, region);
5224			return;
5225		}
5226
5227		if (bo != dst_priv->gpu_bo)
5228			goto fallback;
5229
5230		if (use_shm_bo(sna, bo, src_priv, alu, replaces)) {
5231			bool ret;
5232
5233			DBG(("%s: region overlaps CPU damage, copy from CPU bo (shm? %d)\n",
5234			     __FUNCTION__, src_priv->shm));
5235
5236			assert(bo != dst_priv->cpu_bo);
5237
5238			RegionTranslate(region, src_dx, src_dy);
5239			ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
5240							      region,
5241							      MOVE_READ | MOVE_ASYNC_HINT);
5242			RegionTranslate(region, -src_dx, -src_dy);
5243			if (!ret)
5244				goto fallback;
5245
5246			if (replaces && UNDO)
5247				kgem_bo_undo(&sna->kgem, bo);
5248
5249			if (src_priv->shm) {
5250				assert(!src_priv->flush);
5251				sna_add_flush_pixmap(sna, src_priv, src_priv->cpu_bo);
5252			}
5253
5254			if (!sna->render.copy_boxes(sna, alu,
5255						    src_pixmap, src_priv->cpu_bo, src_dx, src_dy,
5256						    dst_pixmap, bo, 0, 0,
5257						    box, n, src_priv->shm ? COPY_LAST : 0)) {
5258				DBG(("%s: fallback - accelerated copy boxes failed\n",
5259				     __FUNCTION__));
5260				goto fallback;
5261			}
5262
5263			if (damage)
5264				sna_damage_add(damage, region);
5265			return;
5266		}
5267
5268		if (src_priv) {
5269			bool ret;
5270
5271			RegionTranslate(region, src_dx, src_dy);
5272			ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
5273							      region, MOVE_READ);
5274			RegionTranslate(region, -src_dx, -src_dy);
5275			if (!ret)
5276				goto fallback;
5277
5278			assert(!src_priv->mapped);
5279			if (src_pixmap->devPrivate.ptr == NULL)
5280				/* uninitialised!*/
5281				return;
5282		}
5283
5284		if (USE_USERPTR_UPLOADS &&
5285		    sna->kgem.has_userptr &&
5286		    (alu != GXcopy ||
5287		     (box_inplace(src_pixmap, &region->extents) &&
5288		      __kgem_bo_is_busy(&sna->kgem, bo)))) {
5289			struct kgem_bo *src_bo;
5290			bool ok = false;
5291
5292			DBG(("%s: upload through a temporary map\n",
5293			     __FUNCTION__));
5294
5295			src_bo = kgem_create_map(&sna->kgem,
5296						 src_pixmap->devPrivate.ptr,
5297						 src_pixmap->devKind * src_pixmap->drawable.height,
5298						 true);
5299			if (src_bo) {
5300				src_bo->pitch = src_pixmap->devKind;
5301				kgem_bo_mark_unreusable(src_bo);
5302
5303				ok = sna->render.copy_boxes(sna, alu,
5304							    src_pixmap, src_bo, src_dx, src_dy,
5305							    dst_pixmap, bo, 0, 0,
5306							    box, n, COPY_LAST);
5307
5308				kgem_bo_sync__cpu(&sna->kgem, src_bo);
5309				assert(src_bo->rq == NULL);
5310				kgem_bo_destroy(&sna->kgem, src_bo);
5311			}
5312
5313			if (ok) {
5314				if (damage)
5315					sna_damage_add(damage, region);
5316				return;
5317			}
5318		}
5319
5320		if (alu != GXcopy) {
5321			PixmapPtr tmp;
5322			struct kgem_bo *src_bo;
5323			int i;
5324
5325			assert(src_pixmap->drawable.depth != 1);
5326
5327			DBG(("%s: creating temporary source upload for non-copy alu [%d]\n",
5328			     __FUNCTION__, alu));
5329
5330			tmp = sna_pixmap_create_upload(src->pScreen,
5331						       region->extents.x2 - region->extents.x1,
5332						       region->extents.y2 - region->extents.y1,
5333						       src->depth,
5334						       KGEM_BUFFER_WRITE_INPLACE);
5335			if (tmp == NullPixmap)
5336				return;
5337
5338			src_bo = __sna_pixmap_get_bo(tmp);
5339			assert(src_bo != NULL);
5340
5341			dx = -region->extents.x1;
5342			dy = -region->extents.y1;
5343			for (i = 0; i < n; i++) {
5344				assert(box[i].x1 + src_dx >= 0);
5345				assert(box[i].y1 + src_dy >= 0);
5346				assert(box[i].x2 + src_dx <= src_pixmap->drawable.width);
5347				assert(box[i].y2 + src_dy <= src_pixmap->drawable.height);
5348
5349				assert(box[i].x1 + dx >= 0);
5350				assert(box[i].y1 + dy >= 0);
5351				assert(box[i].x2 + dx <= tmp->drawable.width);
5352				assert(box[i].y2 + dy <= tmp->drawable.height);
5353
5354				assert(has_coherent_ptr(sna_pixmap(src_pixmap)));
5355				assert(has_coherent_ptr(sna_pixmap(tmp)));
5356				memcpy_blt(src_pixmap->devPrivate.ptr,
5357					   tmp->devPrivate.ptr,
5358					   src_pixmap->drawable.bitsPerPixel,
5359					   src_pixmap->devKind,
5360					   tmp->devKind,
5361					   box[i].x1 + src_dx,
5362					   box[i].y1 + src_dy,
5363					   box[i].x1 + dx,
5364					   box[i].y1 + dy,
5365					   box[i].x2 - box[i].x1,
5366					   box[i].y2 - box[i].y1);
5367			}
5368
5369			if (n == 1 &&
5370			    tmp->drawable.width == src_pixmap->drawable.width &&
5371			    tmp->drawable.height == src_pixmap->drawable.height) {
5372				DBG(("%s: caching upload for src bo\n",
5373				     __FUNCTION__));
5374				assert(src_priv->gpu_damage == NULL);
5375				assert(src_priv->gpu_bo == NULL);
5376				kgem_proxy_bo_attach(src_bo, &src_priv->gpu_bo);
5377			}
5378
5379			if (!sna->render.copy_boxes(sna, alu,
5380						    tmp, src_bo, dx, dy,
5381						    dst_pixmap, bo, 0, 0,
5382						    box, n, 0)) {
5383				DBG(("%s: fallback - accelerated copy boxes failed\n",
5384				     __FUNCTION__));
5385				tmp->drawable.pScreen->DestroyPixmap(tmp);
5386				goto fallback;
5387			}
5388			tmp->drawable.pScreen->DestroyPixmap(tmp);
5389
5390			if (damage)
5391				sna_damage_add(damage, region);
5392			return;
5393		} else {
5394			DBG(("%s: dst is on the GPU, src is on the CPU, uploading into dst\n",
5395			     __FUNCTION__));
5396
5397			if (!dst_priv->pinned && replaces) {
5398				stride = src_pixmap->devKind;
5399				bits = src_pixmap->devPrivate.ptr;
5400				bits += (src_dy + box->y1) * stride + (src_dx + box->x1) * bpp / 8;
5401
5402				if (!sna_replace(sna, dst_pixmap,
5403						 &dst_priv->gpu_bo,
5404						 bits, stride))
5405					goto fallback;
5406			} else {
5407				assert(!DAMAGE_IS_ALL(dst_priv->cpu_damage));
5408				if (!sna_write_boxes(sna, dst_pixmap,
5409						     dst_priv->gpu_bo, 0, 0,
5410						     src_pixmap->devPrivate.ptr,
5411						     src_pixmap->devKind,
5412						     src_dx, src_dy,
5413						     box, n))
5414					goto fallback;
5415			}
5416
5417			assert(dst_priv->clear == false);
5418			dst_priv->cpu = false;
5419			if (damage) {
5420				assert(!dst_priv->clear);
5421				assert(dst_priv->gpu_bo);
5422				assert(dst_priv->gpu_bo->proxy == NULL);
5423				assert(*damage == dst_priv->gpu_damage);
5424				if (replaces) {
5425					sna_damage_destroy(&dst_priv->cpu_damage);
5426					sna_damage_all(&dst_priv->gpu_damage,
5427						       dst_pixmap->drawable.width,
5428						       dst_pixmap->drawable.height);
5429					list_del(&dst_priv->flush_list);
5430				} else
5431					sna_damage_add(&dst_priv->gpu_damage,
5432						       region);
5433				assert_pixmap_damage(dst_pixmap);
5434			}
5435		}
5436
5437		return;
5438	}
5439
5440fallback:
5441	if (alu == GXcopy && src_priv && src_priv->clear) {
5442		DBG(("%s: copying clear [%08x]\n",
5443		     __FUNCTION__, src_priv->clear_color));
5444
5445		if (dst_priv) {
5446			if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable,
5447							     region,
5448							     MOVE_WRITE | MOVE_INPLACE_HINT))
5449				return;
5450		}
5451
5452		assert(dst_pixmap->devPrivate.ptr);
5453		do {
5454			pixman_fill(dst_pixmap->devPrivate.ptr,
5455				    dst_pixmap->devKind/sizeof(uint32_t),
5456				    dst_pixmap->drawable.bitsPerPixel,
5457				    box->x1, box->y1,
5458				    box->x2 - box->x1,
5459				    box->y2 - box->y1,
5460				    src_priv->clear_color);
5461			box++;
5462		} while (--n);
5463	} else {
5464		FbBits *dst_bits, *src_bits;
5465		int dst_stride, src_stride;
5466
5467		DBG(("%s: fallback -- src=(%d, %d), dst=(%d, %d)\n",
5468		     __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy));
5469		if (src_priv) {
5470			unsigned mode;
5471
5472			RegionTranslate(region, src_dx, src_dy);
5473
5474			assert_pixmap_contains_box(src_pixmap,
5475						   RegionExtents(region));
5476
5477			mode = MOVE_READ;
5478			if (!sna->kgem.can_blt_cpu ||
5479			    (src_priv->cpu_bo == NULL &&
5480			     (src_priv->create & KGEM_CAN_CREATE_CPU) == 0))
5481				mode |= MOVE_INPLACE_HINT;
5482
5483			if (!sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
5484							     region, mode))
5485				return;
5486
5487			RegionTranslate(region, -src_dx, -src_dy);
5488		}
5489
5490		if (dst_priv) {
5491			unsigned mode;
5492
5493			if (alu_overwrites(alu))
5494				mode = MOVE_WRITE | MOVE_INPLACE_HINT;
5495			else
5496				mode = MOVE_WRITE | MOVE_READ;
5497			if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable,
5498							     region, mode))
5499				return;
5500		}
5501
5502		dst_stride = dst_pixmap->devKind;
5503		src_stride = src_pixmap->devKind;
5504
5505		if (alu == GXcopy && bpp >= 8) {
5506			dst_bits = (FbBits *)dst_pixmap->devPrivate.ptr;
5507			src_bits = (FbBits *)
5508				((char *)src_pixmap->devPrivate.ptr +
5509				 src_dy * src_stride + src_dx * bpp / 8);
5510
5511			do {
5512				DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n",
5513				     __FUNCTION__,
5514				     box->x1, box->y1,
5515				     box->x2 - box->x1,
5516				     box->y2 - box->y1,
5517				     src_dx, src_dy,
5518				     src_stride, dst_stride));
5519
5520				assert(box->x1 >= 0);
5521				assert(box->y1 >= 0);
5522				assert(box->x2 <= dst_pixmap->drawable.width);
5523				assert(box->y2 <= dst_pixmap->drawable.height);
5524
5525				assert(box->x1 + src_dx >= 0);
5526				assert(box->y1 + src_dy >= 0);
5527				assert(box->x2 + src_dx <= src_pixmap->drawable.width);
5528				assert(box->y2 + src_dy <= src_pixmap->drawable.height);
5529				assert(has_coherent_ptr(sna_pixmap(src_pixmap)));
5530				assert(has_coherent_ptr(sna_pixmap(dst_pixmap)));
5531				memcpy_blt(src_bits, dst_bits, bpp,
5532					   src_stride, dst_stride,
5533					   box->x1, box->y1,
5534					   box->x1, box->y1,
5535					   box->x2 - box->x1,
5536					   box->y2 - box->y1);
5537				box++;
5538			} while (--n);
5539		} else {
5540			DBG(("%s: fallback -- miCopyRegion\n", __FUNCTION__));
5541
5542			RegionTranslate(region, -dst_dx, -dst_dy);
5543
5544			if (!sna_gc_move_to_cpu(gc, dst, region))
5545				return;
5546
5547			miCopyRegion(src, dst, gc,
5548				     region, dx, dy,
5549				     fbCopyNtoN, 0, NULL);
5550
5551			sna_gc_move_to_gpu(gc);
5552		}
5553	}
5554}
5555
5556typedef void (*sna_copy_func)(DrawablePtr src, DrawablePtr dst, GCPtr gc,
5557			      RegionPtr region, int dx, int dy,
5558			      Pixel bitPlane, void *closure);
5559
5560static inline bool box_equal(const BoxRec *a, const BoxRec *b)
5561{
5562	return *(const uint64_t *)a == *(const uint64_t *)b;
5563}
5564
5565static RegionPtr
5566sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc,
5567	    int sx, int sy,
5568	    int width, int height,
5569	    int dx, int dy,
5570	    sna_copy_func copy, Pixel bitPlane, void *closure)
5571{
5572	RegionPtr clip;
5573	RegionRec region;
5574	BoxRec src_extents;
5575	bool expose;
5576
5577	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n",
5578	     __FUNCTION__, sx, sy, dx, dy, width, height));
5579
5580	/* Short cut for unmapped windows */
5581	if (dst->type == DRAWABLE_WINDOW && !((WindowPtr)dst)->realized) {
5582		DBG(("%s: unmapped\n", __FUNCTION__));
5583		return NULL;
5584	}
5585
5586	SourceValidate(src, sx, sy, width, height, gc->subWindowMode);
5587
5588	sx += src->x;
5589	sy += src->y;
5590
5591	dx += dst->x;
5592	dy += dst->y;
5593
5594	DBG(("%s: after drawable: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n",
5595	     __FUNCTION__, sx, sy, dx, dy, width, height));
5596
5597	region.extents.x1 = dx;
5598	region.extents.y1 = dy;
5599	region.extents.x2 = bound(dx, width);
5600	region.extents.y2 = bound(dy, height);
5601	region.data = NULL;
5602
5603	DBG(("%s: dst extents (%d, %d), (%d, %d)\n", __FUNCTION__,
5604	     region.extents.x1, region.extents.y1,
5605	     region.extents.x2, region.extents.y2));
5606
5607	if (!box_intersect(&region.extents, &gc->pCompositeClip->extents)) {
5608		DBG(("%s: dst clipped out\n", __FUNCTION__));
5609		return NULL;
5610	}
5611
5612	region.extents.x1 = clamp(region.extents.x1, sx - dx);
5613	region.extents.x2 = clamp(region.extents.x2, sx - dx);
5614	region.extents.y1 = clamp(region.extents.y1, sy - dy);
5615	region.extents.y2 = clamp(region.extents.y2, sy - dy);
5616
5617	src_extents = region.extents;
5618	expose = gc->fExpose;
5619
5620	if (region.extents.x1 < src->x)
5621		region.extents.x1 = src->x;
5622	if (region.extents.y1 < src->y)
5623		region.extents.y1 = src->y;
5624	if (region.extents.x2 > src->x + (int) src->width)
5625		region.extents.x2 = src->x + (int) src->width;
5626	if (region.extents.y2 > src->y + (int) src->height)
5627		region.extents.y2 = src->y + (int) src->height;
5628
5629	/* Compute source clip region */
5630	if (src->type == DRAWABLE_PIXMAP) {
5631		if (src == dst && gc->clientClipType == CT_NONE) {
5632			DBG(("%s: pixmap -- using gc clip\n", __FUNCTION__));
5633			clip = gc->pCompositeClip;
5634		} else {
5635			DBG(("%s: pixmap -- no source clipping\n", __FUNCTION__));
5636			expose = false;
5637			clip = NULL;
5638		}
5639	} else {
5640		WindowPtr w = (WindowPtr)src;
5641		if (gc->subWindowMode == IncludeInferiors) {
5642			DBG(("%s: window -- include inferiors\n", __FUNCTION__));
5643
5644			assert(!w->winSize.data);
5645			box_intersect(&region.extents, &w->winSize.extents);
5646			clip = &w->borderClip;
5647		} else {
5648			DBG(("%s: window -- clip by children\n", __FUNCTION__));
5649			clip = &w->clipList;
5650		}
5651	}
5652	if (clip != NULL) {
5653		if (clip->data == NULL) {
5654			box_intersect(&region.extents, &clip->extents);
5655			if (box_equal(&src_extents, &region.extents))
5656				expose = false;
5657		} else
5658			RegionIntersect(&region, &region, clip);
5659	}
5660	DBG(("%s: src extents (%d, %d), (%d, %d) x %ld\n", __FUNCTION__,
5661	     region.extents.x1, region.extents.y1,
5662	     region.extents.x2, region.extents.y2,
5663	     (long)RegionNumRects(&region)));
5664
5665	RegionTranslate(&region, dx-sx, dy-sy);
5666	if (gc->pCompositeClip->data)
5667		RegionIntersect(&region, &region, gc->pCompositeClip);
5668	DBG(("%s: copy region (%d, %d), (%d, %d) x %ld\n", __FUNCTION__,
5669	     region.extents.x1, region.extents.y1,
5670	     region.extents.x2, region.extents.y2,
5671	     (long)RegionNumRects(&region)));
5672
5673	if (!box_empty(&region.extents))
5674		copy(src, dst, gc, &region, sx-dx, sy-dy, bitPlane, closure);
5675	RegionUninit(&region);
5676
5677	/* Pixmap sources generate a NoExposed (we return NULL to do this) */
5678	clip = NULL;
5679	if (expose)
5680		clip = miHandleExposures(src, dst, gc,
5681					 sx - src->x, sy - src->y,
5682					 width, height,
5683					 dx - dst->x, dy - dst->y,
5684					 (unsigned long) bitPlane);
5685	return clip;
5686}
5687
5688static void
5689sna_fallback_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
5690			RegionPtr region, int dx, int dy,
5691			Pixel bitplane, void *closure)
5692{
5693	DBG(("%s (boxes=%ldx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d\n",
5694	     __FUNCTION__, (long)RegionNumRects(region),
5695	     region->extents.x1, region->extents.y1,
5696	     region->extents.x2, region->extents.y2,
5697	     dx, dy, gc->alu));
5698
5699	if (!sna_gc_move_to_cpu(gc, dst, region))
5700		return;
5701
5702	RegionTranslate(region, dx, dy);
5703	if (!sna_drawable_move_region_to_cpu(src, region, MOVE_READ))
5704		goto out_gc;
5705	RegionTranslate(region, -dx, -dy);
5706
5707	if (src == dst ||
5708	    get_drawable_pixmap(src) == get_drawable_pixmap(dst)) {
5709		DBG(("%s: self-copy\n", __FUNCTION__));
5710		if (!sna_drawable_move_to_cpu(dst, MOVE_WRITE | MOVE_READ))
5711			goto out_gc;
5712	} else {
5713		if (!sna_drawable_move_region_to_cpu(dst, region,
5714						     drawable_gc_flags(dst, gc, false)))
5715			goto out_gc;
5716	}
5717
5718	miCopyRegion(src, dst, gc,
5719		     region, dx, dy,
5720		     fbCopyNtoN, 0, NULL);
5721	FALLBACK_FLUSH(dst);
5722out_gc:
5723	sna_gc_move_to_gpu(gc);
5724}
5725
5726static RegionPtr
5727sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
5728	      int src_x, int src_y,
5729	      int width, int height,
5730	      int dst_x, int dst_y)
5731{
5732	struct sna *sna = to_sna_from_drawable(dst);
5733	sna_copy_func copy;
5734
5735	if (gc->planemask == 0)
5736		return NULL;
5737
5738	DBG(("%s: src=(%d, %d)x(%d, %d)+(%d, %d) -> dst=(%d, %d)+(%d, %d); alu=%d, pm=%lx\n",
5739	     __FUNCTION__,
5740	     src_x, src_y, width, height, src->x, src->y,
5741	     dst_x, dst_y, dst->x, dst->y,
5742	     gc->alu, gc->planemask));
5743
5744	if (FORCE_FALLBACK || !ACCEL_COPY_AREA || wedged(sna) ||
5745	    !PM_IS_SOLID(dst, gc->planemask))
5746		copy = sna_fallback_copy_boxes;
5747	else if (src == dst)
5748		copy = sna_self_copy_boxes;
5749	else
5750		copy = sna_copy_boxes;
5751
5752	return sna_do_copy(src, dst, gc,
5753			   src_x, src_y,
5754			   width, height,
5755			   dst_x, dst_y,
5756			   copy, 0, NULL);
5757}
5758
5759static const BoxRec *
5760find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y)
5761{
5762    const BoxRec *mid;
5763
5764    if (end == begin)
5765	return end;
5766
5767    if (end - begin == 1) {
5768	if (begin->y2 > y)
5769	    return begin;
5770	else
5771	    return end;
5772    }
5773
5774    mid = begin + (end - begin) / 2;
5775    if (mid->y2 > y)
5776	/* If no box is found in [begin, mid], the function
5777	 * will return @mid, which is then known to be the
5778	 * correct answer.
5779	 */
5780	return find_clip_box_for_y(begin, mid, y);
5781    else
5782	return find_clip_box_for_y(mid, end, y);
5783}
5784
5785struct sna_fill_spans {
5786	struct sna *sna;
5787	PixmapPtr pixmap;
5788	RegionRec region;
5789	unsigned flags;
5790	struct kgem_bo *bo;
5791	struct sna_damage **damage;
5792	int16_t dx, dy;
5793	void *op;
5794};
5795
5796static void
5797sna_poly_point__cpu(DrawablePtr drawable, GCPtr gc,
5798		    int mode, int n, DDXPointPtr pt)
5799{
5800	fbPolyPoint(drawable, gc, mode, n, pt, -1);
5801}
5802
5803static void
5804sna_poly_point__fill(DrawablePtr drawable, GCPtr gc,
5805		     int mode, int n, DDXPointPtr pt)
5806{
5807	struct sna_fill_spans *data = sna_gc(gc)->priv;
5808	struct sna_fill_op *op = data->op;
5809	BoxRec box[512];
5810	DDXPointRec last;
5811
5812	DBG(("%s: count=%d\n", __FUNCTION__, n));
5813
5814	last.x = drawable->x + data->dx;
5815	last.y = drawable->y + data->dy;
5816	while (n) {
5817		BoxRec *b = box;
5818		unsigned nbox = n;
5819		if (nbox > ARRAY_SIZE(box))
5820			nbox = ARRAY_SIZE(box);
5821		n -= nbox;
5822		do {
5823			*(DDXPointRec *)b = *pt++;
5824
5825			b->x1 += last.x;
5826			b->y1 += last.y;
5827			if (mode == CoordModePrevious)
5828				last = *(DDXPointRec *)b;
5829
5830			b->x2 = b->x1 + 1;
5831			b->y2 = b->y1 + 1;
5832			b++;
5833		} while (--nbox);
5834		op->boxes(data->sna, op, box, b - box);
5835	}
5836}
5837
5838static void
5839sna_poly_point__gpu(DrawablePtr drawable, GCPtr gc,
5840		     int mode, int n, DDXPointPtr pt)
5841{
5842	struct sna_fill_spans *data = sna_gc(gc)->priv;
5843	struct sna_fill_op fill;
5844	BoxRec box[512];
5845	DDXPointRec last;
5846
5847	if (!sna_fill_init_blt(&fill,
5848			       data->sna, data->pixmap,
5849			       data->bo, gc->alu, gc->fgPixel))
5850		return;
5851
5852	DBG(("%s: count=%d\n", __FUNCTION__, n));
5853
5854	last.x = drawable->x;
5855	last.y = drawable->y;
5856	while (n) {
5857		BoxRec *b = box;
5858		unsigned nbox = n;
5859		if (nbox > ARRAY_SIZE(box))
5860			nbox = ARRAY_SIZE(box);
5861		n -= nbox;
5862		do {
5863			*(DDXPointRec *)b = *pt++;
5864
5865			b->x1 += last.x;
5866			b->y1 += last.y;
5867			if (mode == CoordModePrevious)
5868				last = *(DDXPointRec *)b;
5869
5870			if (RegionContainsPoint(&data->region,
5871						b->x1, b->y1, NULL)) {
5872				b->x1 += data->dx;
5873				b->y1 += data->dy;
5874				b->x2 = b->x1 + 1;
5875				b->y2 = b->y1 + 1;
5876				b++;
5877			}
5878		} while (--nbox);
5879		fill.boxes(data->sna, &fill, box, b - box);
5880	}
5881	fill.done(data->sna, &fill);
5882}
5883
5884static void
5885sna_poly_point__fill_clip_extents(DrawablePtr drawable, GCPtr gc,
5886				  int mode, int n, DDXPointPtr pt)
5887{
5888	struct sna_fill_spans *data = sna_gc(gc)->priv;
5889	struct sna_fill_op *op = data->op;
5890	const BoxRec *extents = &data->region.extents;
5891	BoxRec box[512], *b = box;
5892	const BoxRec *const last_box = b + ARRAY_SIZE(box);
5893	DDXPointRec last;
5894
5895	DBG(("%s: count=%d\n", __FUNCTION__, n));
5896
5897	last.x = drawable->x + data->dx;
5898	last.y = drawable->y + data->dy;
5899	while (n--) {
5900		*(DDXPointRec *)b = *pt++;
5901
5902		b->x1 += last.x;
5903		b->y1 += last.y;
5904		if (mode == CoordModePrevious)
5905			last = *(DDXPointRec *)b;
5906
5907		if (b->x1 >= extents->x1 && b->x1 < extents->x2 &&
5908		    b->y1 >= extents->y1 && b->y1 < extents->y2) {
5909			b->x2 = b->x1 + 1;
5910			b->y2 = b->y1 + 1;
5911			if (++b == last_box) {
5912				op->boxes(data->sna, op, box, last_box - box);
5913				b = box;
5914			}
5915		}
5916	}
5917	if (b != box)
5918		op->boxes(data->sna, op, box, b - box);
5919}
5920
5921static void
5922sna_poly_point__fill_clip_boxes(DrawablePtr drawable, GCPtr gc,
5923				int mode, int n, DDXPointPtr pt)
5924{
5925	struct sna_fill_spans *data = sna_gc(gc)->priv;
5926	struct sna_fill_op *op = data->op;
5927	RegionRec *clip = &data->region;
5928	BoxRec box[512], *b = box;
5929	const BoxRec *const last_box = b + ARRAY_SIZE(box);
5930	DDXPointRec last;
5931
5932	DBG(("%s: count=%d\n", __FUNCTION__, n));
5933
5934	last.x = drawable->x + data->dx;
5935	last.y = drawable->y + data->dy;
5936	while (n--) {
5937		*(DDXPointRec *)b = *pt++;
5938
5939		b->x1 += last.x;
5940		b->y1 += last.y;
5941		if (mode == CoordModePrevious)
5942			last = *(DDXPointRec *)b;
5943
5944		if (RegionContainsPoint(clip, b->x1, b->y1, NULL)) {
5945			b->x2 = b->x1 + 1;
5946			b->y2 = b->y1 + 1;
5947			if (++b == last_box) {
5948				op->boxes(data->sna, op, box, last_box - box);
5949				b = box;
5950			}
5951		}
5952	}
5953	if (b != box)
5954		op->boxes(data->sna, op, box, b - box);
5955}
5956
5957static void
5958sna_poly_point__dash(DrawablePtr drawable, GCPtr gc,
5959		     int mode, int n, DDXPointPtr pt)
5960{
5961	struct sna_fill_spans *data = sna_gc(gc)->priv;
5962	struct sna_fill_op *op = data->op;
5963
5964	if (op->base.u.blt.pixel == gc->fgPixel)
5965		sna_poly_point__fill(drawable, gc, mode, n, pt);
5966}
5967
5968static void
5969sna_poly_point__dash_clip_extents(DrawablePtr drawable, GCPtr gc,
5970				  int mode, int n, DDXPointPtr pt)
5971{
5972	struct sna_fill_spans *data = sna_gc(gc)->priv;
5973	struct sna_fill_op *op = data->op;
5974
5975	if (op->base.u.blt.pixel == gc->fgPixel)
5976		sna_poly_point__fill_clip_extents(drawable, gc, mode, n, pt);
5977}
5978
5979static void
5980sna_poly_point__dash_clip_boxes(DrawablePtr drawable, GCPtr gc,
5981				  int mode, int n, DDXPointPtr pt)
5982{
5983	struct sna_fill_spans *data = sna_gc(gc)->priv;
5984	struct sna_fill_op *op = data->op;
5985
5986	if (op->base.u.blt.pixel == gc->fgPixel)
5987		sna_poly_point__fill_clip_boxes(drawable, gc, mode, n, pt);
5988}
5989
5990static void
5991sna_fill_spans__fill(DrawablePtr drawable,
5992		     GCPtr gc, int n,
5993		     DDXPointPtr pt, int *width, int sorted)
5994{
5995	struct sna_fill_spans *data = sna_gc(gc)->priv;
5996	struct sna_fill_op *op = data->op;
5997	BoxRec box[512];
5998
5999	DBG(("%s: alu=%d, fg=%08lx, count=%d\n",
6000	     __FUNCTION__, gc->alu, gc->fgPixel, n));
6001
6002	while (n) {
6003		BoxRec *b = box;
6004		int nbox = n;
6005		if (nbox > ARRAY_SIZE(box))
6006			nbox = ARRAY_SIZE(box);
6007		n -= nbox;
6008		do {
6009			*(DDXPointRec *)b = *pt++;
6010			b->x2 = b->x1 + (int)*width++;
6011			b->y2 = b->y1 + 1;
6012			DBG(("%s: (%d, %d), (%d, %d)\n",
6013			     __FUNCTION__, b->x1, b->y1, b->x2, b->y2));
6014			assert(b->x1 >= drawable->x);
6015			assert(b->x2 <= drawable->x + drawable->width);
6016			assert(b->y1 >= drawable->y);
6017			assert(b->y2 <= drawable->y + drawable->height);
6018			if (b->x2 > b->x1) {
6019				if (b != box &&
6020				    b->y1 == b[-1].y2 &&
6021				    b->x1 == b[-1].x1 &&
6022				    b->x2 == b[-1].x2)
6023					b[-1].y2 = b->y2;
6024				else
6025					b++;
6026			}
6027		} while (--nbox);
6028		if (b != box)
6029			op->boxes(data->sna, op, box, b - box);
6030	}
6031}
6032
6033static void
6034sna_fill_spans__dash(DrawablePtr drawable,
6035		     GCPtr gc, int n,
6036		     DDXPointPtr pt, int *width, int sorted)
6037{
6038	struct sna_fill_spans *data = sna_gc(gc)->priv;
6039	struct sna_fill_op *op = data->op;
6040
6041	if (op->base.u.blt.pixel == gc->fgPixel)
6042		sna_fill_spans__fill(drawable, gc, n, pt, width, sorted);
6043}
6044
6045static void
6046sna_fill_spans__fill_offset(DrawablePtr drawable,
6047			    GCPtr gc, int n,
6048			    DDXPointPtr pt, int *width, int sorted)
6049{
6050	struct sna_fill_spans *data = sna_gc(gc)->priv;
6051	struct sna_fill_op *op = data->op;
6052	BoxRec box[512];
6053
6054	DBG(("%s: alu=%d, fg=%08lx\n", __FUNCTION__, gc->alu, gc->fgPixel));
6055
6056	while (n) {
6057		BoxRec *b = box;
6058		int nbox = n;
6059		if (nbox > ARRAY_SIZE(box))
6060			nbox = ARRAY_SIZE(box);
6061		n -= nbox;
6062		do {
6063			*(DDXPointRec *)b = *pt++;
6064			b->x1 += data->dx;
6065			b->y1 += data->dy;
6066			b->x2 = b->x1 + (int)*width++;
6067			b->y2 = b->y1 + 1;
6068			if (b->x2 > b->x1)
6069				b++;
6070		} while (--nbox);
6071		if (b != box)
6072			op->boxes(data->sna, op, box, b - box);
6073	}
6074}
6075
6076static void
6077sna_fill_spans__dash_offset(DrawablePtr drawable,
6078			    GCPtr gc, int n,
6079			    DDXPointPtr pt, int *width, int sorted)
6080{
6081	struct sna_fill_spans *data = sna_gc(gc)->priv;
6082	struct sna_fill_op *op = data->op;
6083
6084	if (op->base.u.blt.pixel == gc->fgPixel)
6085		sna_fill_spans__fill_offset(drawable, gc, n, pt, width, sorted);
6086}
6087
6088static void
6089sna_fill_spans__fill_clip_extents(DrawablePtr drawable,
6090				  GCPtr gc, int n,
6091				  DDXPointPtr pt, int *width, int sorted)
6092{
6093	struct sna_fill_spans *data = sna_gc(gc)->priv;
6094	struct sna_fill_op *op = data->op;
6095	const BoxRec *extents = &data->region.extents;
6096	BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box);
6097
6098	DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n",
6099	     __FUNCTION__, gc->alu, gc->fgPixel, n,
6100	     extents->x1, extents->y1,
6101	     extents->x2, extents->y2));
6102
6103	while (n--) {
6104		DBG(("%s: [%d] pt=(%d, %d), width=%d\n",
6105		     __FUNCTION__, n, pt->x, pt->y, *width));
6106		*(DDXPointRec *)b = *pt++;
6107		b->x2 = b->x1 + (int)*width++;
6108		b->y2 = b->y1 + 1;
6109		if (box_intersect(b, extents)) {
6110			DBG(("%s: [%d] clipped=(%d, %d), (%d, %d)\n",
6111			     __FUNCTION__, n, b->x1, b->y1, b->x2, b->y2));
6112			if (data->dx|data->dy) {
6113				b->x1 += data->dx; b->x2 += data->dx;
6114				b->y1 += data->dy; b->y2 += data->dy;
6115			}
6116			if (b != box &&
6117			    b->y1 == b[-1].y2 &&
6118			    b->x1 == b[-1].x1 &&
6119			    b->x2 == b[-1].x2) {
6120				b[-1].y2 = b->y2;
6121			} else if (++b == last_box) {
6122				op->boxes(data->sna, op, box, last_box - box);
6123				b = box;
6124			}
6125		}
6126	}
6127	if (b != box)
6128		op->boxes(data->sna, op, box, b - box);
6129}
6130
6131static void
6132sna_fill_spans__dash_clip_extents(DrawablePtr drawable,
6133				  GCPtr gc, int n,
6134				  DDXPointPtr pt, int *width, int sorted)
6135{
6136	struct sna_fill_spans *data = sna_gc(gc)->priv;
6137	struct sna_fill_op *op = data->op;
6138
6139	if (op->base.u.blt.pixel == gc->fgPixel)
6140		sna_fill_spans__fill_clip_extents(drawable, gc, n, pt, width, sorted);
6141}
6142
6143static void
6144sna_fill_spans__fill_clip_boxes(DrawablePtr drawable,
6145				GCPtr gc, int n,
6146				DDXPointPtr pt, int *width, int sorted)
6147{
6148	struct sna_fill_spans *data = sna_gc(gc)->priv;
6149	struct sna_fill_op *op = data->op;
6150	BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box);
6151	const BoxRec * const clip_start = RegionBoxptr(&data->region);
6152	const BoxRec * const clip_end = clip_start + data->region.data->numRects;
6153
6154	DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n",
6155	     __FUNCTION__, gc->alu, gc->fgPixel, n,
6156	     data->region.extents.x1, data->region.extents.y1,
6157	     data->region.extents.x2, data->region.extents.y2));
6158
6159	while (n--) {
6160		int16_t X1 = pt->x;
6161		int16_t y = pt->y;
6162		int16_t X2 = X1 + (int)*width;
6163		const BoxRec *c;
6164
6165		pt++;
6166		width++;
6167
6168		if (y < data->region.extents.y1 || data->region.extents.y2 <= y)
6169			continue;
6170
6171		if (X1 < data->region.extents.x1)
6172			X1 = data->region.extents.x1;
6173
6174		if (X2 > data->region.extents.x2)
6175			X2 = data->region.extents.x2;
6176
6177		if (X1 >= X2)
6178			continue;
6179
6180		c = find_clip_box_for_y(clip_start, clip_end, y);
6181		while (c != clip_end) {
6182			if (y + 1 <= c->y1 || X2 <= c->x1)
6183				break;
6184
6185			if (X1 >= c->x2) {
6186				c++;
6187				continue;
6188			}
6189
6190			b->x1 = c->x1;
6191			b->x2 = c->x2;
6192			c++;
6193
6194			if (b->x1 < X1)
6195				b->x1 = X1;
6196			if (b->x2 > X2)
6197				b->x2 = X2;
6198			if (b->x2 <= b->x1)
6199				continue;
6200
6201			b->x1 += data->dx;
6202			b->x2 += data->dx;
6203			b->y1 = y + data->dy;
6204			b->y2 = b->y1 + 1;
6205			if (++b == last_box) {
6206				op->boxes(data->sna, op, box, last_box - box);
6207				b = box;
6208			}
6209		}
6210	}
6211	if (b != box)
6212		op->boxes(data->sna, op, box, b - box);
6213}
6214
6215static void
6216sna_fill_spans__dash_clip_boxes(DrawablePtr drawable,
6217				GCPtr gc, int n,
6218				DDXPointPtr pt, int *width, int sorted)
6219{
6220	struct sna_fill_spans *data = sna_gc(gc)->priv;
6221	struct sna_fill_op *op = data->op;
6222
6223	if (op->base.u.blt.pixel == gc->fgPixel)
6224		sna_fill_spans__fill_clip_boxes(drawable, gc, n, pt, width, sorted);
6225}
6226
6227static bool
6228sna_fill_spans_blt(DrawablePtr drawable,
6229		   struct kgem_bo *bo, struct sna_damage **damage,
6230		   GCPtr gc, uint32_t pixel,
6231		   int n, DDXPointPtr pt, int *width, int sorted,
6232		   const BoxRec *extents, unsigned clipped)
6233{
6234	PixmapPtr pixmap = get_drawable_pixmap(drawable);
6235	struct sna *sna = to_sna_from_pixmap(pixmap);
6236	int16_t dx, dy;
6237	struct sna_fill_op fill;
6238	BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box);
6239	static void * const jump[] = {
6240		&&no_damage,
6241		&&damage,
6242		&&no_damage_clipped,
6243		&&damage_clipped,
6244	};
6245	unsigned v;
6246
6247	DBG(("%s: alu=%d, fg=%08lx, damge=%p, clipped?=%d\n",
6248	     __FUNCTION__, gc->alu, gc->fgPixel, damage, clipped));
6249
6250	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel))
6251		return false;
6252
6253	get_drawable_deltas(drawable, pixmap, &dx, &dy);
6254
6255	v = (damage != NULL) | clipped;
6256	goto *jump[v];
6257
6258no_damage:
6259	if (dx|dy) {
6260		do {
6261			int nbox = n;
6262			if (nbox > last_box - box)
6263				nbox = last_box - box;
6264			n -= nbox;
6265			do {
6266				*(DDXPointRec *)b = *pt++;
6267				b->x1 += dx;
6268				b->y1 += dy;
6269				b->x2 = b->x1 + (int)*width++;
6270				b->y2 = b->y1 + 1;
6271				b++;
6272			} while (--nbox);
6273			fill.boxes(sna, &fill, box, b - box);
6274			b = box;
6275		} while (n);
6276	} else {
6277		do {
6278			int nbox = n;
6279			if (nbox > last_box - box)
6280				nbox = last_box - box;
6281			n -= nbox;
6282			do {
6283				*(DDXPointRec *)b = *pt++;
6284				b->x2 = b->x1 + (int)*width++;
6285				b->y2 = b->y1 + 1;
6286				b++;
6287			} while (--nbox);
6288			fill.boxes(sna, &fill, box, b - box);
6289			b = box;
6290		} while (n);
6291	}
6292	goto done;
6293
6294damage:
6295	do {
6296		*(DDXPointRec *)b = *pt++;
6297		b->x1 += dx;
6298		b->y1 += dy;
6299		b->x2 = b->x1 + (int)*width++;
6300		b->y2 = b->y1 + 1;
6301
6302		if (++b == last_box) {
6303			assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0);
6304			fill.boxes(sna, &fill, box, last_box - box);
6305			sna_damage_add_boxes(damage, box, last_box - box, 0, 0);
6306			b = box;
6307		}
6308	} while (--n);
6309	if (b != box) {
6310		assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
6311		fill.boxes(sna, &fill, box, b - box);
6312		sna_damage_add_boxes(damage, box, b - box, 0, 0);
6313	}
6314	goto done;
6315
6316no_damage_clipped:
6317	{
6318		RegionRec clip;
6319
6320		region_set(&clip, extents);
6321		region_maybe_clip(&clip, gc->pCompositeClip);
6322		if (RegionNil(&clip))
6323			return true;
6324
6325		assert(dx + clip.extents.x1 >= 0);
6326		assert(dy + clip.extents.y1 >= 0);
6327		assert(dx + clip.extents.x2 <= pixmap->drawable.width);
6328		assert(dy + clip.extents.y2 <= pixmap->drawable.height);
6329
6330		DBG(("%s: clip %ld x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n",
6331		     __FUNCTION__,
6332		     (long)RegionNumRects(&clip),
6333		     clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2,
6334		     n, pt->x, pt->y));
6335
6336		if (clip.data == NULL) {
6337			do {
6338				*(DDXPointRec *)b = *pt++;
6339				b->x2 = b->x1 + (int)*width++;
6340				b->y2 = b->y1 + 1;
6341
6342				if (box_intersect(b, &clip.extents)) {
6343					if (dx|dy) {
6344						b->x1 += dx; b->x2 += dx;
6345						b->y1 += dy; b->y2 += dy;
6346					}
6347					if (++b == last_box) {
6348						fill.boxes(sna, &fill, box, last_box - box);
6349						b = box;
6350					}
6351				}
6352			} while (--n);
6353		} else {
6354			const BoxRec * const clip_start = RegionBoxptr(&clip);
6355			const BoxRec * const clip_end = clip_start + clip.data->numRects;
6356			do {
6357				int16_t X1 = pt->x;
6358				int16_t y = pt->y;
6359				int16_t X2 = X1 + (int)*width;
6360				const BoxRec *c;
6361
6362				pt++;
6363				width++;
6364
6365				if (y < extents->y1 || extents->y2 <= y)
6366					continue;
6367
6368				if (X1 < extents->x1)
6369					X1 = extents->x1;
6370
6371				if (X2 > extents->x2)
6372					X2 = extents->x2;
6373
6374				if (X1 >= X2)
6375					continue;
6376
6377				c = find_clip_box_for_y(clip_start,
6378							clip_end,
6379							y);
6380				while (c != clip_end) {
6381					if (y + 1 <= c->y1 || X2 <= c->x1)
6382						break;
6383
6384					if (X1 >= c->x2) {
6385						c++;
6386						continue;
6387					}
6388
6389					b->x1 = c->x1;
6390					b->x2 = c->x2;
6391					c++;
6392
6393					if (b->x1 < X1)
6394						b->x1 = X1;
6395					if (b->x2 > X2)
6396						b->x2 = X2;
6397					if (b->x2 <= b->x1)
6398						continue;
6399
6400					b->x1 += dx;
6401					b->x2 += dx;
6402					b->y1 = y + dy;
6403					b->y2 = b->y1 + 1;
6404					if (++b == last_box) {
6405						fill.boxes(sna, &fill, box, last_box - box);
6406						b = box;
6407					}
6408				}
6409			} while (--n);
6410			RegionUninit(&clip);
6411		}
6412		if (b != box)
6413			fill.boxes(sna, &fill, box, b - box);
6414		goto done;
6415	}
6416
6417damage_clipped:
6418	{
6419		RegionRec clip;
6420
6421		region_set(&clip, extents);
6422		region_maybe_clip(&clip, gc->pCompositeClip);
6423		if (RegionNil(&clip))
6424			return true;
6425
6426		assert(dx + clip.extents.x1 >= 0);
6427		assert(dy + clip.extents.y1 >= 0);
6428		assert(dx + clip.extents.x2 <= pixmap->drawable.width);
6429		assert(dy + clip.extents.y2 <= pixmap->drawable.height);
6430
6431		DBG(("%s: clip %ld x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n",
6432		     __FUNCTION__,
6433		     (long)RegionNumRects(&clip),
6434		     clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2,
6435		     n, pt->x, pt->y));
6436
6437		if (clip.data == NULL) {
6438			do {
6439				*(DDXPointRec *)b = *pt++;
6440				b->x2 = b->x1 + (int)*width++;
6441				b->y2 = b->y1 + 1;
6442
6443				if (box_intersect(b, &clip.extents)) {
6444					b->x1 += dx;
6445					b->x2 += dx;
6446					b->y1 += dy;
6447					b->y2 += dy;
6448					if (++b == last_box) {
6449						assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
6450						fill.boxes(sna, &fill, box, last_box - box);
6451						sna_damage_add_boxes(damage, box, b - box, 0, 0);
6452						b = box;
6453					}
6454				}
6455			} while (--n);
6456		} else {
6457			const BoxRec * const clip_start = RegionBoxptr(&clip);
6458			const BoxRec * const clip_end = clip_start + clip.data->numRects;
6459			do {
6460				int16_t X1 = pt->x;
6461				int16_t y = pt->y;
6462				int16_t X2 = X1 + (int)*width;
6463				const BoxRec *c;
6464
6465				pt++;
6466				width++;
6467
6468				if (y < extents->y1 || extents->y2 <= y)
6469					continue;
6470
6471				if (X1 < extents->x1)
6472					X1 = extents->x1;
6473
6474				if (X2 > extents->x2)
6475					X2 = extents->x2;
6476
6477				if (X1 >= X2)
6478					continue;
6479
6480				c = find_clip_box_for_y(clip_start,
6481							clip_end,
6482							y);
6483				while (c != clip_end) {
6484					if (y + 1 <= c->y1 || X2 <= c->x1)
6485						break;
6486
6487					if (X1 >= c->x2) {
6488						c++;
6489						continue;
6490					}
6491
6492					b->x1 = c->x1;
6493					b->x2 = c->x2;
6494					c++;
6495
6496					if (b->x1 < X1)
6497						b->x1 = X1;
6498					if (b->x2 > X2)
6499						b->x2 = X2;
6500					if (b->x2 <= b->x1)
6501						continue;
6502
6503					b->x1 += dx;
6504					b->x2 += dx;
6505					b->y1 = y + dy;
6506					b->y2 = b->y1 + 1;
6507					if (++b == last_box) {
6508						assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0);
6509						fill.boxes(sna, &fill, box, last_box - box);
6510						sna_damage_add_boxes(damage, box, last_box - box, 0, 0);
6511						b = box;
6512					}
6513				}
6514			} while (--n);
6515			RegionUninit(&clip);
6516		}
6517		if (b != box) {
6518			assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
6519			fill.boxes(sna, &fill, box, b - box);
6520			sna_damage_add_boxes(damage, box, b - box, 0, 0);
6521		}
6522		goto done;
6523	}
6524
6525done:
6526	fill.done(sna, &fill);
6527	assert_pixmap_damage(pixmap);
6528	return true;
6529}
6530
6531static bool
6532sna_poly_fill_rect_tiled_blt(DrawablePtr drawable,
6533			     struct kgem_bo *bo,
6534			     struct sna_damage **damage,
6535			     GCPtr gc, int n, xRectangle *rect,
6536			     const BoxRec *extents, unsigned clipped);
6537
6538static bool
6539sna_poly_fill_rect_stippled_blt(DrawablePtr drawable,
6540				struct kgem_bo *bo,
6541				struct sna_damage **damage,
6542				GCPtr gc, int n, xRectangle *rect,
6543				const BoxRec *extents, unsigned clipped);
6544
6545static inline bool
6546gc_is_solid(GCPtr gc, uint32_t *color)
6547{
6548	if (gc->fillStyle == FillSolid ||
6549	    (gc->fillStyle == FillTiled && gc->tileIsPixel) ||
6550	    (gc->fillStyle == FillOpaqueStippled && gc->bgPixel == gc->fgPixel)) {
6551		*color = gc->fillStyle == FillTiled ? gc->tile.pixel : gc->fgPixel;
6552		return true;
6553	}
6554
6555	return false;
6556}
6557
6558static void
6559sna_fill_spans__gpu(DrawablePtr drawable, GCPtr gc, int n,
6560		    DDXPointPtr pt, int *width, int sorted)
6561{
6562	struct sna_fill_spans *data = sna_gc(gc)->priv;
6563	uint32_t color;
6564
6565	DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n",
6566	     __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted));
6567
6568	assert(PM_IS_SOLID(drawable, gc->planemask));
6569	if (n == 0)
6570		return;
6571
6572	/* The mi routines do not attempt to keep the spans it generates
6573	 * within the clip, so we must run them through the clipper.
6574	 */
6575
6576	if (gc_is_solid(gc, &color)) {
6577		sna_fill_spans_blt(drawable,
6578				   data->bo, NULL,
6579				   gc, color, n, pt, width, sorted,
6580				   &data->region.extents, 2);
6581	} else {
6582		/* Try converting these to a set of rectangles instead */
6583		xRectangle *rect;
6584		int i;
6585
6586		DBG(("%s: converting to rectagnles\n", __FUNCTION__));
6587
6588		rect = malloc (n * sizeof (xRectangle));
6589		if (rect == NULL)
6590			return;
6591
6592		for (i = 0; i < n; i++) {
6593			rect[i].x = pt[i].x - drawable->x;
6594			rect[i].width = width[i];
6595			rect[i].y = pt[i].y - drawable->y;
6596			rect[i].height = 1;
6597		}
6598
6599		if (gc->fillStyle == FillTiled) {
6600			(void)sna_poly_fill_rect_tiled_blt(drawable,
6601							   data->bo, NULL,
6602							   gc, n, rect,
6603							   &data->region.extents, 2);
6604		} else {
6605			(void)sna_poly_fill_rect_stippled_blt(drawable,
6606							      data->bo, NULL,
6607							      gc, n, rect,
6608							      &data->region.extents, 2);
6609		}
6610		free (rect);
6611	}
6612}
6613
6614static unsigned
6615sna_spans_extents(DrawablePtr drawable, GCPtr gc,
6616		  int n, DDXPointPtr pt, int *width,
6617		  BoxPtr out)
6618{
6619	BoxRec box;
6620	bool clipped = false;
6621
6622	if (n == 0)
6623		return 0;
6624
6625	box.x1 = pt->x;
6626	box.x2 = box.x1 + *width;
6627	box.y2 = box.y1 = pt->y;
6628
6629	while (--n) {
6630		pt++;
6631		width++;
6632		if (box.x1 > pt->x)
6633			box.x1 = pt->x;
6634		if (box.x2 < pt->x + *width)
6635			box.x2 = pt->x + *width;
6636
6637		if (box.y1 > pt->y)
6638			box.y1 = pt->y;
6639		else if (box.y2 < pt->y)
6640			box.y2 = pt->y;
6641	}
6642	box.y2++;
6643
6644	if (gc)
6645		clipped = clip_box(&box, gc);
6646	if (box_empty(&box))
6647		return 0;
6648
6649	*out = box;
6650	return 1 | clipped << 1;
6651}
6652
6653static void
6654sna_fill_spans(DrawablePtr drawable, GCPtr gc, int n,
6655	       DDXPointPtr pt, int *width, int sorted)
6656{
6657	PixmapPtr pixmap = get_drawable_pixmap(drawable);
6658	struct sna *sna = to_sna_from_pixmap(pixmap);
6659	struct sna_damage **damage;
6660	struct kgem_bo *bo;
6661	RegionRec region;
6662	unsigned flags;
6663	uint32_t color;
6664
6665	DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n",
6666	     __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted));
6667
6668	flags = sna_spans_extents(drawable, gc, n, pt, width, &region.extents);
6669	if (flags == 0)
6670		return;
6671
6672	DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__,
6673	     region.extents.x1, region.extents.y1,
6674	     region.extents.x2, region.extents.y2));
6675
6676	if (FORCE_FALLBACK)
6677		goto fallback;
6678
6679	if (!ACCEL_FILL_SPANS)
6680		goto fallback;
6681
6682	if (wedged(sna)) {
6683		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
6684		goto fallback;
6685	}
6686
6687	DBG(("%s: fillStyle=%x [%d], mask=%lx [%d]\n", __FUNCTION__,
6688	     gc->fillStyle, gc->fillStyle == FillSolid,
6689	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask)));
6690	if (!PM_IS_SOLID(drawable, gc->planemask))
6691		goto fallback;
6692
6693	bo = sna_drawable_use_bo(drawable, PREFER_GPU,
6694				 &region.extents, &damage);
6695	if (bo) {
6696		if (gc_is_solid(gc, &color)) {
6697			DBG(("%s: trying solid fill [alu=%d, pixel=%08lx] blt paths\n",
6698			     __FUNCTION__, gc->alu, gc->fgPixel));
6699
6700			sna_fill_spans_blt(drawable,
6701					   bo, damage,
6702					   gc, color, n, pt, width, sorted,
6703					   &region.extents, flags & 2);
6704		} else {
6705			/* Try converting these to a set of rectangles instead */
6706			xRectangle *rect;
6707			int i;
6708
6709			DBG(("%s: converting to rectagnles\n", __FUNCTION__));
6710
6711			rect = malloc (n * sizeof (xRectangle));
6712			if (rect == NULL)
6713				return;
6714
6715			for (i = 0; i < n; i++) {
6716				rect[i].x = pt[i].x - drawable->x;
6717				rect[i].width = width[i];
6718				rect[i].y = pt[i].y - drawable->y;
6719				rect[i].height = 1;
6720			}
6721
6722			if (gc->fillStyle == FillTiled) {
6723				i = sna_poly_fill_rect_tiled_blt(drawable,
6724								 bo, damage,
6725								 gc, n, rect,
6726								 &region.extents, flags & 2);
6727			} else {
6728				i = sna_poly_fill_rect_stippled_blt(drawable,
6729								    bo, damage,
6730								    gc, n, rect,
6731								    &region.extents, flags & 2);
6732			}
6733			free (rect);
6734
6735			if (i)
6736				return;
6737		}
6738	}
6739
6740fallback:
6741	DBG(("%s: fallback\n", __FUNCTION__));
6742	region.data = NULL;
6743	region_maybe_clip(&region, gc->pCompositeClip);
6744	if (RegionNil(&region))
6745		return;
6746
6747	if (!sna_gc_move_to_cpu(gc, drawable, &region))
6748		goto out;
6749	if (!sna_drawable_move_region_to_cpu(drawable, &region,
6750					     drawable_gc_flags(drawable, gc, n > 1)))
6751		goto out_gc;
6752
6753	DBG(("%s: fbFillSpans\n", __FUNCTION__));
6754	fbFillSpans(drawable, gc, n, pt, width, sorted);
6755	FALLBACK_FLUSH(drawable);
6756out_gc:
6757	sna_gc_move_to_gpu(gc);
6758out:
6759	RegionUninit(&region);
6760}
6761
6762static void
6763sna_set_spans(DrawablePtr drawable, GCPtr gc, char *src,
6764	      DDXPointPtr pt, int *width, int n, int sorted)
6765{
6766	RegionRec region;
6767
6768	if (sna_spans_extents(drawable, gc, n, pt, width, &region.extents) == 0)
6769		return;
6770
6771	DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__,
6772	     region.extents.x1, region.extents.y1,
6773	     region.extents.x2, region.extents.y2));
6774
6775	if (FORCE_FALLBACK)
6776		goto fallback;
6777
6778	if (!ACCEL_SET_SPANS)
6779		goto fallback;
6780
6781fallback:
6782	region.data = NULL;
6783	region_maybe_clip(&region, gc->pCompositeClip);
6784	if (RegionNil(&region))
6785		return;
6786
6787	if (!sna_gc_move_to_cpu(gc, drawable, &region))
6788		goto out;
6789	if (!sna_drawable_move_region_to_cpu(drawable, &region,
6790					     drawable_gc_flags(drawable, gc, n > 1)))
6791		goto out_gc;
6792
6793	DBG(("%s: fbSetSpans\n", __FUNCTION__));
6794	fbSetSpans(drawable, gc, src, pt, width, n, sorted);
6795	FALLBACK_FLUSH(drawable);
6796out_gc:
6797	sna_gc_move_to_gpu(gc);
6798out:
6799	RegionUninit(&region);
6800}
6801
6802struct sna_copy_plane {
6803	struct sna_damage **damage;
6804	struct kgem_bo *bo;
6805};
6806
6807static void
6808sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
6809		    RegionRec *region, int sx, int sy,
6810		    Pixel bitplane, void *closure)
6811{
6812	PixmapPtr pixmap = get_drawable_pixmap(drawable);
6813	struct sna *sna = to_sna_from_pixmap(pixmap);
6814	struct sna_copy_plane *arg = closure;
6815	PixmapPtr bitmap = (PixmapPtr)_bitmap;
6816	uint32_t br00, br13;
6817	int16_t dx, dy;
6818	BoxPtr box;
6819	int n;
6820
6821	DBG(("%s: plane=%x (%d,%d),(%d,%d)x%ld\n",
6822	     __FUNCTION__, (unsigned)bitplane,
6823	     region->extents.x1, region->extents.y1,
6824	     region->extents.x2, region->extents.y2,
6825	     (long)RegionNumRects(region)));
6826
6827	box = RegionRects(region);
6828	n = RegionNumRects(region);
6829	assert(n);
6830
6831	get_drawable_deltas(drawable, pixmap, &dx, &dy);
6832	assert_pixmap_contains_boxes(pixmap, box, n, dx, dy);
6833
6834	br00 = 3 << 20;
6835	br13 = arg->bo->pitch;
6836	if (sna->kgem.gen >= 040 && arg->bo->tiling) {
6837		br00 |= BLT_DST_TILED;
6838		br13 >>= 2;
6839	}
6840	br13 |= blt_depth(drawable->depth) << 24;
6841	br13 |= copy_ROP[gc->alu] << 16;
6842
6843	kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo);
6844	do {
6845		int bx1 = (box->x1 + sx) & ~7;
6846		int bx2 = (box->x2 + sx + 7) & ~7;
6847		int bw = (bx2 - bx1)/8;
6848		int bh = box->y2 - box->y1;
6849		int bstride = ALIGN(bw, 2);
6850		int src_stride;
6851		uint8_t *dst, *src;
6852		uint32_t *b;
6853
6854		DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n",
6855		     __FUNCTION__,
6856		     box->x1, box->y1,
6857		     box->x2, box->y2,
6858		     sx, sy, bx1, bx2));
6859
6860		src_stride = bstride*bh;
6861		if (src_stride <= 128) {
6862			src_stride = ALIGN(src_stride, 8) / 4;
6863			assert(src_stride <= 32);
6864			if (!kgem_check_batch(&sna->kgem, 7+src_stride) ||
6865			    !kgem_check_bo_fenced(&sna->kgem, arg->bo) ||
6866			    !kgem_check_reloc(&sna->kgem, 1)) {
6867				kgem_submit(&sna->kgem);
6868				if (!kgem_check_bo_fenced(&sna->kgem, arg->bo))
6869					return; /* XXX fallback? */
6870				_kgem_set_mode(&sna->kgem, KGEM_BLT);
6871			}
6872
6873			b = sna->kgem.batch + sna->kgem.nbatch;
6874			b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
6875			b[0] |= ((box->x1 + sx) & 7) << 17;
6876			b[1] = br13;
6877			b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
6878			b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
6879			b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4,
6880					      arg->bo,
6881					      I915_GEM_DOMAIN_RENDER << 16 |
6882					      I915_GEM_DOMAIN_RENDER |
6883					      KGEM_RELOC_FENCED,
6884					      0);
6885			b[5] = gc->bgPixel;
6886			b[6] = gc->fgPixel;
6887
6888			sna->kgem.nbatch += 7 + src_stride;
6889
6890			dst = (uint8_t *)&b[7];
6891			src_stride = bitmap->devKind;
6892			src = bitmap->devPrivate.ptr;
6893			src += (box->y1 + sy) * src_stride + bx1/8;
6894			src_stride -= bstride;
6895			do {
6896				int i = bstride;
6897				do {
6898					*dst++ = byte_reverse(*src++);
6899					*dst++ = byte_reverse(*src++);
6900					i -= 2;
6901				} while (i);
6902				src += src_stride;
6903			} while (--bh);
6904		} else {
6905			struct kgem_bo *upload;
6906			void *ptr;
6907
6908			if (!kgem_check_batch(&sna->kgem, 8) ||
6909			    !kgem_check_bo_fenced(&sna->kgem, arg->bo) ||
6910			    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
6911				kgem_submit(&sna->kgem);
6912				if (!kgem_check_bo_fenced(&sna->kgem, arg->bo))
6913					return; /* XXX fallback? */
6914				_kgem_set_mode(&sna->kgem, KGEM_BLT);
6915			}
6916
6917			upload = kgem_create_buffer(&sna->kgem,
6918						    bstride*bh,
6919						    KGEM_BUFFER_WRITE_INPLACE,
6920						    &ptr);
6921			if (!upload)
6922				break;
6923
6924			b = sna->kgem.batch + sna->kgem.nbatch;
6925			b[0] = XY_MONO_SRC_COPY | br00;
6926			b[0] |= ((box->x1 + sx) & 7) << 17;
6927			b[1] = br13;
6928			b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
6929			b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
6930			b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4,
6931					      arg->bo,
6932					      I915_GEM_DOMAIN_RENDER << 16 |
6933					      I915_GEM_DOMAIN_RENDER |
6934					      KGEM_RELOC_FENCED,
6935					      0);
6936			b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5,
6937					      upload,
6938					      I915_GEM_DOMAIN_RENDER << 16 |
6939					      KGEM_RELOC_FENCED,
6940					      0);
6941			b[6] = gc->bgPixel;
6942			b[7] = gc->fgPixel;
6943
6944			sna->kgem.nbatch += 8;
6945
6946			dst = ptr;
6947			src_stride = bitmap->devKind;
6948			src = bitmap->devPrivate.ptr;
6949			src += (box->y1 + sy) * src_stride + bx1/8;
6950			src_stride -= bstride;
6951			do {
6952				int i = bstride;
6953				do {
6954					*dst++ = byte_reverse(*src++);
6955					*dst++ = byte_reverse(*src++);
6956					i -= 2;
6957				} while (i);
6958				src += src_stride;
6959			} while (--bh);
6960
6961			kgem_bo_destroy(&sna->kgem, upload);
6962		}
6963
6964		box++;
6965	} while (--n);
6966
6967	if (arg->damage) {
6968		RegionTranslate(region, dx, dy);
6969		sna_damage_add(arg->damage, region);
6970	}
6971	assert_pixmap_damage(pixmap);
6972	sna->blt_state.fill_bo = 0;
6973}
6974
6975static void
6976sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc,
6977		   RegionPtr region, int sx, int sy,
6978		   Pixel bitplane, void *closure)
6979{
6980	PixmapPtr dst_pixmap = get_drawable_pixmap(drawable);
6981	PixmapPtr src_pixmap = get_drawable_pixmap(source);
6982	struct sna *sna = to_sna_from_pixmap(dst_pixmap);
6983	struct sna_copy_plane *arg = closure;
6984	int16_t dx, dy;
6985	int bit = ffs(bitplane) - 1;
6986	uint32_t br00, br13;
6987	BoxPtr box = RegionRects(region);
6988	int n = RegionNumRects(region);
6989
6990	DBG(("%s: plane=%x [%d] x%d\n", __FUNCTION__,
6991	     (unsigned)bitplane, bit, n));
6992
6993	if (n == 0)
6994		return;
6995
6996	if (get_drawable_deltas(source, src_pixmap, &dx, &dy))
6997		sx += dx, sy += dy;
6998
6999	get_drawable_deltas(drawable, dst_pixmap, &dx, &dy);
7000	assert_pixmap_contains_boxes(dst_pixmap, box, n, dx, dy);
7001
7002	br00 = XY_MONO_SRC_COPY | 3 << 20;
7003	br13 = arg->bo->pitch;
7004	if (sna->kgem.gen >= 040 && arg->bo->tiling) {
7005		br00 |= BLT_DST_TILED;
7006		br13 >>= 2;
7007	}
7008	br13 |= blt_depth(drawable->depth) << 24;
7009	br13 |= copy_ROP[gc->alu] << 16;
7010
7011	kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo);
7012	do {
7013		int bx1 = (box->x1 + sx) & ~7;
7014		int bx2 = (box->x2 + sx + 7) & ~7;
7015		int bw = (bx2 - bx1)/8;
7016		int bh = box->y2 - box->y1;
7017		int bstride = ALIGN(bw, 2);
7018		uint32_t *b;
7019		struct kgem_bo *upload;
7020		void *ptr;
7021
7022		DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n",
7023		     __FUNCTION__,
7024		     box->x1, box->y1,
7025		     box->x2, box->y2,
7026		     sx, sy, bx1, bx2));
7027
7028		if (!kgem_check_batch(&sna->kgem, 8) ||
7029		    !kgem_check_bo_fenced(&sna->kgem, arg->bo) ||
7030		    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
7031			kgem_submit(&sna->kgem);
7032			if (!kgem_check_bo_fenced(&sna->kgem, arg->bo))
7033				return; /* XXX fallback? */
7034			_kgem_set_mode(&sna->kgem, KGEM_BLT);
7035		}
7036
7037		upload = kgem_create_buffer(&sna->kgem,
7038					    bstride*bh,
7039					    KGEM_BUFFER_WRITE_INPLACE,
7040					    &ptr);
7041		if (!upload)
7042			break;
7043
7044		switch (source->bitsPerPixel) {
7045		case 32:
7046			{
7047				uint32_t *src = src_pixmap->devPrivate.ptr;
7048				int src_stride = src_pixmap->devKind/sizeof(uint32_t);
7049				uint8_t *dst = ptr;
7050
7051				src += (box->y1 + sy) * src_stride;
7052				src += bx1;
7053
7054				src_stride -= bw * 8;
7055				bstride -= bw;
7056
7057				do {
7058					int i = bw;
7059					do {
7060						uint8_t v = 0;
7061
7062						v |= ((*src++ >> bit) & 1) << 7;
7063						v |= ((*src++ >> bit) & 1) << 6;
7064						v |= ((*src++ >> bit) & 1) << 5;
7065						v |= ((*src++ >> bit) & 1) << 4;
7066						v |= ((*src++ >> bit) & 1) << 3;
7067						v |= ((*src++ >> bit) & 1) << 2;
7068						v |= ((*src++ >> bit) & 1) << 1;
7069						v |= ((*src++ >> bit) & 1) << 0;
7070
7071						*dst++ = v;
7072					} while (--i);
7073					dst += bstride;
7074					src += src_stride;
7075				} while (--bh);
7076				break;
7077			}
7078		case 16:
7079			{
7080				uint16_t *src = src_pixmap->devPrivate.ptr;
7081				int src_stride = src_pixmap->devKind/sizeof(uint16_t);
7082				uint8_t *dst = ptr;
7083
7084				src += (box->y1 + sy) * src_stride;
7085				src += bx1;
7086
7087				src_stride -= bw * 8;
7088				bstride -= bw;
7089
7090				do {
7091					int i = bw;
7092					do {
7093						uint8_t v = 0;
7094
7095						v |= ((*src++ >> bit) & 1) << 7;
7096						v |= ((*src++ >> bit) & 1) << 6;
7097						v |= ((*src++ >> bit) & 1) << 5;
7098						v |= ((*src++ >> bit) & 1) << 4;
7099						v |= ((*src++ >> bit) & 1) << 3;
7100						v |= ((*src++ >> bit) & 1) << 2;
7101						v |= ((*src++ >> bit) & 1) << 1;
7102						v |= ((*src++ >> bit) & 1) << 0;
7103
7104						*dst++ = v;
7105					} while (--i);
7106					dst += bstride;
7107					src += src_stride;
7108				} while (--bh);
7109				break;
7110			}
7111		default:
7112			assert(0);
7113		case 8:
7114			{
7115				uint8_t *src = src_pixmap->devPrivate.ptr;
7116				int src_stride = src_pixmap->devKind/sizeof(uint8_t);
7117				uint8_t *dst = ptr;
7118
7119				src += (box->y1 + sy) * src_stride;
7120				src += bx1;
7121
7122				src_stride -= bw * 8;
7123				bstride -= bw;
7124
7125				do {
7126					int i = bw;
7127					do {
7128						uint8_t v = 0;
7129
7130						v |= ((*src++ >> bit) & 1) << 7;
7131						v |= ((*src++ >> bit) & 1) << 6;
7132						v |= ((*src++ >> bit) & 1) << 5;
7133						v |= ((*src++ >> bit) & 1) << 4;
7134						v |= ((*src++ >> bit) & 1) << 3;
7135						v |= ((*src++ >> bit) & 1) << 2;
7136						v |= ((*src++ >> bit) & 1) << 1;
7137						v |= ((*src++ >> bit) & 1) << 0;
7138
7139						*dst++ = v;
7140					} while (--i);
7141					dst += bstride;
7142					src += src_stride;
7143				} while (--bh);
7144				break;
7145			}
7146		}
7147
7148		b = sna->kgem.batch + sna->kgem.nbatch;
7149		b[0] = br00 | ((box->x1 + sx) & 7) << 17;
7150		b[1] = br13;
7151		b[2] = (box->y1 + dy) << 16 | (box->x1 + dx);
7152		b[3] = (box->y2 + dy) << 16 | (box->x2 + dx);
7153		b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4,
7154				      arg->bo,
7155				      I915_GEM_DOMAIN_RENDER << 16 |
7156				      I915_GEM_DOMAIN_RENDER |
7157				      KGEM_RELOC_FENCED,
7158				      0);
7159		b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5,
7160				      upload,
7161				      I915_GEM_DOMAIN_RENDER << 16 |
7162				      KGEM_RELOC_FENCED,
7163				      0);
7164		b[6] = gc->bgPixel;
7165		b[7] = gc->fgPixel;
7166
7167		sna->kgem.nbatch += 8;
7168		kgem_bo_destroy(&sna->kgem, upload);
7169
7170		box++;
7171	} while (--n);
7172
7173	if (arg->damage) {
7174		RegionTranslate(region, dx, dy);
7175		sna_damage_add(arg->damage, region);
7176	}
7177	assert_pixmap_damage(dst_pixmap);
7178	sna->blt_state.fill_bo = 0;
7179}
7180
7181static RegionPtr
7182sna_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc,
7183	       int src_x, int src_y,
7184	       int w, int h,
7185	       int dst_x, int dst_y,
7186	       unsigned long bit)
7187{
7188	PixmapPtr pixmap = get_drawable_pixmap(dst);
7189	struct sna *sna = to_sna_from_pixmap(pixmap);
7190	RegionRec region, *ret = NULL;
7191	struct sna_copy_plane arg;
7192
7193	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=%dx%d\n", __FUNCTION__,
7194	     src_x, src_y, dst_x, dst_y, w, h));
7195
7196	if (gc->planemask == 0)
7197		goto empty;
7198
7199	if (src->bitsPerPixel == 1 && (bit&1) == 0)
7200		goto empty;
7201
7202	region.extents.x1 = dst_x + dst->x;
7203	region.extents.y1 = dst_y + dst->y;
7204	region.extents.x2 = region.extents.x1 + w;
7205	region.extents.y2 = region.extents.y1 + h;
7206	region.data = NULL;
7207	RegionIntersect(&region, &region, gc->pCompositeClip);
7208
7209	DBG(("%s: dst extents (%d, %d), (%d, %d)\n",
7210	     __FUNCTION__,
7211	     region.extents.x1, region.extents.y1,
7212	     region.extents.x2, region.extents.y2));
7213
7214	{
7215		RegionRec clip;
7216
7217		clip.extents.x1 = src->x - (src->x + src_x) + (dst->x + dst_x);
7218		clip.extents.y1 = src->y - (src->y + src_y) + (dst->y + dst_y);
7219		clip.extents.x2 = clip.extents.x1 + src->width;
7220		clip.extents.y2 = clip.extents.y1 + src->height;
7221		clip.data = NULL;
7222
7223		DBG(("%s: src extents (%d, %d), (%d, %d)\n",
7224		     __FUNCTION__,
7225		     clip.extents.x1, clip.extents.y1,
7226		     clip.extents.x2, clip.extents.y2));
7227
7228		RegionIntersect(&region, &region, &clip);
7229	}
7230	DBG(("%s: dst^src extents (%d, %d), (%d, %d)\n",
7231	     __FUNCTION__,
7232	     region.extents.x1, region.extents.y1,
7233	     region.extents.x2, region.extents.y2));
7234	if (RegionNil(&region))
7235		goto empty;
7236
7237	RegionTranslate(&region,
7238			src_x - dst_x - dst->x + src->x,
7239			src_y - dst_y - dst->y + src->y);
7240
7241	if (!sna_drawable_move_region_to_cpu(src, &region, MOVE_READ))
7242		goto out;
7243
7244	RegionTranslate(&region,
7245			-(src_x - dst_x - dst->x + src->x),
7246			-(src_y - dst_y - dst->y + src->y));
7247
7248	if (FORCE_FALLBACK)
7249		goto fallback;
7250
7251	if (!ACCEL_COPY_PLANE)
7252		goto fallback;
7253
7254	if (wedged(sna))
7255		goto fallback;
7256
7257	if (!PM_IS_SOLID(dst, gc->planemask))
7258		goto fallback;
7259
7260	arg.bo = sna_drawable_use_bo(dst, PREFER_GPU,
7261				     &region.extents, &arg.damage);
7262	if (arg.bo) {
7263		if (arg.bo->tiling == I915_TILING_Y) {
7264			assert(arg.bo == __sna_pixmap_get_bo(pixmap));
7265			arg.bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
7266			if (arg.bo == NULL) {
7267				DBG(("%s: fallback -- unable to change tiling\n",
7268				     __FUNCTION__));
7269				goto fallback;
7270			}
7271		}
7272		RegionUninit(&region);
7273		return sna_do_copy(src, dst, gc,
7274				   src_x, src_y,
7275				   w, h,
7276				   dst_x, dst_y,
7277				   src->depth == 1 ? sna_copy_bitmap_blt : sna_copy_plane_blt,
7278				   (Pixel)bit, &arg);
7279	}
7280
7281fallback:
7282	DBG(("%s: fallback\n", __FUNCTION__));
7283	if (!sna_gc_move_to_cpu(gc, dst, &region))
7284		goto out;
7285	if (!sna_drawable_move_region_to_cpu(dst, &region,
7286					     drawable_gc_flags(dst, gc, false)))
7287		goto out_gc;
7288
7289	DBG(("%s: fbCopyPlane(%d, %d, %d, %d, %d,%d) %x\n",
7290	     __FUNCTION__, src_x, src_y, w, h, dst_x, dst_y, (unsigned)bit));
7291	ret = miDoCopy(src, dst, gc,
7292		       src_x, src_y, w, h, dst_x, dst_y,
7293		       src->bitsPerPixel > 1 ? fbCopyNto1 : fbCopy1toN,
7294		       bit, 0);
7295	FALLBACK_FLUSH(dst);
7296out_gc:
7297	sna_gc_move_to_gpu(gc);
7298out:
7299	RegionUninit(&region);
7300	return ret;
7301empty:
7302	return miHandleExposures(src, dst, gc,
7303				 src_x, src_y,
7304				 w, h,
7305				 dst_x, dst_y, bit);
7306}
7307
7308static bool
7309sna_poly_point_blt(DrawablePtr drawable,
7310		   struct kgem_bo *bo,
7311		   struct sna_damage **damage,
7312		   GCPtr gc, int mode, int n, DDXPointPtr pt,
7313		   bool clipped)
7314{
7315	PixmapPtr pixmap = get_drawable_pixmap(drawable);
7316	struct sna *sna = to_sna_from_pixmap(pixmap);
7317	BoxRec box[512], *b = box, * const last_box = box + ARRAY_SIZE(box);
7318	struct sna_fill_op fill;
7319	DDXPointRec last;
7320	int16_t dx, dy;
7321
7322	DBG(("%s: alu=%d, pixel=%08lx, clipped?=%d\n",
7323	     __FUNCTION__, gc->alu, gc->fgPixel, clipped));
7324
7325	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel))
7326		return false;
7327
7328	get_drawable_deltas(drawable, pixmap, &dx, &dy);
7329
7330	last.x = drawable->x;
7331	last.y = drawable->y;
7332
7333	if (!clipped) {
7334		last.x += dx;
7335		last.y += dy;
7336
7337		assert_pixmap_contains_points(pixmap, pt, n, last.x, last.y);
7338		sna_damage_add_points(damage, pt, n, last.x, last.y);
7339		do {
7340			unsigned nbox = n;
7341			if (nbox > ARRAY_SIZE(box))
7342				nbox = ARRAY_SIZE(box);
7343			n -= nbox;
7344			do {
7345				*(DDXPointRec *)b = *pt++;
7346
7347				b->x1 += last.x;
7348				b->y1 += last.y;
7349				if (mode == CoordModePrevious)
7350					last = *(DDXPointRec *)b;
7351
7352				b->x2 = b->x1 + 1;
7353				b->y2 = b->y1 + 1;
7354				b++;
7355			} while (--nbox);
7356			fill.boxes(sna, &fill, box, b - box);
7357			b = box;
7358		} while (n);
7359	} else {
7360		RegionPtr clip = gc->pCompositeClip;
7361
7362		while (n--) {
7363			int x, y;
7364
7365			x = pt->x;
7366			y = pt->y;
7367			pt++;
7368			if (mode == CoordModePrevious) {
7369				x += last.x;
7370				y += last.y;
7371				last.x = x;
7372				last.y = y;
7373			} else {
7374				x += drawable->x;
7375				y += drawable->y;
7376			}
7377
7378			if (RegionContainsPoint(clip, x, y, NULL)) {
7379				b->x1 = x + dx;
7380				b->y1 = y + dy;
7381				b->x2 = b->x1 + 1;
7382				b->y2 = b->y1 + 1;
7383				if (++b == last_box){
7384					assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0);
7385					fill.boxes(sna, &fill, box, last_box - box);
7386					if (damage)
7387						sna_damage_add_boxes(damage, box, last_box-box, 0, 0);
7388					b = box;
7389				}
7390			}
7391		}
7392		if (b != box){
7393			assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
7394			fill.boxes(sna, &fill, box, b - box);
7395			if (damage)
7396				sna_damage_add_boxes(damage, box, b-box, 0, 0);
7397		}
7398	}
7399	fill.done(sna, &fill);
7400	assert_pixmap_damage(pixmap);
7401	return true;
7402}
7403
7404static unsigned
7405sna_poly_point_extents(DrawablePtr drawable, GCPtr gc,
7406		       int mode, int n, DDXPointPtr pt, BoxPtr out)
7407{
7408	BoxRec box;
7409	bool clipped;
7410
7411	if (n == 0)
7412		return 0;
7413
7414	box.x2 = box.x1 = pt->x;
7415	box.y2 = box.y1 = pt->y;
7416	if (mode == CoordModePrevious) {
7417		DDXPointRec last = *pt++;
7418		while (--n) {
7419			last.x += pt->x;
7420			last.y += pt->y;
7421			pt++;
7422			box_add_pt(&box, last.x, last.y);
7423		}
7424	} else {
7425		while (--n) {
7426			++pt;
7427			box_add_pt(&box, pt->x, pt->y);
7428		}
7429	}
7430	box.x2++;
7431	box.y2++;
7432
7433	clipped = trim_and_translate_box(&box, drawable, gc);
7434	if (box_empty(&box))
7435		return 0;
7436
7437	*out = box;
7438	return 1 | clipped << 1;
7439}
7440
7441static void
7442sna_poly_point(DrawablePtr drawable, GCPtr gc,
7443	       int mode, int n, DDXPointPtr pt)
7444{
7445	PixmapPtr pixmap = get_drawable_pixmap(drawable);
7446	struct sna *sna = to_sna_from_pixmap(pixmap);
7447	RegionRec region;
7448	unsigned flags;
7449
7450	DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d)\n",
7451	     __FUNCTION__, mode, n, pt[0].x, pt[0].y));
7452
7453	flags = sna_poly_point_extents(drawable, gc, mode, n, pt, &region.extents);
7454	if (flags == 0)
7455		return;
7456
7457	DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
7458	     region.extents.x1, region.extents.y1,
7459	     region.extents.x2, region.extents.y2,
7460	     flags));
7461
7462	if (FORCE_FALLBACK)
7463		goto fallback;
7464
7465	if (!ACCEL_POLY_POINT)
7466		goto fallback;
7467
7468	if (wedged(sna)) {
7469		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
7470		goto fallback;
7471	}
7472
7473	if (PM_IS_SOLID(drawable, gc->planemask)) {
7474		struct sna_damage **damage;
7475		struct kgem_bo *bo;
7476
7477		DBG(("%s: trying solid fill [%08lx] blt paths\n",
7478		     __FUNCTION__, gc->fgPixel));
7479
7480		if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU,
7481					      &region.extents, &damage)) &&
7482		    sna_poly_point_blt(drawable, bo, damage,
7483				       gc, mode, n, pt, flags & 2))
7484			return;
7485	}
7486
7487fallback:
7488	DBG(("%s: fallback\n", __FUNCTION__));
7489	region.data = NULL;
7490	region_maybe_clip(&region, gc->pCompositeClip);
7491	if (RegionNil(&region))
7492		return;
7493
7494	if (!sna_gc_move_to_cpu(gc, drawable, &region))
7495		goto out;
7496	if (!sna_drawable_move_region_to_cpu(drawable, &region,
7497					     MOVE_READ | MOVE_WRITE))
7498		goto out_gc;
7499
7500	DBG(("%s: fbPolyPoint\n", __FUNCTION__));
7501	fbPolyPoint(drawable, gc, mode, n, pt, flags);
7502	FALLBACK_FLUSH(drawable);
7503out_gc:
7504	sna_gc_move_to_gpu(gc);
7505out:
7506	RegionUninit(&region);
7507}
7508
7509static bool
7510sna_poly_zero_line_blt(DrawablePtr drawable,
7511		       struct kgem_bo *bo,
7512		       struct sna_damage **damage,
7513		       GCPtr gc, int mode, const int _n, const DDXPointRec * const _pt,
7514		       const BoxRec *extents, unsigned clipped)
7515{
7516	static void * const _jump[] = {
7517		&&no_damage,
7518		&&damage,
7519
7520		&&no_damage_offset,
7521		&&damage_offset,
7522	};
7523
7524	PixmapPtr pixmap = get_drawable_pixmap(drawable);
7525	struct sna *sna = to_sna_from_pixmap(pixmap);
7526	int x2, y2, xstart, ystart, oc2;
7527	unsigned int bias = miGetZeroLineBias(drawable->pScreen);
7528	bool degenerate = true;
7529	struct sna_fill_op fill;
7530	RegionRec clip;
7531	BoxRec box[512], *b, * const last_box = box + ARRAY_SIZE(box);
7532	const BoxRec *last_extents;
7533	int16_t dx, dy;
7534	void *jump, *ret;
7535
7536	DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n",
7537	     __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage));
7538	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel))
7539		return false;
7540
7541	get_drawable_deltas(drawable, pixmap, &dx, &dy);
7542
7543	region_set(&clip, extents);
7544	if (clipped) {
7545		region_maybe_clip(&clip, gc->pCompositeClip);
7546		if (RegionNil(&clip))
7547			return true;
7548	}
7549
7550	jump = _jump[(damage != NULL) | !!(dx|dy) << 1];
7551	DBG(("%s: [clipped=%x] extents=(%d, %d), (%d, %d), delta=(%d, %d), damage=%p\n",
7552	     __FUNCTION__, clipped,
7553	     clip.extents.x1, clip.extents.y1,
7554	     clip.extents.x2, clip.extents.y2,
7555	     dx, dy, damage));
7556
7557	extents = RegionRects(&clip);
7558	last_extents = extents + RegionNumRects(&clip);
7559
7560	b = box;
7561	do {
7562		int n = _n;
7563		const DDXPointRec *pt = _pt;
7564
7565		xstart = pt->x + drawable->x;
7566		ystart = pt->y + drawable->y;
7567
7568		x2 = xstart;
7569		y2 = ystart;
7570		oc2 = 0;
7571		OUTCODES(oc2, x2, y2, extents);
7572
7573		while (--n) {
7574			int16_t sdx, sdy;
7575			int adx, ady, length;
7576			int e, e1, e2, e3;
7577			int x1 = x2, x;
7578			int y1 = y2, y;
7579			int oc1 = oc2;
7580			int octant;
7581
7582			++pt;
7583
7584			x2 = pt->x;
7585			y2 = pt->y;
7586			if (mode == CoordModePrevious) {
7587				x2 += x1;
7588				y2 += y1;
7589			} else {
7590				x2 += drawable->x;
7591				y2 += drawable->y;
7592			}
7593			DBG(("%s: segment (%d, %d) to (%d, %d)\n",
7594			     __FUNCTION__, x1, y1, x2, y2));
7595			if (x2 == x1 && y2 == y1)
7596				continue;
7597
7598			degenerate = false;
7599
7600			oc2 = 0;
7601			OUTCODES(oc2, x2, y2, extents);
7602			if (oc1 & oc2)
7603				continue;
7604
7605			CalcLineDeltas(x1, y1, x2, y2,
7606				       adx, ady, sdx, sdy,
7607				       1, 1, octant);
7608
7609			DBG(("%s: adx=(%d, %d), sdx=(%d, %d), oc1=%x, oc2=%x\n",
7610			     __FUNCTION__, adx, ady, sdx, sdy, oc1, oc2));
7611			if (adx == 0 || ady == 0) {
7612				if (x1 <= x2) {
7613					b->x1 = x1;
7614					b->x2 = x2;
7615				} else {
7616					b->x1 = x2;
7617					b->x2 = x1;
7618				}
7619				if (y1 <= y2) {
7620					b->y1 = y1;
7621					b->y2 = y2;
7622				} else {
7623					b->y1 = y2;
7624					b->y2 = y1;
7625				}
7626				b->x2++;
7627				b->y2++;
7628				if (oc1 | oc2) {
7629					bool intersects;
7630
7631					intersects = box_intersect(b, extents);
7632					assert(intersects);
7633				}
7634				if (++b == last_box) {
7635					ret = &&rectangle_continue;
7636					goto *jump;
7637rectangle_continue:
7638					b = box;
7639				}
7640			} else if (adx >= ady) {
7641				int x2_clipped = x2, y2_clipped = y2;
7642				bool dirty;
7643
7644				/* X-major segment */
7645				e1 = ady << 1;
7646				e2 = e1 - (adx << 1);
7647				e  = e1 - adx;
7648				length = adx;
7649
7650				FIXUP_ERROR(e, octant, bias);
7651
7652				x = x1;
7653				y = y1;
7654
7655				if (oc1 | oc2) {
7656					int pt1_clipped, pt2_clipped;
7657
7658					if (miZeroClipLine(extents->x1, extents->y1,
7659							   extents->x2-1, extents->y2-1,
7660							   &x, &y, &x2_clipped, &y2_clipped,
7661							   adx, ady,
7662							   &pt1_clipped, &pt2_clipped,
7663							   octant, bias, oc1, oc2) == -1)
7664						continue;
7665
7666					length = abs(x2_clipped - x);
7667					if (length == 0)
7668						continue;
7669
7670					if (pt1_clipped) {
7671						int clipdx = abs(x - x1);
7672						int clipdy = abs(y - y1);
7673						e += clipdy * e2 + (clipdx - clipdy) * e1;
7674					}
7675				}
7676
7677				e3 = e2 - e1;
7678				e  = e - e1;
7679
7680				b->x1 = x;
7681				b->y1 = y;
7682				dirty = false;
7683				while (length--) {
7684					e += e1;
7685					dirty = true;
7686					if (e >= 0) {
7687						e += e3;
7688
7689						if (sdx < 0) {
7690							b->x2 = b->x1 + 1;
7691							b->x1 = x;
7692						} else
7693							b->x2 = x + 1;
7694						b->y2 = b->y1 + 1;
7695
7696						if (++b == last_box) {
7697							ret = &&X_continue;
7698							goto *jump;
7699X_continue:
7700							b = box;
7701						}
7702
7703						b->x1 = x + sdx;
7704						b->y1 = y += sdy;
7705						dirty = false;
7706					}
7707					x += sdx;
7708				}
7709				if (dirty) {
7710					x -= sdx;
7711					if (sdx < 0) {
7712						b->x2 = b->x1 + 1;
7713						b->x1 = x;
7714					} else
7715						b->x2 = x + 1;
7716					b->y2 = b->y1 + 1;
7717
7718					if (++b == last_box) {
7719						ret = &&X2_continue;
7720						goto *jump;
7721X2_continue:
7722						b = box;
7723					}
7724				}
7725			} else {
7726				int x2_clipped = x2, y2_clipped = y2;
7727				bool dirty;
7728
7729				/* Y-major segment */
7730				e1 = adx << 1;
7731				e2 = e1 - (ady << 1);
7732				e  = e1 - ady;
7733				length  = ady;
7734
7735				SetYMajorOctant(octant);
7736				FIXUP_ERROR(e, octant, bias);
7737
7738				x = x1;
7739				y = y1;
7740
7741				if (oc1 | oc2) {
7742					int pt1_clipped, pt2_clipped;
7743
7744					if (miZeroClipLine(extents->x1, extents->y1,
7745							   extents->x2-1, extents->y2-1,
7746							   &x, &y, &x2_clipped, &y2_clipped,
7747							   adx, ady,
7748							   &pt1_clipped, &pt2_clipped,
7749							   octant, bias, oc1, oc2) == -1)
7750						continue;
7751
7752					length = abs(y2_clipped - y);
7753					if (length == 0)
7754						continue;
7755
7756					if (pt1_clipped) {
7757						int clipdx = abs(x - x1);
7758						int clipdy = abs(y - y1);
7759						e += clipdx * e2 + (clipdy - clipdx) * e1;
7760					}
7761				}
7762
7763				e3 = e2 - e1;
7764				e  = e - e1;
7765
7766				b->x1 = x;
7767				b->y1 = y;
7768				dirty = false;
7769				while (length--) {
7770					e += e1;
7771					dirty = true;
7772					if (e >= 0) {
7773						e += e3;
7774
7775						if (sdy < 0) {
7776							b->y2 = b->y1 + 1;
7777							b->y1 = y;
7778						} else
7779							b->y2 = y + 1;
7780						b->x2 = x + 1;
7781
7782						if (++b == last_box) {
7783							ret = &&Y_continue;
7784							goto *jump;
7785Y_continue:
7786							b = box;
7787						}
7788
7789						b->x1 = x += sdx;
7790						b->y1 = y + sdy;
7791						dirty = false;
7792					}
7793					y += sdy;
7794				}
7795
7796				if (dirty) {
7797					y -= sdy;
7798					if (sdy < 0) {
7799						b->y2 = b->y1 + 1;
7800						b->y1 = y;
7801					} else
7802						b->y2 = y + 1;
7803					b->x2 = x + 1;
7804
7805					if (++b == last_box) {
7806						ret = &&Y2_continue;
7807						goto *jump;
7808Y2_continue:
7809						b = box;
7810					}
7811				}
7812			}
7813		}
7814
7815#if 0
7816		/* Only do the CapNotLast check on the last segment
7817		 * and only if the endpoint wasn't clipped.  And then, if the last
7818		 * point is the same as the first point, do not draw it, unless the
7819		 * line is degenerate
7820		 */
7821		if (!pt2_clipped &&
7822		    gc->capStyle != CapNotLast &&
7823		    !(xstart == x2 && ystart == y2 && !degenerate))
7824		{
7825			b->x2 = x2;
7826			b->y2 = y2;
7827			if (b->x2 < b->x1) {
7828				int16_t t = b->x1;
7829				b->x1 = b->x2;
7830				b->x2 = t;
7831			}
7832			if (b->y2 < b->y1) {
7833				int16_t t = b->y1;
7834				b->y1 = b->y2;
7835				b->y2 = t;
7836			}
7837			b->x2++;
7838			b->y2++;
7839			b++;
7840		}
7841#endif
7842	} while (++extents != last_extents);
7843
7844	if (b != box) {
7845		ret = &&done;
7846		goto *jump;
7847	}
7848
7849done:
7850	fill.done(sna, &fill);
7851	assert_pixmap_damage(pixmap);
7852	RegionUninit(&clip);
7853	return true;
7854
7855damage:
7856	assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
7857	sna_damage_add_boxes(damage, box, b-box, 0, 0);
7858no_damage:
7859	fill.boxes(sna, &fill, box, b-box);
7860	goto *ret;
7861
7862no_damage_offset:
7863	{
7864		BoxRec *bb = box;
7865		do {
7866			bb->x1 += dx;
7867			bb->x2 += dx;
7868			bb->y1 += dy;
7869			bb->y2 += dy;
7870		} while (++bb != b);
7871		assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
7872		fill.boxes(sna, &fill, box, b - box);
7873	}
7874	goto *ret;
7875
7876damage_offset:
7877	{
7878		BoxRec *bb = box;
7879		do {
7880			bb->x1 += dx;
7881			bb->x2 += dx;
7882			bb->y1 += dy;
7883			bb->y2 += dy;
7884		} while (++bb != b);
7885		assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0);
7886		fill.boxes(sna, &fill, box, b - box);
7887		sna_damage_add_boxes(damage, box, b - box, 0, 0);
7888	}
7889	goto *ret;
7890}
7891
7892static bool
7893sna_poly_line_blt(DrawablePtr drawable,
7894		  struct kgem_bo *bo,
7895		  struct sna_damage **damage,
7896		  GCPtr gc, uint32_t pixel,
7897		  int mode, int n, DDXPointPtr pt,
7898		  const BoxRec *extents, bool clipped)
7899{
7900	PixmapPtr pixmap = get_drawable_pixmap(drawable);
7901	struct sna *sna = to_sna_from_pixmap(pixmap);
7902	BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes);
7903	struct sna_fill_op fill;
7904	DDXPointRec last;
7905	int16_t dx, dy;
7906
7907	DBG(("%s: alu=%d, fg=%08x\n", __FUNCTION__, gc->alu, (unsigned)pixel));
7908
7909	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel))
7910		return false;
7911
7912	get_drawable_deltas(drawable, pixmap, &dx, &dy);
7913
7914	if (!clipped) {
7915		dx += drawable->x;
7916		dy += drawable->y;
7917
7918		last.x = pt->x + dx;
7919		last.y = pt->y + dy;
7920		pt++;
7921
7922		while (--n) {
7923			DDXPointRec p;
7924
7925			p = *pt++;
7926			if (mode == CoordModePrevious) {
7927				p.x += last.x;
7928				p.y += last.y;
7929			} else {
7930				p.x += dx;
7931				p.y += dy;
7932			}
7933			if (last.x == p.x) {
7934				b->x1 = last.x;
7935				b->x2 = last.x + 1;
7936			} else if (last.x < p.x) {
7937				b->x1 = last.x;
7938				b->x2 = p.x;
7939			} else {
7940				b->x1 = p.x;
7941				b->x2 = last.x;
7942			}
7943			if (last.y == p.y) {
7944				b->y1 = last.y;
7945				b->y2 = last.y + 1;
7946			} else if (last.y < p.y) {
7947				b->y1 = last.y;
7948				b->y2 = p.y;
7949			} else {
7950				b->y1 = p.y;
7951				b->y2 = last.y;
7952			}
7953			b->y2 += last.x == p.x;
7954			b->x2 += last.y == p.y;
7955			DBG(("%s: blt (%d, %d), (%d, %d)\n",
7956			     __FUNCTION__,
7957			     b->x1, b->y1, b->x2, b->y2));
7958			if (++b == last_box) {
7959				assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0);
7960				fill.boxes(sna, &fill, boxes, last_box - boxes);
7961				if (damage)
7962					sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0);
7963				b = boxes;
7964			}
7965
7966			last = p;
7967		}
7968	} else {
7969		RegionRec clip;
7970
7971		region_set(&clip, extents);
7972		region_maybe_clip(&clip, gc->pCompositeClip);
7973		if (RegionNil(&clip))
7974			return true;
7975
7976		last.x = pt->x + drawable->x;
7977		last.y = pt->y + drawable->y;
7978		pt++;
7979
7980		if (clip.data == NULL) {
7981			while (--n) {
7982				DDXPointRec p;
7983
7984				p = *pt++;
7985				if (mode == CoordModePrevious) {
7986					p.x += last.x;
7987					p.y += last.y;
7988				} else {
7989					p.x += drawable->x;
7990					p.y += drawable->y;
7991				}
7992				if (last.x == p.x) {
7993					b->x1 = last.x;
7994					b->x2 = last.x + 1;
7995				} else if (last.x < p.x) {
7996					b->x1 = last.x;
7997					b->x2 = p.x;
7998				} else {
7999					b->x1 = p.x;
8000					b->x2 = last.x;
8001				}
8002				if (last.y == p.y) {
8003					b->y1 = last.y;
8004					b->y2 = last.y + 1;
8005				} else if (last.y < p.y) {
8006					b->y1 = last.y;
8007					b->y2 = p.y;
8008				} else {
8009					b->y1 = p.y;
8010					b->y2 = last.y;
8011				}
8012				b->y2 += last.x == p.x;
8013				b->x2 += last.y == p.y;
8014				DBG(("%s: blt (%d, %d), (%d, %d)\n",
8015				     __FUNCTION__,
8016				     b->x1, b->y1, b->x2, b->y2));
8017				if (box_intersect(b, &clip.extents)) {
8018					b->x1 += dx;
8019					b->x2 += dx;
8020					b->y1 += dy;
8021					b->y2 += dy;
8022					if (++b == last_box) {
8023						assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0);
8024						fill.boxes(sna, &fill, boxes, last_box - boxes);
8025						if (damage)
8026							sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0);
8027						b = boxes;
8028					}
8029				}
8030
8031				last = p;
8032			}
8033		} else {
8034			const BoxRec * const clip_start = RegionBoxptr(&clip);
8035			const BoxRec * const clip_end = clip_start + clip.data->numRects;
8036			const BoxRec *c;
8037
8038			while (--n) {
8039				DDXPointRec p;
8040				BoxRec box;
8041
8042				p = *pt++;
8043				if (mode == CoordModePrevious) {
8044					p.x += last.x;
8045					p.y += last.y;
8046				} else {
8047					p.x += drawable->x;
8048					p.y += drawable->y;
8049				}
8050				if (last.x == p.x) {
8051					box.x1 = last.x;
8052					box.x2 = last.x + 1;
8053				} else if (last.x < p.x) {
8054					box.x1 = last.x;
8055					box.x2 = p.x;
8056				} else {
8057					box.x1 = p.x;
8058					box.x2 = last.x;
8059				}
8060				if (last.y == p.y) {
8061					box.y1 = last.y;
8062					box.y2 = last.y + 1;
8063				} else if (last.y < p.y) {
8064					box.y1 = last.y;
8065					box.y2 = p.y;
8066				} else {
8067					box.y1 = p.y;
8068					box.y2 = last.y;
8069				}
8070				b->y2 += last.x == p.x;
8071				b->x2 += last.y == p.y;
8072				DBG(("%s: blt (%d, %d), (%d, %d)\n",
8073				     __FUNCTION__,
8074				     box.x1, box.y1, box.x2, box.y2));
8075
8076				c = find_clip_box_for_y(clip_start,
8077							clip_end,
8078							box.y1);
8079				while (c != clip_end) {
8080					if (box.y2 <= c->y1)
8081						break;
8082
8083					*b = box;
8084					if (box_intersect(b, c++)) {
8085						b->x1 += dx;
8086						b->x2 += dx;
8087						b->y1 += dy;
8088						b->y2 += dy;
8089						if (++b == last_box) {
8090							assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0);
8091							fill.boxes(sna, &fill, boxes, last_box-boxes);
8092							if (damage)
8093								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
8094							b = boxes;
8095						}
8096					}
8097				}
8098
8099				last = p;
8100			}
8101		}
8102		RegionUninit(&clip);
8103	}
8104	if (b != boxes) {
8105		assert_pixmap_contains_boxes(pixmap, boxes, b-boxes, 0, 0);
8106		fill.boxes(sna, &fill, boxes, b - boxes);
8107		if (damage)
8108			sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0);
8109	}
8110	fill.done(sna, &fill);
8111	assert_pixmap_damage(pixmap);
8112	return true;
8113}
8114
8115static unsigned
8116sna_poly_line_extents(DrawablePtr drawable, GCPtr gc,
8117		      int mode, int n, DDXPointPtr pt,
8118		      BoxPtr out)
8119{
8120	BoxRec box;
8121	bool clip, blt = true;
8122
8123	if (n == 0)
8124		return 0;
8125
8126	box.x2 = box.x1 = pt->x;
8127	box.y2 = box.y1 = pt->y;
8128	if (mode == CoordModePrevious) {
8129		int x = box.x1;
8130		int y = box.y1;
8131		while (--n) {
8132			pt++;
8133			x += pt->x;
8134			y += pt->y;
8135			if (blt)
8136				blt &= pt->x == 0 || pt->y == 0;
8137			box_add_pt(&box, x, y);
8138		}
8139	} else {
8140		int x = box.x1;
8141		int y = box.y1;
8142		while (--n) {
8143			pt++;
8144			if (blt) {
8145				blt &= pt->x == x || pt->y == y;
8146				x = pt->x;
8147				y = pt->y;
8148			}
8149			box_add_pt(&box, pt->x, pt->y);
8150		}
8151	}
8152	box.x2++;
8153	box.y2++;
8154
8155	if (gc->lineWidth) {
8156		int extra = gc->lineWidth >> 1;
8157		if (n > 1) {
8158			if (gc->joinStyle == JoinMiter)
8159				extra = 6 * gc->lineWidth;
8160			else if (gc->capStyle == CapProjecting)
8161				extra = gc->lineWidth;
8162		}
8163		if (extra) {
8164			box.x1 -= extra;
8165			box.x2 += extra;
8166			box.y1 -= extra;
8167			box.y2 += extra;
8168		}
8169	}
8170
8171	clip = trim_and_translate_box(&box, drawable, gc);
8172	if (box_empty(&box))
8173		return 0;
8174
8175	*out = box;
8176	return 1 | blt << 2 | clip << 1;
8177}
8178
8179/* Only use our spans code if the destination is busy and we can't perform
8180 * the operation in place.
8181 *
8182 * Currently it looks to be faster to use the GPU for zero spans on all
8183 * platforms.
8184 */
8185inline static int
8186_use_zero_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents)
8187{
8188	if (USE_ZERO_SPANS)
8189		return USE_ZERO_SPANS > 0;
8190
8191	return !drawable_gc_inplace_hint(drawable, gc);
8192}
8193
8194static int
8195use_zero_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents)
8196{
8197	bool ret = _use_zero_spans(drawable, gc, extents);
8198	DBG(("%s? %d\n", __FUNCTION__, ret));
8199	return ret;
8200}
8201
8202/* Only use our spans code if the destination is busy and we can't perform
8203 * the operation in place.
8204 *
8205 * Currently it looks to be faster to use the CPU for wide spans on all
8206 * platforms, slow MI code. But that does not take into account the true
8207 * cost of readback?
8208 */
8209inline static int
8210_use_wide_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents)
8211{
8212	if (USE_WIDE_SPANS)
8213		return USE_WIDE_SPANS > 0;
8214
8215	return !drawable_gc_inplace_hint(drawable, gc);
8216}
8217
8218static int
8219use_wide_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents)
8220{
8221	int ret = _use_wide_spans(drawable, gc, extents);
8222	DBG(("%s? %d\n", __FUNCTION__, ret));
8223	return ret;
8224}
8225
8226static void
8227sna_poly_line(DrawablePtr drawable, GCPtr gc,
8228	      int mode, int n, DDXPointPtr pt)
8229{
8230	struct sna_pixmap *priv;
8231	struct sna_fill_spans data;
8232	uint32_t color;
8233
8234	DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d), lineWidth=%d\n",
8235	     __FUNCTION__, mode, n, pt[0].x, pt[0].y, gc->lineWidth));
8236
8237	data.flags = sna_poly_line_extents(drawable, gc, mode, n, pt,
8238					   &data.region.extents);
8239	if (data.flags == 0)
8240		return;
8241
8242	DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__,
8243	     data.region.extents.x1, data.region.extents.y1,
8244	     data.region.extents.x2, data.region.extents.y2));
8245
8246	data.region.data = NULL;
8247
8248	if (FORCE_FALLBACK)
8249		goto fallback;
8250
8251	if (!ACCEL_POLY_LINE)
8252		goto fallback;
8253
8254	data.pixmap = get_drawable_pixmap(drawable);
8255	data.sna = to_sna_from_pixmap(data.pixmap);
8256	if (wedged(data.sna)) {
8257		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
8258		goto fallback;
8259	}
8260
8261	DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lu [%d], rectlinear=%d\n",
8262	     __FUNCTION__,
8263	     gc->fillStyle, gc->fillStyle == FillSolid,
8264	     gc->lineStyle, gc->lineStyle == LineSolid,
8265	     gc->lineWidth,
8266	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask),
8267	     data.flags & 4));
8268
8269	if (!PM_IS_SOLID(drawable, gc->planemask))
8270		goto fallback;
8271
8272	priv = sna_pixmap(data.pixmap);
8273	if (!priv) {
8274		DBG(("%s: not attached to pixmap %ld\n",
8275		     __FUNCTION__, data.pixmap->drawable.serialNumber));
8276		goto fallback;
8277	}
8278
8279	if (gc->lineStyle != LineSolid) {
8280		DBG(("%s: lineStyle, %d, is not solid\n",
8281		     __FUNCTION__, gc->lineStyle));
8282		goto spans_fallback;
8283	}
8284	if (!(gc->lineWidth == 0 ||
8285	      (gc->lineWidth == 1 && (n == 1 || gc->alu == GXcopy)))) {
8286		DBG(("%s: non-zero lineWidth %d\n",
8287		     __FUNCTION__, gc->lineWidth));
8288		goto spans_fallback;
8289	}
8290
8291	if (gc_is_solid(gc, &color)) {
8292		DBG(("%s: trying solid fill [%08x]\n",
8293		     __FUNCTION__, (unsigned)color));
8294
8295		if (data.flags & 4) {
8296			data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
8297						      &data.region.extents,
8298						      &data.damage);
8299			if (data.bo &&
8300			    sna_poly_line_blt(drawable,
8301					      data.bo, data.damage,
8302					      gc, color, mode, n, pt,
8303					      &data.region.extents,
8304					      data.flags & 2))
8305				return;
8306		} else { /* !rectilinear */
8307			if ((data.bo = sna_drawable_use_bo(drawable,
8308							   use_zero_spans(drawable, gc, &data.region.extents),
8309							   &data.region.extents,
8310							   &data.damage)) &&
8311			    sna_poly_zero_line_blt(drawable,
8312						   data.bo, data.damage,
8313						   gc, mode, n, pt,
8314						   &data.region.extents,
8315						   data.flags & 2))
8316				return;
8317
8318		}
8319	} else if (data.flags & 4) {
8320		/* Try converting these to a set of rectangles instead */
8321		data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
8322					      &data.region.extents, &data.damage);
8323		if (data.bo) {
8324			DDXPointRec p1, p2;
8325			xRectangle *rect;
8326			int i;
8327
8328			DBG(("%s: converting to rectagnles\n", __FUNCTION__));
8329
8330			rect = malloc (n * sizeof (xRectangle));
8331			if (rect == NULL)
8332				return;
8333
8334			p1 = pt[0];
8335			for (i = 1; i < n; i++) {
8336				if (mode == CoordModePrevious) {
8337					p2.x = p1.x + pt[i].x;
8338					p2.y = p1.y + pt[i].y;
8339				} else
8340					p2 = pt[i];
8341				if (p1.x < p2.x) {
8342					rect[i].x = p1.x;
8343					rect[i].width = p2.x - p1.x + 1;
8344				} else if (p1.x > p2.x) {
8345					rect[i].x = p2.x;
8346					rect[i].width = p1.x - p2.x + 1;
8347				} else {
8348					rect[i].x = p1.x;
8349					rect[i].width = 1;
8350				}
8351				if (p1.y < p2.y) {
8352					rect[i].y = p1.y;
8353					rect[i].height = p2.y - p1.y + 1;
8354				} else if (p1.y > p2.y) {
8355					rect[i].y = p2.y;
8356					rect[i].height = p1.y - p2.y + 1;
8357				} else {
8358					rect[i].y = p1.y;
8359					rect[i].height = 1;
8360				}
8361
8362				/* don't paint last pixel */
8363				if (gc->capStyle == CapNotLast) {
8364					if (p1.x == p2.x)
8365						rect[i].height--;
8366					else
8367						rect[i].width--;
8368				}
8369				p1 = p2;
8370			}
8371
8372			if (gc->fillStyle == FillTiled) {
8373				i = sna_poly_fill_rect_tiled_blt(drawable,
8374								 data.bo, data.damage,
8375								 gc, n - 1, rect + 1,
8376								 &data.region.extents,
8377								 data.flags & 2);
8378			} else {
8379				i = sna_poly_fill_rect_stippled_blt(drawable,
8380								    data.bo, data.damage,
8381								    gc, n - 1, rect + 1,
8382								    &data.region.extents,
8383								    data.flags & 2);
8384			}
8385			free (rect);
8386
8387			if (i)
8388				return;
8389		}
8390	}
8391
8392spans_fallback:
8393	if ((data.bo = sna_drawable_use_bo(drawable,
8394					   use_wide_spans(drawable, gc, &data.region.extents),
8395					   &data.region.extents, &data.damage))) {
8396		DBG(("%s: converting line into spans\n", __FUNCTION__));
8397		get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy);
8398		sna_gc(gc)->priv = &data;
8399
8400		if (gc->lineWidth == 0 && gc_is_solid(gc, &color)) {
8401			struct sna_fill_op fill;
8402
8403			if (gc->lineStyle == LineSolid) {
8404				if (!sna_fill_init_blt(&fill,
8405						       data.sna, data.pixmap,
8406						       data.bo, gc->alu, color))
8407					goto fallback;
8408
8409				data.op = &fill;
8410
8411				if ((data.flags & 2) == 0) {
8412					if (data.dx | data.dy)
8413						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
8414					else
8415						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
8416					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill;
8417				} else {
8418					region_maybe_clip(&data.region,
8419							  gc->pCompositeClip);
8420					if (RegionNil(&data.region))
8421						return;
8422
8423					if (region_is_singular(&data.region)) {
8424						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
8425						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents;
8426					} else {
8427						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
8428						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes;
8429					}
8430				}
8431				assert(gc->miTranslate);
8432
8433				gc->ops = &sna_gc_ops__tmp;
8434				DBG(("%s: miZeroLine (solid fill)\n", __FUNCTION__));
8435				miZeroLine(drawable, gc, mode, n, pt);
8436				fill.done(data.sna, &fill);
8437			} else {
8438				data.op = &fill;
8439
8440				if ((data.flags & 2) == 0) {
8441					if (data.dx | data.dy)
8442						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_offset;
8443					else
8444						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash;
8445					sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash;
8446				} else {
8447					region_maybe_clip(&data.region,
8448							  gc->pCompositeClip);
8449					if (RegionNil(&data.region))
8450						return;
8451
8452					if (region_is_singular(&data.region)) {
8453						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_extents;
8454						sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_extents;
8455					} else {
8456						sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_boxes;
8457						sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_boxes;
8458					}
8459				}
8460				assert(gc->miTranslate);
8461
8462				DBG(("%s: miZeroLine (solid dash)\n", __FUNCTION__));
8463				if (!sna_fill_init_blt(&fill,
8464						       data.sna, data.pixmap,
8465						       data.bo, gc->alu, color))
8466					goto fallback;
8467
8468				gc->ops = &sna_gc_ops__tmp;
8469				miZeroDashLine(drawable, gc, mode, n, pt);
8470				fill.done(data.sna, &fill);
8471
8472				if (sna_fill_init_blt(&fill,
8473						       data.sna, data.pixmap,
8474						       data.bo, gc->alu,
8475						       gc->bgPixel)) {
8476					miZeroDashLine(drawable, gc, mode, n, pt);
8477					fill.done(data.sna, &fill);
8478				}
8479			}
8480		} else {
8481			/* Note that the WideDash functions alternate
8482			 * between filling using fgPixel and bgPixel
8483			 * so we need to reset state between FillSpans and
8484			 * cannot use the fill fast paths.
8485			 */
8486			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
8487			sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu;
8488			sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu;
8489			gc->ops = &sna_gc_ops__tmp;
8490
8491			switch (gc->lineStyle) {
8492			default:
8493				assert(0);
8494			case LineSolid:
8495				if (gc->lineWidth == 0) {
8496					DBG(("%s: miZeroLine\n", __FUNCTION__));
8497					miZeroLine(drawable, gc, mode, n, pt);
8498				} else {
8499					DBG(("%s: miWideLine\n", __FUNCTION__));
8500					miWideLine(drawable, gc, mode, n, pt);
8501				}
8502				break;
8503			case LineOnOffDash:
8504			case LineDoubleDash:
8505				if (gc->lineWidth == 0) {
8506					DBG(("%s: miZeroDashLine\n", __FUNCTION__));
8507					miZeroDashLine(drawable, gc, mode, n, pt);
8508				} else {
8509					DBG(("%s: miWideDash\n", __FUNCTION__));
8510					miWideDash(drawable, gc, mode, n, pt);
8511				}
8512				break;
8513			}
8514		}
8515
8516		gc->ops = (GCOps *)&sna_gc_ops;
8517		if (data.damage) {
8518			if (data.dx | data.dy)
8519				pixman_region_translate(&data.region, data.dx, data.dy);
8520			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
8521			sna_damage_add(data.damage, &data.region);
8522			assert_pixmap_damage(data.pixmap);
8523		}
8524		RegionUninit(&data.region);
8525		return;
8526	}
8527
8528fallback:
8529	DBG(("%s: fallback\n", __FUNCTION__));
8530	region_maybe_clip(&data.region, gc->pCompositeClip);
8531	if (RegionNil(&data.region))
8532		return;
8533
8534	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
8535		goto out;
8536	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
8537					     drawable_gc_flags(drawable, gc,
8538							       !(data.flags & 4 && n == 2))))
8539		goto out_gc;
8540
8541	DBG(("%s: fbPolyLine\n", __FUNCTION__));
8542	fbPolyLine(drawable, gc, mode, n, pt);
8543	FALLBACK_FLUSH(drawable);
8544
8545out_gc:
8546	sna_gc_move_to_gpu(gc);
8547out:
8548	RegionUninit(&data.region);
8549}
8550
8551static inline void box_from_seg(BoxPtr b, xSegment *seg, GCPtr gc)
8552{
8553	if (seg->x1 == seg->x2) {
8554		if (seg->y1 > seg->y2) {
8555			b->y2 = seg->y1 + 1;
8556			b->y1 = seg->y2 + 1;
8557			if (gc->capStyle != CapNotLast)
8558				b->y1--;
8559		} else {
8560			b->y1 = seg->y1;
8561			b->y2 = seg->y2;
8562			if (gc->capStyle != CapNotLast)
8563				b->y2++;
8564		}
8565		b->x1 = seg->x1;
8566		b->x2 = seg->x1 + 1;
8567	} else {
8568		if (seg->x1 > seg->x2) {
8569			b->x2 = seg->x1 + 1;
8570			b->x1 = seg->x2 + 1;
8571			if (gc->capStyle != CapNotLast)
8572				b->x1--;
8573		} else {
8574			b->x1 = seg->x1;
8575			b->x2 = seg->x2;
8576			if (gc->capStyle != CapNotLast)
8577				b->x2++;
8578		}
8579		b->y1 = seg->y1;
8580		b->y2 = seg->y1 + 1;
8581	}
8582
8583	DBG(("%s: seg=(%d,%d),(%d,%d); box=(%d,%d),(%d,%d)\n",
8584	     __FUNCTION__,
8585	     seg->x1, seg->y1, seg->x2, seg->y2,
8586	     b->x1, b->y1, b->x2, b->y2));
8587}
8588
8589static bool
8590sna_poly_segment_blt(DrawablePtr drawable,
8591		     struct kgem_bo *bo,
8592		     struct sna_damage **damage,
8593		     GCPtr gc, uint32_t pixel,
8594		     int n, xSegment *seg,
8595		     const BoxRec *extents, unsigned clipped)
8596{
8597	PixmapPtr pixmap = get_drawable_pixmap(drawable);
8598	struct sna *sna = to_sna_from_pixmap(pixmap);
8599	BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes);
8600	struct sna_fill_op fill;
8601	int16_t dx, dy;
8602
8603	DBG(("%s: n=%d, alu=%d, fg=%08lx, clipped=%d\n",
8604	     __FUNCTION__, n, gc->alu, gc->fgPixel, clipped));
8605
8606	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel))
8607		return false;
8608
8609	get_drawable_deltas(drawable, pixmap, &dx, &dy);
8610
8611	if (!clipped) {
8612		dx += drawable->x;
8613		dy += drawable->y;
8614		if (dx|dy) {
8615			do {
8616				unsigned nbox = n;
8617				if (nbox > ARRAY_SIZE(boxes))
8618					nbox = ARRAY_SIZE(boxes);
8619				n -= nbox;
8620				do {
8621					box_from_seg(b, seg++, gc);
8622					if (b->y2 > b->y1 && b->x2 > b->x1) {
8623						b->x1 += dx;
8624						b->x2 += dx;
8625						b->y1 += dy;
8626						b->y2 += dy;
8627						b++;
8628					}
8629				} while (--nbox);
8630
8631				if (b != boxes) {
8632					fill.boxes(sna, &fill, boxes, b-boxes);
8633					if (damage)
8634						sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
8635					b = boxes;
8636				}
8637			} while (n);
8638		} else {
8639			do {
8640				unsigned nbox = n;
8641				if (nbox > ARRAY_SIZE(boxes))
8642					nbox = ARRAY_SIZE(boxes);
8643				n -= nbox;
8644				do {
8645					box_from_seg(b++, seg++, gc);
8646				} while (--nbox);
8647
8648				if (b != boxes) {
8649					fill.boxes(sna, &fill, boxes, b-boxes);
8650					if (damage)
8651						sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
8652					b = boxes;
8653				}
8654			} while (n);
8655		}
8656	} else {
8657		RegionRec clip;
8658
8659		region_set(&clip, extents);
8660		region_maybe_clip(&clip, gc->pCompositeClip);
8661		if (RegionNil(&clip))
8662			goto done;
8663
8664		if (clip.data) {
8665			const BoxRec * const clip_start = RegionBoxptr(&clip);
8666			const BoxRec * const clip_end = clip_start + clip.data->numRects;
8667			const BoxRec *c;
8668			do {
8669				BoxRec box;
8670
8671				box_from_seg(&box, seg++, gc);
8672				box.x1 += drawable->x;
8673				box.x2 += drawable->x;
8674				box.y1 += drawable->y;
8675				box.y2 += drawable->y;
8676				c = find_clip_box_for_y(clip_start,
8677							clip_end,
8678							box.y1);
8679				while (c != clip_end) {
8680					if (box.y2 <= c->y1)
8681						break;
8682
8683					*b = box;
8684					if (box_intersect(b, c++)) {
8685						b->x1 += dx;
8686						b->x2 += dx;
8687						b->y1 += dy;
8688						b->y2 += dy;
8689						if (++b == last_box) {
8690							fill.boxes(sna, &fill, boxes, last_box-boxes);
8691							if (damage)
8692								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
8693							b = boxes;
8694						}
8695					}
8696				}
8697			} while (--n);
8698		} else {
8699			do {
8700				box_from_seg(b, seg++, gc);
8701				b->x1 += drawable->x;
8702				b->x2 += drawable->x;
8703				b->y1 += drawable->y;
8704				b->y2 += drawable->y;
8705				if (box_intersect(b, &clip.extents)) {
8706					b->x1 += dx;
8707					b->x2 += dx;
8708					b->y1 += dy;
8709					b->y2 += dy;
8710					if (++b == last_box) {
8711						fill.boxes(sna, &fill, boxes, last_box-boxes);
8712						if (damage)
8713							sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
8714						b = boxes;
8715					}
8716				}
8717			} while (--n);
8718		}
8719		RegionUninit(&clip);
8720	}
8721	if (b != boxes) {
8722		fill.boxes(sna, &fill, boxes, b - boxes);
8723		if (damage)
8724			sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0);
8725	}
8726done:
8727	fill.done(sna, &fill);
8728	assert_pixmap_damage(pixmap);
8729	return true;
8730}
8731
8732static bool
8733sna_poly_zero_segment_blt(DrawablePtr drawable,
8734			  struct kgem_bo *bo,
8735			  struct sna_damage **damage,
8736			  GCPtr gc, const int _n, const xSegment *_s,
8737			  const BoxRec *extents, unsigned clipped)
8738{
8739	static void * const _jump[] = {
8740		&&no_damage,
8741		&&damage,
8742
8743		&&no_damage_offset,
8744		&&damage_offset,
8745	};
8746
8747	PixmapPtr pixmap = get_drawable_pixmap(drawable);
8748	struct sna *sna = to_sna_from_pixmap(pixmap);
8749	unsigned int bias = miGetZeroLineBias(drawable->pScreen);
8750	struct sna_fill_op fill;
8751	RegionRec clip;
8752	const BoxRec *last_extents;
8753	BoxRec box[512], *b;
8754	BoxRec *const last_box = box + ARRAY_SIZE(box);
8755	int16_t dx, dy;
8756	void *jump, *ret;
8757
8758	DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n",
8759	     __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage));
8760	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel))
8761		return false;
8762
8763	get_drawable_deltas(drawable, pixmap, &dx, &dy);
8764
8765	region_set(&clip, extents);
8766	if (clipped) {
8767		region_maybe_clip(&clip, gc->pCompositeClip);
8768		if (RegionNil(&clip))
8769			return true;
8770	}
8771	DBG(("%s: [clipped] extents=(%d, %d), (%d, %d), delta=(%d, %d)\n",
8772	     __FUNCTION__,
8773	     clip.extents.x1, clip.extents.y1,
8774	     clip.extents.x2, clip.extents.y2,
8775	     dx, dy));
8776
8777	jump = _jump[(damage != NULL) | !!(dx|dy) << 1];
8778
8779	b = box;
8780	extents = RegionRects(&clip);
8781	last_extents = extents + RegionNumRects(&clip);
8782	do {
8783		int n = _n;
8784		const xSegment *s = _s;
8785		do {
8786			int16_t sdx, sdy;
8787			int adx, ady, length;
8788			int e, e1, e2, e3;
8789			int x1, x2;
8790			int y1, y2;
8791			int oc1, oc2;
8792			int octant;
8793
8794			x1 = s->x1 + drawable->x;
8795			y1 = s->y1 + drawable->y;
8796			x2 = s->x2 + drawable->x;
8797			y2 = s->y2 + drawable->y;
8798			s++;
8799
8800			DBG(("%s: segment (%d, %d) to (%d, %d)\n",
8801			     __FUNCTION__, x1, y1, x2, y2));
8802			if (x2 == x1 && y2 == y1)
8803				continue;
8804
8805			oc1 = 0;
8806			OUTCODES(oc1, x1, y1, extents);
8807			oc2 = 0;
8808			OUTCODES(oc2, x2, y2, extents);
8809			if (oc1 & oc2)
8810				continue;
8811
8812			CalcLineDeltas(x1, y1, x2, y2,
8813				       adx, ady, sdx, sdy,
8814				       1, 1, octant);
8815
8816			DBG(("%s: adx=(%d, %d), sdx=(%d, %d)\n",
8817			     __FUNCTION__, adx, ady, sdx, sdy));
8818			if (adx == 0 || ady == 0) {
8819				if (x1 <= x2) {
8820					b->x1 = x1;
8821					b->x2 = x2;
8822				} else {
8823					b->x1 = x2;
8824					b->x2 = x1;
8825				}
8826				if (y1 <= y2) {
8827					b->y1 = y1;
8828					b->y2 = y2;
8829				} else {
8830					b->y1 = y2;
8831					b->y2 = y1;
8832				}
8833				b->x2++;
8834				b->y2++;
8835				if (oc1 | oc2)
8836					box_intersect(b, extents);
8837				if (++b == last_box) {
8838					ret = &&rectangle_continue;
8839					goto *jump;
8840rectangle_continue:
8841					b = box;
8842				}
8843			} else if (adx >= ady) {
8844				bool dirty;
8845
8846				/* X-major segment */
8847				e1 = ady << 1;
8848				e2 = e1 - (adx << 1);
8849				e  = e1 - adx;
8850				length = adx;	/* don't draw endpoint in main loop */
8851
8852				FIXUP_ERROR(e, octant, bias);
8853
8854				if (oc1 | oc2) {
8855					int pt1_clipped, pt2_clipped;
8856					int x = x1, y = y1;
8857
8858					if (miZeroClipLine(extents->x1, extents->y1,
8859							   extents->x2-1, extents->y2-1,
8860							   &x1, &y1, &x2, &y2,
8861							   adx, ady,
8862							   &pt1_clipped, &pt2_clipped,
8863							   octant, bias, oc1, oc2) == -1)
8864						continue;
8865
8866					length = abs(x2 - x1);
8867					if (length == 0)
8868						continue;
8869
8870					if (pt1_clipped) {
8871						int clipdx = abs(x1 - x);
8872						int clipdy = abs(y1 - y);
8873						e += clipdy * e2 + (clipdx - clipdy) * e1;
8874					}
8875				}
8876				e3 = e2 - e1;
8877				e  = e - e1;
8878
8879				b->x1 = x1;
8880				b->y1 = y1;
8881				dirty = false;
8882				while (length--) {
8883					dirty = true;
8884					e += e1;
8885					if (e >= 0) {
8886						e += e3;
8887
8888						if (sdx < 0) {
8889							b->x2 = b->x1 + 1;
8890							b->x1 = x1;
8891						} else
8892							b->x2 = x1 + 1;
8893						b->y2 = b->y1 + 1;
8894
8895						DBG(("%s: horizontal step: (%d, %d), box: (%d, %d), (%d, %d)\n",
8896						     __FUNCTION__, x1, y1,
8897						     b->x1, b->y1, b->x2, b->y2));
8898
8899						if (++b == last_box) {
8900							ret = &&X_continue;
8901							goto *jump;
8902X_continue:
8903							b = box;
8904						}
8905
8906						b->x1 = x1 + sdx;
8907						b->y1 = y1 += sdy;
8908						dirty = false;
8909					}
8910					x1 += sdx;
8911				}
8912				if (dirty) {
8913					x1 -= sdx;
8914					DBG(("%s: horizontal tail: (%d, %d)\n",
8915					     __FUNCTION__, x1, y1));
8916					if (sdx < 0) {
8917						b->x2 = b->x1 + 1;
8918						b->x1 = x1;
8919					} else
8920						b->x2 = x1 + 1;
8921					b->y2 = b->y1 + 1;
8922
8923					if (++b == last_box) {
8924						ret = &&X2_continue;
8925						goto *jump;
8926X2_continue:
8927						b = box;
8928					}
8929				}
8930			} else {
8931				bool dirty;
8932
8933				/* Y-major segment */
8934				e1 = adx << 1;
8935				e2 = e1 - (ady << 1);
8936				e  = e1 - ady;
8937				length  = ady;	/* don't draw endpoint in main loop */
8938
8939				SetYMajorOctant(octant);
8940				FIXUP_ERROR(e, octant, bias);
8941
8942				if (oc1 | oc2) {
8943					int pt1_clipped, pt2_clipped;
8944					int x = x1, y = y1;
8945
8946					if (miZeroClipLine(extents->x1, extents->y1,
8947							   extents->x2-1, extents->y2-1,
8948							   &x1, &y1, &x2, &y2,
8949							   adx, ady,
8950							   &pt1_clipped, &pt2_clipped,
8951							   octant, bias, oc1, oc2) == -1)
8952						continue;
8953
8954					length = abs(y2 - y1);
8955					if (length == 0)
8956						continue;
8957
8958					if (pt1_clipped) {
8959						int clipdx = abs(x1 - x);
8960						int clipdy = abs(y1 - y);
8961						e += clipdx * e2 + (clipdy - clipdx) * e1;
8962					}
8963				}
8964
8965				e3 = e2 - e1;
8966				e  = e - e1;
8967
8968				b->x1 = x1;
8969				b->y1 = y1;
8970				dirty = false;
8971				while (length--) {
8972					e += e1;
8973					dirty = true;
8974					if (e >= 0) {
8975						e += e3;
8976
8977						if (sdy < 0) {
8978							b->y2 = b->y1 + 1;
8979							b->y1 = y1;
8980						} else
8981							b->y2 = y1 + 1;
8982						b->x2 = x1 + 1;
8983
8984						if (++b == last_box) {
8985							ret = &&Y_continue;
8986							goto *jump;
8987Y_continue:
8988							b = box;
8989						}
8990
8991						b->x1 = x1 += sdx;
8992						b->y1 = y1 + sdy;
8993						dirty = false;
8994					}
8995					y1 += sdy;
8996				}
8997
8998				if (dirty) {
8999					y1 -= sdy;
9000					if (sdy < 0) {
9001						b->y2 = b->y1 + 1;
9002						b->y1 = y1;
9003					} else
9004						b->y2 = y1 + 1;
9005					b->x2 = x1 + 1;
9006
9007					if (++b == last_box) {
9008						ret = &&Y2_continue;
9009						goto *jump;
9010Y2_continue:
9011						b = box;
9012					}
9013				}
9014			}
9015		} while (--n);
9016	} while (++extents != last_extents);
9017
9018	if (b != box) {
9019		ret = &&done;
9020		goto *jump;
9021	}
9022
9023done:
9024	fill.done(sna, &fill);
9025	assert_pixmap_damage(pixmap);
9026	RegionUninit(&clip);
9027	return true;
9028
9029damage:
9030	sna_damage_add_boxes(damage, box, b-box, 0, 0);
9031no_damage:
9032	fill.boxes(sna, &fill, box, b-box);
9033	goto *ret;
9034
9035no_damage_offset:
9036	{
9037		BoxRec *bb = box;
9038		do {
9039			bb->x1 += dx;
9040			bb->x2 += dx;
9041			bb->y1 += dy;
9042			bb->y2 += dy;
9043		} while (++bb != b);
9044		fill.boxes(sna, &fill, box, b - box);
9045	}
9046	goto *ret;
9047
9048damage_offset:
9049	{
9050		BoxRec *bb = box;
9051		do {
9052			bb->x1 += dx;
9053			bb->x2 += dx;
9054			bb->y1 += dy;
9055			bb->y2 += dy;
9056		} while (++bb != b);
9057		fill.boxes(sna, &fill, box, b - box);
9058		sna_damage_add_boxes(damage, box, b - box, 0, 0);
9059	}
9060	goto *ret;
9061}
9062
9063static unsigned
9064sna_poly_segment_extents(DrawablePtr drawable, GCPtr gc,
9065			 int n, xSegment *seg,
9066			 BoxPtr out)
9067{
9068	BoxRec box;
9069	bool clipped, can_blit;
9070
9071	if (n == 0)
9072		return 0;
9073
9074	if (seg->x2 >= seg->x1) {
9075		box.x1 = seg->x1;
9076		box.x2 = seg->x2;
9077	} else {
9078		box.x2 = seg->x1;
9079		box.x1 = seg->x2;
9080	}
9081
9082	if (seg->y2 >= seg->y1) {
9083		box.y1 = seg->y1;
9084		box.y2 = seg->y2;
9085	} else {
9086		box.y2 = seg->y1;
9087		box.y1 = seg->y2;
9088	}
9089
9090	can_blit = seg->x1 == seg->x2 || seg->y1 == seg->y2;
9091	while (--n) {
9092		seg++;
9093		if (seg->x2 > seg->x1) {
9094			if (seg->x1 < box.x1) box.x1 = seg->x1;
9095			if (seg->x2 > box.x2) box.x2 = seg->x2;
9096		} else {
9097			if (seg->x2 < box.x1) box.x1 = seg->x2;
9098			if (seg->x1 > box.x2) box.x2 = seg->x1;
9099		}
9100
9101		if (seg->y2 > seg->y1) {
9102			if (seg->y1 < box.y1) box.y1 = seg->y1;
9103			if (seg->y2 > box.y2) box.y2 = seg->y2;
9104		} else {
9105			if (seg->y2 < box.y1) box.y1 = seg->y2;
9106			if (seg->y1 > box.y2) box.y2 = seg->y1;
9107		}
9108
9109		if (can_blit && !(seg->x1 == seg->x2 || seg->y1 == seg->y2))
9110			can_blit = false;
9111	}
9112
9113	box.x2++;
9114	box.y2++;
9115
9116	if (gc->lineWidth) {
9117		int extra = gc->lineWidth;
9118		if (gc->capStyle != CapProjecting)
9119			extra >>= 1;
9120		if (extra) {
9121			box.x1 -= extra;
9122			box.x2 += extra;
9123			box.y1 -= extra;
9124			box.y2 += extra;
9125		}
9126	}
9127
9128	DBG(("%s: unclipped, untranslated extents (%d, %d), (%d, %d)\n",
9129	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
9130
9131	clipped = trim_and_translate_box(&box, drawable, gc);
9132	if (box_empty(&box))
9133		return 0;
9134
9135	*out = box;
9136	return 1 | clipped << 1 | can_blit << 2;
9137}
9138
9139static void
9140sna_poly_segment(DrawablePtr drawable, GCPtr gc, int n, xSegment *seg)
9141{
9142	struct sna_pixmap *priv;
9143	struct sna_fill_spans data;
9144	uint32_t color;
9145
9146	DBG(("%s(n=%d, first=((%d, %d), (%d, %d)), lineWidth=%d\n",
9147	     __FUNCTION__,
9148	     n, seg->x1, seg->y1, seg->x2, seg->y2,
9149	     gc->lineWidth));
9150
9151	data.flags = sna_poly_segment_extents(drawable, gc, n, seg,
9152					      &data.region.extents);
9153	if (data.flags == 0)
9154		return;
9155
9156	DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__,
9157	     data.region.extents.x1, data.region.extents.y1,
9158	     data.region.extents.x2, data.region.extents.y2));
9159
9160	data.region.data = NULL;
9161
9162	if (FORCE_FALLBACK)
9163		goto fallback;
9164
9165	if (!ACCEL_POLY_SEGMENT)
9166		goto fallback;
9167
9168	data.pixmap = get_drawable_pixmap(drawable);
9169	data.sna = to_sna_from_pixmap(data.pixmap);
9170	priv = sna_pixmap(data.pixmap);
9171	if (priv == NULL) {
9172		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
9173		goto fallback;
9174	}
9175
9176	if (wedged(data.sna)) {
9177		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
9178		goto fallback;
9179	}
9180
9181	DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lu [%d], rectlinear=%d\n",
9182	     __FUNCTION__,
9183	     gc->fillStyle, gc->fillStyle == FillSolid,
9184	     gc->lineStyle, gc->lineStyle == LineSolid,
9185	     gc->lineWidth,
9186	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask),
9187	     data.flags & 4));
9188	if (!PM_IS_SOLID(drawable, gc->planemask))
9189		goto fallback;
9190
9191	if (gc->lineStyle != LineSolid || gc->lineWidth > 1)
9192		goto spans_fallback;
9193	if (gc_is_solid(gc, &color)) {
9194		DBG(("%s: trying blt solid fill [%08x, flags=%x] paths\n",
9195		     __FUNCTION__, (unsigned)color, data.flags));
9196
9197		if (data.flags & 4) {
9198			if ((data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
9199							   &data.region.extents,
9200							   &data.damage)) &&
9201			     sna_poly_segment_blt(drawable,
9202						 data.bo, data.damage,
9203						 gc, color, n, seg,
9204						 &data.region.extents,
9205						 data.flags & 2))
9206				return;
9207		} else {
9208			if ((data.bo = sna_drawable_use_bo(drawable,
9209							   use_zero_spans(drawable, gc, &data.region.extents),
9210							   &data.region.extents,
9211							   &data.damage)) &&
9212			    sna_poly_zero_segment_blt(drawable,
9213						      data.bo, data.damage,
9214						      gc, n, seg,
9215						      &data.region.extents,
9216						      data.flags & 2))
9217				return;
9218		}
9219	} else if (data.flags & 4) {
9220		/* Try converting these to a set of rectangles instead */
9221		xRectangle *rect;
9222		int i;
9223
9224		data.bo = sna_drawable_use_bo(drawable, PREFER_GPU,
9225					      &data.region.extents,
9226					      &data.damage);
9227		if (data.bo == NULL)
9228			goto fallback;
9229
9230		DBG(("%s: converting to rectagnles\n", __FUNCTION__));
9231
9232		rect = malloc (n * sizeof (xRectangle));
9233		if (rect == NULL)
9234			return;
9235
9236		for (i = 0; i < n; i++) {
9237			if (seg[i].x1 < seg[i].x2) {
9238				rect[i].x = seg[i].x1;
9239				rect[i].width = seg[i].x2 - seg[i].x1 + 1;
9240			} else if (seg[i].x1 > seg[i].x2) {
9241				rect[i].x = seg[i].x2;
9242				rect[i].width = seg[i].x1 - seg[i].x2 + 1;
9243			} else {
9244				rect[i].x = seg[i].x1;
9245				rect[i].width = 1;
9246			}
9247			if (seg[i].y1 < seg[i].y2) {
9248				rect[i].y = seg[i].y1;
9249				rect[i].height = seg[i].y2 - seg[i].y1 + 1;
9250			} else if (seg[i].y1 > seg[i].y2) {
9251				rect[i].y = seg[i].y2;
9252				rect[i].height = seg[i].y1 - seg[i].y2 + 1;
9253			} else {
9254				rect[i].y = seg[i].y1;
9255				rect[i].height = 1;
9256			}
9257
9258			/* don't paint last pixel */
9259			if (gc->capStyle == CapNotLast) {
9260				if (seg[i].x1 == seg[i].x2)
9261					rect[i].height--;
9262				else
9263					rect[i].width--;
9264			}
9265		}
9266
9267		if (gc->fillStyle == FillTiled) {
9268			i = sna_poly_fill_rect_tiled_blt(drawable,
9269							 data.bo, data.damage,
9270							 gc, n, rect,
9271							 &data.region.extents,
9272							 data.flags & 2);
9273		} else {
9274			i = sna_poly_fill_rect_stippled_blt(drawable,
9275							    data.bo, data.damage,
9276							    gc, n, rect,
9277							    &data.region.extents,
9278							    data.flags & 2);
9279		}
9280		free (rect);
9281
9282		if (i)
9283			return;
9284	}
9285
9286spans_fallback:
9287	if ((data.bo = sna_drawable_use_bo(drawable,
9288					   use_wide_spans(drawable, gc, &data.region.extents),
9289					   &data.region.extents,
9290					   &data.damage))) {
9291		void (*line)(DrawablePtr, GCPtr, int, int, DDXPointPtr);
9292		int i;
9293
9294		DBG(("%s: converting segments into spans\n", __FUNCTION__));
9295
9296		switch (gc->lineStyle) {
9297		default:
9298		case LineSolid:
9299			if (gc->lineWidth == 0)
9300				line = miZeroLine;
9301			else
9302				line = miWideLine;
9303			break;
9304		case LineOnOffDash:
9305		case LineDoubleDash:
9306			if (gc->lineWidth == 0)
9307				line = miZeroDashLine;
9308			else
9309				line = miWideDash;
9310			break;
9311		}
9312
9313		get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy);
9314		sna_gc(gc)->priv = &data;
9315
9316		if (gc->lineWidth == 0 &&
9317		    gc->lineStyle == LineSolid &&
9318		    gc_is_solid(gc, &color)) {
9319			struct sna_fill_op fill;
9320
9321			if (!sna_fill_init_blt(&fill,
9322					       data.sna, data.pixmap,
9323					       data.bo, gc->alu, color))
9324				goto fallback;
9325
9326			data.op = &fill;
9327
9328			if ((data.flags & 2) == 0) {
9329				if (data.dx | data.dy)
9330					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
9331				else
9332					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
9333				sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill;
9334			} else {
9335				region_maybe_clip(&data.region,
9336						  gc->pCompositeClip);
9337				if (RegionNil(&data.region))
9338					return;
9339
9340				if (region_is_singular(&data.region)) {
9341					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
9342					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents;
9343				} else {
9344					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
9345					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes;
9346				}
9347			}
9348			assert(gc->miTranslate);
9349			gc->ops = &sna_gc_ops__tmp;
9350			for (i = 0; i < n; i++)
9351				line(drawable, gc, CoordModeOrigin, 2,
9352				     (DDXPointPtr)&seg[i]);
9353
9354			fill.done(data.sna, &fill);
9355		} else {
9356			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
9357			sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu;
9358			sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu;
9359			gc->ops = &sna_gc_ops__tmp;
9360
9361			for (i = 0; i < n; i++)
9362				line(drawable, gc, CoordModeOrigin, 2,
9363				     (DDXPointPtr)&seg[i]);
9364		}
9365
9366		gc->ops = (GCOps *)&sna_gc_ops;
9367		if (data.damage) {
9368			if (data.dx | data.dy)
9369				pixman_region_translate(&data.region, data.dx, data.dy);
9370			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
9371			sna_damage_add(data.damage, &data.region);
9372		}
9373		assert_pixmap_damage(data.pixmap);
9374		RegionUninit(&data.region);
9375		return;
9376	}
9377
9378fallback:
9379	DBG(("%s: fallback\n", __FUNCTION__));
9380	region_maybe_clip(&data.region, gc->pCompositeClip);
9381	if (RegionNil(&data.region))
9382		return;
9383
9384	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
9385		goto out;
9386	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
9387					     drawable_gc_flags(drawable, gc,
9388							       !(data.flags & 4 && n == 1))))
9389		goto out_gc;
9390
9391	DBG(("%s: fbPolySegment\n", __FUNCTION__));
9392	fbPolySegment(drawable, gc, n, seg);
9393	FALLBACK_FLUSH(drawable);
9394
9395out_gc:
9396	sna_gc_move_to_gpu(gc);
9397out:
9398	RegionUninit(&data.region);
9399}
9400
9401static unsigned
9402sna_poly_rectangle_extents(DrawablePtr drawable, GCPtr gc,
9403			   int n, xRectangle *r,
9404			   BoxPtr out)
9405{
9406	Box32Rec box;
9407	int extra = gc->lineWidth >> 1;
9408	bool clipped;
9409	bool zero = false;
9410
9411	if (n == 0)
9412		return 0;
9413
9414	box.x1 = r->x;
9415	box.y1 = r->y;
9416	box.x2 = box.x1 + r->width;
9417	box.y2 = box.y1 + r->height;
9418	zero |= (r->width | r->height) == 0;
9419
9420	while (--n) {
9421		r++;
9422		zero |= (r->width | r->height) == 0;
9423		box32_add_rect(&box, r);
9424	}
9425
9426	box.x2++;
9427	box.y2++;
9428
9429	if (extra) {
9430		box.x1 -= extra;
9431		box.x2 += extra;
9432		box.y1 -= extra;
9433		box.y2 += extra;
9434		zero = !zero;
9435	} else
9436		zero = true;
9437
9438	clipped = box32_trim_and_translate(&box, drawable, gc);
9439	if (!box32_to_box16(&box, out))
9440		return 0;
9441
9442	return 1 | clipped << 1 | zero << 2;
9443}
9444
9445static bool
9446sna_poly_rectangle_blt(DrawablePtr drawable,
9447		       struct kgem_bo *bo,
9448		       struct sna_damage **damage,
9449		       GCPtr gc, int n, xRectangle *r,
9450		       const BoxRec *extents, unsigned clipped)
9451{
9452	PixmapPtr pixmap = get_drawable_pixmap(drawable);
9453	struct sna *sna = to_sna_from_pixmap(pixmap);
9454	struct sna_fill_op fill;
9455	BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes);
9456	int16_t dx, dy;
9457	static void * const jump[] = {
9458		&&wide,
9459		&&zero,
9460		&&wide_clipped,
9461		&&zero_clipped,
9462	};
9463
9464	DBG(("%s: n=%d, alu=%d, width=%d, fg=%08lx, damge=%p, clipped?=%d\n",
9465	     __FUNCTION__, n, gc->alu, gc->lineWidth, gc->fgPixel, damage, clipped));
9466	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel))
9467		return false;
9468
9469	get_drawable_deltas(drawable, pixmap, &dx, &dy);
9470
9471	goto *jump[(gc->lineWidth <= 1) | clipped];
9472
9473zero:
9474	dx += drawable->x;
9475	dy += drawable->y;
9476
9477	do {
9478		xRectangle rr = *r++;
9479
9480		if ((rr.width | rr.height) == 0)
9481			continue; /* XXX -> PolyLine */
9482
9483		DBG(("%s - zero : r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__,
9484		     n, rr.x, rr.y, rr.width, rr.height));
9485		rr.x += dx;
9486		rr.y += dy;
9487
9488		if (b+4 > last_box) {
9489			fill.boxes(sna, &fill, boxes, b-boxes);
9490			if (damage)
9491				sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
9492			b = boxes;
9493		}
9494
9495		if (rr.width <= 1 || rr.height <= 1) {
9496			b->x1 = rr.x;
9497			b->y1 = rr.y;
9498			b->x2 = rr.x + rr.width + (rr.height != 0);
9499			b->y2 = rr.y + rr.height + (rr.width != 0);
9500			DBG(("%s: blt (%d, %d), (%d, %d)\n",
9501			     __FUNCTION__,
9502			     b->x1, b->y1, b->x2,b->y2));
9503			b++;
9504		} else {
9505			b[0].x1 = rr.x;
9506			b[0].y1 = rr.y;
9507			b[0].x2 = rr.x + rr.width + 1;
9508			b[0].y2 = rr.y + 1;
9509
9510			b[1] = b[0];
9511			b[1].y1 += rr.height;
9512			b[1].y2 += rr.height;
9513
9514			b[2].y1 = rr.y + 1;
9515			b[2].y2 = rr.y + rr.height;
9516			b[2].x1 = rr.x;
9517			b[2].x2 = rr.x + 1;
9518
9519			b[3] = b[2];
9520			b[3].x1 += rr.width;
9521			b[3].x2 += rr.width;
9522
9523			b += 4;
9524		}
9525	} while (--n);
9526	goto done;
9527
9528zero_clipped:
9529	{
9530		RegionRec clip;
9531		BoxRec box[4];
9532		int count;
9533
9534		region_set(&clip, extents);
9535		region_maybe_clip(&clip, gc->pCompositeClip);
9536		if (RegionNil(&clip))
9537			goto done;
9538
9539		if (clip.data) {
9540			const BoxRec * const clip_start = RegionBoxptr(&clip);
9541			const BoxRec * const clip_end = clip_start + clip.data->numRects;
9542			const BoxRec *c;
9543			do {
9544				xRectangle rr = *r++;
9545
9546				DBG(("%s - zero, clipped complex: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__,
9547				     n, rr.x, rr.y, rr.width, rr.height));
9548
9549				if ((rr.width | rr.height) == 0)
9550					continue; /* XXX -> PolyLine */
9551
9552				rr.x += drawable->x;
9553				rr.y += drawable->y;
9554
9555				if (rr.width <= 1 || rr.height <= 1) {
9556					box[0].x1 = rr.x;
9557					box[0].y1 = rr.y;
9558					box[0].x2 = rr.x + rr.width + (rr.height != 0);
9559					box[0].y2 = rr.y + rr.height + (rr.width != 0);
9560					count = 1;
9561				} else {
9562					box[0].x1 = rr.x;
9563					box[0].y1 = rr.y;
9564					box[0].x2 = rr.x + rr.width + 1;
9565					box[0].y2 = rr.y + 1;
9566
9567					box[1] = box[0];
9568					box[1].y1 += rr.height;
9569					box[1].y2 += rr.height;
9570
9571					box[2].y1 = rr.y + 1;
9572					box[2].y2 = rr.y + rr.height;
9573					box[2].x1 = rr.x;
9574					box[2].x2 = rr.x + 1;
9575
9576					box[3] = box[2];
9577					box[3].x1 += rr.width;
9578					box[3].x2 += rr.width;
9579					count = 4;
9580				}
9581
9582				while (count--) {
9583					c = find_clip_box_for_y(clip_start,
9584								clip_end,
9585								box[count].y1);
9586					while (c != clip_end) {
9587						if (box[count].y2 <= c->y1)
9588							break;
9589
9590						*b = box[count];
9591						if (box_intersect(b, c++)) {
9592							b->x1 += dx;
9593							b->x2 += dx;
9594							b->y1 += dy;
9595							b->y2 += dy;
9596							if (++b == last_box) {
9597								fill.boxes(sna, &fill, boxes, last_box-boxes);
9598								if (damage)
9599									sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
9600								b = boxes;
9601							}
9602						}
9603
9604					}
9605				}
9606			} while (--n);
9607		} else {
9608			do {
9609				xRectangle rr = *r++;
9610				DBG(("%s - zero, clip: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__,
9611				     n, rr.x, rr.y, rr.width, rr.height));
9612
9613				if ((rr.width | rr.height) == 0)
9614					continue; /* XXX -> PolyLine */
9615
9616				rr.x += drawable->x;
9617				rr.y += drawable->y;
9618
9619				if (rr.width <= 1 || rr.height <= 1) {
9620					box[0].x1 = rr.x;
9621					box[0].y1 = rr.y;
9622					box[0].x2 = rr.x + rr.width + (rr.height != 0);
9623					box[0].y2 = rr.y + rr.height + (rr.width != 0);
9624					count = 1;
9625				} else {
9626					box[0].x1 = rr.x;
9627					box[0].y1 = rr.y;
9628					box[0].x2 = rr.x + rr.width + 1;
9629					box[0].y2 = rr.y + 1;
9630
9631					box[1] = box[0];
9632					box[1].y1 += rr.height;
9633					box[1].y2 += rr.height;
9634
9635					box[2].y1 = rr.y + 1;
9636					box[2].y2 = rr.y + rr.height;
9637					box[2].x1 = rr.x;
9638					box[2].x2 = rr.x + 1;
9639
9640					box[3] = box[2];
9641					box[3].x1 += rr.width;
9642					box[3].x2 += rr.width;
9643					count = 4;
9644				}
9645
9646				while (count--) {
9647					*b = box[count];
9648					if (box_intersect(b, &clip.extents)) {
9649						b->x1 += dx;
9650						b->x2 += dx;
9651						b->y1 += dy;
9652						b->y2 += dy;
9653						if (++b == last_box) {
9654							fill.boxes(sna, &fill, boxes, last_box-boxes);
9655							if (damage)
9656								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
9657							b = boxes;
9658						}
9659					}
9660
9661				}
9662			} while (--n);
9663		}
9664		RegionUninit(&clip);
9665	}
9666	goto done;
9667
9668wide_clipped:
9669	{
9670		RegionRec clip;
9671		BoxRec box[4];
9672		int16_t offset2 = gc->lineWidth;
9673		int16_t offset1 = offset2 >> 1;
9674		int16_t offset3 = offset2 - offset1;
9675
9676		region_set(&clip, extents);
9677		region_maybe_clip(&clip, gc->pCompositeClip);
9678		DBG(("%s: wide clipped: extents=((%d, %d), (%d, %d))\n",
9679		     __FUNCTION__,
9680		     clip.extents.x1, clip.extents.y1,
9681		     clip.extents.x2, clip.extents.y2));
9682		if (RegionNil(&clip))
9683			goto done;
9684
9685		if (clip.data) {
9686			const BoxRec * const clip_start = RegionBoxptr(&clip);
9687			const BoxRec * const clip_end = clip_start + clip.data->numRects;
9688			const BoxRec *c;
9689			do {
9690				xRectangle rr = *r++;
9691				int count;
9692
9693				if ((rr.width | rr.height) == 0)
9694					continue; /* XXX -> PolyLine */
9695
9696				rr.x += drawable->x;
9697				rr.y += drawable->y;
9698
9699				if (rr.height <= offset2 || rr.width <= offset2) {
9700					if (rr.height == 0) {
9701						box[0].x1 = rr.x;
9702						box[0].x2 = rr.x + rr.width;
9703					} else {
9704						box[0].x1 = rr.x - offset1;
9705						box[0].x2 = rr.x + rr.width + offset3;
9706					}
9707					if (rr.width == 0) {
9708						box[0].y1 = rr.y;
9709						box[0].y2 = rr.y + rr.height;
9710					} else {
9711						box[0].y1 = rr.y - offset1;
9712						box[0].y2 = rr.y + rr.height + offset3;
9713					}
9714					count = 1;
9715				} else {
9716					box[0].x1 = rr.x - offset1;
9717					box[0].x2 = box[0].x1 + rr.width + offset2;
9718					box[0].y1 = rr.y - offset1;
9719					box[0].y2 = box[0].y1 + offset2;
9720
9721					box[1].x1 = rr.x - offset1;
9722					box[1].x2 = box[1].x1 + offset2;
9723					box[1].y1 = rr.y + offset3;
9724					box[1].y2 = rr.y + rr.height - offset1;
9725
9726					box[2] = box[1];
9727					box[2].x1 += rr.width;
9728					box[2].x2 += rr.width;
9729
9730					box[3] = box[0];
9731					box[3].y1 += rr.height;
9732					box[3].y2 += rr.height;
9733					count = 4;
9734				}
9735
9736				while (count--) {
9737					c = find_clip_box_for_y(clip_start,
9738								clip_end,
9739								box[count].y1);
9740					while (c != clip_end) {
9741						if (box[count].y2 <= c->y1)
9742							break;
9743
9744						*b = box[count];
9745						if (box_intersect(b, c++)) {
9746							b->x1 += dx;
9747							b->x2 += dx;
9748							b->y1 += dy;
9749							b->y2 += dy;
9750							if (++b == last_box) {
9751								fill.boxes(sna, &fill, boxes, last_box-boxes);
9752								if (damage)
9753									sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
9754								b = boxes;
9755							}
9756						}
9757					}
9758				}
9759			} while (--n);
9760		} else {
9761			DBG(("%s: singular clip offset1=%d, offset2=%d, offset3=%d\n",
9762			     __FUNCTION__, offset1, offset2, offset3));
9763			do {
9764				xRectangle rr = *r++;
9765				int count;
9766				rr.x += drawable->x;
9767				rr.y += drawable->y;
9768
9769				DBG(("%s: r=(%d, %d)x(%d, %d)\n",
9770				     __FUNCTION__, rr.x, rr.y, rr.width, rr.height));
9771				if (rr.height <= offset2 || rr.width <= offset2) {
9772					if (rr.height == 0) {
9773						box[0].x1 = rr.x;
9774						box[0].x2 = rr.x + rr.width;
9775					} else {
9776						box[0].x1 = rr.x - offset1;
9777						box[0].x2 = box[0].x1 + rr.width + offset2;
9778					}
9779					if (rr.width == 0) {
9780						box[0].y1 = rr.y;
9781						box[0].y2 = rr.y + rr.height;
9782					} else {
9783						box[0].y1 = rr.y - offset1;
9784						box[0].y2 = box[0].y1 + rr.height + offset2;
9785					}
9786					count = 1;
9787				} else {
9788					box[0].x1 = rr.x - offset1;
9789					box[0].x2 = box[0].x1 + rr.width + offset2;
9790					box[0].y1 = rr.y - offset1;
9791					box[0].y2 = box[0].y1 + offset2;
9792					DBG(("%s: box[0]=(%d, %d), (%d, %d)\n",
9793					     __FUNCTION__,
9794					     box[0].x1, box[0].y1,
9795					     box[0].x2, box[0].y2));
9796
9797					box[1].x1 = rr.x - offset1;
9798					box[1].x2 = box[1].x1 + offset2;
9799					box[1].y1 = rr.y + offset3;
9800					box[1].y2 = rr.y + rr.height - offset1;
9801					DBG(("%s: box[1]=(%d, %d), (%d, %d)\n",
9802					     __FUNCTION__,
9803					     box[1].x1, box[1].y1,
9804					     box[1].x2, box[1].y2));
9805
9806					box[2] = box[1];
9807					box[2].x1 += rr.width;
9808					box[2].x2 += rr.width;
9809					DBG(("%s: box[2]=(%d, %d), (%d, %d)\n",
9810					     __FUNCTION__,
9811					     box[2].x1, box[2].y1,
9812					     box[2].x2, box[2].y2));
9813
9814					box[3] = box[0];
9815					box[3].y1 += rr.height;
9816					box[3].y2 += rr.height;
9817					DBG(("%s: box[3]=(%d, %d), (%d, %d)\n",
9818					     __FUNCTION__,
9819					     box[3].x1, box[3].y1,
9820					     box[3].x2, box[3].y2));
9821
9822					count = 4;
9823				}
9824
9825				while (count--) {
9826					*b = box[count];
9827					if (box_intersect(b, &clip.extents)) {
9828						b->x1 += dx;
9829						b->x2 += dx;
9830						b->y1 += dy;
9831						b->y2 += dy;
9832						if (++b == last_box) {
9833							fill.boxes(sna, &fill, boxes, last_box-boxes);
9834							if (damage)
9835								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
9836							b = boxes;
9837						}
9838					}
9839				}
9840			} while (--n);
9841		}
9842		RegionUninit(&clip);
9843	}
9844	goto done;
9845
9846wide:
9847	{
9848		int offset2 = gc->lineWidth;
9849		int offset1 = offset2 >> 1;
9850		int offset3 = offset2 - offset1;
9851
9852		dx += drawable->x;
9853		dy += drawable->y;
9854
9855		do {
9856			xRectangle rr = *r++;
9857
9858			if ((rr.width | rr.height) == 0)
9859				continue; /* XXX -> PolyLine */
9860
9861			rr.x += dx;
9862			rr.y += dy;
9863
9864			if (b+4 > last_box) {
9865				fill.boxes(sna, &fill, boxes, last_box-boxes);
9866				if (damage)
9867					sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
9868				b = boxes;
9869			}
9870
9871			if (rr.height <= offset2 || rr.width <= offset2) {
9872				if (rr.height == 0) {
9873					b->x1 = rr.x;
9874					b->x2 = rr.x + rr.width;
9875				} else {
9876					b->x1 = rr.x - offset1;
9877					b->x2 = rr.x + rr.width + offset3;
9878				}
9879				if (rr.width == 0) {
9880					b->y1 = rr.y;
9881					b->y2 = rr.y + rr.height;
9882				} else {
9883					b->y1 = rr.y - offset1;
9884					b->y2 = rr.y + rr.height + offset3;
9885				}
9886				b++;
9887			} else {
9888				b[0].x1 = rr.x - offset1;
9889				b[0].x2 = b[0].x1 + rr.width + offset2;
9890				b[0].y1 = rr.y - offset1;
9891				b[0].y2 = b[0].y1 + offset2;
9892
9893				b[1].x1 = rr.x - offset1;
9894				b[1].x2 = b[1].x1 + offset2;
9895				b[1].y1 = rr.y + offset3;
9896				b[1].y2 = rr.y + rr.height - offset1;
9897
9898				b[2] = b[1];
9899				b[2].x1 += rr.width;
9900				b[2].x2 += rr.width;
9901
9902				b[3] = b[0];
9903				b[3].y1 += rr.height;
9904				b[3].y2 += rr.height;
9905				b += 4;
9906			}
9907		} while (--n);
9908	}
9909	goto done;
9910
9911done:
9912	if (b != boxes) {
9913		fill.boxes(sna, &fill, boxes, b-boxes);
9914		if (damage)
9915			sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
9916	}
9917	fill.done(sna, &fill);
9918	assert_pixmap_damage(pixmap);
9919	return true;
9920}
9921
9922static void
9923sna_poly_rectangle(DrawablePtr drawable, GCPtr gc, int n, xRectangle *r)
9924{
9925	PixmapPtr pixmap = get_drawable_pixmap(drawable);
9926	struct sna *sna = to_sna_from_pixmap(pixmap);
9927	struct sna_damage **damage;
9928	struct kgem_bo *bo;
9929	RegionRec region;
9930	unsigned flags;
9931
9932	DBG(("%s(n=%d, first=((%d, %d)x(%d, %d)), lineWidth=%d\n",
9933	     __FUNCTION__,
9934	     n, r->x, r->y, r->width, r->height,
9935	     gc->lineWidth));
9936
9937	flags = sna_poly_rectangle_extents(drawable, gc, n, r, &region.extents);
9938	if (flags == 0)
9939		return;
9940
9941	DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
9942	     region.extents.x1, region.extents.y1,
9943	     region.extents.x2, region.extents.y2,
9944	     flags));
9945
9946	if (FORCE_FALLBACK)
9947		goto fallback;
9948
9949	if (!ACCEL_POLY_RECTANGLE)
9950		goto fallback;
9951
9952	if (wedged(sna)) {
9953		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
9954		goto fallback;
9955	}
9956
9957	DBG(("%s: fill=_%d [%d], line=%d [%d], join=%d [%d], mask=%lu [%d]\n",
9958	     __FUNCTION__,
9959	     gc->fillStyle, gc->fillStyle == FillSolid,
9960	     gc->lineStyle, gc->lineStyle == LineSolid,
9961	     gc->joinStyle, gc->joinStyle == JoinMiter,
9962	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask)));
9963
9964	if (!PM_IS_SOLID(drawable, gc->planemask))
9965		goto fallback;
9966
9967	if (flags & 4 && gc->fillStyle == FillSolid && gc->lineStyle == LineSolid && gc->joinStyle == JoinMiter) {
9968		DBG(("%s: trying blt solid fill [%08lx] paths\n",
9969		     __FUNCTION__, gc->fgPixel));
9970		if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU,
9971					      &region.extents, &damage)) &&
9972		    sna_poly_rectangle_blt(drawable, bo, damage,
9973					   gc, n, r, &region.extents, flags&2))
9974			return;
9975	} else {
9976		/* Not a trivial outline, but we still maybe able to break it
9977		 * down into simpler operations that we can accelerate.
9978		 */
9979		if (sna_drawable_use_bo(drawable, PREFER_GPU,
9980					&region.extents, &damage)) {
9981			miPolyRectangle(drawable, gc, n, r);
9982			return;
9983		}
9984	}
9985
9986fallback:
9987	DBG(("%s: fallback\n", __FUNCTION__));
9988
9989	region.data = NULL;
9990	region_maybe_clip(&region, gc->pCompositeClip);
9991	if (RegionNil(&region))
9992		return;
9993
9994	if (!sna_gc_move_to_cpu(gc, drawable, &region))
9995		goto out;
9996	if (!sna_drawable_move_region_to_cpu(drawable, &region,
9997					     drawable_gc_flags(drawable, gc, true)))
9998		goto out_gc;
9999
10000	DBG(("%s: miPolyRectangle\n", __FUNCTION__));
10001	miPolyRectangle(drawable, gc, n, r);
10002	FALLBACK_FLUSH(drawable);
10003out_gc:
10004	sna_gc_move_to_gpu(gc);
10005out:
10006	RegionUninit(&region);
10007}
10008
10009static unsigned
10010sna_poly_arc_extents(DrawablePtr drawable, GCPtr gc,
10011		     int n, xArc *arc,
10012		     BoxPtr out)
10013{
10014	BoxRec box;
10015	bool clipped;
10016	int v;
10017
10018	if (n == 0)
10019		return 0;
10020
10021	box.x1 = arc->x;
10022	box.x2 = bound(box.x1, arc->width);
10023	box.y1 = arc->y;
10024	box.y2 = bound(box.y1, arc->height);
10025
10026	while (--n) {
10027		arc++;
10028		if (box.x1 > arc->x)
10029			box.x1 = arc->x;
10030		v = bound(arc->x, arc->width);
10031		if (box.x2 < v)
10032			box.x2 = v;
10033		if (box.y1 > arc->y)
10034			box.y1 = arc->y;
10035		v = bound(arc->y, arc->height);
10036		if (box.y2 < v)
10037			box.y2 = v;
10038	}
10039
10040	v = gc->lineWidth >> 1;
10041	if (v) {
10042		box.x1 -= v;
10043		box.x2 += v;
10044		box.y1 -= v;
10045		box.y2 += v;
10046	}
10047
10048	box.x2++;
10049	box.y2++;
10050
10051	clipped = trim_and_translate_box(&box, drawable, gc);
10052	if (box_empty(&box))
10053		return 0;
10054
10055	*out = box;
10056	return 1 | clipped << 1;
10057}
10058
10059static void
10060sna_poly_arc(DrawablePtr drawable, GCPtr gc, int n, xArc *arc)
10061{
10062	struct sna_fill_spans data;
10063	struct sna_pixmap *priv;
10064
10065	DBG(("%s(n=%d, lineWidth=%d\n", __FUNCTION__, n, gc->lineWidth));
10066
10067	data.flags = sna_poly_arc_extents(drawable, gc, n, arc,
10068					  &data.region.extents);
10069	if (data.flags == 0)
10070		return;
10071
10072	DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
10073	     data.region.extents.x1, data.region.extents.y1,
10074	     data.region.extents.x2, data.region.extents.y2,
10075	     data.flags));
10076
10077	data.region.data = NULL;
10078
10079	if (FORCE_FALLBACK)
10080		goto fallback;
10081
10082	if (!ACCEL_POLY_ARC)
10083		goto fallback;
10084
10085	data.pixmap = get_drawable_pixmap(drawable);
10086	data.sna = to_sna_from_pixmap(data.pixmap);
10087	priv = sna_pixmap(data.pixmap);
10088	if (priv == NULL) {
10089		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
10090		goto fallback;
10091	}
10092
10093	if (wedged(data.sna)) {
10094		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
10095		goto fallback;
10096	}
10097
10098	if (!PM_IS_SOLID(drawable, gc->planemask))
10099		goto fallback;
10100
10101	if ((data.bo = sna_drawable_use_bo(drawable,
10102					   use_wide_spans(drawable, gc, &data.region.extents),
10103					   &data.region.extents, &data.damage))) {
10104		uint32_t color;
10105
10106		DBG(("%s: converting arcs into spans\n", __FUNCTION__));
10107		get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy);
10108
10109		if (gc_is_solid(gc, &color)) {
10110			sna_gc(gc)->priv = &data;
10111
10112			assert(gc->miTranslate);
10113			if (gc->lineStyle == LineSolid) {
10114				struct sna_fill_op fill;
10115
10116				if (!sna_fill_init_blt(&fill,
10117						       data.sna, data.pixmap,
10118						       data.bo, gc->alu, color))
10119					goto fallback;
10120
10121				if ((data.flags & 2) == 0) {
10122					if (data.dx | data.dy)
10123						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
10124					else
10125						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
10126					sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill;
10127				} else {
10128					region_maybe_clip(&data.region,
10129							  gc->pCompositeClip);
10130					if (RegionNil(&data.region))
10131						return;
10132
10133					if (region_is_singular(&data.region)) {
10134						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
10135						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents;
10136					} else {
10137						sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
10138						sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes;
10139					}
10140				}
10141
10142				data.op = &fill;
10143				gc->ops = &sna_gc_ops__tmp;
10144				if (gc->lineWidth == 0)
10145					miZeroPolyArc(drawable, gc, n, arc);
10146				else
10147					miPolyArc(drawable, gc, n, arc);
10148				gc->ops = (GCOps *)&sna_gc_ops;
10149
10150				fill.done(data.sna, &fill);
10151			} else {
10152				region_maybe_clip(&data.region,
10153						  gc->pCompositeClip);
10154				if (RegionNil(&data.region))
10155					return;
10156
10157				sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
10158				sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu;
10159
10160				gc->ops = &sna_gc_ops__tmp;
10161				if (gc->lineWidth == 0)
10162					miZeroPolyArc(drawable, gc, n, arc);
10163				else
10164					miPolyArc(drawable, gc, n, arc);
10165				gc->ops = (GCOps *)&sna_gc_ops;
10166			}
10167
10168			if (data.damage) {
10169				if (data.dx | data.dy)
10170					pixman_region_translate(&data.region, data.dx, data.dy);
10171				assert_pixmap_contains_box(data.pixmap, &data.region.extents);
10172				sna_damage_add(data.damage, &data.region);
10173			}
10174			assert_pixmap_damage(data.pixmap);
10175			RegionUninit(&data.region);
10176			return;
10177		}
10178
10179		/* XXX still around 10x slower for x11perf -ellipse */
10180		if (gc->lineWidth == 0)
10181			miZeroPolyArc(drawable, gc, n, arc);
10182		else
10183			miPolyArc(drawable, gc, n, arc);
10184		return;
10185	}
10186
10187fallback:
10188	DBG(("%s -- fallback\n", __FUNCTION__));
10189	region_maybe_clip(&data.region, gc->pCompositeClip);
10190	if (RegionNil(&data.region))
10191		return;
10192
10193	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
10194		goto out;
10195	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
10196					     drawable_gc_flags(drawable, gc, true)))
10197		goto out_gc;
10198
10199	DBG(("%s -- fbPolyArc\n", __FUNCTION__));
10200	fbPolyArc(drawable, gc, n, arc);
10201	FALLBACK_FLUSH(drawable);
10202
10203out_gc:
10204	sna_gc_move_to_gpu(gc);
10205out:
10206	RegionUninit(&data.region);
10207}
10208
10209static bool
10210sna_poly_fill_rect_blt(DrawablePtr drawable,
10211		       struct kgem_bo *bo,
10212		       struct sna_damage **damage,
10213		       GCPtr gc, uint32_t pixel,
10214		       int n, xRectangle *rect,
10215		       const BoxRec *extents,
10216		       bool clipped)
10217{
10218	PixmapPtr pixmap = get_drawable_pixmap(drawable);
10219	struct sna *sna = to_sna_from_pixmap(pixmap);
10220	struct sna_fill_op fill;
10221	BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes);
10222	int16_t dx, dy;
10223
10224	DBG(("%s x %d [(%d, %d)x(%d, %d)...]+(%d,%d), clipped?=%d\n",
10225	     __FUNCTION__, n,
10226	     rect->x, rect->y, rect->width, rect->height,
10227	     drawable->x, drawable->y,
10228	     clipped));
10229
10230	if (n == 1 && region_is_singular(gc->pCompositeClip)) {
10231		BoxRec r;
10232		bool success = true;
10233
10234		r.x1 = rect->x + drawable->x;
10235		r.y1 = rect->y + drawable->y;
10236		r.x2 = bound(r.x1, rect->width);
10237		r.y2 = bound(r.y1, rect->height);
10238		if (box_intersect(&r, &gc->pCompositeClip->extents)) {
10239			if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) {
10240				r.x1 += dx; r.y1 += dy;
10241				r.x2 += dx; r.y2 += dy;
10242			}
10243			if (sna->render.fill_one(sna, pixmap, bo, pixel,
10244						 r.x1, r.y1, r.x2, r.y2,
10245						 gc->alu)) {
10246				if (damage) {
10247					assert_pixmap_contains_box(pixmap, &r);
10248					if (r.x2 - r.x1 == pixmap->drawable.width &&
10249					    r.y2 - r.y1 == pixmap->drawable.height) {
10250						sna_damage_all(damage,
10251							       pixmap->drawable.width,
10252							       pixmap->drawable.height);
10253					} else
10254						sna_damage_add_box(damage, &r);
10255				}
10256				assert_pixmap_damage(pixmap);
10257
10258				if ((gc->alu == GXcopy || gc->alu == GXclear) &&
10259				    r.x2 - r.x1 == pixmap->drawable.width &&
10260				    r.y2 - r.y1 == pixmap->drawable.height) {
10261					struct sna_pixmap *priv = sna_pixmap(pixmap);
10262					if (bo == priv->gpu_bo) {
10263						assert(priv->gpu_bo->proxy == NULL);
10264						sna_damage_all(&priv->gpu_damage,
10265							       pixmap->drawable.width,
10266							       pixmap->drawable.height);
10267						sna_damage_destroy(&priv->cpu_damage);
10268						list_del(&priv->flush_list);
10269						priv->clear = true;
10270						priv->clear_color = gc->alu == GXcopy ? pixel : 0;
10271
10272						DBG(("%s: pixmap=%ld, marking clear [%08x]\n",
10273						     __FUNCTION__, pixmap->drawable.serialNumber, priv->clear_color));
10274					}
10275				}
10276			} else
10277				success = false;
10278		}
10279
10280		return success;
10281	}
10282
10283	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel)) {
10284		DBG(("%s: unsupported blt\n", __FUNCTION__));
10285		return false;
10286	}
10287
10288	get_drawable_deltas(drawable, pixmap, &dx, &dy);
10289	if (!clipped) {
10290		dx += drawable->x;
10291		dy += drawable->y;
10292
10293		sna_damage_add_rectangles(damage, rect, n, dx, dy);
10294		if (dx|dy) {
10295			do {
10296				unsigned nbox = n;
10297				if (nbox > ARRAY_SIZE(boxes))
10298					nbox = ARRAY_SIZE(boxes);
10299				n -= nbox;
10300				do {
10301					b->x1 = rect->x + dx;
10302					b->y1 = rect->y + dy;
10303					b->x2 = b->x1 + rect->width;
10304					b->y2 = b->y1 + rect->height;
10305					b++;
10306					rect++;
10307				} while (--nbox);
10308				fill.boxes(sna, &fill, boxes, b-boxes);
10309				b = boxes;
10310			} while (n);
10311		} else {
10312			do {
10313				unsigned nbox = n;
10314				if (nbox > ARRAY_SIZE(boxes))
10315					nbox = ARRAY_SIZE(boxes);
10316				n -= nbox;
10317				do {
10318					b->x1 = rect->x;
10319					b->y1 = rect->y;
10320					b->x2 = b->x1 + rect->width;
10321					b->y2 = b->y1 + rect->height;
10322					b++;
10323					rect++;
10324				} while (--nbox);
10325				fill.boxes(sna, &fill, boxes, b-boxes);
10326				b = boxes;
10327			} while (n);
10328		}
10329	} else {
10330		RegionRec clip;
10331
10332		region_set(&clip, extents);
10333		region_maybe_clip(&clip, gc->pCompositeClip);
10334		if (RegionNil(&clip))
10335			goto done;
10336
10337		if (clip.data == NULL) {
10338			do {
10339				b->x1 = rect->x + drawable->x;
10340				b->y1 = rect->y + drawable->y;
10341				b->x2 = bound(b->x1, rect->width);
10342				b->y2 = bound(b->y1, rect->height);
10343				rect++;
10344
10345				if (box_intersect(b, &clip.extents)) {
10346					b->x1 += dx;
10347					b->x2 += dx;
10348					b->y1 += dy;
10349					b->y2 += dy;
10350					if (++b == last_box) {
10351						fill.boxes(sna, &fill, boxes, last_box-boxes);
10352						if (damage)
10353							sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
10354						b = boxes;
10355					}
10356				}
10357			} while (--n);
10358		} else {
10359			const BoxRec * const clip_start = RegionBoxptr(&clip);
10360			const BoxRec * const clip_end = clip_start + clip.data->numRects;
10361			const BoxRec *c;
10362
10363			do {
10364				BoxRec box;
10365
10366				box.x1 = rect->x + drawable->x;
10367				box.y1 = rect->y + drawable->y;
10368				box.x2 = bound(box.x1, rect->width);
10369				box.y2 = bound(box.y1, rect->height);
10370				rect++;
10371
10372				c = find_clip_box_for_y(clip_start,
10373							clip_end,
10374							box.y1);
10375				while (c != clip_end) {
10376					if (box.y2 <= c->y1)
10377						break;
10378
10379					*b = box;
10380					if (box_intersect(b, c++)) {
10381						b->x1 += dx;
10382						b->x2 += dx;
10383						b->y1 += dy;
10384						b->y2 += dy;
10385						if (++b == last_box) {
10386							fill.boxes(sna, &fill, boxes, last_box-boxes);
10387							if (damage)
10388								sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0);
10389							b = boxes;
10390						}
10391					}
10392
10393				}
10394			} while (--n);
10395		}
10396
10397		RegionUninit(&clip);
10398		if (b != boxes) {
10399			fill.boxes(sna, &fill, boxes, b-boxes);
10400			if (damage)
10401				sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0);
10402		}
10403	}
10404done:
10405	fill.done(sna, &fill);
10406	assert_pixmap_damage(pixmap);
10407	return true;
10408}
10409
10410static uint32_t
10411get_pixel(PixmapPtr pixmap)
10412{
10413	DBG(("%s\n", __FUNCTION__));
10414	if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
10415		return 0;
10416
10417	switch (pixmap->drawable.bitsPerPixel) {
10418	case 32: return *(uint32_t *)pixmap->devPrivate.ptr;
10419	case 16: return *(uint16_t *)pixmap->devPrivate.ptr;
10420	default: return *(uint8_t *)pixmap->devPrivate.ptr;
10421	}
10422}
10423
10424static void
10425sna_poly_fill_polygon(DrawablePtr draw, GCPtr gc,
10426		      int shape, int mode,
10427		      int n, DDXPointPtr pt)
10428{
10429	struct sna_fill_spans data;
10430	struct sna_pixmap *priv;
10431
10432	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
10433	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
10434	     (gc->fillStyle == FillSolid ||
10435	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
10436	     gc->fillStyle, gc->tileIsPixel,
10437	     gc->alu));
10438	DBG(("%s: draw=%ld, offset=(%d, %d), size=%dx%d\n",
10439	     __FUNCTION__, draw->serialNumber,
10440	     draw->x, draw->y, draw->width, draw->height));
10441
10442	data.flags = sna_poly_point_extents(draw, gc, mode, n, pt,
10443					    &data.region.extents);
10444	if (data.flags == 0) {
10445		DBG(("%s, nothing to do\n", __FUNCTION__));
10446		return;
10447	}
10448
10449	DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
10450	     data.region.extents.x1, data.region.extents.y1,
10451	     data.region.extents.x2, data.region.extents.y2,
10452	     data.flags));
10453
10454	data.region.data = NULL;
10455
10456	if (FORCE_FALLBACK)
10457		goto fallback;
10458
10459	if (!ACCEL_POLY_FILL_POLYGON)
10460		goto fallback;
10461
10462	data.pixmap = get_drawable_pixmap(draw);
10463	data.sna = to_sna_from_pixmap(data.pixmap);
10464	priv = sna_pixmap(data.pixmap);
10465	if (priv == NULL) {
10466		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
10467		goto fallback;
10468	}
10469
10470	if (wedged(data.sna)) {
10471		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
10472		goto fallback;
10473	}
10474
10475	if (!PM_IS_SOLID(draw, gc->planemask))
10476		goto fallback;
10477
10478	if ((data.bo = sna_drawable_use_bo(draw,
10479					   (shape == Convex ? use_zero_spans : use_wide_spans)(draw, gc, &data.region.extents),
10480					   &data.region.extents,
10481					   &data.damage))) {
10482		uint32_t color;
10483
10484		sna_gc(gc)->priv = &data;
10485		get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy);
10486
10487		if (gc_is_solid(gc, &color)) {
10488			struct sna_fill_op fill;
10489
10490			if (!sna_fill_init_blt(&fill,
10491					       data.sna, data.pixmap,
10492					       data.bo, gc->alu, color))
10493				goto fallback;
10494
10495			data.op = &fill;
10496
10497			if ((data.flags & 2) == 0) {
10498				if (data.dx | data.dy)
10499					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
10500				else
10501					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
10502			} else {
10503				region_maybe_clip(&data.region,
10504						  gc->pCompositeClip);
10505				if (RegionNil(&data.region))
10506					return;
10507
10508				if (region_is_singular(&data.region))
10509					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
10510				else
10511					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
10512			}
10513			assert(gc->miTranslate);
10514			gc->ops = &sna_gc_ops__tmp;
10515
10516			miFillPolygon(draw, gc, shape, mode, n, pt);
10517			fill.done(data.sna, &fill);
10518		} else {
10519			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
10520			gc->ops = &sna_gc_ops__tmp;
10521
10522			miFillPolygon(draw, gc, shape, mode, n, pt);
10523		}
10524
10525		gc->ops = (GCOps *)&sna_gc_ops;
10526		if (data.damage) {
10527			if (data.dx | data.dy)
10528				pixman_region_translate(&data.region, data.dx, data.dy);
10529			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
10530			sna_damage_add(data.damage, &data.region);
10531		}
10532		assert_pixmap_damage(data.pixmap);
10533		RegionUninit(&data.region);
10534		return;
10535	}
10536
10537fallback:
10538	DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__,
10539	     data.region.extents.x1, data.region.extents.y1,
10540	     data.region.extents.x2, data.region.extents.y2));
10541	region_maybe_clip(&data.region, gc->pCompositeClip);
10542	if (RegionNil(&data.region)) {
10543		DBG(("%s: nothing to do, all clipped\n", __FUNCTION__));
10544		return;
10545	}
10546
10547	if (!sna_gc_move_to_cpu(gc, draw, &data.region))
10548		goto out;
10549	if (!sna_drawable_move_region_to_cpu(draw, &data.region,
10550					     drawable_gc_flags(draw, gc, true)))
10551		goto out_gc;
10552
10553	DBG(("%s: fallback -- miFillPolygon -> sna_fill_spans__cpu\n",
10554	     __FUNCTION__));
10555	miFillPolygon(draw, gc, shape, mode, n, pt);
10556out_gc:
10557	sna_gc_move_to_gpu(gc);
10558out:
10559	RegionUninit(&data.region);
10560}
10561
10562static struct kgem_bo *
10563sna_pixmap_get_source_bo(PixmapPtr pixmap)
10564{
10565	struct sna_pixmap *priv = sna_pixmap(pixmap);
10566
10567	if (priv == NULL) {
10568		struct kgem_bo *upload;
10569		struct sna *sna = to_sna_from_pixmap(pixmap);
10570		void *ptr;
10571
10572		upload = kgem_create_buffer_2d(&sna->kgem,
10573					       pixmap->drawable.width,
10574					       pixmap->drawable.height,
10575					       pixmap->drawable.bitsPerPixel,
10576					       KGEM_BUFFER_WRITE_INPLACE,
10577					       &ptr);
10578		if (upload == NULL)
10579			return NULL;
10580
10581		assert(has_coherent_ptr(sna_pixmap(pixmap)));
10582		memcpy_blt(pixmap->devPrivate.ptr, ptr,
10583			   pixmap->drawable.bitsPerPixel,
10584			   pixmap->devKind, upload->pitch,
10585			   0, 0,
10586			   0, 0,
10587			   pixmap->drawable.width,
10588			   pixmap->drawable.height);
10589
10590		return upload;
10591	}
10592
10593	if (priv->gpu_damage &&
10594	    !sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT))
10595		return NULL;
10596
10597	if (priv->cpu_damage && priv->cpu_bo)
10598		return kgem_bo_reference(priv->cpu_bo);
10599
10600	if (!sna_pixmap_force_to_gpu(pixmap, MOVE_READ))
10601		return NULL;
10602
10603	return kgem_bo_reference(priv->gpu_bo);
10604}
10605
10606/*
10607static bool
10608tile(DrawablePtr drawable,
10609	struct kgem_bo *bo, struct sna_damage **damage,
10610	PixmapPtr tile, const DDXPointRec * const origin, int alu,
10611	int n, xRectangle *rect,
10612	const BoxRec *extents, unsigned clipped)
10613	*/
10614
10615static bool
10616sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
10617				 struct kgem_bo *bo, struct sna_damage **damage,
10618				 struct kgem_bo *tile_bo, GCPtr gc,
10619				 int n, const xRectangle *r,
10620				 const BoxRec *extents, unsigned clipped)
10621{
10622	PixmapPtr pixmap = get_drawable_pixmap(drawable);
10623	struct sna *sna = to_sna_from_pixmap(pixmap);
10624	const DDXPointRec * const origin = &gc->patOrg;
10625	uint32_t br00, br13;
10626	int tx, ty;
10627	int16_t dx, dy;
10628	uint32_t *b;
10629
10630	if (NO_TILE_8x8)
10631		return false;
10632
10633	DBG(("%s x %d [(%d, %d)x(%d, %d)...], clipped=%x\n",
10634	     __FUNCTION__, n, r->x, r->y, r->width, r->height, clipped));
10635
10636	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
10637	if (!kgem_check_batch(&sna->kgem, 8+2*3) ||
10638	    !kgem_check_reloc(&sna->kgem, 2) ||
10639	    !kgem_check_bo_fenced(&sna->kgem, bo)) {
10640		kgem_submit(&sna->kgem);
10641		if (!kgem_check_bo_fenced(&sna->kgem, bo))
10642			return false;
10643		_kgem_set_mode(&sna->kgem, KGEM_BLT);
10644	}
10645
10646	br00 = XY_SCANLINE_BLT;
10647	br13 = bo->pitch;
10648	if (sna->kgem.gen >= 040 && bo->tiling) {
10649		br00 |= BLT_DST_TILED;
10650		br13 >>= 2;
10651	}
10652	br13 |= blt_depth(drawable->depth) << 24;
10653	br13 |= fill_ROP[gc->alu] << 16;
10654
10655	get_drawable_deltas(drawable, pixmap, &dx, &dy);
10656	assert(extents->x1 + dx >= 0);
10657	assert(extents->y1 + dy >= 0);
10658	assert(extents->x2 + dx <= pixmap->drawable.width);
10659	assert(extents->y2 + dy <= pixmap->drawable.height);
10660
10661	if (!clipped) {
10662		dx += drawable->x;
10663		dy += drawable->y;
10664
10665		sna_damage_add_rectangles(damage, r, n, dx, dy);
10666		if (n == 1) {
10667			tx = (r->x - origin->x) % 8;
10668			if (tx < 0)
10669				tx = 8 - tx;
10670			ty = (r->y - origin->y) % 8;
10671			if (ty < 0)
10672				ty = 8 - ty;
10673
10674			assert(r->x + dx >= 0);
10675			assert(r->y + dy >= 0);
10676			assert(r->x + dx + r->width  <= pixmap->drawable.width);
10677			assert(r->y + dy + r->height <= pixmap->drawable.height);
10678
10679			b = sna->kgem.batch + sna->kgem.nbatch;
10680			b[0] = XY_PAT_BLT | tx << 12 | ty << 8 | 3 << 20 | (br00 & BLT_DST_TILED);
10681			b[1] = br13;
10682			b[2] = (r->y + dy) << 16 | (r->x + dx);
10683			b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
10684			b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
10685					      I915_GEM_DOMAIN_RENDER << 16 |
10686					      I915_GEM_DOMAIN_RENDER |
10687					      KGEM_RELOC_FENCED,
10688					      0);
10689			b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, tile_bo,
10690					      I915_GEM_DOMAIN_RENDER << 16 |
10691					      KGEM_RELOC_FENCED,
10692					      0);
10693			sna->kgem.nbatch += 6;
10694		} else do {
10695			int n_this_time;
10696
10697			b = sna->kgem.batch + sna->kgem.nbatch;
10698			b[0] = XY_SETUP_BLT | 3 << 20;
10699			b[1] = br13;
10700			b[2] = 0;
10701			b[3] = 0;
10702			b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
10703					      I915_GEM_DOMAIN_RENDER << 16 |
10704					      I915_GEM_DOMAIN_RENDER |
10705					      KGEM_RELOC_FENCED,
10706					      0);
10707			b[5] = gc->bgPixel;
10708			b[6] = gc->fgPixel;
10709			b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
10710					      I915_GEM_DOMAIN_RENDER << 16 |
10711					      KGEM_RELOC_FENCED,
10712					      0);
10713			sna->kgem.nbatch += 8;
10714
10715			n_this_time = n;
10716			if (3*n_this_time > sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED)
10717				n_this_time = (sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED) / 3;
10718			assert(n_this_time);
10719			n -= n_this_time;
10720
10721			b = sna->kgem.batch + sna->kgem.nbatch;
10722			sna->kgem.nbatch += 3*n_this_time;
10723			do {
10724				assert(r->x + dx >= 0);
10725				assert(r->y + dy >= 0);
10726				assert(r->x + dx + r->width  <= pixmap->drawable.width);
10727				assert(r->y + dy + r->height <= pixmap->drawable.height);
10728
10729				tx = (r->x - origin->x) % 8;
10730				if (tx < 0)
10731					tx = 8 - tx;
10732				ty = (r->y - origin->y) % 8;
10733				if (ty < 0)
10734					ty = 8 - ty;
10735
10736				b[0] = br00 | tx << 12 | ty << 8;
10737				b[1] = (r->y + dy) << 16 | (r->x + dx);
10738				b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
10739				b += 3; r++;
10740			} while (--n_this_time);
10741
10742			if (!n)
10743				break;
10744
10745			_kgem_submit(&sna->kgem);
10746			_kgem_set_mode(&sna->kgem, KGEM_BLT);
10747		} while (1);
10748	} else {
10749		RegionRec clip;
10750		uint16_t unwind_batch, unwind_reloc;
10751
10752		region_set(&clip, extents);
10753		region_maybe_clip(&clip, gc->pCompositeClip);
10754		if (RegionNil(&clip))
10755			goto done;
10756
10757		unwind_batch = sna->kgem.nbatch;
10758		unwind_reloc = sna->kgem.nreloc;
10759
10760		b = sna->kgem.batch + sna->kgem.nbatch;
10761		b[0] = XY_SETUP_BLT | 3 << 20;
10762		b[1] = br13;
10763		b[2] = 0;
10764		b[3] = 0;
10765		b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
10766				      I915_GEM_DOMAIN_RENDER << 16 |
10767				      I915_GEM_DOMAIN_RENDER |
10768				      KGEM_RELOC_FENCED,
10769				      0);
10770		b[5] = gc->bgPixel;
10771		b[6] = gc->fgPixel;
10772		b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
10773				      I915_GEM_DOMAIN_RENDER << 16 |
10774				      KGEM_RELOC_FENCED,
10775				      0);
10776		sna->kgem.nbatch += 8;
10777
10778		if (clip.data == NULL) {
10779			const BoxRec *c = &clip.extents;
10780			while (n--) {
10781				BoxRec box;
10782
10783				box.x1 = r->x + drawable->x;
10784				box.y1 = r->y + drawable->y;
10785				box.x2 = bound(box.x1, r->width);
10786				box.y2 = bound(box.y1, r->height);
10787				r++;
10788
10789				if (box_intersect(&box, c)) {
10790					if (!kgem_check_batch(&sna->kgem, 3)) {
10791						_kgem_submit(&sna->kgem);
10792						_kgem_set_mode(&sna->kgem, KGEM_BLT);
10793
10794						unwind_batch = sna->kgem.nbatch;
10795						unwind_reloc = sna->kgem.nreloc;
10796
10797						b = sna->kgem.batch + sna->kgem.nbatch;
10798						b[0] = XY_SETUP_BLT | 3 << 20;
10799						b[1] = br13;
10800						b[2] = 0;
10801						b[3] = 0;
10802						b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
10803								      I915_GEM_DOMAIN_RENDER << 16 |
10804								      I915_GEM_DOMAIN_RENDER |
10805								      KGEM_RELOC_FENCED,
10806								      0);
10807						b[5] = gc->bgPixel;
10808						b[6] = gc->fgPixel;
10809						b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
10810								      I915_GEM_DOMAIN_RENDER << 16 |
10811								      KGEM_RELOC_FENCED,
10812								      0);
10813						sna->kgem.nbatch += 8;
10814					}
10815
10816					assert(box.x1 + dx >= 0);
10817					assert(box.y1 + dy >= 0);
10818					assert(box.x2 + dx <= pixmap->drawable.width);
10819					assert(box.y2 + dy <= pixmap->drawable.height);
10820
10821					ty = (box.y1 - drawable->y - origin->y) % 8;
10822					if (ty < 0)
10823						ty = 8 - ty;
10824
10825					tx = (box.x1 - drawable->x - origin->x) % 8;
10826					if (tx < 0)
10827						tx = 8 - tx;
10828
10829					b = sna->kgem.batch + sna->kgem.nbatch;
10830					b[0] = br00 | tx << 12 | ty << 8;
10831					b[1] = (box.y1 + dy) << 16 | (box.x1 + dx);
10832					b[2] = (box.y2 + dy) << 16 | (box.x2 + dx);
10833					sna->kgem.nbatch += 3;
10834				}
10835			}
10836		} else {
10837			const BoxRec * const clip_start = RegionBoxptr(&clip);
10838			const BoxRec * const clip_end = clip_start + clip.data->numRects;
10839			const BoxRec *c;
10840
10841			do {
10842				BoxRec box;
10843
10844				box.x1 = r->x + drawable->x;
10845				box.y1 = r->y + drawable->y;
10846				box.x2 = bound(box.x1, r->width);
10847				box.y2 = bound(box.y1, r->height);
10848				r++;
10849
10850				c = find_clip_box_for_y(clip_start,
10851							clip_end,
10852							box.y1);
10853				while (c != clip_end) {
10854					BoxRec bb;
10855
10856					if (box.y2 <= c->y1)
10857						break;
10858
10859					bb = box;
10860					if (box_intersect(&bb, c++)) {
10861						if (!kgem_check_batch(&sna->kgem, 3)) {
10862							_kgem_submit(&sna->kgem);
10863							_kgem_set_mode(&sna->kgem, KGEM_BLT);
10864
10865							unwind_batch = sna->kgem.nbatch;
10866							unwind_reloc = sna->kgem.nreloc;
10867
10868							b = sna->kgem.batch + sna->kgem.nbatch;
10869							b[0] = XY_SETUP_BLT | 3 << 20;
10870							b[1] = br13;
10871							b[2] = 0;
10872							b[3] = 0;
10873							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
10874									      I915_GEM_DOMAIN_RENDER << 16 |
10875									      I915_GEM_DOMAIN_RENDER |
10876									      KGEM_RELOC_FENCED,
10877									      0);
10878							b[5] = gc->bgPixel;
10879							b[6] = gc->fgPixel;
10880							b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo,
10881									      I915_GEM_DOMAIN_RENDER << 16 |
10882									      KGEM_RELOC_FENCED,
10883									      0);
10884							sna->kgem.nbatch += 8;
10885						}
10886
10887						assert(bb.x1 + dx >= 0);
10888						assert(bb.y1 + dy >= 0);
10889						assert(bb.x2 + dx <= pixmap->drawable.width);
10890						assert(bb.y2 + dy <= pixmap->drawable.height);
10891
10892						ty = (bb.y1 - drawable->y - origin->y) % 8;
10893						if (ty < 0)
10894							ty = 8 - ty;
10895
10896						tx = (bb.x1 - drawable->x - origin->x) % 8;
10897						if (tx < 0)
10898							tx = 8 - tx;
10899
10900						b = sna->kgem.batch + sna->kgem.nbatch;
10901						b[0] = br00 | tx << 12 | ty << 8;
10902						b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx);
10903						b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx);
10904						sna->kgem.nbatch += 3;
10905					}
10906				}
10907			} while (--n);
10908		}
10909
10910		if (sna->kgem.nbatch == unwind_batch + 8) {
10911			sna->kgem.nbatch = unwind_batch;
10912			sna->kgem.nreloc = unwind_reloc;
10913		}
10914	}
10915done:
10916	assert_pixmap_damage(pixmap);
10917	sna->blt_state.fill_bo = 0;
10918	return true;
10919}
10920
10921static bool
10922sna_poly_fill_rect_tiled_nxm_blt(DrawablePtr drawable,
10923				 struct kgem_bo *bo,
10924				 struct sna_damage **damage,
10925				 GCPtr gc, int n, const xRectangle *rect,
10926				 const BoxRec *extents, unsigned clipped)
10927{
10928	PixmapPtr pixmap = get_drawable_pixmap(drawable);
10929	struct sna *sna = to_sna_from_pixmap(pixmap);
10930	PixmapPtr tile = gc->tile.pixmap;
10931	struct kgem_bo *upload;
10932	int w, h, cpp;
10933	void *ptr;
10934	bool ret;
10935
10936	DBG(("%s: %dx%d\n", __FUNCTION__,
10937	     tile->drawable.width, tile->drawable.height));
10938
10939	if (!sna_pixmap_move_to_cpu(tile, MOVE_READ))
10940		return false;
10941
10942	upload = kgem_create_buffer(&sna->kgem, 8*tile->drawable.bitsPerPixel,
10943				    KGEM_BUFFER_WRITE_INPLACE,
10944				    &ptr);
10945	if (upload == NULL)
10946		return false;
10947
10948	assert(tile->drawable.height && tile->drawable.height <= 8);
10949	assert(tile->drawable.width && tile->drawable.width <= 8);
10950	assert(has_coherent_ptr(sna_pixmap(tile)));
10951
10952	cpp = tile->drawable.bitsPerPixel/8;
10953	for (h = 0; h < tile->drawable.height; h++) {
10954		uint8_t *src = (uint8_t *)tile->devPrivate.ptr + tile->devKind*h;
10955		uint8_t *dst = (uint8_t *)ptr + 8*cpp*h;
10956
10957		w = tile->drawable.width*cpp;
10958		memcpy(dst, src, w);
10959		while (w < 8*cpp) {
10960			memcpy(dst+w, dst, w);
10961			w *= 2;
10962		}
10963	}
10964	while (h < 8) {
10965		memcpy((uint8_t*)ptr + h*w, ptr, h*w);
10966		h *= 2;
10967	}
10968
10969	ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage,
10970					       upload, gc, n, rect,
10971					       extents, clipped);
10972
10973	kgem_bo_destroy(&sna->kgem, upload);
10974	return ret;
10975}
10976
10977static bool
10978sna_poly_fill_rect_tiled_blt(DrawablePtr drawable,
10979			     struct kgem_bo *bo,
10980			     struct sna_damage **damage,
10981			     GCPtr gc, int n, xRectangle *rect,
10982			     const BoxRec *extents, unsigned clipped)
10983{
10984	PixmapPtr pixmap = get_drawable_pixmap(drawable);
10985	struct sna *sna = to_sna_from_pixmap(pixmap);
10986	PixmapPtr tile = gc->tile.pixmap;
10987	struct kgem_bo *tile_bo;
10988	const DDXPointRec * const origin = &gc->patOrg;
10989	struct sna_copy_op copy;
10990	CARD32 alu = gc->alu;
10991	int tile_width, tile_height;
10992	int16_t dx, dy;
10993
10994	DBG(("%s x %d [(%d, %d)x(%d, %d)...]\n",
10995	     __FUNCTION__, n, rect->x, rect->y, rect->width, rect->height));
10996
10997	tile_width = tile->drawable.width;
10998	tile_height = tile->drawable.height;
10999	if ((tile_width | tile_height) == 1) {
11000		DBG(("%s: single pixel tile pixmap ,converting to solid fill\n",
11001		     __FUNCTION__));
11002		return sna_poly_fill_rect_blt(drawable, bo, damage,
11003					      gc, get_pixel(tile),
11004					      n, rect,
11005					      extents, clipped);
11006	}
11007
11008	/* XXX [248]x[238] tiling can be reduced to a pattern fill.
11009	 * Also we can do the lg2 reduction for BLT and use repeat modes for
11010	 * RENDER.
11011	 */
11012
11013	if ((tile->drawable.width | tile->drawable.height) == 8) {
11014		bool ret;
11015
11016		tile_bo = sna_pixmap_get_source_bo(tile);
11017		ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage,
11018						       tile_bo, gc, n, rect,
11019						       extents, clipped);
11020		kgem_bo_destroy(&sna->kgem, tile_bo);
11021
11022		return ret;
11023	}
11024
11025	if ((tile->drawable.width | tile->drawable.height) <= 0xc &&
11026	    is_power_of_two(tile->drawable.width) &&
11027	    is_power_of_two(tile->drawable.height))
11028		return sna_poly_fill_rect_tiled_nxm_blt(drawable, bo, damage,
11029							gc, n, rect,
11030							extents, clipped);
11031
11032	tile_bo = sna_pixmap_get_source_bo(tile);
11033	if (tile_bo == NULL) {
11034		DBG(("%s: unable to move tile go GPU, fallback\n",
11035		     __FUNCTION__));
11036		return false;
11037	}
11038
11039	if (!sna_copy_init_blt(&copy, sna, tile, tile_bo, pixmap, bo, alu)) {
11040		DBG(("%s: unsupported blt\n", __FUNCTION__));
11041		kgem_bo_destroy(&sna->kgem, tile_bo);
11042		return false;
11043	}
11044
11045	get_drawable_deltas(drawable, pixmap, &dx, &dy);
11046	if (!clipped) {
11047		dx += drawable->x;
11048		dy += drawable->y;
11049
11050		sna_damage_add_rectangles(damage, rect, n, dx, dy);
11051		do {
11052			xRectangle r = *rect++;
11053			int16_t tile_y = (r.y - origin->y) % tile_height;
11054			if (tile_y < 0)
11055				tile_y += tile_height;
11056
11057			assert(r.x + dx >= 0);
11058			assert(r.y + dy >= 0);
11059			assert(r.x + dx + r.width  <= pixmap->drawable.width);
11060			assert(r.y + dy + r.height <= pixmap->drawable.height);
11061
11062			r.y += dy;
11063			do {
11064				int16_t width = r.width;
11065				int16_t x = r.x + dx, tile_x;
11066				int16_t h = tile_height - tile_y;
11067				if (h > r.height)
11068					h = r.height;
11069				r.height -= h;
11070
11071				tile_x = (r.x - origin->x) % tile_width;
11072				if (tile_x < 0)
11073					tile_x += tile_width;
11074
11075				do {
11076					int16_t w = tile_width - tile_x;
11077					if (w > width)
11078						w = width;
11079					width -= w;
11080
11081					copy.blt(sna, &copy,
11082						 tile_x, tile_y,
11083						 w, h,
11084						 x, r.y);
11085
11086					x += w;
11087					tile_x = 0;
11088				} while (width);
11089				r.y += h;
11090				tile_y = 0;
11091			} while (r.height);
11092		} while (--n);
11093	} else {
11094		RegionRec clip;
11095
11096		region_set(&clip, extents);
11097		region_maybe_clip(&clip, gc->pCompositeClip);
11098		if (RegionNil(&clip))
11099			goto done;
11100
11101		if (clip.data == NULL) {
11102			const BoxRec *box = &clip.extents;
11103			while (n--) {
11104				BoxRec r;
11105
11106				r.x1 = rect->x + drawable->x;
11107				r.y1 = rect->y + drawable->y;
11108				r.x2 = bound(r.x1, rect->width);
11109				r.y2 = bound(r.y1, rect->height);
11110				rect++;
11111
11112				if (box_intersect(&r, box)) {
11113					int height = r.y2 - r.y1;
11114					int dst_y = r.y1;
11115					int tile_y = (r.y1 - drawable->y - origin->y) % tile_height;
11116					if (tile_y < 0)
11117						tile_y += tile_height;
11118
11119					while (height) {
11120						int width = r.x2 - r.x1;
11121						int dst_x = r.x1, tile_x;
11122						int h = tile_height - tile_y;
11123						if (h > height)
11124							h = height;
11125						height -= h;
11126
11127						tile_x = (r.x1 - drawable->x - origin->x) % tile_width;
11128						if (tile_x < 0)
11129							tile_x += tile_width;
11130
11131						while (width > 0) {
11132							int w = tile_width - tile_x;
11133							if (w > width)
11134								w = width;
11135							width -= w;
11136
11137							copy.blt(sna, &copy,
11138								 tile_x, tile_y,
11139								 w, h,
11140								 dst_x + dx, dst_y + dy);
11141							if (damage) {
11142								BoxRec b;
11143
11144								b.x1 = dst_x + dx;
11145								b.y1 = dst_y + dy;
11146								b.x2 = b.x1 + w;
11147								b.y2 = b.y1 + h;
11148
11149								assert_pixmap_contains_box(pixmap, &b);
11150								sna_damage_add_box(damage, &b);
11151							}
11152
11153							dst_x += w;
11154							tile_x = 0;
11155						}
11156						dst_y += h;
11157						tile_y = 0;
11158					}
11159				}
11160			}
11161		} else {
11162			while (n--) {
11163				RegionRec region;
11164				BoxRec *box;
11165				int nbox;
11166
11167				region.extents.x1 = rect->x + drawable->x;
11168				region.extents.y1 = rect->y + drawable->y;
11169				region.extents.x2 = bound(region.extents.x1, rect->width);
11170				region.extents.y2 = bound(region.extents.y1, rect->height);
11171				rect++;
11172
11173				region.data = NULL;
11174				RegionIntersect(&region, &region, &clip);
11175
11176				nbox = RegionNumRects(&region);
11177				box = RegionRects(&region);
11178				while (nbox--) {
11179					int height = box->y2 - box->y1;
11180					int dst_y = box->y1;
11181					int tile_y = (box->y1 - drawable->y - origin->y) % tile_height;
11182					if (tile_y < 0)
11183						tile_y += tile_height;
11184
11185					while (height) {
11186						int width = box->x2 - box->x1;
11187						int dst_x = box->x1, tile_x;
11188						int h = tile_height - tile_y;
11189						if (h > height)
11190							h = height;
11191						height -= h;
11192
11193						tile_x = (box->x1 - drawable->x - origin->x) % tile_width;
11194						if (tile_x < 0)
11195							tile_x += tile_width;
11196
11197						while (width > 0) {
11198							int w = tile_width - tile_x;
11199							if (w > width)
11200								w = width;
11201							width -= w;
11202
11203							copy.blt(sna, &copy,
11204								 tile_x, tile_y,
11205								 w, h,
11206								 dst_x + dx, dst_y + dy);
11207							if (damage) {
11208								BoxRec b;
11209
11210								b.x1 = dst_x + dx;
11211								b.y1 = dst_y + dy;
11212								b.x2 = b.x1 + w;
11213								b.y2 = b.y1 + h;
11214
11215								assert_pixmap_contains_box(pixmap, &b);
11216								sna_damage_add_box(damage, &b);
11217							}
11218
11219							dst_x += w;
11220							tile_x = 0;
11221						}
11222						dst_y += h;
11223						tile_y = 0;
11224					}
11225					box++;
11226				}
11227
11228				RegionUninit(&region);
11229			}
11230		}
11231
11232		RegionUninit(&clip);
11233	}
11234done:
11235	copy.done(sna, &copy);
11236	assert_pixmap_damage(pixmap);
11237	kgem_bo_destroy(&sna->kgem, tile_bo);
11238	return true;
11239}
11240
11241static bool
11242sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
11243				    struct kgem_bo *bo,
11244				    struct sna_damage **damage,
11245				    GCPtr gc, int n, xRectangle *r,
11246				    const BoxRec *extents, unsigned clipped)
11247{
11248	PixmapPtr pixmap = get_drawable_pixmap(drawable);
11249	struct sna *sna = to_sna_from_pixmap(pixmap);
11250	uint32_t pat[2] = {0, 0}, br00, br13;
11251	int16_t dx, dy;
11252	uint32_t *b;
11253
11254	if (NO_STIPPLE_8x8)
11255		return false;
11256
11257	DBG(("%s: alu=%d, upload (%d, %d), (%d, %d), origin (%d, %d)\n",
11258	     __FUNCTION__, gc->alu,
11259	     extents->x1, extents->y1,
11260	     extents->x2, extents->y2,
11261	     gc->patOrg.x, gc->patOrg.y));
11262
11263	get_drawable_deltas(drawable, pixmap, &dx, &dy);
11264	{
11265		unsigned px = (0 - gc->patOrg.x - dx) & 7;
11266		unsigned py = (0 - gc->patOrg.y - dy) & 7;
11267		DBG(("%s: pat offset (%d, %d)\n", __FUNCTION__ ,px, py));
11268		br00 = XY_SCANLINE_BLT | px << 12 | py << 8 | 3 << 20;
11269		br13 = bo->pitch;
11270		if (sna->kgem.gen >= 040 && bo->tiling) {
11271			br00 |= BLT_DST_TILED;
11272			br13 >>= 2;
11273		}
11274		br13 |= (gc->fillStyle == FillStippled) << 28;
11275		br13 |= blt_depth(drawable->depth) << 24;
11276		br13 |= fill_ROP[gc->alu] << 16;
11277	}
11278
11279	{
11280		uint8_t *dst = (uint8_t *)pat;
11281		const uint8_t *src = gc->stipple->devPrivate.ptr;
11282		int stride = gc->stipple->devKind;
11283		int j = gc->stipple->drawable.height;
11284		do {
11285			*dst++ = byte_reverse(*src);
11286			src += stride;
11287		} while (--j);
11288	}
11289
11290	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
11291	if (!kgem_check_batch(&sna->kgem, 9 + 2*3) ||
11292	    !kgem_check_bo_fenced(&sna->kgem, bo) ||
11293	    !kgem_check_reloc(&sna->kgem, 1)) {
11294		kgem_submit(&sna->kgem);
11295		if (!kgem_check_bo_fenced(&sna->kgem, bo))
11296			return false;
11297		_kgem_set_mode(&sna->kgem, KGEM_BLT);
11298	}
11299
11300	if (!clipped) {
11301		dx += drawable->x;
11302		dy += drawable->y;
11303
11304		sna_damage_add_rectangles(damage, r, n, dx, dy);
11305		if (n == 1) {
11306			DBG(("%s: single unclipped rect (%d, %d)x(%d, %d)\n",
11307			     __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height));
11308
11309			b = sna->kgem.batch + sna->kgem.nbatch;
11310			b[0] = XY_MONO_PAT | (br00 & (BLT_DST_TILED | 0x7<<12 | 0x7<<8)) | 3<<20;
11311			b[1] = br13;
11312			b[2] = (r->y + dy) << 16 | (r->x + dx);
11313			b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
11314			b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
11315					      I915_GEM_DOMAIN_RENDER << 16 |
11316					      I915_GEM_DOMAIN_RENDER |
11317					      KGEM_RELOC_FENCED,
11318					      0);
11319			b[5] = gc->bgPixel;
11320			b[6] = gc->fgPixel;
11321			b[7] = pat[0];
11322			b[8] = pat[1];
11323			sna->kgem.nbatch += 9;
11324		} else do {
11325			int n_this_time;
11326
11327			b = sna->kgem.batch + sna->kgem.nbatch;
11328			b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20;
11329			b[1] = br13;
11330			b[2] = 0;
11331			b[3] = 0;
11332			b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
11333					      I915_GEM_DOMAIN_RENDER << 16 |
11334					      I915_GEM_DOMAIN_RENDER |
11335					      KGEM_RELOC_FENCED,
11336					      0);
11337			b[5] = gc->bgPixel;
11338			b[6] = gc->fgPixel;
11339			b[7] = pat[0];
11340			b[8] = pat[1];
11341			sna->kgem.nbatch += 9;
11342
11343			n_this_time = n;
11344			if (3*n_this_time > sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED)
11345				n_this_time = (sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED) / 3;
11346			assert(n_this_time);
11347			n -= n_this_time;
11348
11349			b = sna->kgem.batch + sna->kgem.nbatch;
11350			sna->kgem.nbatch += 3 * n_this_time;
11351			do {
11352				DBG(("%s: rect (%d, %d)x(%d, %d)\n",
11353				     __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height));
11354				assert(r->x + dx >= 0);
11355				assert(r->y + dy >= 0);
11356				assert(r->x + dx + r->width  <= pixmap->drawable.width);
11357				assert(r->y + dy + r->height <= pixmap->drawable.height);
11358
11359				b[0] = br00;
11360				b[1] = (r->y + dy) << 16 | (r->x + dx);
11361				b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
11362
11363				b += 3; r++;
11364			} while(--n_this_time);
11365
11366			if (!n)
11367				break;
11368
11369			_kgem_submit(&sna->kgem);
11370			_kgem_set_mode(&sna->kgem, KGEM_BLT);
11371		} while (1);
11372	} else {
11373		RegionRec clip;
11374
11375		region_set(&clip, extents);
11376		region_maybe_clip(&clip, gc->pCompositeClip);
11377		if (RegionNil(&clip))
11378			return true;
11379
11380		b = sna->kgem.batch + sna->kgem.nbatch;
11381		b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20;
11382		b[1] = br13;
11383		b[2] = 0;
11384		b[3] = 0;
11385		b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
11386				      I915_GEM_DOMAIN_RENDER << 16 |
11387				      I915_GEM_DOMAIN_RENDER |
11388				      KGEM_RELOC_FENCED,
11389				      0);
11390		b[5] = gc->bgPixel;
11391		b[6] = gc->fgPixel;
11392		b[7] = pat[0];
11393		b[8] = pat[1];
11394		sna->kgem.nbatch += 9;
11395
11396		if (clip.data == NULL) {
11397			do {
11398				BoxRec box;
11399
11400				box.x1 = r->x + drawable->x;
11401				box.y1 = r->y + drawable->y;
11402				box.x2 = bound(box.x1, r->width);
11403				box.y2 = bound(box.y1, r->height);
11404				r++;
11405
11406				if (box_intersect(&box, &clip.extents)) {
11407					if (!kgem_check_batch(&sna->kgem, 3)) {
11408						_kgem_submit(&sna->kgem);
11409						_kgem_set_mode(&sna->kgem, KGEM_BLT);
11410
11411						b = sna->kgem.batch + sna->kgem.nbatch;
11412						b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20;
11413						b[1] = br13;
11414						b[2] = 0;
11415						b[3] = 0;
11416						b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
11417								      I915_GEM_DOMAIN_RENDER << 16 |
11418								      I915_GEM_DOMAIN_RENDER |
11419								      KGEM_RELOC_FENCED,
11420								      0);
11421						b[5] = gc->bgPixel;
11422						b[6] = gc->fgPixel;
11423						b[7] = pat[0];
11424						b[8] = pat[1];
11425						sna->kgem.nbatch += 9;
11426					}
11427
11428					b = sna->kgem.batch + sna->kgem.nbatch;
11429					sna->kgem.nbatch += 3;
11430					b[0] = br00;
11431					b[1] = (box.y1 + dy) << 16 | (box.x1 + dx);
11432					b[2] = (box.y2 + dy) << 16 | (box.x2 + dx);
11433				}
11434			} while (--n);
11435		} else {
11436			const BoxRec * const clip_start = RegionBoxptr(&clip);
11437			const BoxRec * const clip_end = clip_start + clip.data->numRects;
11438			const BoxRec *c;
11439
11440			do {
11441				BoxRec box;
11442
11443				box.x1 = r->x + drawable->x;
11444				box.y1 = r->y + drawable->y;
11445				box.x2 = bound(box.x1, r->width);
11446				box.y2 = bound(box.y1, r->height);
11447				r++;
11448
11449				c = find_clip_box_for_y(clip_start,
11450							clip_end,
11451							box.y1);
11452				while (c != clip_end) {
11453					BoxRec bb;
11454					if (box.y2 <= c->y1)
11455						break;
11456
11457					bb = box;
11458					if (box_intersect(&bb, c++)) {
11459						if (!kgem_check_batch(&sna->kgem, 3)) {
11460							_kgem_submit(&sna->kgem);
11461							_kgem_set_mode(&sna->kgem, KGEM_BLT);
11462
11463							b = sna->kgem.batch + sna->kgem.nbatch;
11464							b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20;
11465							b[1] = br13;
11466							b[2] = 0;
11467							b[3] = 0;
11468							b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
11469									      I915_GEM_DOMAIN_RENDER << 16 |
11470									      I915_GEM_DOMAIN_RENDER |
11471									      KGEM_RELOC_FENCED,
11472									      0);
11473							b[5] = gc->bgPixel;
11474							b[6] = gc->fgPixel;
11475							b[7] = pat[0];
11476							b[8] = pat[1];
11477							sna->kgem.nbatch += 9;
11478						}
11479
11480						b = sna->kgem.batch + sna->kgem.nbatch;
11481						sna->kgem.nbatch += 3;
11482						b[0] = br00;
11483						b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx);
11484						b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx);
11485					}
11486				}
11487			} while (--n);
11488		}
11489	}
11490
11491	assert_pixmap_damage(pixmap);
11492	sna->blt_state.fill_bo = 0;
11493	return true;
11494}
11495
11496static bool
11497sna_poly_fill_rect_stippled_nxm_blt(DrawablePtr drawable,
11498				    struct kgem_bo *bo,
11499				    struct sna_damage **damage,
11500				    GCPtr gc, int n, xRectangle *r,
11501				    const BoxRec *extents, unsigned clipped)
11502{
11503	PixmapPtr scratch, stipple;
11504	uint8_t bytes[8], *dst = bytes;
11505	const uint8_t *src, *end;
11506	int j, stride;
11507	bool ret;
11508
11509	DBG(("%s: expanding %dx%d stipple to 8x8\n",
11510	     __FUNCTION__,
11511	     gc->stipple->drawable.width,
11512	     gc->stipple->drawable.height));
11513
11514	scratch = GetScratchPixmapHeader(drawable->pScreen,
11515					 8, 8, 1, 1, 1, bytes);
11516	if (scratch == NullPixmap)
11517		return false;
11518
11519	stipple = gc->stipple;
11520	gc->stipple = scratch;
11521
11522	stride = stipple->devKind;
11523	src = stipple->devPrivate.ptr;
11524	end = src + stride * stipple->drawable.height;
11525	for(j = 0; j < 8; j++) {
11526		switch (stipple->drawable.width) {
11527		case 1: *dst = (*src & 1) * 0xff; break;
11528		case 2: *dst = (*src & 3) * 0x55; break;
11529		case 4: *dst = (*src & 15) * 0x11; break;
11530		case 8: *dst = *src; break;
11531		default: assert(0); break;
11532		}
11533		dst++;
11534		src += stride;
11535		if (src == end)
11536			src = stipple->devPrivate.ptr;
11537	}
11538
11539	ret = sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage,
11540						  gc, n, r, extents, clipped);
11541
11542	gc->stipple = stipple;
11543	FreeScratchPixmapHeader(scratch);
11544
11545	return ret;
11546}
11547
11548static bool
11549sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
11550				  struct kgem_bo *bo,
11551				  struct sna_damage **damage,
11552				  GCPtr gc, int n, xRectangle *r,
11553				  const BoxRec *extents, unsigned clipped)
11554{
11555	PixmapPtr pixmap = get_drawable_pixmap(drawable);
11556	struct sna *sna = to_sna_from_pixmap(pixmap);
11557	PixmapPtr stipple = gc->stipple;
11558	const DDXPointRec *origin = &gc->patOrg;
11559	int16_t dx, dy;
11560	uint32_t br00, br13;
11561
11562	DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%x\n", __FUNCTION__,
11563	     extents->x1, extents->y1,
11564	     extents->x2, extents->y2,
11565	     origin->x, origin->y,
11566	     clipped));
11567
11568	get_drawable_deltas(drawable, pixmap, &dx, &dy);
11569	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
11570
11571	br00 = 3 << 20;
11572	br13 = bo->pitch;
11573	if (sna->kgem.gen >= 040 && bo->tiling) {
11574		br00 |= BLT_DST_TILED;
11575		br13 >>= 2;
11576	}
11577	br13 |= (gc->fillStyle == FillStippled) << 29;
11578	br13 |= blt_depth(drawable->depth) << 24;
11579	br13 |= copy_ROP[gc->alu] << 16;
11580
11581	if (!clipped) {
11582		dx += drawable->x;
11583		dy += drawable->y;
11584
11585		sna_damage_add_rectangles(damage, r, n, dx, dy);
11586		do {
11587			int bx1 = (r->x - origin->x) & ~7;
11588			int bx2 = (r->x + r->width - origin->x + 7) & ~7;
11589			int bw = (bx2 - bx1)/8;
11590			int bh = r->height;
11591			int bstride = ALIGN(bw, 2);
11592			int src_stride;
11593			uint8_t *dst, *src;
11594			uint32_t *b;
11595
11596			DBG(("%s: rect (%d, %d)x(%d, %d) stipple [%d,%d]\n",
11597			     __FUNCTION__,
11598			     r->x, r->y, r->width, r->height,
11599			     bx1, bx2));
11600
11601			src_stride = bstride*bh;
11602			if (src_stride <= 128) {
11603				src_stride = ALIGN(src_stride, 8) / 4;
11604				assert(src_stride <= 32);
11605				if (!kgem_check_batch(&sna->kgem, 7+src_stride) ||
11606				    !kgem_check_bo_fenced(&sna->kgem, bo) ||
11607				    !kgem_check_reloc(&sna->kgem, 1)) {
11608					kgem_submit(&sna->kgem);
11609					if (!kgem_check_bo_fenced(&sna->kgem, bo))
11610						return false;
11611					_kgem_set_mode(&sna->kgem, KGEM_BLT);
11612				}
11613
11614				b = sna->kgem.batch + sna->kgem.nbatch;
11615				b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
11616				b[0] |= ((r->x - origin->x) & 7) << 17;
11617				b[1] = br13;
11618				b[2] = (r->y + dy) << 16 | (r->x + dx);
11619				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
11620				b[4] = kgem_add_reloc(&sna->kgem,
11621						      sna->kgem.nbatch + 4, bo,
11622						      I915_GEM_DOMAIN_RENDER << 16 |
11623						      I915_GEM_DOMAIN_RENDER |
11624						      KGEM_RELOC_FENCED,
11625						      0);
11626				b[5] = gc->bgPixel;
11627				b[6] = gc->fgPixel;
11628
11629				sna->kgem.nbatch += 7 + src_stride;
11630
11631				dst = (uint8_t *)&b[7];
11632				src_stride = stipple->devKind;
11633				src = stipple->devPrivate.ptr;
11634				src += (r->y - origin->y) * src_stride + bx1/8;
11635				src_stride -= bstride;
11636				do {
11637					int i = bstride;
11638					do {
11639						*dst++ = byte_reverse(*src++);
11640						*dst++ = byte_reverse(*src++);
11641						i -= 2;
11642					} while (i);
11643					src += src_stride;
11644				} while (--bh);
11645			} else {
11646				struct kgem_bo *upload;
11647				void *ptr;
11648
11649				if (!kgem_check_batch(&sna->kgem, 8) ||
11650				    !kgem_check_bo_fenced(&sna->kgem, bo) ||
11651				    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
11652					kgem_submit(&sna->kgem);
11653					if (!kgem_check_bo_fenced(&sna->kgem, bo))
11654						return false;
11655					_kgem_set_mode(&sna->kgem, KGEM_BLT);
11656				}
11657
11658				upload = kgem_create_buffer(&sna->kgem,
11659							    bstride*bh,
11660							    KGEM_BUFFER_WRITE_INPLACE,
11661							    &ptr);
11662				if (!upload)
11663					break;
11664
11665				dst = ptr;
11666				src_stride = stipple->devKind;
11667				src = stipple->devPrivate.ptr;
11668				src += (r->y - origin->y) * src_stride + bx1/8;
11669				src_stride -= bstride;
11670				do {
11671					int i = bstride;
11672					do {
11673						*dst++ = byte_reverse(*src++);
11674						*dst++ = byte_reverse(*src++);
11675						i -= 2;
11676					} while (i);
11677					src += src_stride;
11678				} while (--bh);
11679				b = sna->kgem.batch + sna->kgem.nbatch;
11680				b[0] = XY_MONO_SRC_COPY | br00;
11681				b[0] |= ((r->x - origin->x) & 7) << 17;
11682				b[1] = br13;
11683				b[2] = (r->y + dy) << 16 | (r->x + dx);
11684				b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx);
11685				b[4] = kgem_add_reloc(&sna->kgem,
11686						      sna->kgem.nbatch + 4, bo,
11687						      I915_GEM_DOMAIN_RENDER << 16 |
11688						      I915_GEM_DOMAIN_RENDER |
11689						      KGEM_RELOC_FENCED,
11690						      0);
11691				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5,
11692						      upload,
11693						      I915_GEM_DOMAIN_RENDER << 16 |
11694						      KGEM_RELOC_FENCED,
11695						      0);
11696				b[6] = gc->bgPixel;
11697				b[7] = gc->fgPixel;
11698
11699				sna->kgem.nbatch += 8;
11700				kgem_bo_destroy(&sna->kgem, upload);
11701			}
11702
11703			r++;
11704		} while (--n);
11705	} else {
11706		RegionRec clip;
11707		DDXPointRec pat;
11708
11709		region_set(&clip, extents);
11710		region_maybe_clip(&clip, gc->pCompositeClip);
11711		if (RegionNil(&clip))
11712			return true;
11713
11714		pat.x = origin->x + drawable->x;
11715		pat.y = origin->y + drawable->y;
11716
11717		if (clip.data == NULL) {
11718			do {
11719				BoxRec box;
11720				int bx1, bx2, bw, bh, bstride;
11721				int src_stride;
11722				uint8_t *dst, *src;
11723				uint32_t *b;
11724				struct kgem_bo *upload;
11725				void *ptr;
11726
11727				box.x1 = r->x + drawable->x;
11728				box.x2 = bound(box.x1, r->width);
11729				box.y1 = r->y + drawable->y;
11730				box.y2 = bound(box.y1, r->height);
11731				r++;
11732
11733				if (!box_intersect(&box, &clip.extents))
11734					continue;
11735
11736				bx1 = (box.x1 - pat.x) & ~7;
11737				bx2 = (box.x2 - pat.x + 7) & ~7;
11738				bw = (bx2 - bx1)/8;
11739				bh = box.y2 - box.y1;
11740				bstride = ALIGN(bw, 2);
11741
11742				DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d], pitch=%d, stride=%d\n",
11743				     __FUNCTION__,
11744				     r->x, r->y, r->width, r->height,
11745				     box.x1, box.y1, box.x2, box.y2,
11746				     bx1, bx2, bw, bstride));
11747
11748				src_stride = bstride*bh;
11749				if (src_stride <= 128) {
11750					src_stride = ALIGN(src_stride, 8) / 4;
11751					assert(src_stride <= 32);
11752					if (!kgem_check_batch(&sna->kgem, 7+src_stride) ||
11753					    !kgem_check_bo_fenced(&sna->kgem, bo) ||
11754					    !kgem_check_reloc(&sna->kgem, 1)) {
11755						kgem_submit(&sna->kgem);
11756						if (!kgem_check_bo_fenced(&sna->kgem, bo))
11757							return false;
11758						_kgem_set_mode(&sna->kgem, KGEM_BLT);
11759					}
11760
11761					b = sna->kgem.batch + sna->kgem.nbatch;
11762					b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
11763					b[0] |= ((box.x1 - pat.x) & 7) << 17;
11764					b[1] = br13;
11765					b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
11766					b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
11767					b[4] = kgem_add_reloc(&sna->kgem,
11768							      sna->kgem.nbatch + 4, bo,
11769							      I915_GEM_DOMAIN_RENDER << 16 |
11770							      I915_GEM_DOMAIN_RENDER |
11771							      KGEM_RELOC_FENCED,
11772							      0);
11773					b[5] = gc->bgPixel;
11774					b[6] = gc->fgPixel;
11775
11776					sna->kgem.nbatch += 7 + src_stride;
11777
11778					dst = (uint8_t *)&b[7];
11779					src_stride = stipple->devKind;
11780					src = stipple->devPrivate.ptr;
11781					src += (box.y1 - pat.y) * src_stride + bx1/8;
11782					src_stride -= bstride;
11783					do {
11784						int i = bstride;
11785						do {
11786							*dst++ = byte_reverse(*src++);
11787							*dst++ = byte_reverse(*src++);
11788							i -= 2;
11789						} while (i);
11790						src += src_stride;
11791					} while (--bh);
11792				} else {
11793					if (!kgem_check_batch(&sna->kgem, 8) ||
11794					    !kgem_check_bo_fenced(&sna->kgem, bo) ||
11795					    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
11796						kgem_submit(&sna->kgem);
11797						if (!kgem_check_bo_fenced(&sna->kgem, bo))
11798							return false;
11799						_kgem_set_mode(&sna->kgem, KGEM_BLT);
11800					}
11801
11802					upload = kgem_create_buffer(&sna->kgem,
11803								    bstride*bh,
11804								    KGEM_BUFFER_WRITE_INPLACE,
11805								    &ptr);
11806					if (!upload)
11807						break;
11808
11809					dst = ptr;
11810					src_stride = stipple->devKind;
11811					src = stipple->devPrivate.ptr;
11812					src += (box.y1 - pat.y) * src_stride + bx1/8;
11813					src_stride -= bstride;
11814					do {
11815						int i = bstride;
11816						do {
11817							*dst++ = byte_reverse(*src++);
11818							*dst++ = byte_reverse(*src++);
11819							i -= 2;
11820						} while (i);
11821						src += src_stride;
11822					} while (--bh);
11823
11824					b = sna->kgem.batch + sna->kgem.nbatch;
11825					b[0] = XY_MONO_SRC_COPY | br00;
11826					b[0] |= ((box.x1 - pat.x) & 7) << 17;
11827					b[1] = br13;
11828					b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
11829					b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
11830					b[4] = kgem_add_reloc(&sna->kgem,
11831							      sna->kgem.nbatch + 4, bo,
11832							      I915_GEM_DOMAIN_RENDER << 16 |
11833							      I915_GEM_DOMAIN_RENDER |
11834							      KGEM_RELOC_FENCED,
11835							      0);
11836					b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5,
11837							      upload,
11838							      I915_GEM_DOMAIN_RENDER << 16 |
11839							      KGEM_RELOC_FENCED,
11840							      0);
11841					b[6] = gc->bgPixel;
11842					b[7] = gc->fgPixel;
11843
11844					sna->kgem.nbatch += 8;
11845					kgem_bo_destroy(&sna->kgem, upload);
11846				}
11847			} while (--n);
11848		} else {
11849			const BoxRec * const clip_start = RegionBoxptr(&clip);
11850			const BoxRec * const clip_end = clip_start + clip.data->numRects;
11851			const BoxRec *c;
11852
11853			do {
11854				BoxRec unclipped;
11855				int bx1, bx2, bw, bh, bstride;
11856				int src_stride;
11857				uint8_t *dst, *src;
11858				uint32_t *b;
11859				struct kgem_bo *upload;
11860				void *ptr;
11861
11862				unclipped.x1 = r->x + drawable->x;
11863				unclipped.x2 = bound(unclipped.x2, r->width);
11864				unclipped.y1 = r->y + drawable->y;
11865				unclipped.y2 = bound(unclipped.y2, r->height);
11866				r++;
11867
11868				c = find_clip_box_for_y(clip_start,
11869							clip_end,
11870							unclipped.y1);
11871				while (c != clip_end) {
11872					BoxRec box;
11873
11874					if (unclipped.y2 <= c->y1)
11875						break;
11876
11877					box = unclipped;
11878					if (!box_intersect(&box, c++))
11879						continue;
11880
11881					bx1 = (box.x1 - pat.x) & ~7;
11882					bx2 = (box.x2 - pat.x + 7) & ~7;
11883					bw = (bx2 - bx1)/8;
11884					bh = box.y2 - box.y1;
11885					bstride = ALIGN(bw, 2);
11886
11887					DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d]\n",
11888					     __FUNCTION__,
11889					     r->x, r->y, r->width, r->height,
11890					     box.x1, box.y1, box.x2, box.y2,
11891					     bx1, bx2));
11892
11893					src_stride = bstride*bh;
11894					if (src_stride <= 128) {
11895						src_stride = ALIGN(src_stride, 8) / 4;
11896						assert(src_stride <= 32);
11897						if (!kgem_check_batch(&sna->kgem, 7+src_stride) ||
11898						    !kgem_check_bo_fenced(&sna->kgem, bo) ||
11899						    !kgem_check_reloc(&sna->kgem, 1)) {
11900							kgem_submit(&sna->kgem);
11901							if (!kgem_check_bo_fenced(&sna->kgem, bo))
11902								return false;
11903							_kgem_set_mode(&sna->kgem, KGEM_BLT);
11904						}
11905
11906						b = sna->kgem.batch + sna->kgem.nbatch;
11907						b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00;
11908						b[0] |= ((box.x1 - pat.x) & 7) << 17;
11909						b[1] = br13;
11910						b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
11911						b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
11912						b[4] = kgem_add_reloc(&sna->kgem,
11913								      sna->kgem.nbatch + 4, bo,
11914								      I915_GEM_DOMAIN_RENDER << 16 |
11915								      I915_GEM_DOMAIN_RENDER |
11916								      KGEM_RELOC_FENCED,
11917								      0);
11918						b[5] = gc->bgPixel;
11919						b[6] = gc->fgPixel;
11920
11921						sna->kgem.nbatch += 7 + src_stride;
11922
11923						dst = (uint8_t *)&b[7];
11924						src_stride = stipple->devKind;
11925						src = stipple->devPrivate.ptr;
11926						src += (box.y1 - pat.y) * src_stride + bx1/8;
11927						src_stride -= bstride;
11928						do {
11929							int i = bstride;
11930							do {
11931								*dst++ = byte_reverse(*src++);
11932								*dst++ = byte_reverse(*src++);
11933								i -= 2;
11934							} while (i);
11935							src += src_stride;
11936						} while (--bh);
11937					} else {
11938						if (!kgem_check_batch(&sna->kgem, 8) ||
11939						    !kgem_check_bo_fenced(&sna->kgem, bo) ||
11940						    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
11941							kgem_submit(&sna->kgem);
11942							if (!kgem_check_bo_fenced(&sna->kgem, bo))
11943								return false;
11944							_kgem_set_mode(&sna->kgem, KGEM_BLT);
11945						}
11946
11947						upload = kgem_create_buffer(&sna->kgem,
11948									    bstride*bh,
11949									    KGEM_BUFFER_WRITE_INPLACE,
11950									    &ptr);
11951						if (!upload)
11952							break;
11953
11954						dst = ptr;
11955						src_stride = stipple->devKind;
11956						src = stipple->devPrivate.ptr;
11957						src += (box.y1 - pat.y) * src_stride + bx1/8;
11958						src_stride -= bstride;
11959						do {
11960							int i = bstride;
11961							do {
11962								*dst++ = byte_reverse(*src++);
11963								*dst++ = byte_reverse(*src++);
11964								i -= 2;
11965							} while (i);
11966							src += src_stride;
11967						} while (--bh);
11968
11969						b = sna->kgem.batch + sna->kgem.nbatch;
11970						b[0] = XY_MONO_SRC_COPY | br00;
11971						b[0] |= ((box.x1 - pat.x) & 7) << 17;
11972						b[1] = br13;
11973						b[2] = (box.y1 + dy) << 16 | (box.x1 + dx);
11974						b[3] = (box.y2 + dy) << 16 | (box.x2 + dx);
11975						b[4] = kgem_add_reloc(&sna->kgem,
11976								      sna->kgem.nbatch + 4, bo,
11977								      I915_GEM_DOMAIN_RENDER << 16 |
11978								      I915_GEM_DOMAIN_RENDER |
11979								      KGEM_RELOC_FENCED,
11980								      0);
11981						b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5,
11982								      upload,
11983								      I915_GEM_DOMAIN_RENDER << 16 |
11984								      KGEM_RELOC_FENCED,
11985								      0);
11986						b[6] = gc->bgPixel;
11987						b[7] = gc->fgPixel;
11988
11989						sna->kgem.nbatch += 8;
11990						kgem_bo_destroy(&sna->kgem, upload);
11991					}
11992				}
11993			} while (--n);
11994
11995		}
11996	}
11997
11998	sna->blt_state.fill_bo = 0;
11999	return true;
12000}
12001
12002static void
12003sna_poly_fill_rect_stippled_n_box__imm(struct sna *sna,
12004				       struct kgem_bo *bo,
12005				       uint32_t br00, uint32_t br13,
12006				       const GC *gc,
12007				       const BoxRec *box,
12008				       const DDXPointRec *origin)
12009{
12010	int x1, x2, y1, y2;
12011	uint32_t *b;
12012
12013	for (y1 = box->y1; y1 < box->y2; y1 = y2) {
12014		int oy = (y1 - origin->y) % gc->stipple->drawable.height;
12015		if (oy < 0)
12016			oy += gc->stipple->drawable.height;
12017
12018		y2 = box->y2;
12019		if (y2 - y1 > gc->stipple->drawable.height - oy)
12020			y2 = y1 + gc->stipple->drawable.height - oy;
12021
12022		for (x1 = box->x1; x1 < box->x2; x1 = x2) {
12023			int bx1, bx2, bw, bh, len, ox;
12024			uint8_t *dst, *src;
12025
12026			x2 = box->x2;
12027			ox = (x1 - origin->x) % gc->stipple->drawable.width;
12028			if (ox < 0)
12029				ox += gc->stipple->drawable.width;
12030			bx1 = ox & ~7;
12031			bx2 = ox + (x2 - x1);
12032			if (bx2 > gc->stipple->drawable.width) {
12033				bx2 = gc->stipple->drawable.width;
12034				x2 = x1 + bx2-ox;
12035			}
12036			bw = (bx2 - bx1 + 7)/8;
12037			bw = ALIGN(bw, 2);
12038			bh = y2 - y1;
12039
12040			DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d\n",
12041			     __FUNCTION__,
12042			     x1, y1, x2-x1, y2-y1,
12043			     origin->x, origin->y,
12044			     ox, oy, bx1, bx2,
12045			     gc->stipple->drawable.width,
12046			     gc->stipple->drawable.height));
12047
12048			len = bw*bh;
12049			len = ALIGN(len, 8) / 4;
12050			assert(len <= 32);
12051			if (!kgem_check_batch(&sna->kgem, 7+len) ||
12052			    !kgem_check_bo_fenced(&sna->kgem, bo) ||
12053			    !kgem_check_reloc(&sna->kgem, 1)) {
12054				kgem_submit(&sna->kgem);
12055				if (!kgem_check_bo_fenced(&sna->kgem, bo))
12056					return; /* XXX fallback? */
12057				_kgem_set_mode(&sna->kgem, KGEM_BLT);
12058			}
12059
12060			b = sna->kgem.batch + sna->kgem.nbatch;
12061			b[0] = br00 | (5 + len) | (ox & 7) << 17;
12062			b[1] = br13;
12063			b[2] = y1 << 16 | x1;
12064			b[3] = y2 << 16 | x2;
12065			b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4,
12066					      bo,
12067					      I915_GEM_DOMAIN_RENDER << 16 |
12068					      I915_GEM_DOMAIN_RENDER |
12069					      KGEM_RELOC_FENCED,
12070					      0);
12071			b[5] = gc->bgPixel;
12072			b[6] = gc->fgPixel;
12073
12074			sna->kgem.nbatch += 7 + len;
12075
12076			dst = (uint8_t *)&b[7];
12077			len = gc->stipple->devKind;
12078			src = gc->stipple->devPrivate.ptr;
12079			src += oy*len + ox/8;
12080			len -= bw;
12081			do {
12082				int i = bw;
12083				do {
12084					*dst++ = byte_reverse(*src++);
12085					*dst++ = byte_reverse(*src++);
12086					i -= 2;
12087				} while (i);
12088				src += len;
12089			} while (--bh);
12090		}
12091	}
12092}
12093
12094static void
12095sna_poly_fill_rect_stippled_n_box(struct sna *sna,
12096				  struct kgem_bo *bo,
12097				  struct kgem_bo **tile,
12098				  uint32_t br00, uint32_t br13,
12099				  const GC *gc,
12100				  const BoxRec *box,
12101				  const DDXPointRec *origin)
12102{
12103	int x1, x2, y1, y2;
12104	int w = gc->stipple->drawable.width;
12105	int h = gc->stipple->drawable.height;
12106	int stride = gc->stipple->devKind;
12107	uint32_t *b;
12108
12109	if ((((box->y2-box->y1) | (box->x2-box->x1)) & ~31) == 0) {
12110		br00 = XY_MONO_SRC_COPY_IMM |(br00 & (BLT_DST_TILED | 3 << 20));
12111		sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
12112						       br00, br13, gc,
12113						       box, origin);
12114		return;
12115	}
12116
12117	for (y1 = box->y1; y1 < box->y2; y1 = y2) {
12118		int row, oy = (y1 - origin->y) % gc->stipple->drawable.height;
12119		if (oy < 0)
12120			oy += h;
12121
12122		y2 = box->y2;
12123		if (y2 - y1 > h - oy)
12124			y2 = y1 + h - oy;
12125
12126		row = oy * stride;
12127		for (x1 = box->x1; x1 < box->x2; x1 = x2) {
12128			int bx1, bx2, bw, bh, len, ox;
12129			bool use_tile;
12130
12131			x2 = box->x2;
12132			ox = (x1 - origin->x) % w;
12133			if (ox < 0)
12134				ox += w;
12135			bx1 = ox & ~7;
12136			bx2 = ox + (x2 - x1);
12137			if (bx2 > w) {
12138				bx2 = w;
12139				x2 = x1 + bx2-ox;
12140			}
12141
12142			use_tile = y2-y1 == h && x2-x1 == w;
12143
12144			DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d, full tile?=%d\n",
12145			     __FUNCTION__,
12146			     x1, y1, x2-x1, y2-y1,
12147			     origin->x, origin->y,
12148			     ox, oy, bx1, bx2, w, h,
12149			     use_tile));
12150
12151			bw = (bx2 - bx1 + 7)/8;
12152			bw = ALIGN(bw, 2);
12153			bh = y2 - y1;
12154
12155			len = bw*bh;
12156			len = ALIGN(len, 8) / 4;
12157			if (!kgem_check_batch(&sna->kgem, 7+len) ||
12158			    !kgem_check_bo_fenced(&sna->kgem, bo) ||
12159			    !kgem_check_reloc(&sna->kgem, 2)) {
12160				kgem_submit(&sna->kgem);
12161				if (!kgem_check_bo_fenced(&sna->kgem, bo))
12162					return; /* XXX fallback? */
12163				_kgem_set_mode(&sna->kgem, KGEM_BLT);
12164			}
12165
12166			b = sna->kgem.batch + sna->kgem.nbatch;
12167
12168			if (!use_tile && len <= 32) {
12169				uint8_t *dst, *src;
12170
12171				b[0] = XY_MONO_SRC_COPY_IMM;
12172				b[0] |= (br00 & (BLT_DST_TILED | 3 << 20));
12173				b[0] |= (ox & 7) << 17;
12174				b[0] |= (5 + len);
12175				b[1] = br13;
12176				b[2] = y1 << 16 | x1;
12177				b[3] = y2 << 16 | x2;
12178				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4,
12179						      bo,
12180						      I915_GEM_DOMAIN_RENDER << 16 |
12181						      I915_GEM_DOMAIN_RENDER |
12182						      KGEM_RELOC_FENCED,
12183						      0);
12184				b[5] = gc->bgPixel;
12185				b[6] = gc->fgPixel;
12186
12187				sna->kgem.nbatch += 7 + len;
12188
12189				dst = (uint8_t *)&b[7];
12190				len = gc->stipple->devKind;
12191				src = gc->stipple->devPrivate.ptr;
12192				src += oy*len + ox/8;
12193				len -= bw;
12194				do {
12195					int i = bw;
12196					do {
12197						*dst++ = byte_reverse(*src++);
12198						*dst++ = byte_reverse(*src++);
12199						i -= 2;
12200					} while (i);
12201					src += len;
12202				} while (--bh);
12203			} else {
12204				bool has_tile = use_tile && *tile;
12205				struct kgem_bo *upload;
12206				uint8_t *dst, *src;
12207				void *ptr;
12208
12209				if (has_tile) {
12210					upload = kgem_bo_reference(*tile);
12211				} else {
12212					upload = kgem_create_buffer(&sna->kgem, bw*bh,
12213								    KGEM_BUFFER_WRITE_INPLACE,
12214								    &ptr);
12215					if (!upload)
12216						return;
12217				}
12218
12219				b = sna->kgem.batch + sna->kgem.nbatch;
12220				b[0] = br00 | (ox & 7) << 17;
12221				b[1] = br13;
12222				b[2] = y1 << 16 | x1;
12223				b[3] = y2 << 16 | x2;
12224				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4,
12225						      bo,
12226						      I915_GEM_DOMAIN_RENDER << 16 |
12227						      I915_GEM_DOMAIN_RENDER |
12228						      KGEM_RELOC_FENCED,
12229						      0);
12230				b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5,
12231						      upload,
12232						      I915_GEM_DOMAIN_RENDER << 16 |
12233						      KGEM_RELOC_FENCED,
12234						      0);
12235				b[6] = gc->bgPixel;
12236				b[7] = gc->fgPixel;
12237
12238				sna->kgem.nbatch += 8;
12239
12240				if (!has_tile) {
12241					dst = ptr;
12242					len = stride;
12243					src = gc->stipple->devPrivate.ptr;
12244					src += row + (ox >> 3);
12245					len -= bw;
12246					do {
12247						int i = bw;
12248						do {
12249							*dst++ = byte_reverse(*src++);
12250							*dst++ = byte_reverse(*src++);
12251							i -= 2;
12252						} while (i);
12253						src += len;
12254					} while (--bh);
12255					if (use_tile)
12256						*tile = kgem_bo_reference(upload);
12257				}
12258
12259				kgem_bo_destroy(&sna->kgem, upload);
12260			}
12261		}
12262	}
12263}
12264
12265static bool
12266sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable,
12267				       struct kgem_bo *bo,
12268				       struct sna_damage **damage,
12269				       GCPtr gc, int n, xRectangle *r,
12270				       const BoxRec *extents, unsigned clipped)
12271{
12272	PixmapPtr pixmap = get_drawable_pixmap(drawable);
12273	struct sna *sna = to_sna_from_pixmap(pixmap);
12274	DDXPointRec origin = gc->patOrg;
12275	int16_t dx, dy;
12276	uint32_t br00, br13;
12277
12278	DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__,
12279	     extents->x1, extents->y1,
12280	     extents->x2, extents->y2,
12281	     origin.x, origin.y,
12282	     clipped, gc->alu, gc->fillStyle == FillOpaqueStippled));
12283
12284	get_drawable_deltas(drawable, pixmap, &dx, &dy);
12285	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
12286
12287	br00 = XY_MONO_SRC_COPY_IMM | 3 << 20;
12288	br13 = bo->pitch;
12289	if (sna->kgem.gen >= 040 && bo->tiling) {
12290		br00 |= BLT_DST_TILED;
12291		br13 >>= 2;
12292	}
12293	br13 |= (gc->fillStyle == FillStippled) << 29;
12294	br13 |= blt_depth(drawable->depth) << 24;
12295	br13 |= copy_ROP[gc->alu] << 16;
12296
12297	origin.x += dx + drawable->x;
12298	origin.y += dy + drawable->y;
12299
12300	if (!clipped) {
12301		dx += drawable->x;
12302		dy += drawable->y;
12303
12304		sna_damage_add_rectangles(damage, r, n, dx, dy);
12305		do {
12306			BoxRec box;
12307
12308			box.x1 = r->x + dx;
12309			box.y1 = r->y + dy;
12310			box.x2 = box.x1 + r->width;
12311			box.y2 = box.y1 + r->height;
12312
12313			sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
12314							       br00, br13, gc,
12315							       &box, &origin);
12316			r++;
12317		} while (--n);
12318	} else {
12319		RegionRec clip;
12320
12321		region_set(&clip, extents);
12322		region_maybe_clip(&clip, gc->pCompositeClip);
12323		if (RegionNil(&clip)) {
12324			DBG(("%s: all clipped\n", __FUNCTION__));
12325			return true;
12326		}
12327
12328		if (clip.data == NULL) {
12329			DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n",
12330			     __FUNCTION__,
12331			     clip.extents.x1, clip.extents.y1,
12332			     clip.extents.x2, clip.extents.y2));
12333			do {
12334				BoxRec box;
12335
12336				box.x1 = r->x + drawable->x;
12337				box.x2 = bound(box.x1, r->width);
12338				box.y1 = r->y + drawable->y;
12339				box.y2 = bound(box.y1, r->height);
12340				r++;
12341
12342				DBG(("%s: box (%d, %d), (%d, %d)\n",
12343				     __FUNCTION__,
12344				     box.x1, box.y1, box.x2, box.y2));
12345				if (!box_intersect(&box, &clip.extents))
12346					continue;
12347
12348				box.x1 += dx; box.x2 += dx;
12349				box.y1 += dy; box.y2 += dy;
12350
12351				sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
12352								       br00, br13, gc,
12353								       &box, &origin);
12354			} while (--n);
12355		} else {
12356			const BoxRec * const clip_start = RegionBoxptr(&clip);
12357			const BoxRec * const clip_end = clip_start + clip.data->numRects;
12358			const BoxRec *c;
12359
12360			DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__,
12361			     clip_start->x1, clip_start->y1,
12362			     clip_start->x2, clip_start->y2,
12363			     clip_end->x1, clip_end->y1,
12364			     clip_end->x2, clip_end->y2));
12365			do {
12366				BoxRec unclipped;
12367
12368				unclipped.x1 = r->x + drawable->x;
12369				unclipped.x2 = bound(unclipped.x1, r->width);
12370				unclipped.y1 = r->y + drawable->y;
12371				unclipped.y2 = bound(unclipped.y1, r->height);
12372				r++;
12373
12374				c = find_clip_box_for_y(clip_start,
12375							clip_end,
12376							unclipped.y1);
12377				while (c != clip_end) {
12378					BoxRec box;
12379
12380					if (unclipped.y2 <= c->y1)
12381						break;
12382
12383					box = unclipped;
12384					if (!box_intersect(&box, c++))
12385						continue;
12386
12387					box.x1 += dx; box.x2 += dx;
12388					box.y1 += dy; box.y2 += dy;
12389
12390					sna_poly_fill_rect_stippled_n_box__imm(sna, bo,
12391									       br00, br13, gc,
12392									       &box, &origin);
12393				}
12394			} while (--n);
12395		}
12396	}
12397
12398	assert_pixmap_damage(pixmap);
12399	sna->blt_state.fill_bo = 0;
12400	return true;
12401}
12402
12403static bool
12404sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable,
12405				  struct kgem_bo *bo,
12406				  struct sna_damage **damage,
12407				  GCPtr gc, int n, xRectangle *r,
12408				  const BoxRec *extents, unsigned clipped)
12409{
12410	PixmapPtr pixmap = get_drawable_pixmap(drawable);
12411	struct sna *sna = to_sna_from_pixmap(pixmap);
12412	DDXPointRec origin = gc->patOrg;
12413	struct kgem_bo *tile = NULL;
12414	int16_t dx, dy;
12415	uint32_t br00, br13;
12416
12417	DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__,
12418	     extents->x1, extents->y1,
12419	     extents->x2, extents->y2,
12420	     origin.x, origin.y,
12421	     clipped, gc->alu, gc->fillStyle == FillOpaqueStippled));
12422
12423	if (((gc->stipple->drawable.width | gc->stipple->drawable.height) & ~31) == 0)
12424		return sna_poly_fill_rect_stippled_n_blt__imm(drawable,
12425							      bo, damage,
12426							      gc, n, r,
12427							      extents, clipped);
12428
12429	get_drawable_deltas(drawable, pixmap, &dx, &dy);
12430	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
12431
12432	br00 = XY_MONO_SRC_COPY | 3 << 20;
12433	br13 = bo->pitch;
12434	if (sna->kgem.gen >= 040 && bo->tiling) {
12435		br00 |= BLT_DST_TILED;
12436		br13 >>= 2;
12437	}
12438	br13 |= (gc->fillStyle == FillStippled) << 29;
12439	br13 |= blt_depth(drawable->depth) << 24;
12440	br13 |= copy_ROP[gc->alu] << 16;
12441
12442	origin.x += dx + drawable->x;
12443	origin.y += dy + drawable->y;
12444
12445	if (!clipped) {
12446		dx += drawable->x;
12447		dy += drawable->y;
12448
12449		sna_damage_add_rectangles(damage, r, n, dx, dy);
12450		do {
12451			BoxRec box;
12452
12453			box.x1 = r->x + dx;
12454			box.y1 = r->y + dy;
12455			box.x2 = box.x1 + r->width;
12456			box.y2 = box.y1 + r->height;
12457
12458			sna_poly_fill_rect_stippled_n_box(sna, bo, &tile,
12459							  br00, br13, gc,
12460							  &box, &origin);
12461			r++;
12462		} while (--n);
12463	} else {
12464		RegionRec clip;
12465
12466		region_set(&clip, extents);
12467		region_maybe_clip(&clip, gc->pCompositeClip);
12468		if (RegionNil(&clip)) {
12469			DBG(("%s: all clipped\n", __FUNCTION__));
12470			return true;
12471		}
12472
12473		if (clip.data == NULL) {
12474			DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n",
12475			     __FUNCTION__,
12476			     clip.extents.x1, clip.extents.y1,
12477			     clip.extents.x2, clip.extents.y2));
12478			do {
12479				BoxRec box;
12480
12481				box.x1 = r->x + drawable->x;
12482				box.x2 = bound(box.x1, r->width);
12483				box.y1 = r->y + drawable->y;
12484				box.y2 = bound(box.y1, r->height);
12485				r++;
12486
12487				DBG(("%s: box (%d, %d), (%d, %d)\n",
12488				     __FUNCTION__,
12489				     box.x1, box.y1, box.x2, box.y2));
12490				if (!box_intersect(&box, &clip.extents))
12491					continue;
12492
12493				box.x1 += dx; box.x2 += dx;
12494				box.y1 += dy; box.y2 += dy;
12495
12496				sna_poly_fill_rect_stippled_n_box(sna, bo, &tile,
12497								  br00, br13, gc,
12498								  &box, &origin);
12499			} while (--n);
12500		} else {
12501			const BoxRec * const clip_start = RegionBoxptr(&clip);
12502			const BoxRec * const clip_end = clip_start + clip.data->numRects;
12503			const BoxRec *c;
12504
12505			DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__,
12506			     clip_start->x1, clip_start->y1,
12507			     clip_start->x2, clip_start->y2,
12508			     clip_end->x1, clip_end->y1,
12509			     clip_end->x2, clip_end->y2));
12510			do {
12511				BoxRec unclipped;
12512
12513				unclipped.x1 = r->x + drawable->x;
12514				unclipped.x2 = bound(unclipped.x1, r->width);
12515				unclipped.y1 = r->y + drawable->y;
12516				unclipped.y2 = bound(unclipped.y1, r->height);
12517				r++;
12518
12519				c = find_clip_box_for_y(clip_start,
12520							clip_end,
12521							unclipped.y1);
12522				while (c != clip_end) {
12523					BoxRec box;
12524
12525					if (unclipped.y2 <= c->y1)
12526						break;
12527
12528					box = unclipped;
12529					if (!box_intersect(&box, c++))
12530						continue;
12531
12532					box.x1 += dx; box.x2 += dx;
12533					box.y1 += dy; box.y2 += dy;
12534
12535					sna_poly_fill_rect_stippled_n_box(sna, bo, &tile,
12536									  br00, br13, gc,
12537									  &box, &origin);
12538				}
12539			} while (--n);
12540		}
12541	}
12542
12543	assert_pixmap_damage(pixmap);
12544	if (tile)
12545		kgem_bo_destroy(&sna->kgem, tile);
12546	sna->blt_state.fill_bo = 0;
12547	return true;
12548}
12549
12550static bool
12551sna_poly_fill_rect_stippled_blt(DrawablePtr drawable,
12552				struct kgem_bo *bo,
12553				struct sna_damage **damage,
12554				GCPtr gc, int n, xRectangle *rect,
12555				const BoxRec *extents, unsigned clipped)
12556{
12557
12558	PixmapPtr stipple = gc->stipple;
12559
12560	if (bo->tiling == I915_TILING_Y) {
12561		PixmapPtr pixmap = get_drawable_pixmap(drawable);
12562
12563		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
12564		/* This is cheating, but only the gpu_bo can be tiled */
12565		assert(bo == __sna_pixmap_get_bo(pixmap));
12566		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
12567		if (bo == NULL) {
12568			DBG(("%s: fallback -- unable to change tiling\n",
12569			     __FUNCTION__));
12570			return false;
12571		}
12572	}
12573
12574	if (!sna_drawable_move_to_cpu(&stipple->drawable, MOVE_READ))
12575		return false;
12576
12577	DBG(("%s: origin (%d, %d), extents (stipple): (%d, %d), stipple size %dx%d\n",
12578	     __FUNCTION__, gc->patOrg.x, gc->patOrg.y,
12579	     extents->x2 - gc->patOrg.x - drawable->x,
12580	     extents->y2 - gc->patOrg.y - drawable->y,
12581	     stipple->drawable.width, stipple->drawable.height));
12582
12583	if ((stipple->drawable.width | stipple->drawable.height) == 8)
12584		return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage,
12585							   gc, n, rect,
12586							   extents, clipped);
12587
12588	if ((stipple->drawable.width | stipple->drawable.height) <= 0xc &&
12589	    is_power_of_two(stipple->drawable.width) &&
12590	    is_power_of_two(stipple->drawable.height))
12591		return sna_poly_fill_rect_stippled_nxm_blt(drawable, bo, damage,
12592							   gc, n, rect,
12593							   extents, clipped);
12594
12595	if (extents->x2 - gc->patOrg.x - drawable->x <= stipple->drawable.width &&
12596	    extents->y2 - gc->patOrg.y - drawable->y <= stipple->drawable.height) {
12597		if (stipple->drawable.width <= 8 && stipple->drawable.height <= 8)
12598			return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage,
12599								   gc, n, rect,
12600								   extents, clipped);
12601		else
12602			return sna_poly_fill_rect_stippled_1_blt(drawable, bo, damage,
12603								 gc, n, rect,
12604								 extents, clipped);
12605	} else {
12606		return sna_poly_fill_rect_stippled_n_blt(drawable, bo, damage,
12607							 gc, n, rect,
12608							 extents, clipped);
12609	}
12610}
12611
12612static unsigned
12613sna_poly_fill_rect_extents(DrawablePtr drawable, GCPtr gc,
12614			   int *_n, xRectangle **_r,
12615			   BoxPtr out)
12616{
12617	int n;
12618	xRectangle *r;
12619	Box32Rec box;
12620	bool clipped;
12621
12622	if (*_n == 0)
12623		return 0;
12624
12625	DBG(("%s: [0] = (%d, %d)x(%d, %d)\n",
12626	     __FUNCTION__, (*_r)->x, (*_r)->y, (*_r)->width, (*_r)->height));
12627
12628	/* Remove any zero-size rectangles from the array */
12629	while (*_n && ((*_r)->width == 0 || (*_r)->height == 0))
12630		--*_n, ++*_r;
12631
12632	if (*_n == 0)
12633		return 0;
12634
12635	n = *_n;
12636	r = *_r;
12637
12638	box.x1 = r->x;
12639	box.x2 = box.x1 + r->width;
12640	box.y1 = r->y;
12641	box.y2 = box.y1 + r->height;
12642	r++;
12643
12644	while (--n) {
12645		if (r->width == 0 || r->height == 0)
12646			goto slow;
12647
12648		box32_add_rect(&box, r++);
12649	}
12650	goto done;
12651slow:
12652	{
12653		xRectangle *rr = r;
12654		do {
12655			do {
12656				--*_n, r++;
12657			} while (--n && (r->width == 0 || r->height == 0));
12658			while (n && r->width && r->height) {
12659				box32_add_rect(&box, r);
12660				*rr++ = *r++;
12661				n--;
12662			}
12663		} while (n);
12664	}
12665done:
12666
12667	clipped = box32_trim_and_translate(&box, drawable, gc);
12668	if (!box32_to_box16(&box, out))
12669		return 0;
12670
12671	return 1 | clipped << 1;
12672}
12673
12674static void
12675sna_poly_fill_rect(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect)
12676{
12677	PixmapPtr pixmap = get_drawable_pixmap(draw);
12678	struct sna *sna = to_sna_from_pixmap(pixmap);
12679	struct sna_pixmap *priv = sna_pixmap(pixmap);
12680	struct sna_damage **damage;
12681	struct kgem_bo *bo;
12682	RegionRec region;
12683	unsigned flags, hint;
12684	uint32_t color;
12685
12686	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
12687	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
12688	     (gc->fillStyle == FillSolid ||
12689	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
12690	     gc->fillStyle, gc->tileIsPixel,
12691	     gc->alu));
12692
12693	flags = sna_poly_fill_rect_extents(draw, gc, &n, &rect, &region.extents);
12694	if (flags == 0) {
12695		DBG(("%s, nothing to do\n", __FUNCTION__));
12696		return;
12697	}
12698
12699	DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
12700	     region.extents.x1, region.extents.y1,
12701	     region.extents.x2, region.extents.y2,
12702	     flags));
12703
12704	if (FORCE_FALLBACK || !ACCEL_POLY_FILL_RECT) {
12705		DBG(("%s: fallback forced\n", __FUNCTION__));
12706		goto fallback;
12707	}
12708
12709	if (priv == NULL) {
12710		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
12711		goto fallback;
12712	}
12713
12714	if (wedged(sna)) {
12715		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
12716		goto fallback;
12717	}
12718
12719	if (!PM_IS_SOLID(draw, gc->planemask)) {
12720		DBG(("%s: fallback -- planemask=%#lx (not-solid)\n",
12721		     __FUNCTION__, gc->planemask));
12722		goto fallback;
12723	}
12724
12725	/* Clear the cpu damage so that we refresh the GPU status of the
12726	 * pixmap upon a redraw after a period of inactivity.
12727	 */
12728	hint = PREFER_GPU;
12729	if (n == 1 && gc->fillStyle != FillStippled && alu_overwrites(gc->alu)) {
12730		int16_t dx, dy;
12731
12732		region.data = NULL;
12733
12734		if (get_drawable_deltas(draw, pixmap, &dx, &dy)) {
12735			DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy));
12736			RegionTranslate(&region, dx, dy);
12737		}
12738
12739		if (priv->cpu_damage && (flags & 2) == 0) {
12740			if (region_subsumes_damage(&region, priv->cpu_damage)) {
12741				DBG(("%s: discarding existing CPU damage\n", __FUNCTION__));
12742				if (priv->gpu_bo && priv->gpu_bo->proxy) {
12743					assert(priv->gpu_damage == NULL);
12744					assert(!priv->pinned);
12745					kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
12746					priv->gpu_bo = NULL;
12747				}
12748				sna_damage_destroy(&priv->cpu_damage);
12749				list_del(&priv->flush_list);
12750			}
12751			hint |= IGNORE_CPU;
12752		}
12753		if (region_subsumes_drawable(&region, &pixmap->drawable))
12754			hint |= REPLACES;
12755		if (priv->cpu_damage == NULL) {
12756			if (priv->gpu_bo &&
12757			    (hint & REPLACES || box_inplace(pixmap, &region.extents))) {
12758				DBG(("%s: promoting to full GPU\n",
12759				     __FUNCTION__));
12760				assert(priv->gpu_bo->proxy == NULL);
12761				sna_damage_all(&priv->gpu_damage,
12762					       pixmap->drawable.width,
12763					       pixmap->drawable.height);
12764			}
12765			DBG(("%s: dropping last-cpu hint\n", __FUNCTION__));
12766			priv->cpu = false;
12767		}
12768
12769		if (dx | dy)
12770			RegionTranslate(&region, -dx, -dy);
12771	}
12772
12773	/* If the source is already on the GPU, keep the operation on the GPU */
12774	if (gc->fillStyle == FillTiled && !gc->tileIsPixel &&
12775	    sna_pixmap_is_gpu(gc->tile.pixmap)) {
12776		DBG(("%s: source is already on the gpu\n", __FUNCTION__));
12777		hint |= FORCE_GPU;
12778	}
12779
12780	bo = sna_drawable_use_bo(draw, hint, &region.extents, &damage);
12781	if (bo == NULL) {
12782		DBG(("%s: not using GPU, hint=%x\n", __FUNCTION__, hint));
12783		goto fallback;
12784	}
12785	if (hint & REPLACES && (flags & 2) == 0 && UNDO)
12786		kgem_bo_undo(&sna->kgem, bo);
12787
12788	if (gc_is_solid(gc, &color)) {
12789		DBG(("%s: solid fill [%08x], testing for blt\n",
12790		     __FUNCTION__, color));
12791
12792		if (sna_poly_fill_rect_blt(draw,
12793					   bo, damage,
12794					   gc, color, n, rect,
12795					   &region.extents, flags & 2))
12796			return;
12797	} else if (gc->fillStyle == FillTiled) {
12798		DBG(("%s: tiled fill, testing for blt\n", __FUNCTION__));
12799
12800		if (sna_poly_fill_rect_tiled_blt(draw, bo, damage,
12801						 gc, n, rect,
12802						 &region.extents, flags & 2))
12803			return;
12804	} else {
12805		DBG(("%s: stippled fill, testing for blt\n", __FUNCTION__));
12806
12807		if (sna_poly_fill_rect_stippled_blt(draw, bo, damage,
12808						    gc, n, rect,
12809						    &region.extents, flags & 2))
12810			return;
12811	}
12812
12813fallback:
12814	DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__,
12815	     region.extents.x1, region.extents.y1,
12816	     region.extents.x2, region.extents.y2));
12817	region.data = NULL;
12818	region_maybe_clip(&region, gc->pCompositeClip);
12819	if (RegionNil(&region)) {
12820		DBG(("%s: nothing to do, all clipped\n", __FUNCTION__));
12821		return;
12822	}
12823
12824	if (!sna_gc_move_to_cpu(gc, draw, &region))
12825		goto out;
12826	if (!sna_drawable_move_region_to_cpu(draw, &region,
12827					     drawable_gc_flags(draw, gc, n > 1)))
12828		goto out_gc;
12829
12830	DBG(("%s: fallback - fbPolyFillRect\n", __FUNCTION__));
12831	fbPolyFillRect(draw, gc, n, rect);
12832	FALLBACK_FLUSH(draw);
12833out_gc:
12834	sna_gc_move_to_gpu(gc);
12835out:
12836	RegionUninit(&region);
12837}
12838
12839static void
12840sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *r)
12841{
12842	struct sna_fill_spans *data = sna_gc(gc)->priv;
12843	uint32_t color;
12844
12845	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
12846	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
12847	     (gc->fillStyle == FillSolid ||
12848	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
12849	     gc->fillStyle, gc->tileIsPixel,
12850	     gc->alu));
12851
12852	assert(PM_IS_SOLID(draw, gc->planemask));
12853	if (n == 0)
12854		return;
12855
12856	/* The mi routines do not attempt to keep the spans it generates
12857	 * within the clip, so we must run them through the clipper.
12858	 */
12859
12860	if (gc_is_solid(gc, &color)) {
12861		(void)sna_poly_fill_rect_blt(draw,
12862					     data->bo, data->damage,
12863					     gc, color, n, r,
12864					     &data->region.extents, true);
12865	} else if (gc->fillStyle == FillTiled) {
12866		(void)sna_poly_fill_rect_tiled_blt(draw,
12867						   data->bo, data->damage,
12868						   gc, n, r,
12869						   &data->region.extents, true);
12870	} else {
12871		(void)sna_poly_fill_rect_stippled_blt(draw,
12872						    data->bo, data->damage,
12873						    gc, n, r,
12874						    &data->region.extents, true);
12875	}
12876}
12877
12878static void
12879sna_poly_fill_arc(DrawablePtr draw, GCPtr gc, int n, xArc *arc)
12880{
12881	struct sna_fill_spans data;
12882	struct sna_pixmap *priv;
12883
12884	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
12885	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
12886	     (gc->fillStyle == FillSolid ||
12887	      (gc->fillStyle == FillTiled && gc->tileIsPixel)),
12888	     gc->fillStyle, gc->tileIsPixel,
12889	     gc->alu));
12890
12891	data.flags = sna_poly_arc_extents(draw, gc, n, arc,
12892					  &data.region.extents);
12893	if (data.flags == 0)
12894		return;
12895
12896	DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
12897	     data.region.extents.x1, data.region.extents.y1,
12898	     data.region.extents.x2, data.region.extents.y2,
12899	     data.flags));
12900
12901	data.region.data = NULL;
12902
12903	if (FORCE_FALLBACK)
12904		goto fallback;
12905
12906	if (!ACCEL_POLY_FILL_ARC)
12907		goto fallback;
12908
12909	data.pixmap = get_drawable_pixmap(draw);
12910	data.sna = to_sna_from_pixmap(data.pixmap);
12911	priv = sna_pixmap(data.pixmap);
12912	if (priv == NULL) {
12913		DBG(("%s: fallback -- unattached\n", __FUNCTION__));
12914		goto fallback;
12915	}
12916
12917	if (wedged(data.sna)) {
12918		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
12919		goto fallback;
12920	}
12921
12922	if (!PM_IS_SOLID(draw, gc->planemask))
12923		goto fallback;
12924
12925	if ((data.bo = sna_drawable_use_bo(draw, PREFER_GPU,
12926					   &data.region.extents,
12927					   &data.damage))) {
12928		uint32_t color;
12929
12930		get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy);
12931		sna_gc(gc)->priv = &data;
12932
12933		if (gc_is_solid(gc, &color)) {
12934			struct sna_fill_op fill;
12935
12936			if (!sna_fill_init_blt(&fill,
12937					       data.sna, data.pixmap,
12938					       data.bo, gc->alu, color))
12939				goto fallback;
12940
12941			data.op = &fill;
12942
12943			if ((data.flags & 2) == 0) {
12944				if (data.dx | data.dy)
12945					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset;
12946				else
12947					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill;
12948			} else {
12949				region_maybe_clip(&data.region,
12950						  gc->pCompositeClip);
12951				if (RegionNil(&data.region))
12952					return;
12953
12954				if (region_is_singular(&data.region))
12955					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents;
12956				else
12957					sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes;
12958			}
12959			assert(gc->miTranslate);
12960			gc->ops = &sna_gc_ops__tmp;
12961
12962			miPolyFillArc(draw, gc, n, arc);
12963			fill.done(data.sna, &fill);
12964		} else {
12965			sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu;
12966			gc->ops = &sna_gc_ops__tmp;
12967
12968			miPolyFillArc(draw, gc, n, arc);
12969		}
12970
12971		gc->ops = (GCOps *)&sna_gc_ops;
12972		if (data.damage) {
12973			if (data.dx | data.dy)
12974				pixman_region_translate(&data.region, data.dx, data.dy);
12975			assert_pixmap_contains_box(data.pixmap, &data.region.extents);
12976			sna_damage_add(data.damage, &data.region);
12977		}
12978		assert_pixmap_damage(data.pixmap);
12979		RegionUninit(&data.region);
12980		return;
12981	}
12982
12983fallback:
12984	DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__,
12985	     data.region.extents.x1, data.region.extents.y1,
12986	     data.region.extents.x2, data.region.extents.y2));
12987	region_maybe_clip(&data.region, gc->pCompositeClip);
12988	if (RegionNil(&data.region)) {
12989		DBG(("%s: nothing to do, all clipped\n", __FUNCTION__));
12990		return;
12991	}
12992
12993	if (!sna_gc_move_to_cpu(gc, draw, &data.region))
12994		goto out;
12995	if (!sna_drawable_move_region_to_cpu(draw, &data.region,
12996					     drawable_gc_flags(draw, gc, true)))
12997		goto out_gc;
12998
12999	DBG(("%s: fallback -- miPolyFillArc -> sna_fill_spans__cpu\n",
13000	     __FUNCTION__));
13001
13002	miPolyFillArc(draw, gc, n, arc);
13003out_gc:
13004	sna_gc_move_to_gpu(gc);
13005out:
13006	RegionUninit(&data.region);
13007}
13008
13009struct sna_font {
13010	CharInfoRec glyphs8[256];
13011	CharInfoRec *glyphs16[256];
13012};
13013#define GLYPH_INVALID (void *)1
13014#define GLYPH_EMPTY (void *)2
13015#define GLYPH_CLEAR (void *)3
13016
13017static Bool
13018sna_realize_font(ScreenPtr screen, FontPtr font)
13019{
13020	struct sna_font *priv;
13021
13022	DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key));
13023
13024	priv = calloc(1, sizeof(struct sna_font));
13025	if (priv == NULL)
13026		return FALSE;
13027
13028	if (!FontSetPrivate(font, sna_font_key, priv)) {
13029		free(priv);
13030		return FALSE;
13031	}
13032
13033	return TRUE;
13034}
13035
13036static Bool
13037sna_unrealize_font(ScreenPtr screen, FontPtr font)
13038{
13039	struct sna_font *priv = FontGetPrivate(font, sna_font_key);
13040	int i, j;
13041
13042	DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key));
13043
13044	if (priv == NULL)
13045		return TRUE;
13046
13047	for (i = 0; i < 256; i++) {
13048		if ((uintptr_t)priv->glyphs8[i].bits & ~3)
13049			free(priv->glyphs8[i].bits);
13050	}
13051	for (j = 0; j < 256; j++) {
13052		if (priv->glyphs16[j] == NULL)
13053			continue;
13054
13055		for (i = 0; i < 256; i++) {
13056			if ((uintptr_t)priv->glyphs16[j][i].bits & ~3)
13057				free(priv->glyphs16[j][i].bits);
13058		}
13059		free(priv->glyphs16[j]);
13060	}
13061	free(priv);
13062
13063	FontSetPrivate(font, sna_font_key, NULL);
13064	return TRUE;
13065}
13066
13067static bool
13068sna_glyph_blt(DrawablePtr drawable, GCPtr gc,
13069	      int _x, int _y, unsigned int _n,
13070	      CharInfoPtr *_info,
13071	      RegionRec *clip,
13072	      uint32_t fg, uint32_t bg,
13073	      bool transparent)
13074{
13075	PixmapPtr pixmap = get_drawable_pixmap(drawable);
13076	struct sna *sna = to_sna_from_pixmap(pixmap);
13077	struct kgem_bo *bo;
13078	struct sna_damage **damage;
13079	const BoxRec *extents, *last_extents;
13080	uint32_t *b;
13081	int16_t dx, dy;
13082	uint32_t br00;
13083	uint16_t unwind_batch, unwind_reloc;
13084
13085	uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S;
13086
13087	DBG(("%s (%d, %d) x %d, fg=%08x, bg=%08x alu=%02x\n",
13088	     __FUNCTION__, _x, _y, _n, fg, bg, rop));
13089
13090	if (wedged(sna)) {
13091		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
13092		return false;
13093	}
13094
13095	bo = sna_drawable_use_bo(drawable, PREFER_GPU, &clip->extents, &damage);
13096	if (bo == NULL)
13097		return false;
13098
13099	if (bo->tiling == I915_TILING_Y) {
13100		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
13101		assert(bo == __sna_pixmap_get_bo(pixmap));
13102		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
13103		if (bo == NULL) {
13104			DBG(("%s: fallback -- unable to change tiling\n",
13105			     __FUNCTION__));
13106			return false;
13107		}
13108	}
13109
13110	get_drawable_deltas(drawable, pixmap, &dx, &dy);
13111	_x += drawable->x + dx;
13112	_y += drawable->y + dy;
13113
13114	RegionTranslate(clip, dx, dy);
13115	extents = RegionRects(clip);
13116	last_extents = extents + RegionNumRects(clip);
13117
13118	if (!transparent) /* emulate miImageGlyphBlt */
13119		sna_blt_fill_boxes(sna, GXcopy,
13120				   bo, drawable->bitsPerPixel,
13121				   bg, extents, RegionNumRects(clip));
13122
13123	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
13124	if (!kgem_check_batch(&sna->kgem, 16) ||
13125	    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13126	    !kgem_check_reloc(&sna->kgem, 1)) {
13127		kgem_submit(&sna->kgem);
13128		if (!kgem_check_bo_fenced(&sna->kgem, bo))
13129			return false;
13130		_kgem_set_mode(&sna->kgem, KGEM_BLT);
13131	}
13132
13133	DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
13134	     __FUNCTION__,
13135	     extents->x1, extents->y1,
13136	     extents->x2, extents->y2));
13137
13138	unwind_batch = sna->kgem.nbatch;
13139	unwind_reloc = sna->kgem.nreloc;
13140
13141	b = sna->kgem.batch + sna->kgem.nbatch;
13142	b[0] = XY_SETUP_BLT | 3 << 20;
13143	b[1] = bo->pitch;
13144	if (sna->kgem.gen >= 040 && bo->tiling) {
13145		b[0] |= BLT_DST_TILED;
13146		b[1] >>= 2;
13147	}
13148	b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
13149	b[2] = extents->y1 << 16 | extents->x1;
13150	b[3] = extents->y2 << 16 | extents->x2;
13151	b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13152			      I915_GEM_DOMAIN_RENDER << 16 |
13153			      I915_GEM_DOMAIN_RENDER |
13154			      KGEM_RELOC_FENCED,
13155			      0);
13156	b[5] = bg;
13157	b[6] = fg;
13158	b[7] = 0;
13159	sna->kgem.nbatch += 8;
13160
13161	br00 = XY_TEXT_IMMEDIATE_BLT;
13162	if (bo->tiling && sna->kgem.gen >= 040)
13163		br00 |= BLT_DST_TILED;
13164
13165	do {
13166		CharInfoPtr *info = _info;
13167		int x = _x, y = _y, n = _n;
13168
13169		do {
13170			CharInfoPtr c = *info++;
13171			int w = GLYPHWIDTHPIXELS(c);
13172			int h = GLYPHHEIGHTPIXELS(c);
13173			int w8 = (w + 7) >> 3;
13174			int x1, y1, len;
13175
13176			if (c->bits == GLYPH_EMPTY)
13177				goto skip;
13178
13179			if (!transparent && c->bits == GLYPH_CLEAR)
13180				goto skip;
13181
13182			len = (w8 * h + 7) >> 3 << 1;
13183			x1 = x + c->metrics.leftSideBearing;
13184			y1 = y - c->metrics.ascent;
13185
13186			DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__,
13187			     x,y, x1, y1, w, w8, h, len));
13188
13189			if (x1 >= extents->x2 || y1 >= extents->y2)
13190				goto skip;
13191			if (x1 + w <= extents->x1 || y1 + h <= extents->y1)
13192				goto skip;
13193
13194
13195			if (!kgem_check_batch(&sna->kgem, 3+len)) {
13196				_kgem_submit(&sna->kgem);
13197				_kgem_set_mode(&sna->kgem, KGEM_BLT);
13198
13199				DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n",
13200				     __FUNCTION__,
13201				     extents->x1, extents->y1,
13202				     extents->x2, extents->y2));
13203
13204				unwind_batch = sna->kgem.nbatch;
13205				unwind_reloc = sna->kgem.nreloc;
13206
13207				b = sna->kgem.batch + sna->kgem.nbatch;
13208				b[0] = XY_SETUP_BLT | 3 << 20;
13209				b[1] = bo->pitch;
13210				if (sna->kgem.gen >= 040 && bo->tiling) {
13211					b[0] |= BLT_DST_TILED;
13212					b[1] >>= 2;
13213				}
13214				b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
13215				b[2] = extents->y1 << 16 | extents->x1;
13216				b[3] = extents->y2 << 16 | extents->x2;
13217				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13218						      I915_GEM_DOMAIN_RENDER << 16 |
13219						      I915_GEM_DOMAIN_RENDER |
13220						      KGEM_RELOC_FENCED,
13221						      0);
13222				b[5] = bg;
13223				b[6] = fg;
13224				b[7] = 0;
13225				sna->kgem.nbatch += 8;
13226			}
13227
13228			b = sna->kgem.batch + sna->kgem.nbatch;
13229			sna->kgem.nbatch += 3 + len;
13230
13231			b[0] = br00 | (1 + len);
13232			b[1] = (uint16_t)y1 << 16 | (uint16_t)x1;
13233			b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w);
13234			if (c->bits == GLYPH_CLEAR) {
13235				memset(b+3, 0, len*4);
13236			} else {
13237				uint64_t *src = (uint64_t *)c->bits;
13238				uint64_t *dst = (uint64_t *)(b + 3);
13239				do  {
13240					*dst++ = *src++;
13241					len -= 2;
13242				} while (len);
13243			}
13244
13245			if (damage) {
13246				BoxRec r;
13247
13248				r.x1 = x1;
13249				r.y1 = y1;
13250				r.x2 = x1 + w;
13251				r.y2 = y1 + h;
13252				if (box_intersect(&r, extents))
13253					sna_damage_add_box(damage, &r);
13254			}
13255skip:
13256			x += c->metrics.characterWidth;
13257		} while (--n);
13258
13259		if (++extents == last_extents)
13260			break;
13261
13262		if (kgem_check_batch(&sna->kgem, 3)) {
13263			b = sna->kgem.batch + sna->kgem.nbatch;
13264			sna->kgem.nbatch += 3;
13265
13266			DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
13267			     __FUNCTION__,
13268			     extents->x1, extents->y1,
13269			     extents->x2, extents->y2));
13270
13271			b[0] = XY_SETUP_CLIP;
13272			b[1] = extents->y1 << 16 | extents->x1;
13273			b[2] = extents->y2 << 16 | extents->x2;
13274		}
13275	} while (1);
13276
13277	if (sna->kgem.nbatch == unwind_batch + 8) {
13278		sna->kgem.nbatch = unwind_batch;
13279		sna->kgem.nreloc = unwind_reloc;
13280	}
13281
13282	assert_pixmap_damage(pixmap);
13283	sna->blt_state.fill_bo = 0;
13284	return true;
13285}
13286
13287static void
13288sna_glyph_extents(FontPtr font,
13289		  CharInfoPtr *info,
13290		  unsigned long count,
13291		  ExtentInfoRec *extents)
13292{
13293	extents->drawDirection = font->info.drawDirection;
13294	extents->fontAscent = font->info.fontAscent;
13295	extents->fontDescent = font->info.fontDescent;
13296
13297	extents->overallAscent = info[0]->metrics.ascent;
13298	extents->overallDescent = info[0]->metrics.descent;
13299	extents->overallLeft = info[0]->metrics.leftSideBearing;
13300	extents->overallRight = info[0]->metrics.rightSideBearing;
13301	extents->overallWidth = info[0]->metrics.characterWidth;
13302
13303	while (--count) {
13304		CharInfoPtr p =*++info;
13305		int v;
13306
13307		if (p->metrics.ascent > extents->overallAscent)
13308			extents->overallAscent = p->metrics.ascent;
13309		if (p->metrics.descent > extents->overallDescent)
13310			extents->overallDescent = p->metrics.descent;
13311
13312		v = extents->overallWidth + p->metrics.leftSideBearing;
13313		if (v < extents->overallLeft)
13314			extents->overallLeft = v;
13315
13316		v = extents->overallWidth + p->metrics.rightSideBearing;
13317		if (v > extents->overallRight)
13318			extents->overallRight = v;
13319
13320		extents->overallWidth += p->metrics.characterWidth;
13321	}
13322}
13323
13324static bool sna_set_glyph(CharInfoPtr in, CharInfoPtr out)
13325{
13326	int w = GLYPHWIDTHPIXELS(in);
13327	int h = GLYPHHEIGHTPIXELS(in);
13328	int stride = GLYPHWIDTHBYTESPADDED(in);
13329	uint8_t *dst, *src;
13330	int clear = 1;
13331
13332	out->metrics = in->metrics;
13333
13334	/* Skip empty glyphs */
13335	if (w == 0 || h == 0 || ((w|h) == 1 && (in->bits[0] & 1) == 0)) {
13336		out->bits = GLYPH_EMPTY;
13337		return true;
13338	}
13339
13340	w = (w + 7) >> 3;
13341
13342	out->bits = malloc((w*h + 7) & ~7);
13343	if (out->bits == NULL)
13344		return false;
13345
13346	VG(memset(out->bits, 0, (w*h + 7) & ~7));
13347	src = (uint8_t *)in->bits;
13348	dst = (uint8_t *)out->bits;
13349	stride -= w;
13350	do {
13351		int i = w;
13352		do {
13353			clear &= *src == 0;
13354			*dst++ = byte_reverse(*src++);
13355		} while (--i);
13356		src += stride;
13357	} while (--h);
13358
13359	if (clear) {
13360		free(out->bits);
13361		out->bits = GLYPH_CLEAR;
13362	}
13363
13364	return true;
13365}
13366
13367inline static bool sna_get_glyph8(FontPtr font, struct sna_font *priv,
13368				  uint8_t g, CharInfoPtr *out)
13369{
13370	unsigned long n;
13371	CharInfoPtr p, ret;
13372
13373	p = &priv->glyphs8[g];
13374	if (p->bits) {
13375		*out = p;
13376		return p->bits != GLYPH_INVALID;
13377	}
13378
13379	font->get_glyphs(font, 1, &g, Linear8Bit, &n, &ret);
13380	if (n == 0) {
13381		p->bits = GLYPH_INVALID;
13382		return false;
13383	}
13384
13385	return sna_set_glyph(ret, *out = p);
13386}
13387
13388inline static bool sna_get_glyph16(FontPtr font, struct sna_font *priv,
13389				   uint16_t g, CharInfoPtr *out)
13390{
13391	unsigned long n;
13392	CharInfoPtr page, p, ret;
13393
13394	page = priv->glyphs16[g>>8];
13395	if (page == NULL)
13396		page = priv->glyphs16[g>>8] = calloc(256, sizeof(CharInfoRec));
13397
13398	p = &page[g&0xff];
13399	if (p->bits) {
13400		*out = p;
13401		return p->bits != GLYPH_INVALID;
13402	}
13403
13404	font->get_glyphs(font, 1, (unsigned char *)&g,
13405			 FONTLASTROW(font) ? TwoD16Bit : Linear16Bit,
13406			 &n, &ret);
13407	if (n == 0) {
13408		p->bits = GLYPH_INVALID;
13409		return false;
13410	}
13411
13412	return sna_set_glyph(ret, *out = p);
13413}
13414
13415static inline bool sna_font_too_large(FontPtr font)
13416{
13417	int top = max(FONTMAXBOUNDS(font, ascent), FONTASCENT(font));
13418	int bot = max(FONTMAXBOUNDS(font, descent), FONTDESCENT(font));
13419	int width = max(FONTMAXBOUNDS(font, characterWidth), -FONTMINBOUNDS(font, characterWidth));
13420	DBG(("%s? (%d + %d) x %d: %d > 124\n", __FUNCTION__,
13421	     top, bot, width, (top + bot) * (width + 7)/8));
13422	return (top + bot) * (width + 7)/8 > 124;
13423}
13424
13425static int
13426sna_poly_text8(DrawablePtr drawable, GCPtr gc,
13427	       int x, int y,
13428	       int count, char *chars)
13429{
13430	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
13431	CharInfoPtr info[255];
13432	ExtentInfoRec extents;
13433	RegionRec region;
13434	long unsigned i, n;
13435	uint32_t fg;
13436
13437	for (i = n = 0; i < count; i++) {
13438		if (sna_get_glyph8(gc->font, priv, chars[i], &info[n]))
13439			n++;
13440	}
13441	if (n == 0)
13442		return x;
13443
13444	sna_glyph_extents(gc->font, info, n, &extents);
13445	region.extents.x1 = x + extents.overallLeft;
13446	region.extents.y1 = y - extents.overallAscent;
13447	region.extents.x2 = x + extents.overallRight;
13448	region.extents.y2 = y + extents.overallDescent;
13449
13450	translate_box(&region.extents, drawable);
13451	clip_box(&region.extents, gc);
13452	if (box_empty(&region.extents))
13453		return x + extents.overallRight;
13454
13455	region.data = NULL;
13456	region_maybe_clip(&region, gc->pCompositeClip);
13457	if (RegionNil(&region))
13458		return x + extents.overallRight;
13459
13460	if (FORCE_FALLBACK)
13461		goto fallback;
13462
13463	if (!ACCEL_POLY_TEXT8)
13464		goto fallback;
13465
13466	if (sna_font_too_large(gc->font))
13467		goto fallback;
13468
13469	if (!PM_IS_SOLID(drawable, gc->planemask))
13470		goto fallback;
13471
13472	if (!gc_is_solid(gc, &fg))
13473		goto fallback;
13474
13475	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region, fg, -1, true)) {
13476fallback:
13477		DBG(("%s: fallback\n", __FUNCTION__));
13478		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
13479				     Linear8Bit, &n, info);
13480
13481		if (!sna_gc_move_to_cpu(gc, drawable, &region))
13482			goto out;
13483		if (!sna_drawable_move_region_to_cpu(drawable, &region,
13484						     MOVE_READ | MOVE_WRITE))
13485			goto out_gc;
13486
13487		DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
13488		fbPolyGlyphBlt(drawable, gc, x, y, n,
13489			       info, FONTGLYPHS(gc->font));
13490		FALLBACK_FLUSH(drawable);
13491out_gc:
13492		sna_gc_move_to_gpu(gc);
13493	}
13494out:
13495	RegionUninit(&region);
13496	return x + extents.overallRight;
13497}
13498
13499static int
13500sna_poly_text16(DrawablePtr drawable, GCPtr gc,
13501		int x, int y,
13502		int count, unsigned short *chars)
13503{
13504	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
13505	CharInfoPtr info[255];
13506	ExtentInfoRec extents;
13507	RegionRec region;
13508	long unsigned i, n;
13509	uint32_t fg;
13510
13511	for (i = n = 0; i < count; i++) {
13512		if (sna_get_glyph16(gc->font, priv, chars[i], &info[n]))
13513			n++;
13514	}
13515	if (n == 0)
13516		return x;
13517
13518	sna_glyph_extents(gc->font, info, n, &extents);
13519	region.extents.x1 = x + extents.overallLeft;
13520	region.extents.y1 = y - extents.overallAscent;
13521	region.extents.x2 = x + extents.overallRight;
13522	region.extents.y2 = y + extents.overallDescent;
13523
13524	translate_box(&region.extents, drawable);
13525	clip_box(&region.extents, gc);
13526	if (box_empty(&region.extents))
13527		return x + extents.overallRight;
13528
13529	region.data = NULL;
13530	region_maybe_clip(&region, gc->pCompositeClip);
13531	if (RegionNil(&region))
13532		return x + extents.overallRight;
13533
13534	if (FORCE_FALLBACK)
13535		goto fallback;
13536
13537	if (!ACCEL_POLY_TEXT16)
13538		goto fallback;
13539
13540	if (sna_font_too_large(gc->font))
13541		goto fallback;
13542
13543	if (!PM_IS_SOLID(drawable, gc->planemask))
13544		goto fallback;
13545
13546	if (!gc_is_solid(gc, &fg))
13547		goto fallback;
13548
13549	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region, fg, -1, true)) {
13550fallback:
13551		DBG(("%s: fallback\n", __FUNCTION__));
13552		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
13553				     FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit,
13554				     &n, info);
13555
13556		if (!sna_gc_move_to_cpu(gc, drawable, &region))
13557			goto out;
13558		if (!sna_drawable_move_region_to_cpu(drawable, &region,
13559						     MOVE_READ | MOVE_WRITE))
13560			goto out_gc;
13561
13562		DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
13563		fbPolyGlyphBlt(drawable, gc, x, y, n,
13564			       info, FONTGLYPHS(gc->font));
13565		FALLBACK_FLUSH(drawable);
13566out_gc:
13567		sna_gc_move_to_gpu(gc);
13568	}
13569out:
13570	RegionUninit(&region);
13571	return x + extents.overallRight;
13572}
13573
13574static void
13575sna_image_text8(DrawablePtr drawable, GCPtr gc,
13576	       int x, int y,
13577	       int count, char *chars)
13578{
13579	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
13580	CharInfoPtr info[255];
13581	ExtentInfoRec extents;
13582	RegionRec region;
13583	long unsigned i, n;
13584
13585	for (i = n = 0; i < count; i++) {
13586		if (sna_get_glyph8(gc->font, priv, chars[i], &info[n]))
13587			n++;
13588	}
13589	if (n == 0)
13590		return;
13591
13592	sna_glyph_extents(gc->font, info, n, &extents);
13593	region.extents.x1 = x + MIN(0, extents.overallLeft);
13594	region.extents.y1 = y - extents.fontAscent;
13595	region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight);
13596	region.extents.y2 = y + extents.fontDescent;
13597
13598	DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n",
13599	     __FUNCTION__, n, count,
13600	     extents.overallLeft, extents.overallRight, extents.overallWidth,
13601	     extents.fontAscent, extents.fontDescent,
13602	     region.extents.x1, region.extents.y1,
13603	     region.extents.x2, region.extents.y2));
13604
13605	translate_box(&region.extents, drawable);
13606	clip_box(&region.extents, gc);
13607	if (box_empty(&region.extents))
13608		return;
13609
13610	region.data = NULL;
13611	region_maybe_clip(&region, gc->pCompositeClip);
13612	if (RegionNil(&region))
13613		return;
13614
13615	DBG(("%s: clipped extents (%d, %d), (%d, %d)\n",
13616	     __FUNCTION__,
13617	     region.extents.x1, region.extents.y1,
13618	     region.extents.x2, region.extents.y2));
13619
13620	if (FORCE_FALLBACK)
13621		goto fallback;
13622
13623	if (!ACCEL_IMAGE_TEXT8)
13624		goto fallback;
13625
13626	if (sna_font_too_large(gc->font))
13627		goto fallback;
13628
13629	if (!PM_IS_SOLID(drawable, gc->planemask))
13630		goto fallback;
13631
13632	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region,
13633			   gc->fgPixel, gc->bgPixel, false)) {
13634fallback:
13635		DBG(("%s: fallback\n", __FUNCTION__));
13636		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
13637				     Linear8Bit, &n, info);
13638
13639		if (!sna_gc_move_to_cpu(gc, drawable, &region))
13640			goto out;
13641		if (!sna_drawable_move_region_to_cpu(drawable, &region,
13642						     MOVE_READ | MOVE_WRITE))
13643			goto out_gc;
13644
13645		DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
13646		fbImageGlyphBlt(drawable, gc, x, y, n,
13647				info, FONTGLYPHS(gc->font));
13648		FALLBACK_FLUSH(drawable);
13649out_gc:
13650		sna_gc_move_to_gpu(gc);
13651	}
13652out:
13653	RegionUninit(&region);
13654}
13655
13656static void
13657sna_image_text16(DrawablePtr drawable, GCPtr gc,
13658	       int x, int y,
13659	       int count, unsigned short *chars)
13660{
13661	struct sna_font *priv = gc->font->devPrivates[sna_font_key];
13662	CharInfoPtr info[255];
13663	ExtentInfoRec extents;
13664	RegionRec region;
13665	long unsigned i, n;
13666
13667	for (i = n = 0; i < count; i++) {
13668		if (sna_get_glyph16(gc->font, priv, chars[i], &info[n]))
13669			n++;
13670	}
13671	if (n == 0)
13672		return;
13673
13674	sna_glyph_extents(gc->font, info, n, &extents);
13675	region.extents.x1 = x + MIN(0, extents.overallLeft);
13676	region.extents.y1 = y - extents.fontAscent;
13677	region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight);
13678	region.extents.y2 = y + extents.fontDescent;
13679
13680	DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n",
13681	     __FUNCTION__, n, count,
13682	     extents.overallLeft, extents.overallRight, extents.overallWidth,
13683	     extents.fontAscent, extents.fontDescent,
13684	     region.extents.x1, region.extents.y1,
13685	     region.extents.x2, region.extents.y2));
13686
13687	translate_box(&region.extents, drawable);
13688	clip_box(&region.extents, gc);
13689	if (box_empty(&region.extents))
13690		return;
13691
13692	region.data = NULL;
13693	region_maybe_clip(&region, gc->pCompositeClip);
13694	if (RegionNil(&region))
13695		return;
13696
13697	DBG(("%s: clipped extents (%d, %d), (%d, %d)\n",
13698	     __FUNCTION__,
13699	     region.extents.x1, region.extents.y1,
13700	     region.extents.x2, region.extents.y2));
13701
13702	if (FORCE_FALLBACK)
13703		goto fallback;
13704
13705	if (!ACCEL_IMAGE_TEXT16)
13706		goto fallback;
13707
13708	if (sna_font_too_large(gc->font))
13709		goto fallback;
13710
13711	if (!PM_IS_SOLID(drawable, gc->planemask))
13712		goto fallback;
13713
13714	if (!sna_glyph_blt(drawable, gc, x, y, n, info, &region,
13715			   gc->fgPixel, gc->bgPixel, false)) {
13716fallback:
13717		DBG(("%s: fallback\n", __FUNCTION__));
13718		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
13719				     FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit,
13720				     &n, info);
13721
13722		if (!sna_gc_move_to_cpu(gc, drawable, &region))
13723			goto out;
13724		if (!sna_drawable_move_region_to_cpu(drawable, &region,
13725						     MOVE_READ | MOVE_WRITE))
13726			goto out_gc;
13727
13728		DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
13729		fbImageGlyphBlt(drawable, gc, x, y, n,
13730				info, FONTGLYPHS(gc->font));
13731		FALLBACK_FLUSH(drawable);
13732out_gc:
13733		sna_gc_move_to_gpu(gc);
13734	}
13735out:
13736	RegionUninit(&region);
13737}
13738
13739/* XXX Damage bypasses the Text interface and so we lose our custom gluphs */
13740static bool
13741sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc,
13742		       int _x, int _y, unsigned int _n,
13743		       CharInfoPtr *_info, pointer _base,
13744		       struct kgem_bo *bo,
13745		       struct sna_damage **damage,
13746		       RegionPtr clip,
13747		       uint32_t fg, uint32_t bg,
13748		       bool transparent)
13749{
13750	PixmapPtr pixmap = get_drawable_pixmap(drawable);
13751	struct sna *sna = to_sna_from_pixmap(pixmap);
13752	const BoxRec *extents, *last_extents;
13753	uint32_t *b;
13754	int16_t dx, dy;
13755	uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S;
13756	uint16_t unwind_batch, unwind_reloc;
13757
13758	if (bo->tiling == I915_TILING_Y) {
13759		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
13760		assert(bo == __sna_pixmap_get_bo(pixmap));
13761		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
13762		if (bo == NULL) {
13763			DBG(("%s: fallback -- unable to change tiling\n",
13764			     __FUNCTION__));
13765			return false;
13766		}
13767	}
13768
13769	get_drawable_deltas(drawable, pixmap, &dx, &dy);
13770	_x += drawable->x + dx;
13771	_y += drawable->y + dy;
13772
13773	RegionTranslate(clip, dx, dy);
13774	extents = RegionRects(clip);
13775	last_extents = extents + RegionNumRects(clip);
13776
13777	if (!transparent) /* emulate miImageGlyphBlt */
13778		sna_blt_fill_boxes(sna, GXcopy,
13779				   bo, drawable->bitsPerPixel,
13780				   bg, extents, RegionNumRects(clip));
13781
13782	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
13783	if (!kgem_check_batch(&sna->kgem, 16) ||
13784	    !kgem_check_bo_fenced(&sna->kgem, bo) ||
13785	    !kgem_check_reloc(&sna->kgem, 1)) {
13786		kgem_submit(&sna->kgem);
13787		if (!kgem_check_bo_fenced(&sna->kgem, bo))
13788			return false;
13789		_kgem_set_mode(&sna->kgem, KGEM_BLT);
13790	}
13791
13792	unwind_batch = sna->kgem.nbatch;
13793	unwind_reloc = sna->kgem.nreloc;
13794
13795	DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
13796	     __FUNCTION__,
13797	     extents->x1, extents->y1,
13798	     extents->x2, extents->y2));
13799	b = sna->kgem.batch + sna->kgem.nbatch;
13800	b[0] = XY_SETUP_BLT | 1 << 20;
13801	b[1] = bo->pitch;
13802	if (sna->kgem.gen >= 040 && bo->tiling) {
13803		b[0] |= BLT_DST_TILED;
13804		b[1] >>= 2;
13805	}
13806	b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
13807	b[2] = extents->y1 << 16 | extents->x1;
13808	b[3] = extents->y2 << 16 | extents->x2;
13809	b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
13810			      I915_GEM_DOMAIN_RENDER << 16 |
13811			      I915_GEM_DOMAIN_RENDER |
13812			      KGEM_RELOC_FENCED,
13813			      0);
13814	b[5] = bg;
13815	b[6] = fg;
13816	b[7] = 0;
13817	sna->kgem.nbatch += 8;
13818
13819	do {
13820		CharInfoPtr *info = _info;
13821		int x = _x, y = _y, n = _n;
13822
13823		do {
13824			CharInfoPtr c = *info++;
13825			uint8_t *glyph = FONTGLYPHBITS(base, c);
13826			int w = GLYPHWIDTHPIXELS(c);
13827			int h = GLYPHHEIGHTPIXELS(c);
13828			int stride = GLYPHWIDTHBYTESPADDED(c);
13829			int w8 = (w + 7) >> 3;
13830			int x1, y1, len, i;
13831			uint8_t *byte;
13832
13833			if (w == 0 || h == 0)
13834				goto skip;
13835
13836			len = (w8 * h + 7) >> 3 << 1;
13837			x1 = x + c->metrics.leftSideBearing;
13838			y1 = y - c->metrics.ascent;
13839
13840			DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__,
13841			     x,y, x1, y1, w, w8, h, len));
13842
13843			if (x1 >= extents->x2 || y1 >= extents->y2 ||
13844			    x1 + w <= extents->x1 || y1 + h <= extents->y1) {
13845				DBG(("%s: glyph is clipped (%d, %d)x(%d,%d) against extents (%d, %d), (%d, %d)\n",
13846				     __FUNCTION__,
13847				     x1, y1, w, h,
13848				     extents->x1, extents->y1,
13849				     extents->x2, extents->y2));
13850				goto skip;
13851			}
13852
13853			if (!transparent) {
13854				int clear = 1, j = h;
13855				uint8_t *g = glyph;
13856
13857				do {
13858					i = w8;
13859					do {
13860						clear = *g++ == 0;
13861					} while (clear && --i);
13862					g += stride - w8;
13863				} while (clear && --j);
13864				if (clear) {
13865					DBG(("%s: skipping clear glyph for ImageGlyph\n",
13866					     __FUNCTION__));
13867					goto skip;
13868				}
13869			}
13870
13871			if (!kgem_check_batch(&sna->kgem, 3+len)) {
13872				_kgem_submit(&sna->kgem);
13873				_kgem_set_mode(&sna->kgem, KGEM_BLT);
13874
13875				unwind_batch = sna->kgem.nbatch;
13876				unwind_reloc = sna->kgem.nreloc;
13877
13878				DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n",
13879				     __FUNCTION__,
13880				     extents->x1, extents->y1,
13881				     extents->x2, extents->y2));
13882
13883				b = sna->kgem.batch + sna->kgem.nbatch;
13884				b[0] = XY_SETUP_BLT | 1 << 20;
13885				b[1] = bo->pitch;
13886				if (sna->kgem.gen >= 040 && bo->tiling) {
13887					b[0] |= BLT_DST_TILED;
13888					b[1] >>= 2;
13889				}
13890				b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16;
13891				b[2] = extents->y1 << 16 | extents->x1;
13892				b[3] = extents->y2 << 16 | extents->x2;
13893				b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4,
13894						      bo,
13895						      I915_GEM_DOMAIN_RENDER << 16 |
13896						      I915_GEM_DOMAIN_RENDER |
13897						      KGEM_RELOC_FENCED,
13898						      0);
13899				b[5] = bg;
13900				b[6] = fg;
13901				b[7] = 0;
13902				sna->kgem.nbatch += 8;
13903			}
13904
13905			b = sna->kgem.batch + sna->kgem.nbatch;
13906			sna->kgem.nbatch += 3 + len;
13907
13908			b[0] = XY_TEXT_IMMEDIATE_BLT | (1 + len);
13909			if (bo->tiling && sna->kgem.gen >= 040)
13910				b[0] |= BLT_DST_TILED;
13911			b[1] = (uint16_t)y1 << 16 | (uint16_t)x1;
13912			b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w);
13913
13914			byte = (uint8_t *)&b[3];
13915			stride -= w8;
13916			do {
13917				i = w8;
13918				do {
13919					*byte++ = byte_reverse(*glyph++);
13920				} while (--i);
13921				glyph += stride;
13922			} while (--h);
13923			while ((byte - (uint8_t *)&b[3]) & 7)
13924				*byte++ = 0;
13925			assert((uint32_t *)byte == sna->kgem.batch + sna->kgem.nbatch);
13926
13927			if (damage) {
13928				BoxRec r;
13929
13930				r.x1 = x1;
13931				r.y1 = y1;
13932				r.x2 = x1 + w;
13933				r.y2 = y1 + h;
13934				if (box_intersect(&r, extents))
13935					sna_damage_add_box(damage, &r);
13936			}
13937skip:
13938			x += c->metrics.characterWidth;
13939		} while (--n);
13940
13941		if (++extents == last_extents)
13942			break;
13943
13944		if (kgem_check_batch(&sna->kgem, 3 + 5)) {
13945			b = sna->kgem.batch + sna->kgem.nbatch;
13946			sna->kgem.nbatch += 3;
13947
13948			DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
13949			     __FUNCTION__,
13950			     extents->x1, extents->y1,
13951			     extents->x2, extents->y2));
13952
13953			b[0] = XY_SETUP_CLIP;
13954			b[1] = extents->y1 << 16 | extents->x1;
13955			b[2] = extents->y2 << 16 | extents->x2;
13956		}
13957	} while (1);
13958
13959	if (sna->kgem.nbatch == unwind_batch + 8) {
13960		sna->kgem.nbatch = unwind_batch;
13961		sna->kgem.nreloc = unwind_reloc;
13962	}
13963
13964	assert_pixmap_damage(pixmap);
13965	sna->blt_state.fill_bo = 0;
13966	return true;
13967}
13968
13969static void
13970sna_image_glyph(DrawablePtr drawable, GCPtr gc,
13971		int x, int y, unsigned int n,
13972		CharInfoPtr *info, pointer base)
13973{
13974	PixmapPtr pixmap = get_drawable_pixmap(drawable);
13975	struct sna *sna = to_sna_from_pixmap(pixmap);
13976	ExtentInfoRec extents;
13977	RegionRec region;
13978	struct sna_damage **damage;
13979	struct kgem_bo *bo;
13980
13981	if (n == 0)
13982		return;
13983
13984	sna_glyph_extents(gc->font, info, n, &extents);
13985	region.extents.x1 = x + MIN(0, extents.overallLeft);
13986	region.extents.y1 = y - extents.fontAscent;
13987	region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight);
13988	region.extents.y2 = y + extents.fontDescent;
13989
13990	DBG(("%s: count=%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n",
13991	     __FUNCTION__, n,
13992	     extents.overallLeft, extents.overallRight, extents.overallWidth,
13993	     extents.fontAscent, extents.fontDescent,
13994	     region.extents.x1, region.extents.y1,
13995	     region.extents.x2, region.extents.y2));
13996
13997	translate_box(&region.extents, drawable);
13998	clip_box(&region.extents, gc);
13999	if (box_empty(&region.extents))
14000		return;
14001
14002	DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__,
14003	     region.extents.x1, region.extents.y1,
14004	     region.extents.x2, region.extents.y2));
14005
14006	region.data = NULL;
14007	region_maybe_clip(&region, gc->pCompositeClip);
14008	if (RegionNil(&region))
14009		return;
14010
14011	if (FORCE_FALLBACK)
14012		goto fallback;
14013
14014	if (!ACCEL_IMAGE_GLYPH)
14015		goto fallback;
14016
14017	if (wedged(sna)) {
14018		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
14019		goto fallback;
14020	}
14021
14022	if (!PM_IS_SOLID(drawable, gc->planemask))
14023		goto fallback;
14024
14025	if (sna_font_too_large(gc->font))
14026		goto fallback;
14027
14028	if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU,
14029				      &region.extents, &damage)) &&
14030	    sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base,
14031				   bo, damage, &region,
14032				   gc->fgPixel, gc->bgPixel, false))
14033		goto out;
14034
14035fallback:
14036	DBG(("%s: fallback\n", __FUNCTION__));
14037	if (!sna_gc_move_to_cpu(gc, drawable, &region))
14038		goto out;
14039	if (!sna_drawable_move_region_to_cpu(drawable, &region,
14040					     MOVE_READ | MOVE_WRITE))
14041		goto out_gc;
14042
14043	DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
14044	fbImageGlyphBlt(drawable, gc, x, y, n, info, base);
14045	FALLBACK_FLUSH(drawable);
14046
14047out_gc:
14048	sna_gc_move_to_gpu(gc);
14049out:
14050	RegionUninit(&region);
14051}
14052
14053static void
14054sna_poly_glyph(DrawablePtr drawable, GCPtr gc,
14055	       int x, int y, unsigned int n,
14056	       CharInfoPtr *info, pointer base)
14057{
14058	PixmapPtr pixmap = get_drawable_pixmap(drawable);
14059	struct sna *sna = to_sna_from_pixmap(pixmap);
14060	ExtentInfoRec extents;
14061	RegionRec region;
14062	struct sna_damage **damage;
14063	struct kgem_bo *bo;
14064	uint32_t fg;
14065
14066	if (n == 0)
14067		return;
14068
14069	sna_glyph_extents(gc->font, info, n, &extents);
14070	region.extents.x1 = x + extents.overallLeft;
14071	region.extents.y1 = y - extents.overallAscent;
14072	region.extents.x2 = x + extents.overallRight;
14073	region.extents.y2 = y + extents.overallDescent;
14074
14075	translate_box(&region.extents, drawable);
14076	clip_box(&region.extents, gc);
14077	if (box_empty(&region.extents))
14078		return;
14079
14080	DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__,
14081	     region.extents.x1, region.extents.y1,
14082	     region.extents.x2, region.extents.y2));
14083
14084	region.data = NULL;
14085	region_maybe_clip(&region, gc->pCompositeClip);
14086	if (RegionNil(&region))
14087		return;
14088
14089	if (FORCE_FALLBACK)
14090		goto fallback;
14091
14092	if (!ACCEL_POLY_GLYPH)
14093		goto fallback;
14094
14095	if (wedged(sna)) {
14096		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
14097		goto fallback;
14098	}
14099
14100	if (!PM_IS_SOLID(drawable, gc->planemask))
14101		goto fallback;
14102
14103	if (!gc_is_solid(gc, &fg))
14104		goto fallback;
14105
14106	if (sna_font_too_large(gc->font))
14107		goto fallback;
14108
14109	if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU,
14110				      &region.extents, &damage)) &&
14111	    sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base,
14112				   bo, damage, &region, fg, -1, true))
14113		goto out;
14114
14115fallback:
14116	DBG(("%s: fallback\n", __FUNCTION__));
14117	if (!sna_gc_move_to_cpu(gc, drawable, &region))
14118		goto out;
14119	if (!sna_drawable_move_region_to_cpu(drawable, &region,
14120					     MOVE_READ | MOVE_WRITE))
14121		goto out_gc;
14122
14123	DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
14124	fbPolyGlyphBlt(drawable, gc, x, y, n, info, base);
14125	FALLBACK_FLUSH(drawable);
14126
14127out_gc:
14128	sna_gc_move_to_gpu(gc);
14129out:
14130	RegionUninit(&region);
14131}
14132
14133static bool
14134sna_push_pixels_solid_blt(GCPtr gc,
14135			  PixmapPtr bitmap,
14136			  DrawablePtr drawable,
14137			  RegionPtr region)
14138{
14139	PixmapPtr pixmap = get_drawable_pixmap(drawable);
14140	struct sna *sna = to_sna_from_pixmap(pixmap);
14141	struct sna_damage **damage;
14142	struct kgem_bo *bo;
14143	BoxRec *box;
14144	int16_t dx, dy;
14145	int n;
14146	uint8_t rop = copy_ROP[gc->alu];
14147
14148	bo = sna_drawable_use_bo(drawable, PREFER_GPU, &region->extents, &damage);
14149	if (bo == NULL)
14150		return false;
14151
14152	if (bo->tiling == I915_TILING_Y) {
14153		DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__));
14154		assert(bo == __sna_pixmap_get_bo(pixmap));
14155		bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X);
14156		if (bo == NULL) {
14157			DBG(("%s: fallback -- unable to change tiling\n",
14158			     __FUNCTION__));
14159			return false;
14160		}
14161	}
14162
14163	if (get_drawable_deltas(drawable, pixmap, &dx, &dy))
14164		RegionTranslate(region, dx, dy);
14165
14166	assert_pixmap_contains_box(pixmap, RegionExtents(region));
14167	if (damage)
14168		sna_damage_add(damage, region);
14169	assert_pixmap_damage(pixmap);
14170
14171	DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__,
14172	     region->extents.x1, region->extents.y1,
14173	     region->extents.x2, region->extents.y2));
14174
14175	kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
14176
14177	/* Region is pre-clipped and translated into pixmap space */
14178	box = RegionRects(region);
14179	n = RegionNumRects(region);
14180	do {
14181		int bx1 = (box->x1 - region->extents.x1) & ~7;
14182		int bx2 = (box->x2 - region->extents.x1 + 7) & ~7;
14183		int bw = (bx2 - bx1)/8;
14184		int bh = box->y2 - box->y1;
14185		int bstride = ALIGN(bw, 2);
14186		int src_stride;
14187		uint8_t *dst, *src;
14188		uint32_t *b;
14189		struct kgem_bo *upload;
14190		void *ptr;
14191
14192		if (!kgem_check_batch(&sna->kgem, 8) ||
14193		    !kgem_check_bo_fenced(&sna->kgem, bo) ||
14194		    !kgem_check_reloc_and_exec(&sna->kgem, 2)) {
14195			kgem_submit(&sna->kgem);
14196			if (!kgem_check_bo_fenced(&sna->kgem, bo))
14197				return false;
14198			_kgem_set_mode(&sna->kgem, KGEM_BLT);
14199		}
14200
14201		upload = kgem_create_buffer(&sna->kgem,
14202					    bstride*bh,
14203					    KGEM_BUFFER_WRITE_INPLACE,
14204					    &ptr);
14205		if (!upload)
14206			break;
14207
14208		dst = ptr;
14209
14210		src_stride = bitmap->devKind;
14211		src = (uint8_t*)bitmap->devPrivate.ptr;
14212		src += (box->y1 - region->extents.y1) * src_stride + bx1/8;
14213		src_stride -= bstride;
14214		do {
14215			int i = bstride;
14216			do {
14217				*dst++ = byte_reverse(*src++);
14218				*dst++ = byte_reverse(*src++);
14219				i -= 2;
14220			} while (i);
14221			src += src_stride;
14222		} while (--bh);
14223
14224		b = sna->kgem.batch + sna->kgem.nbatch;
14225		b[0] = XY_MONO_SRC_COPY | 3 << 20;
14226		b[0] |= ((box->x1 - region->extents.x1) & 7) << 17;
14227		b[1] = bo->pitch;
14228		if (sna->kgem.gen >= 040 && bo->tiling) {
14229			b[0] |= BLT_DST_TILED;
14230			b[1] >>= 2;
14231		}
14232		b[1] |= 1 << 29;
14233		b[1] |= blt_depth(drawable->depth) << 24;
14234		b[1] |= rop << 16;
14235		b[2] = box->y1 << 16 | box->x1;
14236		b[3] = box->y2 << 16 | box->x2;
14237		b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo,
14238				      I915_GEM_DOMAIN_RENDER << 16 |
14239				      I915_GEM_DOMAIN_RENDER |
14240				      KGEM_RELOC_FENCED,
14241				      0);
14242		b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5,
14243				      upload,
14244				      I915_GEM_DOMAIN_RENDER << 16 |
14245				      KGEM_RELOC_FENCED,
14246				      0);
14247		b[6] = gc->bgPixel;
14248		b[7] = gc->fgPixel;
14249
14250		sna->kgem.nbatch += 8;
14251		kgem_bo_destroy(&sna->kgem, upload);
14252
14253		box++;
14254	} while (--n);
14255
14256	sna->blt_state.fill_bo = 0;
14257	return true;
14258}
14259
14260static void
14261sna_push_pixels(GCPtr gc, PixmapPtr bitmap, DrawablePtr drawable,
14262		int w, int h,
14263		int x, int y)
14264{
14265	RegionRec region;
14266
14267	if (w == 0 || h == 0)
14268		return;
14269
14270	DBG(("%s (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
14271
14272	region.extents.x1 = x;
14273	region.extents.y1 = y;
14274	region.extents.x2 = region.extents.x1 + w;
14275	region.extents.y2 = region.extents.y1 + h;
14276
14277	clip_box(&region.extents, gc);
14278	if (box_empty(&region.extents))
14279		return;
14280
14281	DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__,
14282	     region.extents.x1, region.extents.y1,
14283	     region.extents.x2, region.extents.y2));
14284
14285	region.data = NULL;
14286	region_maybe_clip(&region, gc->pCompositeClip);
14287	if (RegionNil(&region))
14288		return;
14289
14290	switch (gc->fillStyle) {
14291	case FillSolid:
14292		if (sna_push_pixels_solid_blt(gc, bitmap, drawable, &region))
14293			return;
14294		break;
14295	default:
14296		break;
14297	}
14298
14299	DBG(("%s: fallback\n", __FUNCTION__));
14300	if (!sna_gc_move_to_cpu(gc, drawable, &region))
14301		goto out;
14302	if (!sna_pixmap_move_to_cpu(bitmap, MOVE_READ))
14303		goto out_gc;
14304	if (!sna_drawable_move_region_to_cpu(drawable, &region,
14305					     drawable_gc_flags(drawable, gc, false)))
14306		goto out_gc;
14307
14308	DBG(("%s: fallback, fbPushPixels(%d, %d, %d %d)\n",
14309	     __FUNCTION__, w, h, x, y));
14310	fbPushPixels(gc, bitmap, drawable, w, h, x, y);
14311	FALLBACK_FLUSH(drawable);
14312out_gc:
14313	sna_gc_move_to_gpu(gc);
14314out:
14315	RegionUninit(&region);
14316}
14317
14318static const GCOps sna_gc_ops = {
14319	sna_fill_spans,
14320	sna_set_spans,
14321	sna_put_image,
14322	sna_copy_area,
14323	sna_copy_plane,
14324	sna_poly_point,
14325	sna_poly_line,
14326	sna_poly_segment,
14327	sna_poly_rectangle,
14328	sna_poly_arc,
14329	sna_poly_fill_polygon,
14330	sna_poly_fill_rect,
14331	sna_poly_fill_arc,
14332	sna_poly_text8,
14333	sna_poly_text16,
14334	sna_image_text8,
14335	sna_image_text16,
14336	sna_image_glyph,
14337	sna_poly_glyph,
14338	sna_push_pixels,
14339};
14340
14341static const GCOps sna_gc_ops__cpu = {
14342	fbFillSpans,
14343	fbSetSpans,
14344	fbPutImage,
14345	fbCopyArea,
14346	fbCopyPlane,
14347	sna_poly_point__cpu,
14348	fbPolyLine,
14349	fbPolySegment,
14350	miPolyRectangle,
14351	fbPolyArc,
14352	miFillPolygon,
14353	fbPolyFillRect,
14354	miPolyFillArc,
14355	miPolyText8,
14356	miPolyText16,
14357	miImageText8,
14358	miImageText16,
14359	fbImageGlyphBlt,
14360	fbPolyGlyphBlt,
14361	fbPushPixels
14362};
14363
14364static GCOps sna_gc_ops__tmp = {
14365	sna_fill_spans,
14366	sna_set_spans,
14367	sna_put_image,
14368	sna_copy_area,
14369	sna_copy_plane,
14370	sna_poly_point,
14371	sna_poly_line,
14372	sna_poly_segment,
14373	sna_poly_rectangle,
14374	sna_poly_arc,
14375	sna_poly_fill_polygon,
14376	sna_poly_fill_rect,
14377	sna_poly_fill_arc,
14378	sna_poly_text8,
14379	sna_poly_text16,
14380	sna_image_text8,
14381	sna_image_text16,
14382	sna_image_glyph,
14383	sna_poly_glyph,
14384	sna_push_pixels,
14385};
14386
14387static void
14388sna_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable)
14389{
14390	DBG(("%s changes=%lx\n", __FUNCTION__, changes));
14391
14392	if (changes & (GCClipMask|GCSubwindowMode) ||
14393	    drawable->serialNumber != (gc->serialNumber & DRAWABLE_SERIAL_BITS) ||
14394	    (gc->clientClipType != CT_NONE && (changes & (GCClipXOrigin | GCClipYOrigin))))
14395		miComputeCompositeClip(gc, drawable);
14396
14397	sna_gc(gc)->changes |= changes;
14398}
14399
14400static const GCFuncs sna_gc_funcs = {
14401	sna_validate_gc,
14402	miChangeGC,
14403	miCopyGC,
14404	miDestroyGC,
14405	miChangeClip,
14406	miDestroyClip,
14407	miCopyClip
14408};
14409
14410static const GCFuncs sna_gc_funcs__cpu = {
14411	fbValidateGC,
14412	miChangeGC,
14413	miCopyGC,
14414	miDestroyGC,
14415	miChangeClip,
14416	miDestroyClip,
14417	miCopyClip
14418};
14419
14420static int sna_create_gc(GCPtr gc)
14421{
14422	gc->miTranslate = 1;
14423	gc->fExpose = 1;
14424
14425	gc->freeCompClip = 0;
14426	gc->pCompositeClip = 0;
14427	gc->pRotatedPixmap = 0;
14428
14429	fb_gc(gc)->bpp = bits_per_pixel(gc->depth);
14430
14431	gc->funcs = (GCFuncs *)&sna_gc_funcs;
14432	gc->ops = (GCOps *)&sna_gc_ops;
14433	return true;
14434}
14435
14436static bool
14437sna_get_image_blt(PixmapPtr pixmap,
14438		  RegionPtr region,
14439		  char *dst,
14440		  unsigned flags)
14441{
14442	struct sna_pixmap *priv = sna_pixmap(pixmap);
14443	struct sna *sna = to_sna_from_pixmap(pixmap);
14444	struct kgem_bo *dst_bo;
14445	bool ok = false;
14446	int pitch;
14447
14448	if (priv == NULL)
14449		return false;
14450
14451	if (priv->clear) {
14452		int w = region->extents.x2 - region->extents.x1;
14453		int h = region->extents.y2 - region->extents.y1;
14454
14455		DBG(("%s: applying clear [%08x]\n",
14456		     __FUNCTION__, priv->clear_color));
14457		assert(DAMAGE_IS_ALL(priv->gpu_damage));
14458		assert(priv->cpu_damage == NULL);
14459
14460		pitch = PixmapBytePad(w, pixmap->drawable.depth);
14461		if (priv->clear_color == 0 ||
14462		    pixmap->drawable.bitsPerPixel == 8 ||
14463		    priv->clear_color == (1U << pixmap->drawable.depth) - 1) {
14464			DBG(("%s: memset clear [%02x]\n",
14465			     __FUNCTION__, priv->clear_color & 0xff));
14466			memset(dst, priv->clear_color, pitch * h);
14467		} else {
14468			pixman_fill((uint32_t *)dst,
14469				    pitch/sizeof(uint32_t),
14470				    pixmap->drawable.bitsPerPixel,
14471				    0, 0,
14472				    w, h,
14473				    priv->clear_color);
14474		}
14475
14476		return true;
14477	}
14478
14479	if (!sna->kgem.has_userptr || !USE_USERPTR_DOWNLOADS)
14480		return false;
14481
14482	if (!sna->kgem.can_blt_cpu)
14483		return false;
14484
14485	if (flags & (MOVE_WHOLE_HINT | MOVE_INPLACE_HINT))
14486		return false;
14487
14488	if (priv->gpu_damage == NULL)
14489		return false;
14490
14491	assert(priv->gpu_bo);
14492	if (!__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
14493		return false;
14494
14495	if (!DAMAGE_IS_ALL(priv->gpu_damage) &&
14496	    !sna_damage_contains_box__no_reduce(priv->gpu_damage,
14497						&region->extents))
14498		return false;
14499
14500	DBG(("%s: download through a temporary map\n", __FUNCTION__));
14501
14502	assert(sna_damage_contains_box(priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
14503	assert(sna_damage_contains_box(priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
14504
14505	pitch = PixmapBytePad(region->extents.x2 - region->extents.x1,
14506			      pixmap->drawable.depth);
14507	dst_bo = kgem_create_map(&sna->kgem, dst,
14508				 pitch * (region->extents.y2 - region->extents.y1),
14509				 false);
14510	if (dst_bo) {
14511		dst_bo->pitch = pitch;
14512		kgem_bo_mark_unreusable(dst_bo);
14513
14514		ok = sna->render.copy_boxes(sna, GXcopy,
14515					    pixmap, priv->gpu_bo, 0, 0,
14516					    pixmap, dst_bo,
14517					    -region->extents.x1,
14518					    -region->extents.y1,
14519					    &region->extents, 1,
14520					    COPY_LAST);
14521
14522		kgem_bo_sync__cpu(&sna->kgem, dst_bo);
14523		assert(dst_bo->rq == NULL);
14524		kgem_bo_destroy(&sna->kgem, dst_bo);
14525	}
14526
14527	return ok;
14528}
14529
14530static bool
14531sna_get_image_inplace(PixmapPtr pixmap,
14532		      RegionPtr region,
14533		      char *dst,
14534		      unsigned flags)
14535{
14536	struct sna_pixmap *priv = sna_pixmap(pixmap);
14537	struct sna *sna = to_sna_from_pixmap(pixmap);
14538	char *src;
14539
14540	if (!USE_INPLACE)
14541		return false;
14542
14543	if (priv == NULL || priv->gpu_bo == NULL)
14544		return false;
14545
14546	switch (priv->gpu_bo->tiling) {
14547	case I915_TILING_Y:
14548		return false;
14549	case I915_TILING_X:
14550		if (!sna->kgem.memcpy_from_tiled_x)
14551			return false;
14552	default:
14553		break;
14554	}
14555
14556	if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, false))
14557		return false;
14558
14559	if (priv->gpu_damage == NULL ||
14560	    !(DAMAGE_IS_ALL(priv->gpu_damage) ||
14561	      sna_damage_contains_box__no_reduce(priv->gpu_damage,
14562						 &region->extents)))
14563		return false;
14564
14565	assert(sna_damage_contains_box(priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
14566	assert(sna_damage_contains_box(priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
14567
14568	src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
14569	if (src == NULL)
14570		return false;
14571
14572	kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC);
14573
14574	if (priv->gpu_bo->tiling) {
14575		DBG(("%s: download through a tiled CPU map\n", __FUNCTION__));
14576		memcpy_from_tiled_x(&sna->kgem, src, dst,
14577				    pixmap->drawable.bitsPerPixel,
14578				    priv->gpu_bo->pitch,
14579				    PixmapBytePad(region->extents.x2 - region->extents.x1,
14580						  pixmap->drawable.depth),
14581				    region->extents.x1, region->extents.y1,
14582				    0, 0,
14583				    region->extents.x2 - region->extents.x1,
14584				    region->extents.y2 - region->extents.y1);
14585	} else {
14586		DBG(("%s: download through a linear CPU map\n", __FUNCTION__));
14587		memcpy_blt(src, dst,
14588			   pixmap->drawable.bitsPerPixel,
14589			   priv->gpu_bo->pitch,
14590			   PixmapBytePad(region->extents.x2 - region->extents.x1,
14591					 pixmap->drawable.depth),
14592			   region->extents.x1, region->extents.y1,
14593			   0, 0,
14594			   region->extents.x2 - region->extents.x1,
14595			   region->extents.y2 - region->extents.y1);
14596	}
14597
14598	if (!priv->shm) {
14599		pixmap->devPrivate.ptr = src;
14600		pixmap->devKind = priv->gpu_bo->pitch;
14601		priv->mapped = true;
14602		priv->cpu = true;
14603	}
14604
14605	return true;
14606}
14607
14608static void
14609sna_get_image(DrawablePtr drawable,
14610	      int x, int y, int w, int h,
14611	      unsigned int format, unsigned long mask,
14612	      char *dst)
14613{
14614	RegionRec region;
14615	unsigned int flags;
14616
14617	if (!fbDrawableEnabled(drawable))
14618		return;
14619
14620	DBG(("%s: pixmap=%ld (%d, %d)x(%d, %d), format=%d, mask=%lx, depth=%d\n",
14621	     __FUNCTION__,
14622	     (long)get_drawable_pixmap(drawable)->drawable.serialNumber,
14623	     x, y, w, h, format, mask, drawable->depth));
14624
14625	flags = MOVE_READ;
14626	if ((w | h) == 1)
14627		flags |= MOVE_INPLACE_HINT;
14628	if (w == drawable->width)
14629		flags |= MOVE_WHOLE_HINT;
14630
14631	if (ACCEL_GET_IMAGE &&
14632	    !FORCE_FALLBACK &&
14633	    format == ZPixmap &&
14634	    drawable->bitsPerPixel >= 8 &&
14635	    PM_IS_SOLID(drawable, mask)) {
14636		PixmapPtr pixmap = get_drawable_pixmap(drawable);
14637		int16_t dx, dy;
14638
14639		get_drawable_deltas(drawable, pixmap, &dx, &dy);
14640		region.extents.x1 = x + drawable->x + dx;
14641		region.extents.y1 = y + drawable->y + dy;
14642		region.extents.x2 = region.extents.x1 + w;
14643		region.extents.y2 = region.extents.y1 + h;
14644		region.data = NULL;
14645
14646		if (sna_get_image_blt(pixmap, &region, dst, flags))
14647			return;
14648
14649		if (sna_get_image_inplace(pixmap, &region, dst, flags))
14650			return;
14651
14652		if (!sna_drawable_move_region_to_cpu(&pixmap->drawable,
14653						     &region, flags))
14654			return;
14655
14656		DBG(("%s: copy box (%d, %d), (%d, %d)\n",
14657		     __FUNCTION__,
14658		     region.extents.x1, region.extents.y1,
14659		     region.extents.x2, region.extents.y2));
14660		assert(has_coherent_ptr(sna_pixmap(pixmap)));
14661		memcpy_blt(pixmap->devPrivate.ptr, dst, drawable->bitsPerPixel,
14662			   pixmap->devKind, PixmapBytePad(w, drawable->depth),
14663			   region.extents.x1, region.extents.y1, 0, 0, w, h);
14664	} else {
14665		region.extents.x1 = x + drawable->x;
14666		region.extents.y1 = y + drawable->y;
14667		region.extents.x2 = region.extents.x1 + w;
14668		region.extents.y2 = region.extents.y1 + h;
14669		region.data = NULL;
14670
14671		if (sna_drawable_move_region_to_cpu(drawable, &region, flags))
14672			fbGetImage(drawable, x, y, w, h, format, mask, dst);
14673	}
14674}
14675
14676static void
14677sna_get_spans(DrawablePtr drawable, int wMax,
14678	      DDXPointPtr pt, int *width, int n, char *start)
14679{
14680	RegionRec region;
14681
14682	if (!fbDrawableEnabled(drawable))
14683		return;
14684
14685	if (sna_spans_extents(drawable, NULL, n, pt, width, &region.extents) == 0)
14686		return;
14687
14688	region.data = NULL;
14689	if (!sna_drawable_move_region_to_cpu(drawable, &region, MOVE_READ))
14690		return;
14691
14692	fbGetSpans(drawable, wMax, pt, width, n, start);
14693}
14694
14695static void
14696sna_copy_window(WindowPtr win, DDXPointRec origin, RegionPtr src)
14697{
14698	PixmapPtr pixmap = get_window_pixmap(win);
14699	struct sna *sna = to_sna_from_pixmap(pixmap);
14700	RegionRec dst;
14701	int dx, dy;
14702
14703	DBG(("%s origin=(%d, %d)\n", __FUNCTION__, origin.x, origin.y));
14704	if (!fbWindowEnabled(win))
14705		return;
14706
14707	dx = origin.x - win->drawable.x;
14708	dy = origin.y - win->drawable.y;
14709	RegionTranslate(src, -dx, -dy);
14710
14711	RegionNull(&dst);
14712	RegionIntersect(&dst, &win->borderClip, src);
14713	if (RegionNil(&dst))
14714		return;
14715
14716#ifdef COMPOSITE
14717	if (pixmap->screen_x | pixmap->screen_y)
14718		RegionTranslate(&dst, -pixmap->screen_x, -pixmap->screen_y);
14719#endif
14720
14721	if (wedged(sna) || FORCE_FALLBACK || !ACCEL_COPY_WINDOW) {
14722		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
14723		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE))
14724			return;
14725
14726		miCopyRegion(&pixmap->drawable, &pixmap->drawable,
14727			     0, &dst, dx, dy, fbCopyNtoN, 0, NULL);
14728	} else {
14729		sna_self_copy_boxes(&pixmap->drawable, &pixmap->drawable, NULL,
14730				    &dst, dx, dy, 0, NULL);
14731	}
14732
14733	RegionUninit(&dst);
14734}
14735
14736static Bool sna_change_window_attributes(WindowPtr win, unsigned long mask)
14737{
14738	bool ret = true;
14739
14740	DBG(("%s\n", __FUNCTION__));
14741
14742	/* Check if the fb layer wishes to modify the attached pixmaps,
14743	 * to fix up mismatches between the window and pixmap depths.
14744	 */
14745	if (mask & CWBackPixmap && win->backgroundState == BackgroundPixmap) {
14746		DBG(("%s: flushing background pixmap\n", __FUNCTION__));
14747		ret &= sna_validate_pixmap(&win->drawable, win->background.pixmap);
14748	}
14749
14750	if (mask & CWBorderPixmap && win->borderIsPixel == false) {
14751		DBG(("%s: flushing border pixmap\n", __FUNCTION__));
14752		ret &= sna_validate_pixmap(&win->drawable, win->border.pixmap);
14753	}
14754
14755	return ret;
14756}
14757
14758static void
14759sna_accel_flush_callback(CallbackListPtr *list,
14760			 pointer user_data, pointer call_data)
14761{
14762	struct sna *sna = user_data;
14763	struct sna_pixmap *priv;
14764
14765	/* XXX we should be able to reduce the frequency of flushes further
14766	 * by checking for outgoing damage events or sync replies. Tricky,
14767	 * and doesn't appear to mitigate the performance loss.
14768	 */
14769	DBG(("%s: flush?=%d, dirty?=%d\n", __FUNCTION__,
14770	     sna->kgem.flush, !list_is_empty(&sna->flush_pixmaps)));
14771
14772	/* flush any pending damage from shadow copies to tfp clients */
14773	while (!list_is_empty(&sna->flush_pixmaps)) {
14774		bool ret;
14775
14776		priv = list_first_entry(&sna->flush_pixmaps,
14777					struct sna_pixmap, flush_list);
14778
14779		list_del(&priv->flush_list);
14780		if (priv->shm) {
14781			DBG(("%s: syncing SHM pixmap=%ld (refcnt=%d)\n",
14782			     __FUNCTION__,
14783			     priv->pixmap->drawable.serialNumber,
14784			     priv->pixmap->refcnt));
14785			assert(!priv->flush);
14786			ret = sna_pixmap_move_to_cpu(priv->pixmap,
14787						     MOVE_READ | MOVE_WRITE);
14788			assert(!ret || priv->gpu_bo == NULL);
14789			if (priv->pixmap->refcnt == 0) {
14790				sna_damage_destroy(&priv->cpu_damage);
14791				__sna_free_pixmap(sna, priv->pixmap, priv);
14792			}
14793		} else {
14794			DBG(("%s: flushing DRI pixmap=%ld\n", __FUNCTION__,
14795			     priv->pixmap->drawable.serialNumber));
14796			assert(priv->flush);
14797			if (sna_pixmap_move_to_gpu(priv->pixmap,
14798						   MOVE_READ | __MOVE_FORCE))
14799				kgem_bo_unclean(&sna->kgem, priv->gpu_bo);
14800		}
14801		(void)ret;
14802	}
14803
14804	if (sna->kgem.flush)
14805		kgem_submit(&sna->kgem);
14806}
14807
14808static struct sna_pixmap *sna_accel_scanout(struct sna *sna)
14809{
14810	struct sna_pixmap *priv;
14811
14812	if (sna->vblank_interval == 0)
14813		return NULL;
14814
14815	if (sna->front == NULL)
14816		return NULL;
14817
14818	priv = sna_pixmap(sna->front);
14819	return priv && priv->gpu_bo ? priv : NULL;
14820}
14821
14822#define TIME currentTime.milliseconds
14823static void sna_accel_disarm_timer(struct sna *sna, int id)
14824{
14825	DBG(("%s[%d] (time=%ld)\n", __FUNCTION__, id, (long)TIME));
14826	sna->timer_active &= ~(1<<id);
14827}
14828
14829static bool has_offload_slaves(struct sna *sna)
14830{
14831#if HAS_PIXMAP_SHARING
14832	ScreenPtr screen = sna->scrn->pScreen;
14833	PixmapDirtyUpdatePtr dirty;
14834
14835	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
14836		assert(dirty->src == sna->front);
14837		if (RegionNotEmpty(DamageRegion(dirty->damage)))
14838			return true;
14839	}
14840#endif
14841	return false;
14842}
14843
14844static bool has_shadow(struct sna *sna)
14845{
14846	DamagePtr damage = sna->mode.shadow_damage;
14847
14848	if (!(damage && RegionNotEmpty(DamageRegion(damage))))
14849		return false;
14850
14851	DBG(("%s: has pending damage\n", __FUNCTION__));
14852	if ((sna->flags & SNA_TEAR_FREE) == 0)
14853		return true;
14854
14855	DBG(("%s: outstanding flips: %d\n",
14856	     __FUNCTION__, sna->mode.shadow_flip));
14857	return !sna->mode.shadow_flip;
14858}
14859
14860static bool start_flush(struct sna *sna, struct sna_pixmap *scanout)
14861{
14862	DBG(("%s: scanout=%d shadow?=%d, slaves?=%d, (cpu?=%d || gpu?=%d))\n",
14863	     __FUNCTION__,
14864	     scanout && scanout->gpu_bo ? scanout->gpu_bo->handle : 0,
14865	     has_shadow(sna), has_offload_slaves(sna),
14866	     scanout && scanout->cpu_damage != NULL,
14867	     scanout && scanout->gpu_bo && scanout->gpu_bo->exec != NULL));
14868
14869	if (has_offload_slaves(sna))
14870		return true;
14871
14872	if (has_shadow(sna))
14873		return true;
14874
14875	if (!scanout)
14876		return false;
14877
14878	if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) {
14879		scanout->gpu_bo->needs_flush = true;
14880		return true;
14881	}
14882
14883	return scanout->cpu_damage || scanout->gpu_bo->exec;
14884}
14885
14886static bool stop_flush(struct sna *sna, struct sna_pixmap *scanout)
14887{
14888	DBG(("%s: scanout=%d shadow?=%d, slaves?=%d, (cpu?=%d || gpu?=%d))\n",
14889	     __FUNCTION__,
14890	     scanout && scanout->gpu_bo ? scanout->gpu_bo->handle : 0,
14891	     has_shadow(sna), has_offload_slaves(sna),
14892	     scanout && scanout->cpu_damage != NULL,
14893	     scanout && scanout->gpu_bo && scanout->gpu_bo->rq != NULL));
14894
14895	if (has_offload_slaves(sna))
14896		return true;
14897
14898	if (has_shadow(sna))
14899		return true;
14900
14901	if (!scanout)
14902		return false;
14903
14904	if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) {
14905		scanout->gpu_bo->needs_flush = true;
14906		return true;
14907	}
14908
14909	return scanout->cpu_damage || scanout->gpu_bo->needs_flush;
14910}
14911
14912static void timer_enable(struct sna *sna, int whom, int interval)
14913{
14914	if (!sna->timer_active)
14915		UpdateCurrentTimeIf();
14916	sna->timer_active |= 1 << whom;
14917	sna->timer_expire[whom] = TIME + interval;
14918	DBG(("%s (time=%ld), starting timer %d\n", __FUNCTION__, (long)TIME, whom));
14919}
14920
14921static bool sna_accel_do_flush(struct sna *sna)
14922{
14923	struct sna_pixmap *priv;
14924	int interval;
14925
14926	priv = sna_accel_scanout(sna);
14927	if (priv == NULL && !sna->mode.shadow_active && !has_offload_slaves(sna)) {
14928		DBG(("%s -- no scanout attached\n", __FUNCTION__));
14929		sna_accel_disarm_timer(sna, FLUSH_TIMER);
14930		return false;
14931	}
14932
14933	interval = sna->vblank_interval ?: 20;
14934	if (sna->timer_active & (1<<(FLUSH_TIMER))) {
14935		int32_t delta = sna->timer_expire[FLUSH_TIMER] - TIME;
14936		DBG(("%s: flush timer active: delta=%d\n",
14937		     __FUNCTION__, delta));
14938		if (delta <= 3) {
14939			DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME));
14940			sna->timer_expire[FLUSH_TIMER] = TIME + interval;
14941			return true;
14942		}
14943	} else if (!start_flush(sna, priv)) {
14944		DBG(("%s -- no pending write to scanout\n", __FUNCTION__));
14945		if (priv)
14946			kgem_scanout_flush(&sna->kgem, priv->gpu_bo);
14947	} else
14948		timer_enable(sna, FLUSH_TIMER, interval/2);
14949
14950	return false;
14951}
14952
14953static bool sna_accel_do_throttle(struct sna *sna)
14954{
14955	if (sna->timer_active & (1<<(THROTTLE_TIMER))) {
14956		int32_t delta = sna->timer_expire[THROTTLE_TIMER] - TIME;
14957		if (delta <= 3) {
14958			DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME));
14959			sna->timer_expire[THROTTLE_TIMER] = TIME + 20;
14960			return true;
14961		}
14962	} else if (!sna->kgem.need_retire) {
14963		DBG(("%s -- no pending activity\n", __FUNCTION__));
14964	} else
14965		timer_enable(sna, THROTTLE_TIMER, 20);
14966
14967	return false;
14968}
14969
14970static bool sna_accel_do_expire(struct sna *sna)
14971{
14972	if (sna->timer_active & (1<<(EXPIRE_TIMER))) {
14973		int32_t delta = sna->timer_expire[EXPIRE_TIMER] - TIME;
14974		if (delta <= 3) {
14975			DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME));
14976			sna->timer_expire[EXPIRE_TIMER] =
14977				TIME + MAX_INACTIVE_TIME * 1000;
14978			return true;
14979		}
14980	} else if (sna->kgem.need_expire)
14981		timer_enable(sna, EXPIRE_TIMER, MAX_INACTIVE_TIME * 1000);
14982
14983	return false;
14984}
14985
14986static void sna_accel_post_damage(struct sna *sna)
14987{
14988#if HAS_PIXMAP_SHARING
14989	ScreenPtr screen = sna->scrn->pScreen;
14990	PixmapDirtyUpdatePtr dirty;
14991	bool flush = false;
14992
14993	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
14994		RegionRec region, *damage;
14995		PixmapPtr src, dst;
14996		BoxPtr box;
14997		int n;
14998
14999		assert(dirty->src == sna->front);
15000
15001		damage = DamageRegion(dirty->damage);
15002		if (RegionNil(damage))
15003			continue;
15004
15005		src = dirty->src;
15006		dst = dirty->slave_dst->master_pixmap;
15007
15008		region.extents.x1 = dirty->x;
15009		region.extents.x2 = dirty->x + dst->drawable.width;
15010		region.extents.y1 = dirty->y;
15011		region.extents.y2 = dirty->y + dst->drawable.height;
15012		region.data = NULL;
15013
15014		DBG(("%s: pushing damage ((%d, %d), (%d, %d))x%d to slave pixmap=%ld, ((%d, %d), (%d, %d))\n", __FUNCTION__,
15015		     damage->extents.x1, damage->extents.y1,
15016		     damage->extents.x2, damage->extents.y2,
15017		     RegionNumRects(damage),
15018		     dst->drawable.serialNumber,
15019		     region.extents.x1, region.extents.y1,
15020		     region.extents.x2, region.extents.y2));
15021
15022		RegionIntersect(&region, &region, damage);
15023		if (RegionNil(&region))
15024			goto skip;
15025
15026		RegionTranslate(&region, -dirty->x, -dirty->y);
15027		DamageRegionAppend(&dirty->slave_dst->drawable, &region);
15028
15029		DBG(("%s: slave:  ((%d, %d), (%d, %d))x%d\n", __FUNCTION__,
15030		     region.extents.x1, region.extents.y1,
15031		     region.extents.x2, region.extents.y2,
15032		     RegionNumRects(&region)));
15033
15034		box = RegionRects(&region);
15035		n = RegionNumRects(&region);
15036		if (wedged(sna)) {
15037fallback:
15038			if (!sna_pixmap_move_to_cpu(src, MOVE_READ))
15039				goto skip;
15040
15041			if (!sna_pixmap_move_to_cpu(dst, MOVE_READ | MOVE_WRITE | MOVE_INPLACE_HINT))
15042				goto skip;
15043
15044			assert(src->drawable.bitsPerPixel == dst->drawable.bitsPerPixel);
15045			do {
15046				DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n",
15047				     __FUNCTION__,
15048				     box->x1 + dirty->x, box->y1 + dirty->y,
15049				     box->x1, box->y1,
15050				     box->x2 - box->x1, box->y2 - box->y1));
15051
15052				assert(box->x2 > box->x1);
15053				assert(box->y2 > box->y1);
15054
15055				assert(box->x1 + dirty->x >= 0);
15056				assert(box->y1 + dirty->y >= 0);
15057				assert(box->x2 + dirty->x <= src->drawable.width);
15058				assert(box->y2 + dirty->y <= src->drawable.height);
15059
15060				assert(box->x1 >= 0);
15061				assert(box->y1 >= 0);
15062				assert(box->x2 <= src->drawable.width);
15063				assert(box->y2 <= src->drawable.height);
15064
15065				assert(has_coherent_ptr(sna_pixmap(src)));
15066				assert(has_coherent_ptr(sna_pixmap(dst)));
15067				memcpy_blt(src->devPrivate.ptr,
15068					   dst->devPrivate.ptr,
15069					   src->drawable.bitsPerPixel,
15070					   src->devKind, dst->devKind,
15071					   box->x1 + dirty->x,
15072					   box->y1 + dirty->y,
15073					   box->x1,
15074					   box->y1,
15075					   box->x2 - box->x1,
15076					   box->y2 - box->y1);
15077				box++;
15078			} while (--n);
15079		} else {
15080			if (!sna_pixmap_move_to_gpu(src, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE))
15081				goto fallback;
15082
15083			if (!sna_pixmap_move_to_gpu(dst, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE))
15084				goto fallback;
15085
15086			if (!sna->render.copy_boxes(sna, GXcopy,
15087						    src, __sna_pixmap_get_bo(src), dirty->x, dirty->y,
15088						    dst, __sna_pixmap_get_bo(dst),0, 0,
15089						    box, n, COPY_LAST))
15090				goto fallback;
15091
15092			flush = true;
15093		}
15094
15095		DamageRegionProcessPending(&dirty->slave_dst->drawable);
15096skip:
15097		RegionUninit(&region);
15098		DamageEmpty(dirty->damage);
15099	}
15100	if (flush)
15101		kgem_submit(&sna->kgem);
15102#endif
15103}
15104
15105static void sna_accel_flush(struct sna *sna)
15106{
15107	struct sna_pixmap *priv = sna_accel_scanout(sna);
15108	bool busy;
15109
15110	DBG(("%s (time=%ld), cpu damage? %d, exec? %d nbatch=%d, busy? %d\n",
15111	     __FUNCTION__, (long)TIME,
15112	     priv && priv->cpu_damage,
15113	     priv && priv->gpu_bo->exec != NULL,
15114	     sna->kgem.nbatch,
15115	     sna->kgem.busy));
15116
15117	busy = stop_flush(sna, priv);
15118	if (!sna->kgem.busy && !busy)
15119		sna_accel_disarm_timer(sna, FLUSH_TIMER);
15120	sna->kgem.busy = busy;
15121
15122	if (priv) {
15123		sna_pixmap_force_to_gpu(priv->pixmap,
15124					MOVE_READ | MOVE_ASYNC_HINT);
15125		kgem_scanout_flush(&sna->kgem, priv->gpu_bo);
15126		assert(!priv->cpu);
15127	}
15128
15129	sna_mode_redisplay(sna);
15130	sna_accel_post_damage(sna);
15131}
15132
15133static void sna_accel_throttle(struct sna *sna)
15134{
15135	DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME));
15136
15137	if (sna->kgem.need_throttle) {
15138		kgem_submit(&sna->kgem);
15139		kgem_throttle(&sna->kgem);
15140	}
15141
15142	if (!sna->kgem.need_retire)
15143		sna_accel_disarm_timer(sna, THROTTLE_TIMER);
15144}
15145
15146static void sna_accel_expire(struct sna *sna)
15147{
15148	DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME));
15149
15150	if (!kgem_expire_cache(&sna->kgem))
15151		sna_accel_disarm_timer(sna, EXPIRE_TIMER);
15152}
15153
15154#ifdef DEBUG_MEMORY
15155static bool sna_accel_do_debug_memory(struct sna *sna)
15156{
15157	int32_t delta = sna->timer_expire[DEBUG_MEMORY_TIMER] - TIME;
15158
15159	if (delta <= 3) {
15160		sna->timer_expire[DEBUG_MEMORY_TIMER] = TIME + 10 * 1000;
15161		return true;
15162	} else
15163		return false;
15164}
15165
15166static void sna_accel_debug_memory(struct sna *sna)
15167{
15168	ErrorF("Allocated pixmaps: %d\n",
15169	       sna->debug_memory.pixmap_allocs);
15170	ErrorF("Allocated bo: %d, %ld bytes\n",
15171	       sna->kgem.debug_memory.bo_allocs,
15172	       (long)sna->kgem.debug_memory.bo_bytes);
15173	ErrorF("Allocated CPU bo: %d, %ld bytes\n",
15174	       sna->debug_memory.cpu_bo_allocs,
15175	       (long)sna->debug_memory.cpu_bo_bytes);
15176}
15177
15178#else
15179#define sna_accel_do_debug_memory(x) 0
15180static void sna_accel_debug_memory(struct sna *sna) { }
15181#endif
15182
15183static ShmFuncs shm_funcs = { sna_pixmap_create_shm, NULL };
15184
15185static PixmapPtr
15186sna_get_window_pixmap(WindowPtr window)
15187{
15188	return get_window_pixmap(window);
15189}
15190
15191static void
15192sna_set_window_pixmap(WindowPtr window, PixmapPtr pixmap)
15193{
15194	*(PixmapPtr *)__get_private(window, sna_window_key) = pixmap;
15195}
15196
15197struct sna_visit_set_pixmap_window {
15198	PixmapPtr old, new;
15199};
15200
15201static int
15202sna_visit_set_window_pixmap(WindowPtr window, pointer data)
15203{
15204    struct sna_visit_set_pixmap_window *visit = data;
15205
15206    if (fbGetWindowPixmap(window) == visit->old) {
15207	    window->drawable.pScreen->SetWindowPixmap(window, visit->new);
15208	    return WT_WALKCHILDREN;
15209    }
15210
15211    return WT_DONTWALKCHILDREN;
15212}
15213
15214static void
15215migrate_dirty_tracking(PixmapPtr old_front, PixmapPtr new_front)
15216{
15217#if HAS_PIXMAP_SHARING
15218	ScreenPtr screen = old_front->drawable.pScreen;
15219	PixmapDirtyUpdatePtr dirty, safe;
15220
15221	xorg_list_for_each_entry_safe(dirty, safe, &screen->pixmap_dirty_list, ent) {
15222		assert(dirty->src == old_front);
15223		if (dirty->src != old_front)
15224			continue;
15225
15226		DamageUnregister(&dirty->src->drawable, dirty->damage);
15227		DamageDestroy(dirty->damage);
15228
15229		dirty->damage = DamageCreate(NULL, NULL,
15230					     DamageReportNone,
15231					     TRUE, screen, screen);
15232		if (!dirty->damage) {
15233			xorg_list_del(&dirty->ent);
15234			free(dirty);
15235			continue;
15236		}
15237
15238		DamageRegister(&new_front->drawable, dirty->damage);
15239		dirty->src = new_front;
15240	}
15241#endif
15242}
15243
15244static void
15245sna_set_screen_pixmap(PixmapPtr pixmap)
15246{
15247	PixmapPtr old_front = pixmap->drawable.pScreen->devPrivate;
15248	WindowPtr root;
15249
15250	assert(pixmap == to_sna_from_pixmap(pixmap)->front);
15251
15252	if (old_front)
15253		migrate_dirty_tracking(old_front, pixmap);
15254
15255	root = get_root_window(pixmap->drawable.pScreen);
15256	if (root) {
15257		struct sna_visit_set_pixmap_window visit;
15258
15259		visit.old = old_front;
15260		visit.new = pixmap;
15261		TraverseTree(root, sna_visit_set_window_pixmap, &visit);
15262		assert(fbGetWindowPixmap(root) == pixmap);
15263	}
15264
15265	pixmap->drawable.pScreen->devPrivate = pixmap;
15266}
15267
15268static Bool
15269sna_create_window(WindowPtr win)
15270{
15271	sna_set_window_pixmap(win, win->drawable.pScreen->devPrivate);
15272	return TRUE;
15273}
15274
15275static Bool
15276sna_map_window(WindowPtr win)
15277{
15278	return TRUE;
15279}
15280
15281static Bool
15282sna_position_window(WindowPtr win, int x, int y)
15283{
15284	return TRUE;
15285}
15286
15287static Bool
15288sna_unmap_window(WindowPtr win)
15289{
15290	return TRUE;
15291}
15292
15293static Bool
15294sna_destroy_window(WindowPtr win)
15295{
15296	sna_video_destroy_window(win);
15297	sna_dri_destroy_window(win);
15298	return TRUE;
15299}
15300
15301static void
15302sna_query_best_size(int class,
15303		    unsigned short *width, unsigned short *height,
15304		    ScreenPtr screen)
15305{
15306	unsigned short w;
15307
15308	switch (class) {
15309	case CursorShape:
15310		if (*width > screen->width)
15311			*width = screen->width;
15312		if (*height > screen->height)
15313			*height = screen->height;
15314		break;
15315
15316	case TileShape:
15317	case StippleShape:
15318		w = *width;
15319		if ((w & (w - 1)) && w < FB_UNIT) {
15320			for (w = 1; w < *width; w <<= 1)
15321				;
15322			*width = w;
15323		}
15324		break;
15325	}
15326}
15327
15328static void sna_store_colors(ColormapPtr cmap, int n, xColorItem *def)
15329{
15330}
15331
15332static bool sna_picture_init(ScreenPtr screen)
15333{
15334	PictureScreenPtr ps;
15335
15336	DBG(("%s\n", __FUNCTION__));
15337
15338	if (!miPictureInit(screen, NULL, 0))
15339		return false;
15340
15341	ps = GetPictureScreen(screen);
15342	assert(ps != NULL);
15343	assert(ps->CreatePicture != NULL);
15344	assert(ps->DestroyPicture != NULL);
15345
15346	ps->Composite = sna_composite;
15347	ps->CompositeRects = sna_composite_rectangles;
15348	ps->Glyphs = sna_glyphs;
15349	if (xf86IsEntityShared(xf86ScreenToScrn(screen)->entityList[0]))
15350		ps->Glyphs = sna_glyphs__shared;
15351	ps->UnrealizeGlyph = sna_glyph_unrealize;
15352	ps->AddTraps = sna_add_traps;
15353	ps->Trapezoids = sna_composite_trapezoids;
15354#if HAS_PIXMAN_TRIANGLES
15355	ps->Triangles = sna_composite_triangles;
15356#if PICTURE_SCREEN_VERSION >= 2
15357	ps->TriStrip = sna_composite_tristrip;
15358	ps->TriFan = sna_composite_trifan;
15359#endif
15360#endif
15361
15362	return true;
15363}
15364
15365static bool sna_option_accel_blt(struct sna *sna)
15366{
15367	const char *s;
15368
15369	s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD);
15370	if (s == NULL)
15371		return false;
15372
15373	return strcasecmp(s, "blt") == 0;
15374}
15375
15376bool sna_accel_init(ScreenPtr screen, struct sna *sna)
15377{
15378	const char *backend;
15379
15380	DBG(("%s\n", __FUNCTION__));
15381
15382	sna_font_key = AllocateFontPrivateIndex();
15383
15384	list_init(&sna->flush_pixmaps);
15385	list_init(&sna->active_pixmaps);
15386
15387	AddGeneralSocket(sna->kgem.fd);
15388
15389#ifdef DEBUG_MEMORY
15390	sna->timer_expire[DEBUG_MEMORY_TIMER] = GetTimeInMillis()+ 10 * 1000;
15391#endif
15392
15393	screen->defColormap = FakeClientID(0);
15394	/* let CreateDefColormap do whatever it wants for pixels */
15395	screen->blackPixel = screen->whitePixel = (Pixel) 0;
15396	screen->QueryBestSize = sna_query_best_size;
15397	assert(screen->GetImage == NULL);
15398	screen->GetImage = sna_get_image;
15399	assert(screen->GetSpans == NULL);
15400	screen->GetSpans = sna_get_spans;
15401	assert(screen->CreateWindow == NULL);
15402	screen->CreateWindow = sna_create_window;
15403	assert(screen->DestroyWindow == NULL);
15404	screen->DestroyWindow = sna_destroy_window;
15405	screen->PositionWindow = sna_position_window;
15406	screen->ChangeWindowAttributes = sna_change_window_attributes;
15407	screen->RealizeWindow = sna_map_window;
15408	screen->UnrealizeWindow = sna_unmap_window;
15409	screen->CopyWindow = sna_copy_window;
15410	assert(screen->CreatePixmap == NULL);
15411	screen->CreatePixmap = sna_create_pixmap;
15412	assert(screen->DestroyPixmap == NULL);
15413	screen->DestroyPixmap = sna_destroy_pixmap;
15414#ifdef CREATE_PIXMAP_USAGE_SHARED
15415	screen->SharePixmapBacking = sna_share_pixmap_backing;
15416	screen->SetSharedPixmapBacking = sna_set_shared_pixmap_backing;
15417#endif
15418	screen->RealizeFont = sna_realize_font;
15419	screen->UnrealizeFont = sna_unrealize_font;
15420	assert(screen->CreateGC == NULL);
15421	screen->CreateGC = sna_create_gc;
15422	screen->CreateColormap = miInitializeColormap;
15423	screen->DestroyColormap = (void (*)(ColormapPtr)) NoopDDA;
15424	screen->InstallColormap = miInstallColormap;
15425	screen->UninstallColormap = miUninstallColormap;
15426	screen->ListInstalledColormaps = miListInstalledColormaps;
15427	screen->ResolveColor = miResolveColor;
15428	assert(screen->StoreColors == NULL);
15429	screen->StoreColors = sna_store_colors;
15430	screen->BitmapToRegion = fbBitmapToRegion;
15431
15432#if HAS_PIXMAP_SHARING
15433	screen->StartPixmapTracking = PixmapStartDirtyTracking;
15434	screen->StopPixmapTracking = PixmapStopDirtyTracking;
15435#endif
15436
15437	assert(screen->GetWindowPixmap == NULL);
15438	screen->GetWindowPixmap = sna_get_window_pixmap;
15439	assert(screen->SetWindowPixmap == NULL);
15440	screen->SetWindowPixmap = sna_set_window_pixmap;
15441
15442	screen->SetScreenPixmap = sna_set_screen_pixmap;
15443
15444	if (sna->kgem.has_userptr)
15445		ShmRegisterFuncs(screen, &shm_funcs);
15446	else
15447		ShmRegisterFbFuncs(screen);
15448
15449	if (!sna_picture_init(screen))
15450		return false;
15451
15452	backend = no_render_init(sna);
15453	if (sna_option_accel_blt(sna) || sna->info->gen >= 0100)
15454		(void)backend;
15455	else if (sna->info->gen >= 070)
15456		backend = gen7_render_init(sna, backend);
15457	else if (sna->info->gen >= 060)
15458		backend = gen6_render_init(sna, backend);
15459	else if (sna->info->gen >= 050)
15460		backend = gen5_render_init(sna, backend);
15461	else if (sna->info->gen >= 040)
15462		backend = gen4_render_init(sna, backend);
15463	else if (sna->info->gen >= 030)
15464		backend = gen3_render_init(sna, backend);
15465	else if (sna->info->gen >= 020)
15466		backend = gen2_render_init(sna, backend);
15467
15468	DBG(("%s(backend=%s, prefer_gpu=%x)\n",
15469	     __FUNCTION__, backend, sna->render.prefer_gpu));
15470
15471	kgem_reset(&sna->kgem);
15472
15473	xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
15474		   "SNA initialized with %s backend\n",
15475		   backend);
15476
15477	return true;
15478}
15479
15480void sna_accel_create(struct sna *sna)
15481{
15482	DBG(("%s\n", __FUNCTION__));
15483
15484	if (!sna_glyphs_create(sna))
15485		goto fail;
15486
15487	if (!sna_gradients_create(sna))
15488		goto fail;
15489
15490	if (!sna_composite_create(sna))
15491		goto fail;
15492
15493	return;
15494
15495fail:
15496	xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
15497		   "Failed to allocate caches, disabling RENDER acceleration\n");
15498	no_render_init(sna);
15499}
15500
15501void sna_accel_watch_flush(struct sna *sna, int enable)
15502{
15503	DBG(("%s: enable=%d\n", __FUNCTION__, enable));
15504	assert(enable);
15505
15506	if (sna->watch_flush == 0) {
15507		DBG(("%s: installing watchers\n", __FUNCTION__));
15508		assert(enable > 0);
15509		if (!AddCallback(&FlushCallback, sna_accel_flush_callback, sna)) {
15510			xf86DrvMsg(sna->scrn->scrnIndex, X_Error,
15511				   "Failed to attach ourselves to the flush callbacks, expect missing synchronisation with DRI clients (e.g a compositor)\n");
15512		}
15513		sna->watch_flush++;
15514	}
15515
15516	sna->watch_flush += enable;
15517}
15518
15519void sna_accel_close(struct sna *sna)
15520{
15521	DBG(("%s\n", __FUNCTION__));
15522
15523	sna_composite_close(sna);
15524	sna_gradients_close(sna);
15525	sna_glyphs_close(sna);
15526
15527	while (sna->freed_pixmap) {
15528		PixmapPtr pixmap = sna->freed_pixmap;
15529		sna->freed_pixmap = pixmap->devPrivate.ptr;
15530		assert(pixmap->refcnt == 0);
15531		free(sna_pixmap(pixmap));
15532		FreePixmap(pixmap);
15533	}
15534
15535	DeleteCallback(&FlushCallback, sna_accel_flush_callback, sna);
15536	RemoveGeneralSocket(sna->kgem.fd);
15537
15538	kgem_cleanup_cache(&sna->kgem);
15539}
15540
15541void sna_accel_block_handler(struct sna *sna, struct timeval **tv)
15542{
15543	if (sna->kgem.need_retire)
15544		kgem_retire(&sna->kgem);
15545
15546	if (sna->timer_active)
15547		UpdateCurrentTimeIf();
15548
15549	if (sna->kgem.nbatch &&
15550	    (sna->kgem.scanout_busy ||
15551	     kgem_ring_is_idle(&sna->kgem, sna->kgem.ring))) {
15552		DBG(("%s: GPU idle, flushing\n", __FUNCTION__));
15553		_kgem_submit(&sna->kgem);
15554	}
15555
15556	if (sna_accel_do_flush(sna))
15557		sna_accel_flush(sna);
15558	assert(sna_accel_scanout(sna) == NULL ||
15559	       sna_accel_scanout(sna)->gpu_bo->exec == NULL ||
15560	       sna->timer_active & (1<<(FLUSH_TIMER)));
15561
15562	if (sna_accel_do_throttle(sna))
15563		sna_accel_throttle(sna);
15564	assert(!sna->kgem.need_retire ||
15565	       sna->timer_active & (1<<(THROTTLE_TIMER)));
15566
15567	if (sna_accel_do_expire(sna))
15568		sna_accel_expire(sna);
15569	assert(!sna->kgem.need_expire ||
15570	       sna->timer_active & (1<<(EXPIRE_TIMER)));
15571
15572	if (sna_accel_do_debug_memory(sna))
15573		sna_accel_debug_memory(sna);
15574
15575	if (sna->watch_flush == 1) {
15576		DBG(("%s: removing watchers\n", __FUNCTION__));
15577		DeleteCallback(&FlushCallback, sna_accel_flush_callback, sna);
15578		sna->watch_flush = 0;
15579	}
15580
15581	if (sna->timer_active & 1) {
15582		int32_t timeout;
15583
15584		DBG(("%s: evaluating timers, active=%x\n",
15585		     __FUNCTION__, sna->timer_active));
15586
15587		timeout = sna->timer_expire[0] - TIME;
15588		DBG(("%s: flush timer expires in %d [%d]\n",
15589		     __FUNCTION__, timeout, sna->timer_expire[0]));
15590
15591		if (*tv == NULL) {
15592			*tv = &sna->timer_tv;
15593			goto set_tv;
15594		}
15595		if ((*tv)->tv_sec * 1000 + (*tv)->tv_usec / 1000 > timeout) {
15596set_tv:
15597			(*tv)->tv_sec = timeout / 1000;
15598			(*tv)->tv_usec = timeout % 1000 * 1000;
15599		}
15600	}
15601
15602	sna->kgem.scanout_busy = false;
15603
15604	if (FAULT_INJECTION && (rand() % FAULT_INJECTION) == 0) {
15605		ErrorF("%s hardware acceleration\n",
15606		       sna->kgem.wedged ? "Re-enabling" : "Disabling");
15607		kgem_submit(&sna->kgem);
15608		sna->kgem.wedged = !sna->kgem.wedged;
15609	}
15610}
15611
15612void sna_accel_wakeup_handler(struct sna *sna)
15613{
15614	DBG(("%s: nbatch=%d, need_retire=%d, need_purge=%d\n", __FUNCTION__,
15615	     sna->kgem.nbatch, sna->kgem.need_retire, sna->kgem.need_purge));
15616
15617	if (!sna->kgem.nbatch)
15618		return;
15619
15620	if (kgem_is_idle(&sna->kgem)) {
15621		DBG(("%s: GPU idle, flushing\n", __FUNCTION__));
15622		_kgem_submit(&sna->kgem);
15623	}
15624}
15625
15626void sna_accel_free(struct sna *sna)
15627{
15628	DBG(("%s\n", __FUNCTION__));
15629}
15630